2 * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Use is subject to license terms.
5 * Copyright (c) 1984 AT&T
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.
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
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
25 #include "apr_strings.h"
28 static const char *const trans[040] = {
61 static const char rub[] = {"\\177"};
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);
77 static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
79 if (eval->errfn && eval->pool) {
83 error = apr_pvsprintf(eval->pool, fmt, args);
84 eval->errfn(eval->data, error);
89 #define INIT_BUF_SIZE 1024
94 static void grow_buffer(apr_pool_t *pool, char **buffer,
95 char **spend, unsigned int *cursize,
98 char* newbuffer = NULL;
100 if (*cursize >= newsize)
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;
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;
114 if ((*cursize > 0) && *buffer) {
115 memcpy(newbuffer, *buffer, *cursize);
119 if (spend != buffer) {
120 *spend = *buffer + spendsize;
127 static void grow_line_buffer(sed_eval_t *eval, int newsize)
129 grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
130 &eval->lsize, newsize);
136 static void grow_hold_buffer(sed_eval_t *eval, int newsize)
138 grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
139 &eval->hsize, newsize);
145 static void grow_gen_buffer(sed_eval_t *eval, int newsize,
148 if (gspend == NULL) {
149 gspend = &eval->genbuf;
151 grow_buffer(eval->pool, &eval->genbuf, gspend,
152 &eval->gsize, newsize);
153 eval->lcomend = &eval->genbuf[71];
157 * appendmem_to_linebuf
159 static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
161 unsigned int reqsize = (eval->lspend - eval->linebuf) + len;
162 if (eval->lsize < reqsize) {
163 grow_line_buffer(eval, reqsize);
165 memcpy(eval->lspend, sz, len);
172 static void append_to_linebuf(sed_eval_t *eval, const char* sz)
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 */
183 static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
185 eval->lspend = eval->linebuf;
186 append_to_linebuf(eval, sz);
192 static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
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);
199 memcpy(eval->hspend, sz, len + 1);
200 /* hspend will now point to NULL character */
207 static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
209 eval->hspend = eval->holdbuf;
210 append_to_holdbuf(eval, sz);
216 static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
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);
223 memcpy(*gspend, sz, len + 1);
224 /* *gspend will now point to NULL character */
231 static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
233 int len = strlen(sz);
234 unsigned int reqsize = len + 1;
235 if (eval->gsize < reqsize) {
236 grow_gen_buffer(eval, reqsize, NULL);
238 memcpy(eval->genbuf, sz, len + 1);
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)
246 memset(eval, 0, sizeof(*eval));
248 eval->writefn = writefn;
249 return sed_reset_eval(eval, commands, errfn, data);
255 apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data)
262 eval->commands = commands;
267 if (eval->linebuf == NULL) {
268 eval->lsize = INIT_BUF_SIZE;
269 eval->linebuf = apr_pcalloc(eval->pool, eval->lsize);
271 if (eval->holdbuf == NULL) {
272 eval->hsize = INIT_BUF_SIZE;
273 eval->holdbuf = apr_pcalloc(eval->pool, eval->hsize);
275 if (eval->genbuf == NULL) {
276 eval->gsize = INIT_BUF_SIZE;
277 eval->genbuf = apr_pcalloc(eval->pool, eval->gsize);
279 eval->lspend = eval->linebuf;
280 eval->hspend = eval->holdbuf;
281 eval->lcomend = &eval->genbuf[71];
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;
294 eval->lreadyflag = 0;
296 eval->finalflag = 1; /* assume we're evaluating only one file/stream */
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);
317 void sed_destroy_eval(sed_eval_t *eval)
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;
333 apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout)
337 apr_size_t read_bytes = 0;
339 read_bytes = sizeof(buf);
340 if (apr_file_read(fin, buf, &read_bytes) != APR_SUCCESS)
343 if (sed_eval_buffer(eval, buf, read_bytes, fout) != APR_SUCCESS)
350 return sed_finalize_eval(eval, fout);
356 apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout)
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);
367 eval_errf(eval, error);
374 /* Process leftovers */
375 if (bufsz && eval->lreadyflag) {
376 eval->lreadyflag = 0;
378 *eval->lspend = '\0';
380 if (rv != APR_SUCCESS)
388 n = memchr(buf, '\n', bufsz);
393 if (llen == bufsz - 1) {
394 /* This might be the last line; delay its processing */
395 eval->lreadyflag = 1;
399 appendmem_to_linebuf(eval, buf, llen + 1);
401 /* replace new line character with NULL */
402 *eval->lspend = '\0';
406 if (rv != APR_SUCCESS)
412 /* Save the leftovers for later */
414 appendmem_to_linebuf(eval, buf, bufsz);
423 apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
433 /* Process leftovers */
434 if (eval->lspend > eval->linebuf) {
437 if (eval->lreadyflag) {
438 eval->lreadyflag = 0;
441 /* Code can probably reach here when last character in output
442 * buffer is not a newline.
444 /* Assure space for NULL */
445 append_to_linebuf(eval, "");
448 *eval->lspend = '\0';
450 if (rv != APR_SUCCESS)
462 static apr_status_t execute(sed_eval_t *eval)
464 sed_reptr_t *ipc = eval->commands->ptrspace;
465 step_vars_storage step_vars;
466 apr_status_t rv = APR_SUCCESS;
474 eval->pending = NULL;
477 memset(&step_vars, 0, sizeof(step_vars));
479 while (ipc->command) {
489 if (eval->inar[ipc->nrep]) {
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;
501 if (eval->lnum == eval->commands->tlno[c]) {
502 eval->inar[ipc->nrep] = 0;
504 } else if (match(eval, p2, 0, &step_vars)) {
505 eval->inar[ipc->nrep] = 0;
507 } else if (*p1 == CEND) {
508 if (!eval->dolflag) {
514 } else if (*p1 == CLNUM) {
515 c = (unsigned char)p1[1];
516 if (eval->lnum != eval->commands->tlno[c]) {
523 eval->inar[ipc->nrep] = 1;
524 } else if (match(eval, p1, 0, &step_vars)) {
526 eval->inar[ipc->nrep] = 1;
541 rv = command(eval, ipc, &step_vars);
542 if (rv != APR_SUCCESS)
556 if ((ipc = ipc->lb1) == 0) {
557 ipc = eval->commands->ptrspace;
564 if (!eval->commands->nflag && !eval->delflag) {
565 rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
566 if (rv != APR_SUCCESS)
570 if (eval->aptr > eval->abuf)
575 eval->lspend = eval->linebuf;
583 static int match(sed_eval_t *eval, char *expbuf, int gf,
584 step_vars_storage *step_vars)
590 if (*expbuf) return(0);
591 step_vars->locs = p1 = step_vars->loc2;
598 return(sed_step(p1, expbuf, circf, step_vars));
604 static int substitute(sed_eval_t *eval, sed_reptr_t *ipc,
605 step_vars_storage *step_vars)
607 if (match(eval, ipc->re1, 0, step_vars) == 0) return(0);
610 eval->sflag = 0; /* Flags if any substitution was made */
611 if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS)
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)
627 static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
628 step_vars_storage *step_vars)
632 apr_status_t rv = APR_SUCCESS;
634 if (n > 0 && n < 999) {
636 if (n != eval->numpass) return APR_SUCCESS;
642 sp = place(eval, sp, lp, step_vars->loc1);
643 while ((c = *rp++) != 0) {
645 sp = place(eval, sp, step_vars->loc1, step_vars->loc2);
649 else if (c == '\\') {
651 if (c >= '1' && c < NBRA+'1') {
652 sp = place(eval, sp, step_vars->braslist[c-'1'],
653 step_vars->braelist[c-'1']);
661 if (sp >= eval->genbuf + eval->gsize) {
662 /* expand genbuf and set the sp appropriately */
663 grow_gen_buffer(eval, eval->gsize + 1024, &sp);
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);
676 static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
680 unsigned int reqsize = (sp - eval->genbuf) + n + 1;
682 if (eval->gsize < reqsize) {
683 grow_gen_buffer(eval, reqsize, &sp);
692 static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
693 step_vars_storage *step_vars)
699 char sz[32]; /* 32 bytes enough to store 64 bit integer in decimal */
700 apr_status_t rv = APR_SUCCESS;
703 switch(ipc->command) {
706 if (eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
707 eval_errf(eval, SEDERR_TMAMES, eval->lnum);
716 if (!eval->inar[ipc->nrep] || eval->dolflag) {
717 for (p1 = ipc->re1; *p1; p1++)
719 rv = wline(eval, ipc->re1, p1 - ipc->re1);
730 while (*p1 != '\n') {
738 copy_to_linebuf(eval, p1);
743 length = apr_snprintf(sz, sizeof(sz), "%d", (int) eval->lnum);
744 rv = wline(eval, sz, length);
748 copy_to_linebuf(eval, eval->holdbuf);
752 append_to_linebuf(eval, "\n");
753 append_to_linebuf(eval, eval->holdbuf);
757 copy_to_holdbuf(eval, eval->linebuf);
761 append_to_holdbuf(eval, "\n");
762 append_to_holdbuf(eval, eval->linebuf);
766 for (p1 = ipc->re1; *p1; p1++);
767 rv = wline(eval, ipc->re1, p1 - ipc->re1);
777 eval->genbuf[72] = 0;
779 if ((unsigned char)*p1 >= 040) {
782 while ((*p2++ = *p3++) != 0)
783 if (p2 >= eval->lcomend) {
785 rv = wline(eval, eval->genbuf,
786 strlen(eval->genbuf));
787 if (rv != APR_SUCCESS)
795 if (!isprint(*p1 & 0377)) {
797 if (p2 >= eval->lcomend) {
799 rv = wline(eval, eval->genbuf,
800 strlen(eval->genbuf));
801 if (rv != APR_SUCCESS)
805 *p2++ = (*p1 >> 6) + '0';
806 if (p2 >= eval->lcomend) {
808 rv = wline(eval, eval->genbuf,
809 strlen(eval->genbuf));
810 if (rv != APR_SUCCESS)
814 *p2++ = ((*p1 >> 3) & 07) + '0';
815 if (p2 >= eval->lcomend) {
817 rv = wline(eval, eval->genbuf,
818 strlen(eval->genbuf));
819 if (rv != APR_SUCCESS)
823 *p2++ = (*p1++ & 07) + '0';
824 if (p2 >= eval->lcomend) {
826 rv = wline(eval, eval->genbuf,
827 strlen(eval->genbuf));
828 if (rv != APR_SUCCESS)
834 if (p2 >= eval->lcomend) {
836 rv = wline(eval, eval->genbuf,
837 strlen(eval->genbuf));
838 if (rv != APR_SUCCESS)
844 p3 = trans[(unsigned char)*p1-1];
845 while ((*p2++ = *p3++) != 0)
846 if (p2 >= eval->lcomend) {
848 rv = wline(eval, eval->genbuf,
849 strlen(eval->genbuf));
850 if (rv != APR_SUCCESS)
859 rv = wline(eval, eval->genbuf, strlen(eval->genbuf));
863 if (!eval->commands->nflag) {
864 rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
865 if (rv != APR_SUCCESS)
869 if (eval->aptr > eval->abuf) {
871 if (rv != APR_SUCCESS)
874 eval->lspend = eval->linebuf;
875 eval->pending = ipc->next;
879 if (eval->aptr > eval->abuf) {
881 if (rv != APR_SUCCESS)
884 append_to_linebuf(eval, "\n");
885 eval->pending = ipc->next;
889 rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
893 for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
894 rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
898 if (!eval->commands->nflag) {
899 rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
900 if (rv != APR_SUCCESS)
904 if (eval->aptr > eval->abuf) {
906 if (rv != APR_SUCCESS)
914 if (eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
915 eval_errf(eval, SEDERR_TMRMES, eval->lnum);
923 i = substitute(eval, ipc, step_vars);
927 if (ipc->pfl && eval->commands->nflag && i) {
929 rv = wline(eval, eval->linebuf, eval->lspend -
931 if (rv != APR_SUCCESS)
934 for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
935 rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
936 if (rv != APR_SUCCESS)
940 if (i && (ipc->findex >= 0) && eval->fcode[ipc->findex])
941 apr_file_printf(eval->fcode[ipc->findex], "%s\n",
946 if (eval->sflag == 0) break;
952 if (ipc->findex >= 0)
953 apr_file_printf(eval->fcode[ipc->findex], "%s\n",
958 copy_to_genbuf(eval, eval->linebuf);
959 copy_to_linebuf(eval, eval->holdbuf);
960 copy_to_holdbuf(eval, eval->genbuf);
966 while ((*p1 = p2[(unsigned char)*p1]) != 0) p1++;
975 static apr_status_t arout(sed_eval_t *eval)
977 apr_status_t rv = APR_SUCCESS;
978 eval->aptr = eval->abuf - 1;
979 while (*++eval->aptr) {
980 if ((*eval->aptr)->command == ACOM) {
983 for (p1 = (*eval->aptr)->re1; *p1; p1++);
984 rv = wline(eval, (*eval->aptr)->re1, p1 - (*eval->aptr)->re1);
985 if (rv != APR_SUCCESS)
988 apr_file_t *fi = NULL;
990 apr_size_t n = sizeof(buf);
992 if (apr_file_open(&fi, (*eval->aptr)->re1, APR_READ, 0, eval->pool)
995 while ((apr_file_read(fi, buf, &n)) == APR_SUCCESS) {
998 rv = eval->writefn(eval->fout, buf, n);
999 if (rv != APR_SUCCESS) {
1008 eval->aptr = eval->abuf;
1016 static apr_status_t wline(sed_eval_t *eval, char *buf, int sz)
1018 apr_status_t rv = APR_SUCCESS;
1019 rv = eval->writefn(eval->fout, buf, sz);
1020 if (rv != APR_SUCCESS)
1022 rv = eval->writefn(eval->fout, "\n", 1);