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