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