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