Home | History | Annotate | Download | only in mod_sed
      1 /*
      2  * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
      3  * Use is subject to license terms.
      4  *
      5  *	Copyright (c) 1984 AT&T
      6  *	  All Rights Reserved
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *  http://www.apache.org/licenses/LICENSE-2.0.
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     16  * or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 #include "apr.h"
     22 #include "apr_lib.h"
     23 #include "libsed.h"
     24 #include "sed.h"
     25 #include "apr_strings.h"
     26 #include "regexp.h"
     27 
     28 char    *trans[040]  = {
     29     "\\01",
     30     "\\02",
     31     "\\03",
     32     "\\04",
     33     "\\05",
     34     "\\06",
     35     "\\07",
     36     "-<",
     37     "->",
     38     "\n",
     39     "\\13",
     40     "\\14",
     41     "\\15",
     42     "\\16",
     43     "\\17",
     44     "\\20",
     45     "\\21",
     46     "\\22",
     47     "\\23",
     48     "\\24",
     49     "\\25",
     50     "\\26",
     51     "\\27",
     52     "\\30",
     53     "\\31",
     54     "\\32",
     55     "\\33",
     56     "\\34",
     57     "\\35",
     58     "\\36",
     59     "\\37"
     60 };
     61 char rub[] = {"\\177"};
     62 
     63 extern int sed_step(char *p1, char *p2, int circf, step_vars_storage *vars);
     64 static int substitute(sed_eval_t *eval, sed_reptr_t *ipc,
     65                       step_vars_storage *step_vars);
     66 static apr_status_t execute(sed_eval_t *eval);
     67 static int match(sed_eval_t *eval, char *expbuf, int gf,
     68                  step_vars_storage *step_vars);
     69 static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
     70                           step_vars_storage *step_vars);
     71 static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2);
     72 static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
     73                             step_vars_storage *step_vars);
     74 static void wline(sed_eval_t *eval, char *buf, int sz);
     75 static void arout(sed_eval_t *eval);
     76 
     77 static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
     78 {
     79     if (eval->errfn && eval->pool) {
     80         va_list args;
     81         const char* error;
     82         va_start(args, fmt);
     83         error = apr_pvsprintf(eval->pool, fmt, args);
     84         eval->errfn(eval->data, error);
     85         va_end(args);
     86     }
     87 }
     88 
     89 #define INIT_BUF_SIZE 1024
     90 
     91 /*
     92  * grow_buffer
     93  */
     94 static void grow_buffer(apr_pool_t *pool, char **buffer,
     95                         char **spend, unsigned int *cursize,
     96                         unsigned int newsize)
     97 {
     98     char* newbuffer = NULL;
     99     int spendsize = 0;
    100     if (*cursize >= newsize)
    101         return;
    102     /* Align it to 4 KB boundary */
    103     newsize = (newsize  + ((1 << 12) - 1)) & ~((1 << 12) -1);
    104     newbuffer = apr_pcalloc(pool, newsize);
    105     if (*spend && *buffer && (*cursize > 0)) {
    106         spendsize = *spend - *buffer;
    107     }
    108     if ((*cursize > 0) && *buffer) {
    109         memcpy(newbuffer, *buffer, *cursize);
    110     }
    111     *buffer = newbuffer;
    112     *cursize = newsize;
    113     if (spend != buffer) {
    114         *spend = *buffer + spendsize;
    115     }
    116 }
    117 
    118 /*
    119  * grow_line_buffer
    120  */
    121 static void grow_line_buffer(sed_eval_t *eval, int newsize)
    122 {
    123     grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
    124                 &eval->lsize, newsize);
    125 }
    126 
    127 /*
    128  * grow_hold_buffer
    129  */
    130 static void grow_hold_buffer(sed_eval_t *eval, int newsize)
    131 {
    132     grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
    133                 &eval->hsize, newsize);
    134 }
    135 
    136 /*
    137  * grow_gen_buffer
    138  */
    139 static void grow_gen_buffer(sed_eval_t *eval, int newsize,
    140                             char **gspend)
    141 {
    142     if (gspend == NULL) {
    143         gspend = &eval->genbuf;
    144     }
    145     grow_buffer(eval->pool, &eval->genbuf, gspend,
    146                 &eval->gsize, newsize);
    147     eval->lcomend = &eval->genbuf[71];
    148 }
    149 
    150 /*
    151  * appendmem_to_linebuf
    152  */
    153 static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
    154 {
    155     unsigned int reqsize = (eval->lspend - eval->linebuf) + len;
    156     if (eval->lsize < reqsize) {
    157         grow_line_buffer(eval, reqsize);
    158     }
    159     memcpy(eval->lspend, sz, len);
    160     eval->lspend += len;
    161 }
    162 
    163 /*
    164  * append_to_linebuf
    165  */
    166 static void append_to_linebuf(sed_eval_t *eval, const char* sz)
    167 {
    168     int len = strlen(sz);
    169     /* Copy string including null character */
    170     appendmem_to_linebuf(eval, sz, len + 1);
    171     --eval->lspend; /* lspend will now point to NULL character */
    172 }
    173 
    174 /*
    175  * copy_to_linebuf
    176  */
    177 static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
    178 {
    179     eval->lspend = eval->linebuf;
    180     append_to_linebuf(eval, sz);
    181 }
    182 
    183 /*
    184  * append_to_holdbuf
    185  */
    186 static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
    187 {
    188     int len = strlen(sz);
    189     unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1;
    190     if (eval->hsize <= reqsize) {
    191         grow_hold_buffer(eval, reqsize);
    192     }
    193     strcpy(eval->hspend, sz);
    194     /* hspend will now point to NULL character */
    195     eval->hspend += len;
    196 }
    197 
    198 /*
    199  * copy_to_holdbuf
    200  */
    201 static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
    202 {
    203     eval->hspend = eval->holdbuf;
    204     append_to_holdbuf(eval, sz);
    205 }
    206 
    207 /*
    208  * append_to_genbuf
    209  */
    210 static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
    211 {
    212     int len = strlen(sz);
    213     unsigned int reqsize = (*gspend - eval->genbuf) + len + 1;
    214     if (eval->gsize < reqsize) {
    215         grow_gen_buffer(eval, reqsize, gspend);
    216     }
    217     strcpy(*gspend, sz);
    218     /* *gspend will now point to NULL character */
    219     *gspend += len;
    220 }
    221 
    222 /*
    223  * copy_to_genbuf
    224  */
    225 static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
    226 {
    227     int len = strlen(sz);
    228     unsigned int reqsize = len + 1;
    229     if (eval->gsize < reqsize) {
    230         grow_gen_buffer(eval, reqsize, NULL);
    231     }
    232 }
    233 
    234 /*
    235  * sed_init_eval
    236  */
    237 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)
    238 {
    239     memset(eval, 0, sizeof(*eval));
    240     eval->pool = p;
    241     eval->writefn = writefn;
    242     return sed_reset_eval(eval, commands, errfn, data);
    243 }
    244 
    245 /*
    246  * sed_reset_eval
    247  */
    248 apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data)
    249 {
    250     int i;
    251 
    252     eval->errfn = errfn;
    253     eval->data = data;
    254 
    255     eval->commands = commands;
    256 
    257     eval->lnum = 0;
    258     eval->fout = NULL;
    259 
    260     if (eval->linebuf == NULL) {
    261         eval->lsize = INIT_BUF_SIZE;
    262         eval->linebuf = apr_pcalloc(eval->pool, eval->lsize);
    263     }
    264     if (eval->holdbuf == NULL) {
    265         eval->hsize = INIT_BUF_SIZE;
    266         eval->holdbuf = apr_pcalloc(eval->pool, eval->hsize);
    267     }
    268     if (eval->genbuf == NULL) {
    269         eval->gsize = INIT_BUF_SIZE;
    270         eval->genbuf = apr_pcalloc(eval->pool, eval->gsize);
    271     }
    272     eval->lspend = eval->linebuf;
    273     eval->hspend = eval->holdbuf;
    274     eval->lcomend = &eval->genbuf[71];
    275 
    276     for (i = 0; i < sizeof(eval->abuf) / sizeof(eval->abuf[0]); i++)
    277         eval->abuf[i] = NULL;
    278     eval->aptr = eval->abuf;
    279     eval->pending = NULL;
    280     eval->inar = apr_pcalloc(eval->pool, commands->nrep * sizeof(unsigned char));
    281     eval->nrep = commands->nrep;
    282 
    283     eval->dolflag = 0;
    284     eval->sflag = 0;
    285     eval->jflag = 0;
    286     eval->delflag = 0;
    287     eval->lreadyflag = 0;
    288     eval->quitflag = 0;
    289     eval->finalflag = 1; /* assume we're evaluating only one file/stream */
    290     eval->numpass = 0;
    291     eval->nullmatch = 0;
    292     eval->col = 0;
    293 
    294     for (i = 0; i < commands->nfiles; i++) {
    295         const char* filename = commands->fname[i];
    296         if (apr_file_open(&eval->fcode[i], filename,
    297                           APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
    298                           eval->pool) != APR_SUCCESS) {
    299             eval_errf(eval, SEDERR_COMES, filename);
    300             return APR_EGENERAL;
    301         }
    302     }
    303 
    304     return APR_SUCCESS;
    305 }
    306 
    307 /*
    308  * sed_destroy_eval
    309  */
    310 void sed_destroy_eval(sed_eval_t *eval)
    311 {
    312     int i;
    313     /* eval->linebuf, eval->holdbuf, eval->genbuf and eval->inar are allocated
    314      * on pool. It will be freed when pool will be freed */
    315     for (i = 0; i < eval->commands->nfiles; i++) {
    316         if (eval->fcode[i] != NULL) {
    317             apr_file_close(eval->fcode[i]);
    318             eval->fcode[i] = NULL;
    319         }
    320     }
    321 }
    322 
    323 /*
    324  * sed_eval_file
    325  */
    326 apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout)
    327 {
    328     for (;;) {
    329         char buf[1024];
    330         apr_size_t read_bytes = 0;
    331 
    332         read_bytes = sizeof(buf);
    333         if (apr_file_read(fin, buf, &read_bytes) != APR_SUCCESS)
    334             break;
    335 
    336         if (sed_eval_buffer(eval, buf, read_bytes, fout) != APR_SUCCESS)
    337             return APR_EGENERAL;
    338 
    339         if (eval->quitflag)
    340             return APR_SUCCESS;
    341     }
    342 
    343     return sed_finalize_eval(eval, fout);
    344 }
    345 
    346 /*
    347  * sed_eval_buffer
    348  */
    349 apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout)
    350 {
    351     apr_status_t rv;
    352 
    353     if (eval->quitflag)
    354         return APR_SUCCESS;
    355 
    356     if (!sed_canbe_finalized(eval->commands)) {
    357         /* Commands were not finalized properly. */
    358         const char* error = sed_get_finalize_error(eval->commands, eval->pool);
    359         if (error) {
    360             eval_errf(eval, error);
    361             return APR_EGENERAL;
    362         }
    363     }
    364 
    365     eval->fout = fout;
    366 
    367     /* Process leftovers */
    368     if (bufsz && eval->lreadyflag) {
    369         eval->lreadyflag = 0;
    370         eval->lspend--;
    371         *eval->lspend = '\0';
    372         rv = execute(eval);
    373         if (rv != 0)
    374             return APR_EGENERAL;
    375     }
    376 
    377     while (bufsz) {
    378         char *n;
    379         int llen;
    380 
    381         n = memchr(buf, '\n', bufsz);
    382         if (n == NULL)
    383             break;
    384 
    385         llen = n - buf;
    386         if (llen == bufsz - 1) {
    387             /* This might be the last line; delay its processing */
    388             eval->lreadyflag = 1;
    389             break;
    390         }
    391 
    392         appendmem_to_linebuf(eval, buf, llen + 1);
    393         --eval->lspend;
    394         /* replace new line character with NULL */
    395         *eval->lspend = '\0';
    396         buf += (llen + 1);
    397         bufsz -= (llen + 1);
    398         rv = execute(eval);
    399         if (rv != 0)
    400             return APR_EGENERAL;
    401         if (eval->quitflag)
    402             break;
    403     }
    404 
    405     /* Save the leftovers for later */
    406     if (bufsz) {
    407         appendmem_to_linebuf(eval, buf, bufsz);
    408     }
    409 
    410     return APR_SUCCESS;
    411 }
    412 
    413 /*
    414  * sed_finalize_eval
    415  */
    416 apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
    417 {
    418     if (eval->quitflag)
    419         return APR_SUCCESS;
    420 
    421     if (eval->finalflag)
    422         eval->dolflag = 1;
    423 
    424     eval->fout = fout;
    425 
    426     /* Process leftovers */
    427     if (eval->lspend > eval->linebuf) {
    428         apr_status_t rv;
    429 
    430         if (eval->lreadyflag) {
    431             eval->lreadyflag = 0;
    432             eval->lspend--;
    433         } else {
    434             /* Code can probably reach here when last character in output
    435              * buffer is not a newline.
    436              */
    437             /* Assure space for NULL */
    438             append_to_linebuf(eval, "");
    439         }
    440 
    441         *eval->lspend = '\0';
    442         rv = execute(eval);
    443         if (rv != 0)
    444             return APR_EGENERAL;
    445     }
    446 
    447     eval->quitflag = 1;
    448 
    449     return APR_SUCCESS;
    450 }
    451 
    452 /*
    453  * execute
    454  */
    455 static apr_status_t execute(sed_eval_t *eval)
    456 {
    457     sed_reptr_t *ipc = eval->commands->ptrspace;
    458     step_vars_storage step_vars;
    459 
    460     eval->lnum++;
    461 
    462     eval->sflag = 0;
    463 
    464     if (eval->pending) {
    465         ipc = eval->pending;
    466         eval->pending = NULL;
    467     }
    468 
    469     memset(&step_vars, 0, sizeof(step_vars));
    470 
    471     while (ipc->command) {
    472         char *p1;
    473         char *p2;
    474         apr_status_t rv;
    475         int c;
    476 
    477         p1 = ipc->ad1;
    478         p2 = ipc->ad2;
    479 
    480         if (p1) {
    481 
    482             if (eval->inar[ipc->nrep]) {
    483                 if (*p2 == CEND) {
    484                     p1 = 0;
    485                 } else if (*p2 == CLNUM) {
    486                     c = (unsigned char)p2[1];
    487                     if (eval->lnum > eval->commands->tlno[c]) {
    488                         eval->inar[ipc->nrep] = 0;
    489                         if (ipc->negfl)
    490                             goto yes;
    491                         ipc = ipc->next;
    492                         continue;
    493                     }
    494                     if (eval->lnum == eval->commands->tlno[c]) {
    495                         eval->inar[ipc->nrep] = 0;
    496                     }
    497                 } else if (match(eval, p2, 0, &step_vars)) {
    498                     eval->inar[ipc->nrep] = 0;
    499                 }
    500             } else if (*p1 == CEND) {
    501                 if (!eval->dolflag) {
    502                     if (ipc->negfl)
    503                         goto yes;
    504                     ipc = ipc->next;
    505                     continue;
    506                 }
    507             } else if (*p1 == CLNUM) {
    508                 c = (unsigned char)p1[1];
    509                 if (eval->lnum != eval->commands->tlno[c]) {
    510                     if (ipc->negfl)
    511                         goto yes;
    512                     ipc = ipc->next;
    513                     continue;
    514                 }
    515                 if (p2)
    516                     eval->inar[ipc->nrep] = 1;
    517             } else if (match(eval, p1, 0, &step_vars)) {
    518                 if (p2)
    519                     eval->inar[ipc->nrep] = 1;
    520             } else {
    521                 if (ipc->negfl)
    522                     goto yes;
    523                 ipc = ipc->next;
    524                 continue;
    525             }
    526         }
    527 
    528         if (ipc->negfl) {
    529             ipc = ipc->next;
    530             continue;
    531         }
    532 
    533 yes:
    534         rv = command(eval, ipc, &step_vars);
    535         if (rv != APR_SUCCESS)
    536             return rv;
    537 
    538         if (eval->quitflag)
    539             return APR_SUCCESS;
    540 
    541         if (eval->pending)
    542             return APR_SUCCESS;
    543 
    544         if (eval->delflag)
    545             break;
    546 
    547         if (eval->jflag) {
    548             eval->jflag = 0;
    549             if ((ipc = ipc->lb1) == 0) {
    550                 ipc = eval->commands->ptrspace;
    551                 break;
    552             }
    553         } else
    554             ipc = ipc->next;
    555     }
    556 
    557     if (!eval->commands->nflag && !eval->delflag)
    558         wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
    559 
    560     if (eval->aptr > eval->abuf)
    561         arout(eval);
    562 
    563     eval->delflag = 0;
    564 
    565     eval->lspend = eval->linebuf;
    566 
    567     return APR_SUCCESS;
    568 }
    569 
    570 /*
    571  * match
    572  */
    573 static int match(sed_eval_t *eval, char *expbuf, int gf,
    574                  step_vars_storage *step_vars)
    575 {
    576     char   *p1;
    577     int circf;
    578 
    579     if(gf) {
    580         if(*expbuf)    return(0);
    581         step_vars->locs = p1 = step_vars->loc2;
    582     } else {
    583         p1 = eval->linebuf;
    584         step_vars->locs = 0;
    585     }
    586 
    587     circf = *expbuf++;
    588     return(sed_step(p1, expbuf, circf, step_vars));
    589 }
    590 
    591 /*
    592  * substitute
    593  */
    594 static int substitute(sed_eval_t *eval, sed_reptr_t *ipc,
    595                       step_vars_storage *step_vars)
    596 {
    597     if(match(eval, ipc->re1, 0, step_vars) == 0)    return(0);
    598 
    599     eval->numpass = 0;
    600     eval->sflag = 0;        /* Flags if any substitution was made */
    601     if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS)
    602         return -1;
    603 
    604     if(ipc->gfl) {
    605         while(*step_vars->loc2) {
    606             if(match(eval, ipc->re1, 1, step_vars) == 0) break;
    607             if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS)
    608                 return -1;
    609         }
    610     }
    611     return(eval->sflag);
    612 }
    613 
    614 /*
    615  * dosub
    616  */
    617 static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
    618                           step_vars_storage *step_vars)
    619 {
    620     char *lp, *sp, *rp;
    621     int c;
    622     apr_status_t rv = APR_SUCCESS;
    623 
    624     if(n > 0 && n < 999) {
    625         eval->numpass++;
    626         if(n != eval->numpass) return APR_SUCCESS;
    627     }
    628     eval->sflag = 1;
    629     lp = eval->linebuf;
    630     sp = eval->genbuf;
    631     rp = rhsbuf;
    632     sp = place(eval, sp, lp, step_vars->loc1);
    633     while ((c = *rp++) != 0) {
    634         if (c == '&') {
    635             sp = place(eval, sp, step_vars->loc1, step_vars->loc2);
    636             if (sp == NULL)
    637                 return APR_EGENERAL;
    638         }
    639         else if (c == '\\') {
    640             c = *rp++;
    641             if (c >= '1' && c < NBRA+'1') {
    642                 sp = place(eval, sp, step_vars->braslist[c-'1'],
    643                            step_vars->braelist[c-'1']);
    644                 if (sp == NULL)
    645                     return APR_EGENERAL;
    646             }
    647             else
    648                 *sp++ = c;
    649           } else
    650             *sp++ = c;
    651         if (sp >= eval->genbuf + eval->gsize) {
    652             /* expand genbuf and set the sp appropriately */
    653             grow_gen_buffer(eval, eval->gsize + 1024, &sp);
    654         }
    655     }
    656     lp = step_vars->loc2;
    657     step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
    658     append_to_genbuf(eval, lp, &sp);
    659     copy_to_linebuf(eval, eval->genbuf);
    660     return rv;
    661 }
    662 
    663 /*
    664  * place
    665  */
    666 static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
    667 {
    668     char *sp = asp;
    669     int n = al2 - al1;
    670     unsigned int reqsize = (sp - eval->genbuf) + n + 1;
    671 
    672     if (eval->gsize < reqsize) {
    673         grow_gen_buffer(eval, reqsize, &sp);
    674     }
    675     memcpy(sp, al1, n);
    676     return sp + n;
    677 }
    678 
    679 /*
    680  * command
    681  */
    682 static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
    683                             step_vars_storage *step_vars)
    684 {
    685     int    i;
    686     char   *p1, *p2, *p3;
    687     int length;
    688     char sz[32]; /* 32 bytes enough to store 64 bit integer in decimal */
    689 
    690 
    691     switch(ipc->command) {
    692 
    693         case ACOM:
    694             if(eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
    695                 eval_errf(eval, SEDERR_TMAMES, eval->lnum);
    696             } else {
    697                 *eval->aptr++ = ipc;
    698                 *eval->aptr = NULL;
    699             }
    700             break;
    701 
    702         case CCOM:
    703             eval->delflag = 1;
    704             if(!eval->inar[ipc->nrep] || eval->dolflag) {
    705                 for (p1 = ipc->re1; *p1; p1++)
    706                     ;
    707                 wline(eval, ipc->re1, p1 - ipc->re1);
    708             }
    709             break;
    710         case DCOM:
    711             eval->delflag++;
    712             break;
    713         case CDCOM:
    714             p1 = eval->linebuf;
    715 
    716             while(*p1 != '\n') {
    717                 if(*p1++ == 0) {
    718                     eval->delflag++;
    719                     return APR_SUCCESS;
    720                 }
    721             }
    722 
    723             p1++;
    724             copy_to_linebuf(eval, p1);
    725             eval->jflag++;
    726             break;
    727 
    728         case EQCOM:
    729             length = apr_snprintf(sz, sizeof(sz), "%d", (int) eval->lnum);
    730             wline(eval, sz, length);
    731             break;
    732 
    733         case GCOM:
    734             copy_to_linebuf(eval, eval->holdbuf);
    735             break;
    736 
    737         case CGCOM:
    738             append_to_linebuf(eval, "\n");
    739             append_to_linebuf(eval, eval->holdbuf);
    740             break;
    741 
    742         case HCOM:
    743             copy_to_holdbuf(eval, eval->linebuf);
    744             break;
    745 
    746         case CHCOM:
    747             append_to_holdbuf(eval, "\n");
    748             append_to_holdbuf(eval, eval->linebuf);
    749             break;
    750 
    751         case ICOM:
    752             for (p1 = ipc->re1; *p1; p1++);
    753             wline(eval, ipc->re1, p1 - ipc->re1);
    754             break;
    755 
    756         case BCOM:
    757             eval->jflag = 1;
    758             break;
    759 
    760 
    761         case LCOM:
    762             p1 = eval->linebuf;
    763             p2 = eval->genbuf;
    764             eval->genbuf[72] = 0;
    765             while(*p1)
    766                 if((unsigned char)*p1 >= 040) {
    767                     if(*p1 == 0177) {
    768                         p3 = rub;
    769                         while ((*p2++ = *p3++) != 0)
    770                             if(p2 >= eval->lcomend) {
    771                                 *p2 = '\\';
    772                                 wline(eval, eval->genbuf,
    773                                       strlen(eval->genbuf));
    774                                 p2 = eval->genbuf;
    775                             }
    776                         p2--;
    777                         p1++;
    778                         continue;
    779                     }
    780                     if(!isprint(*p1 & 0377)) {
    781                         *p2++ = '\\';
    782                         if(p2 >= eval->lcomend) {
    783                             *p2 = '\\';
    784                             wline(eval, eval->genbuf, strlen(eval->genbuf));
    785                             p2 = eval->genbuf;
    786                         }
    787                         *p2++ = (*p1 >> 6) + '0';
    788                         if(p2 >= eval->lcomend) {
    789                             *p2 = '\\';
    790                             wline(eval, eval->genbuf, strlen(eval->genbuf));
    791                             p2 = eval->genbuf;
    792                         }
    793                         *p2++ = ((*p1 >> 3) & 07) + '0';
    794                         if(p2 >= eval->lcomend) {
    795                             *p2 = '\\';
    796                             wline(eval, eval->genbuf, strlen(eval->genbuf));
    797                             p2 = eval->genbuf;
    798                         }
    799                         *p2++ = (*p1++ & 07) + '0';
    800                         if(p2 >= eval->lcomend) {
    801                             *p2 = '\\';
    802                             wline(eval, eval->genbuf, strlen(eval->genbuf));
    803                             p2 = eval->genbuf;
    804                         }
    805                     } else {
    806                         *p2++ = *p1++;
    807                         if(p2 >= eval->lcomend) {
    808                             *p2 = '\\';
    809                             wline(eval, eval->genbuf, strlen(eval->genbuf));
    810                             p2 = eval->genbuf;
    811                         }
    812                     }
    813                 } else {
    814                     p3 = trans[(unsigned char)*p1-1];
    815                     while ((*p2++ = *p3++) != 0)
    816                         if(p2 >= eval->lcomend) {
    817                             *p2 = '\\';
    818                             wline(eval, eval->genbuf, strlen(eval->genbuf));
    819                             p2 = eval->genbuf;
    820                         }
    821                     p2--;
    822                     p1++;
    823                 }
    824             *p2 = 0;
    825             wline(eval, eval->genbuf, strlen(eval->genbuf));
    826             break;
    827 
    828         case NCOM:
    829             if(!eval->commands->nflag) {
    830                 wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
    831             }
    832 
    833             if(eval->aptr > eval->abuf)
    834                 arout(eval);
    835             eval->lspend = eval->linebuf;
    836             eval->pending = ipc->next;
    837 
    838             break;
    839         case CNCOM:
    840             if(eval->aptr > eval->abuf)
    841                 arout(eval);
    842             append_to_linebuf(eval, "\n");
    843             eval->pending = ipc->next;
    844             break;
    845 
    846         case PCOM:
    847             wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
    848             break;
    849         case CPCOM:
    850             for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
    851             wline(eval, eval->linebuf, p1 - eval->linebuf);
    852             break;
    853 
    854         case QCOM:
    855             if (!eval->commands->nflag)
    856                 wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
    857 
    858             if(eval->aptr > eval->abuf)
    859                 arout(eval);
    860 
    861             eval->quitflag = 1;
    862             break;
    863         case RCOM:
    864             if(eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
    865                 eval_errf(eval, SEDERR_TMRMES, eval->lnum);
    866             } else {
    867                 *eval->aptr++ = ipc;
    868                 *eval->aptr = NULL;
    869             }
    870             break;
    871 
    872         case SCOM:
    873             i = substitute(eval, ipc, step_vars);
    874             if (i == -1) {
    875                 return APR_EGENERAL;
    876             }
    877             if(ipc->pfl && eval->commands->nflag && i) {
    878                 if(ipc->pfl == 1) {
    879                     wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
    880                 } else {
    881                     for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
    882                     wline(eval, eval->linebuf, p1 - eval->linebuf);
    883                 }
    884             }
    885             if (i && (ipc->findex >= 0) && eval->fcode[ipc->findex])
    886                 apr_file_printf(eval->fcode[ipc->findex], "%s\n",
    887                                 eval->linebuf);
    888             break;
    889 
    890         case TCOM:
    891             if(eval->sflag == 0)  break;
    892             eval->sflag = 0;
    893             eval->jflag = 1;
    894             break;
    895 
    896         case WCOM:
    897             if (ipc->findex >= 0)
    898                 apr_file_printf(eval->fcode[ipc->findex], "%s\n",
    899                                 eval->linebuf);
    900             break;
    901         case XCOM:
    902             copy_to_genbuf(eval, eval->linebuf);
    903             copy_to_linebuf(eval, eval->holdbuf);
    904             copy_to_holdbuf(eval, eval->genbuf);
    905             break;
    906 
    907         case YCOM:
    908             p1 = eval->linebuf;
    909             p2 = ipc->re1;
    910             while((*p1 = p2[(unsigned char)*p1]) != 0)    p1++;
    911             break;
    912     }
    913     return APR_SUCCESS;
    914 }
    915 
    916 /*
    917  * arout
    918  */
    919 static void arout(sed_eval_t *eval)
    920 {
    921     eval->aptr = eval->abuf - 1;
    922     while (*++eval->aptr) {
    923         if ((*eval->aptr)->command == ACOM) {
    924             char *p1;
    925 
    926             for (p1 = (*eval->aptr)->re1; *p1; p1++);
    927             wline(eval, (*eval->aptr)->re1, p1 - (*eval->aptr)->re1);
    928         } else {
    929             apr_file_t *fi = NULL;
    930             char buf[512];
    931             apr_size_t n = sizeof(buf);
    932 
    933             if (apr_file_open(&fi, (*eval->aptr)->re1, APR_READ, 0, eval->pool)
    934                               != APR_SUCCESS)
    935                 continue;
    936             while ((apr_file_read(fi, buf, &n)) == APR_SUCCESS) {
    937                 if (n == 0)
    938                     break;
    939                 eval->writefn(eval->fout, buf, n);
    940                 n = sizeof(buf);
    941             }
    942             apr_file_close(fi);
    943         }
    944     }
    945     eval->aptr = eval->abuf;
    946     *eval->aptr = NULL;
    947 }
    948 
    949 /*
    950  * wline
    951  */
    952 static void wline(sed_eval_t *eval, char *buf, int sz)
    953 {
    954     eval->writefn(eval->fout, buf, sz);
    955     eval->writefn(eval->fout, "\n", 1);
    956 }
    957 
    958