| /* |
| * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved. |
| * Use is subject to license terms. |
| * |
| * Copyright (c) 1984 AT&T |
| * All Rights Reserved |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * http://www.apache.org/licenses/LICENSE-2.0. |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "apr.h" |
| #include "apr_lib.h" |
| #include "libsed.h" |
| #include "sed.h" |
| #include "apr_strings.h" |
| #include "regexp.h" |
| |
| static const char *const trans[040] = { |
| "\\01", |
| "\\02", |
| "\\03", |
| "\\04", |
| "\\05", |
| "\\06", |
| "\\07", |
| "\\10", |
| "\\11", |
| "\n", |
| "\\13", |
| "\\14", |
| "\\15", |
| "\\16", |
| "\\17", |
| "\\20", |
| "\\21", |
| "\\22", |
| "\\23", |
| "\\24", |
| "\\25", |
| "\\26", |
| "\\27", |
| "\\30", |
| "\\31", |
| "\\32", |
| "\\33", |
| "\\34", |
| "\\35", |
| "\\36", |
| "\\37" |
| }; |
| static const char rub[] = {"\\177"}; |
| |
| extern int sed_step(char *p1, char *p2, int circf, step_vars_storage *vars); |
| static int substitute(sed_eval_t *eval, sed_reptr_t *ipc, |
| step_vars_storage *step_vars); |
| static apr_status_t execute(sed_eval_t *eval); |
| static int match(sed_eval_t *eval, char *expbuf, int gf, |
| step_vars_storage *step_vars); |
| static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, |
| step_vars_storage *step_vars); |
| static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2); |
| static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, |
| step_vars_storage *step_vars); |
| static apr_status_t wline(sed_eval_t *eval, char *buf, int sz); |
| static apr_status_t arout(sed_eval_t *eval); |
| |
| static void eval_errf(sed_eval_t *eval, const char *fmt, ...) |
| { |
| if (eval->errfn && eval->pool) { |
| va_list args; |
| const char* error; |
| va_start(args, fmt); |
| error = apr_pvsprintf(eval->pool, fmt, args); |
| eval->errfn(eval->data, error); |
| va_end(args); |
| } |
| } |
| |
| #define INIT_BUF_SIZE 1024 |
| |
| /* |
| * grow_buffer |
| */ |
| static void grow_buffer(apr_pool_t *pool, char **buffer, |
| char **spend, unsigned int *cursize, |
| unsigned int newsize) |
| { |
| char* newbuffer = NULL; |
| int spendsize = 0; |
| if (*cursize >= newsize) |
| return; |
| /* Avoid number of times realloc is called. It could cause huge memory |
| * requirement if line size is huge e.g 2 MB */ |
| if (newsize < *cursize * 2) { |
| newsize = *cursize * 2; |
| } |
| |
| /* Align it to 4 KB boundary */ |
| newsize = (newsize + ((1 << 12) - 1)) & ~((1 << 12) - 1); |
| newbuffer = apr_pcalloc(pool, newsize); |
| if (*spend && *buffer && (*cursize > 0)) { |
| spendsize = *spend - *buffer; |
| } |
| if ((*cursize > 0) && *buffer) { |
| memcpy(newbuffer, *buffer, *cursize); |
| } |
| *buffer = newbuffer; |
| *cursize = newsize; |
| if (spend != buffer) { |
| *spend = *buffer + spendsize; |
| } |
| } |
| |
| /* |
| * grow_line_buffer |
| */ |
| static void grow_line_buffer(sed_eval_t *eval, int newsize) |
| { |
| grow_buffer(eval->pool, &eval->linebuf, &eval->lspend, |
| &eval->lsize, newsize); |
| } |
| |
| /* |
| * grow_hold_buffer |
| */ |
| static void grow_hold_buffer(sed_eval_t *eval, int newsize) |
| { |
| grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend, |
| &eval->hsize, newsize); |
| } |
| |
| /* |
| * grow_gen_buffer |
| */ |
| static void grow_gen_buffer(sed_eval_t *eval, int newsize, |
| char **gspend) |
| { |
| if (gspend == NULL) { |
| gspend = &eval->genbuf; |
| } |
| grow_buffer(eval->pool, &eval->genbuf, gspend, |
| &eval->gsize, newsize); |
| eval->lcomend = &eval->genbuf[71]; |
| } |
| |
| /* |
| * appendmem_to_linebuf |
| */ |
| static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len) |
| { |
| unsigned int reqsize = (eval->lspend - eval->linebuf) + len; |
| if (eval->lsize < reqsize) { |
| grow_line_buffer(eval, reqsize); |
| } |
| memcpy(eval->lspend, sz, len); |
| eval->lspend += len; |
| } |
| |
| /* |
| * append_to_linebuf |
| */ |
| static void append_to_linebuf(sed_eval_t *eval, const char* sz) |
| { |
| int len = strlen(sz); |
| /* Copy string including null character */ |
| appendmem_to_linebuf(eval, sz, len + 1); |
| --eval->lspend; /* lspend will now point to NULL character */ |
| } |
| |
| /* |
| * copy_to_linebuf |
| */ |
| static void copy_to_linebuf(sed_eval_t *eval, const char* sz) |
| { |
| eval->lspend = eval->linebuf; |
| append_to_linebuf(eval, sz); |
| } |
| |
| /* |
| * append_to_holdbuf |
| */ |
| static void append_to_holdbuf(sed_eval_t *eval, const char* sz) |
| { |
| int len = strlen(sz); |
| unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1; |
| if (eval->hsize <= reqsize) { |
| grow_hold_buffer(eval, reqsize); |
| } |
| memcpy(eval->hspend, sz, len + 1); |
| /* hspend will now point to NULL character */ |
| eval->hspend += len; |
| } |
| |
| /* |
| * copy_to_holdbuf |
| */ |
| static void copy_to_holdbuf(sed_eval_t *eval, const char* sz) |
| { |
| eval->hspend = eval->holdbuf; |
| append_to_holdbuf(eval, sz); |
| } |
| |
| /* |
| * append_to_genbuf |
| */ |
| static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) |
| { |
| int len = strlen(sz); |
| unsigned int reqsize = (*gspend - eval->genbuf) + len + 1; |
| if (eval->gsize < reqsize) { |
| grow_gen_buffer(eval, reqsize, gspend); |
| } |
| memcpy(*gspend, sz, len + 1); |
| /* *gspend will now point to NULL character */ |
| *gspend += len; |
| } |
| |
| /* |
| * copy_to_genbuf |
| */ |
| static void copy_to_genbuf(sed_eval_t *eval, const char* sz) |
| { |
| int len = strlen(sz); |
| unsigned int reqsize = len + 1; |
| if (eval->gsize < reqsize) { |
| grow_gen_buffer(eval, reqsize, NULL); |
| } |
| memcpy(eval->genbuf, sz, len + 1); |
| } |
| |
| /* |
| * sed_init_eval |
| */ |
| apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data, sed_write_fn_t *writefn, apr_pool_t* p) |
| { |
| memset(eval, 0, sizeof(*eval)); |
| eval->pool = p; |
| eval->writefn = writefn; |
| return sed_reset_eval(eval, commands, errfn, data); |
| } |
| |
| /* |
| * sed_reset_eval |
| */ |
| apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data) |
| { |
| int i; |
| |
| eval->errfn = errfn; |
| eval->data = data; |
| |
| eval->commands = commands; |
| |
| eval->lnum = 0; |
| eval->fout = NULL; |
| |
| if (eval->linebuf == NULL) { |
| eval->lsize = INIT_BUF_SIZE; |
| eval->linebuf = apr_pcalloc(eval->pool, eval->lsize); |
| } |
| if (eval->holdbuf == NULL) { |
| eval->hsize = INIT_BUF_SIZE; |
| eval->holdbuf = apr_pcalloc(eval->pool, eval->hsize); |
| } |
| if (eval->genbuf == NULL) { |
| eval->gsize = INIT_BUF_SIZE; |
| eval->genbuf = apr_pcalloc(eval->pool, eval->gsize); |
| } |
| eval->lspend = eval->linebuf; |
| eval->hspend = eval->holdbuf; |
| eval->lcomend = &eval->genbuf[71]; |
| |
| for (i = 0; i < sizeof(eval->abuf) / sizeof(eval->abuf[0]); i++) |
| eval->abuf[i] = NULL; |
| eval->aptr = eval->abuf; |
| eval->pending = NULL; |
| eval->inar = apr_pcalloc(eval->pool, commands->nrep * sizeof(unsigned char)); |
| eval->nrep = commands->nrep; |
| |
| eval->dolflag = 0; |
| eval->sflag = 0; |
| eval->jflag = 0; |
| eval->delflag = 0; |
| eval->lreadyflag = 0; |
| eval->quitflag = 0; |
| eval->finalflag = 1; /* assume we're evaluating only one file/stream */ |
| eval->numpass = 0; |
| eval->nullmatch = 0; |
| eval->col = 0; |
| |
| for (i = 0; i < commands->nfiles; i++) { |
| const char* filename = commands->fname[i]; |
| if (apr_file_open(&eval->fcode[i], filename, |
| APR_WRITE | APR_CREATE, APR_OS_DEFAULT, |
| eval->pool) != APR_SUCCESS) { |
| eval_errf(eval, SEDERR_COMES, filename); |
| return APR_EGENERAL; |
| } |
| } |
| |
| return APR_SUCCESS; |
| } |
| |
| /* |
| * sed_destroy_eval |
| */ |
| void sed_destroy_eval(sed_eval_t *eval) |
| { |
| int i; |
| /* eval->linebuf, eval->holdbuf, eval->genbuf and eval->inar are allocated |
| * on pool. It will be freed when pool will be freed */ |
| for (i = 0; i < eval->commands->nfiles; i++) { |
| if (eval->fcode[i] != NULL) { |
| apr_file_close(eval->fcode[i]); |
| eval->fcode[i] = NULL; |
| } |
| } |
| } |
| |
| /* |
| * sed_eval_file |
| */ |
| apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout) |
| { |
| for (;;) { |
| char buf[1024]; |
| apr_size_t read_bytes = 0; |
| |
| read_bytes = sizeof(buf); |
| if (apr_file_read(fin, buf, &read_bytes) != APR_SUCCESS) |
| break; |
| |
| if (sed_eval_buffer(eval, buf, read_bytes, fout) != APR_SUCCESS) |
| return APR_EGENERAL; |
| |
| if (eval->quitflag) |
| return APR_SUCCESS; |
| } |
| |
| return sed_finalize_eval(eval, fout); |
| } |
| |
| /* |
| * sed_eval_buffer |
| */ |
| apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout) |
| { |
| apr_status_t rv; |
| |
| if (eval->quitflag) |
| return APR_SUCCESS; |
| |
| if (!sed_canbe_finalized(eval->commands)) { |
| /* Commands were not finalized properly. */ |
| const char* error = sed_get_finalize_error(eval->commands, eval->pool); |
| if (error) { |
| eval_errf(eval, error); |
| return APR_EGENERAL; |
| } |
| } |
| |
| eval->fout = fout; |
| |
| /* Process leftovers */ |
| if (bufsz && eval->lreadyflag) { |
| eval->lreadyflag = 0; |
| eval->lspend--; |
| *eval->lspend = '\0'; |
| rv = execute(eval); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| |
| while (bufsz) { |
| char *n; |
| int llen; |
| |
| n = memchr(buf, '\n', bufsz); |
| if (n == NULL) |
| break; |
| |
| llen = n - buf; |
| if (llen == bufsz - 1) { |
| /* This might be the last line; delay its processing */ |
| eval->lreadyflag = 1; |
| break; |
| } |
| |
| appendmem_to_linebuf(eval, buf, llen + 1); |
| --eval->lspend; |
| /* replace new line character with NULL */ |
| *eval->lspend = '\0'; |
| buf += (llen + 1); |
| bufsz -= (llen + 1); |
| rv = execute(eval); |
| if (rv != APR_SUCCESS) |
| return rv; |
| if (eval->quitflag) |
| break; |
| } |
| |
| /* Save the leftovers for later */ |
| if (bufsz) { |
| appendmem_to_linebuf(eval, buf, bufsz); |
| } |
| |
| return APR_SUCCESS; |
| } |
| |
| /* |
| * sed_finalize_eval |
| */ |
| apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout) |
| { |
| if (eval->quitflag) |
| return APR_SUCCESS; |
| |
| if (eval->finalflag) |
| eval->dolflag = 1; |
| |
| eval->fout = fout; |
| |
| /* Process leftovers */ |
| if (eval->lspend > eval->linebuf) { |
| apr_status_t rv; |
| |
| if (eval->lreadyflag) { |
| eval->lreadyflag = 0; |
| eval->lspend--; |
| } else { |
| /* Code can probably reach here when last character in output |
| * buffer is not a newline. |
| */ |
| /* Assure space for NULL */ |
| append_to_linebuf(eval, ""); |
| } |
| |
| *eval->lspend = '\0'; |
| rv = execute(eval); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| |
| eval->quitflag = 1; |
| |
| return APR_SUCCESS; |
| } |
| |
| /* |
| * execute |
| */ |
| static apr_status_t execute(sed_eval_t *eval) |
| { |
| sed_reptr_t *ipc = eval->commands->ptrspace; |
| step_vars_storage step_vars; |
| apr_status_t rv = APR_SUCCESS; |
| |
| eval->lnum++; |
| |
| eval->sflag = 0; |
| |
| if (eval->pending) { |
| ipc = eval->pending; |
| eval->pending = NULL; |
| } |
| |
| memset(&step_vars, 0, sizeof(step_vars)); |
| |
| while (ipc->command) { |
| char *p1; |
| char *p2; |
| int c; |
| |
| p1 = ipc->ad1; |
| p2 = ipc->ad2; |
| |
| if (p1) { |
| |
| if (eval->inar[ipc->nrep]) { |
| if (*p2 == CEND) { |
| p1 = 0; |
| } else if (*p2 == CLNUM) { |
| c = (unsigned char)p2[1]; |
| if (eval->lnum > eval->commands->tlno[c]) { |
| eval->inar[ipc->nrep] = 0; |
| if (ipc->negfl) |
| goto yes; |
| ipc = ipc->next; |
| continue; |
| } |
| if (eval->lnum == eval->commands->tlno[c]) { |
| eval->inar[ipc->nrep] = 0; |
| } |
| } else if (match(eval, p2, 0, &step_vars)) { |
| eval->inar[ipc->nrep] = 0; |
| } |
| } else if (*p1 == CEND) { |
| if (!eval->dolflag) { |
| if (ipc->negfl) |
| goto yes; |
| ipc = ipc->next; |
| continue; |
| } |
| } else if (*p1 == CLNUM) { |
| c = (unsigned char)p1[1]; |
| if (eval->lnum != eval->commands->tlno[c]) { |
| if (ipc->negfl) |
| goto yes; |
| ipc = ipc->next; |
| continue; |
| } |
| if (p2) |
| eval->inar[ipc->nrep] = 1; |
| } else if (match(eval, p1, 0, &step_vars)) { |
| if (p2) |
| eval->inar[ipc->nrep] = 1; |
| } else { |
| if (ipc->negfl) |
| goto yes; |
| ipc = ipc->next; |
| continue; |
| } |
| } |
| |
| if (ipc->negfl) { |
| ipc = ipc->next; |
| continue; |
| } |
| |
| yes: |
| rv = command(eval, ipc, &step_vars); |
| if (rv != APR_SUCCESS) |
| return rv; |
| |
| if (eval->quitflag) |
| return APR_SUCCESS; |
| |
| if (eval->pending) |
| return APR_SUCCESS; |
| |
| if (eval->delflag) |
| break; |
| |
| if (eval->jflag) { |
| eval->jflag = 0; |
| if ((ipc = ipc->lb1) == 0) { |
| ipc = eval->commands->ptrspace; |
| break; |
| } |
| } else |
| ipc = ipc->next; |
| } |
| |
| if (!eval->commands->nflag && !eval->delflag) { |
| rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| |
| if (eval->aptr > eval->abuf) |
| rv = arout(eval); |
| |
| eval->delflag = 0; |
| |
| eval->lspend = eval->linebuf; |
| |
| return rv; |
| } |
| |
| /* |
| * match |
| */ |
| static int match(sed_eval_t *eval, char *expbuf, int gf, |
| step_vars_storage *step_vars) |
| { |
| char *p1; |
| int circf; |
| |
| if (gf) { |
| if (*expbuf) return(0); |
| step_vars->locs = p1 = step_vars->loc2; |
| } else { |
| p1 = eval->linebuf; |
| step_vars->locs = 0; |
| } |
| |
| circf = *expbuf++; |
| return(sed_step(p1, expbuf, circf, step_vars)); |
| } |
| |
| /* |
| * substitute |
| */ |
| static int substitute(sed_eval_t *eval, sed_reptr_t *ipc, |
| step_vars_storage *step_vars) |
| { |
| if (match(eval, ipc->re1, 0, step_vars) == 0) return(0); |
| |
| eval->numpass = 0; |
| eval->sflag = 0; /* Flags if any substitution was made */ |
| if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS) |
| return -1; |
| |
| if (ipc->gfl) { |
| while (*step_vars->loc2) { |
| if (match(eval, ipc->re1, 1, step_vars) == 0) break; |
| if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS) |
| return -1; |
| } |
| } |
| return(eval->sflag); |
| } |
| |
| /* |
| * dosub |
| */ |
| static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, |
| step_vars_storage *step_vars) |
| { |
| char *lp, *sp, *rp; |
| int c; |
| apr_status_t rv = APR_SUCCESS; |
| |
| if (n > 0 && n < 999) { |
| eval->numpass++; |
| if (n != eval->numpass) return APR_SUCCESS; |
| } |
| eval->sflag = 1; |
| lp = eval->linebuf; |
| sp = eval->genbuf; |
| rp = rhsbuf; |
| sp = place(eval, sp, lp, step_vars->loc1); |
| while ((c = *rp++) != 0) { |
| if (c == '&') { |
| sp = place(eval, sp, step_vars->loc1, step_vars->loc2); |
| if (sp == NULL) |
| return APR_EGENERAL; |
| } |
| else if (c == '\\') { |
| c = *rp++; |
| if (c >= '1' && c < NBRA+'1') { |
| sp = place(eval, sp, step_vars->braslist[c-'1'], |
| step_vars->braelist[c-'1']); |
| if (sp == NULL) |
| return APR_EGENERAL; |
| } |
| else |
| *sp++ = c; |
| } else |
| *sp++ = c; |
| if (sp >= eval->genbuf + eval->gsize) { |
| /* expand genbuf and set the sp appropriately */ |
| grow_gen_buffer(eval, eval->gsize + 1024, &sp); |
| } |
| } |
| lp = step_vars->loc2; |
| step_vars->loc2 = sp - eval->genbuf + eval->linebuf; |
| append_to_genbuf(eval, lp, &sp); |
| copy_to_linebuf(eval, eval->genbuf); |
| return rv; |
| } |
| |
| /* |
| * place |
| */ |
| static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2) |
| { |
| char *sp = asp; |
| int n = al2 - al1; |
| unsigned int reqsize = (sp - eval->genbuf) + n + 1; |
| |
| if (eval->gsize < reqsize) { |
| grow_gen_buffer(eval, reqsize, &sp); |
| } |
| memcpy(sp, al1, n); |
| return sp + n; |
| } |
| |
| /* |
| * command |
| */ |
| static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, |
| step_vars_storage *step_vars) |
| { |
| int i; |
| char *p1, *p2; |
| const char *p3; |
| int length; |
| char sz[32]; /* 32 bytes enough to store 64 bit integer in decimal */ |
| apr_status_t rv = APR_SUCCESS; |
| |
| |
| switch(ipc->command) { |
| |
| case ACOM: |
| if (eval->aptr >= &eval->abuf[SED_ABUFSIZE]) { |
| eval_errf(eval, SEDERR_TMAMES, eval->lnum); |
| } else { |
| *eval->aptr++ = ipc; |
| *eval->aptr = NULL; |
| } |
| break; |
| |
| case CCOM: |
| eval->delflag = 1; |
| if (!eval->inar[ipc->nrep] || eval->dolflag) { |
| for (p1 = ipc->re1; *p1; p1++) |
| ; |
| rv = wline(eval, ipc->re1, p1 - ipc->re1); |
| } |
| break; |
| |
| case DCOM: |
| eval->delflag++; |
| break; |
| |
| case CDCOM: |
| p1 = eval->linebuf; |
| |
| while (*p1 != '\n') { |
| if (*p1++ == 0) { |
| eval->delflag++; |
| return APR_SUCCESS; |
| } |
| } |
| |
| p1++; |
| copy_to_linebuf(eval, p1); |
| eval->jflag++; |
| break; |
| |
| case EQCOM: |
| length = apr_snprintf(sz, sizeof(sz), "%d", (int) eval->lnum); |
| rv = wline(eval, sz, length); |
| break; |
| |
| case GCOM: |
| copy_to_linebuf(eval, eval->holdbuf); |
| break; |
| |
| case CGCOM: |
| append_to_linebuf(eval, "\n"); |
| append_to_linebuf(eval, eval->holdbuf); |
| break; |
| |
| case HCOM: |
| copy_to_holdbuf(eval, eval->linebuf); |
| break; |
| |
| case CHCOM: |
| append_to_holdbuf(eval, "\n"); |
| append_to_holdbuf(eval, eval->linebuf); |
| break; |
| |
| case ICOM: |
| for (p1 = ipc->re1; *p1; p1++); |
| rv = wline(eval, ipc->re1, p1 - ipc->re1); |
| break; |
| |
| case BCOM: |
| eval->jflag = 1; |
| break; |
| |
| case LCOM: |
| p1 = eval->linebuf; |
| p2 = eval->genbuf; |
| eval->genbuf[72] = 0; |
| while (*p1) { |
| if ((unsigned char)*p1 >= 040) { |
| if (*p1 == 0177) { |
| p3 = rub; |
| while ((*p2++ = *p3++) != 0) |
| if (p2 >= eval->lcomend) { |
| *p2 = '\\'; |
| rv = wline(eval, eval->genbuf, |
| strlen(eval->genbuf)); |
| if (rv != APR_SUCCESS) |
| return rv; |
| p2 = eval->genbuf; |
| } |
| p2--; |
| p1++; |
| continue; |
| } |
| if (!isprint(*p1 & 0377)) { |
| *p2++ = '\\'; |
| if (p2 >= eval->lcomend) { |
| *p2 = '\\'; |
| rv = wline(eval, eval->genbuf, |
| strlen(eval->genbuf)); |
| if (rv != APR_SUCCESS) |
| return rv; |
| p2 = eval->genbuf; |
| } |
| *p2++ = (*p1 >> 6) + '0'; |
| if (p2 >= eval->lcomend) { |
| *p2 = '\\'; |
| rv = wline(eval, eval->genbuf, |
| strlen(eval->genbuf)); |
| if (rv != APR_SUCCESS) |
| return rv; |
| p2 = eval->genbuf; |
| } |
| *p2++ = ((*p1 >> 3) & 07) + '0'; |
| if (p2 >= eval->lcomend) { |
| *p2 = '\\'; |
| rv = wline(eval, eval->genbuf, |
| strlen(eval->genbuf)); |
| if (rv != APR_SUCCESS) |
| return rv; |
| p2 = eval->genbuf; |
| } |
| *p2++ = (*p1++ & 07) + '0'; |
| if (p2 >= eval->lcomend) { |
| *p2 = '\\'; |
| rv = wline(eval, eval->genbuf, |
| strlen(eval->genbuf)); |
| if (rv != APR_SUCCESS) |
| return rv; |
| p2 = eval->genbuf; |
| } |
| } else { |
| *p2++ = *p1++; |
| if (p2 >= eval->lcomend) { |
| *p2 = '\\'; |
| rv = wline(eval, eval->genbuf, |
| strlen(eval->genbuf)); |
| if (rv != APR_SUCCESS) |
| return rv; |
| p2 = eval->genbuf; |
| } |
| } |
| } else { |
| p3 = trans[(unsigned char)*p1-1]; |
| while ((*p2++ = *p3++) != 0) |
| if (p2 >= eval->lcomend) { |
| *p2 = '\\'; |
| rv = wline(eval, eval->genbuf, |
| strlen(eval->genbuf)); |
| if (rv != APR_SUCCESS) |
| return rv; |
| p2 = eval->genbuf; |
| } |
| p2--; |
| p1++; |
| } |
| } |
| *p2 = 0; |
| rv = wline(eval, eval->genbuf, strlen(eval->genbuf)); |
| break; |
| |
| case NCOM: |
| if (!eval->commands->nflag) { |
| rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| |
| if (eval->aptr > eval->abuf) { |
| rv = arout(eval); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| eval->lspend = eval->linebuf; |
| eval->pending = ipc->next; |
| break; |
| |
| case CNCOM: |
| if (eval->aptr > eval->abuf) { |
| rv = arout(eval); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| append_to_linebuf(eval, "\n"); |
| eval->pending = ipc->next; |
| break; |
| |
| case PCOM: |
| rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf); |
| break; |
| |
| case CPCOM: |
| for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++); |
| rv = wline(eval, eval->linebuf, p1 - eval->linebuf); |
| break; |
| |
| case QCOM: |
| if (!eval->commands->nflag) { |
| rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf); |
| if (rv != APR_SUCCESS) |
| break; |
| } |
| |
| if (eval->aptr > eval->abuf) { |
| rv = arout(eval); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| |
| eval->quitflag = 1; |
| break; |
| |
| case RCOM: |
| if (eval->aptr >= &eval->abuf[SED_ABUFSIZE]) { |
| eval_errf(eval, SEDERR_TMRMES, eval->lnum); |
| } else { |
| *eval->aptr++ = ipc; |
| *eval->aptr = NULL; |
| } |
| break; |
| |
| case SCOM: |
| i = substitute(eval, ipc, step_vars); |
| if (i == -1) { |
| return APR_EGENERAL; |
| } |
| if (ipc->pfl && eval->commands->nflag && i) { |
| if (ipc->pfl == 1) { |
| rv = wline(eval, eval->linebuf, eval->lspend - |
| eval->linebuf); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } else { |
| for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++); |
| rv = wline(eval, eval->linebuf, p1 - eval->linebuf); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } |
| } |
| if (i && (ipc->findex >= 0) && eval->fcode[ipc->findex]) |
| apr_file_printf(eval->fcode[ipc->findex], "%s\n", |
| eval->linebuf); |
| break; |
| |
| case TCOM: |
| if (eval->sflag == 0) break; |
| eval->sflag = 0; |
| eval->jflag = 1; |
| break; |
| |
| case WCOM: |
| if (ipc->findex >= 0) |
| apr_file_printf(eval->fcode[ipc->findex], "%s\n", |
| eval->linebuf); |
| break; |
| |
| case XCOM: |
| copy_to_genbuf(eval, eval->linebuf); |
| copy_to_linebuf(eval, eval->holdbuf); |
| copy_to_holdbuf(eval, eval->genbuf); |
| break; |
| |
| case YCOM: |
| p1 = eval->linebuf; |
| p2 = ipc->re1; |
| while ((*p1 = p2[(unsigned char)*p1]) != 0) p1++; |
| break; |
| } |
| return rv; |
| } |
| |
| /* |
| * arout |
| */ |
| static apr_status_t arout(sed_eval_t *eval) |
| { |
| apr_status_t rv = APR_SUCCESS; |
| eval->aptr = eval->abuf - 1; |
| while (*++eval->aptr) { |
| if ((*eval->aptr)->command == ACOM) { |
| char *p1; |
| |
| for (p1 = (*eval->aptr)->re1; *p1; p1++); |
| rv = wline(eval, (*eval->aptr)->re1, p1 - (*eval->aptr)->re1); |
| if (rv != APR_SUCCESS) |
| return rv; |
| } else { |
| apr_file_t *fi = NULL; |
| char buf[512]; |
| apr_size_t n = sizeof(buf); |
| |
| if (apr_file_open(&fi, (*eval->aptr)->re1, APR_READ, 0, eval->pool) |
| != APR_SUCCESS) |
| continue; |
| while ((apr_file_read(fi, buf, &n)) == APR_SUCCESS) { |
| if (n == 0) |
| break; |
| rv = eval->writefn(eval->fout, buf, n); |
| if (rv != APR_SUCCESS) { |
| apr_file_close(fi); |
| return rv; |
| } |
| n = sizeof(buf); |
| } |
| apr_file_close(fi); |
| } |
| } |
| eval->aptr = eval->abuf; |
| *eval->aptr = NULL; |
| return rv; |
| } |
| |
| /* |
| * wline |
| */ |
| static apr_status_t wline(sed_eval_t *eval, char *buf, int sz) |
| { |
| apr_status_t rv = APR_SUCCESS; |
| rv = eval->writefn(eval->fout, buf, sz); |
| if (rv != APR_SUCCESS) |
| return rv; |
| rv = eval->writefn(eval->fout, "\n", 1); |
| return rv; |
| } |
| |