1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984 AT&T */
27 /* All Rights Reserved */
28
29 #include <stdio.h>
30 #include <sys/param.h>
31 #include "sed.h"
32
33 #define NWFILES 11 /* 10 plus one for standard output */
34 FILE *fin;
35 FILE *fcode[NWFILES];
36 char *lastre;
37 char sseof;
38 union reptr *ptrend;
39 int eflag;
40 extern int nbra;
41 char linebuf[LBSIZE+1];
42 int gflag;
43 int nlno;
44 char *fname[NWFILES];
45 int nfiles;
46 union reptr ptrspace[PTRSIZE];
47 union reptr *rep;
48 char *cp;
49 char respace[RESIZE];
50 struct label ltab[LABSIZE];
51 struct label *lab;
52 struct label *labend;
53 int depth;
54 int eargc;
55 char **eargv;
56 union reptr **cmpend[DEPTH];
57
58 #define CCEOF 22
59
60 struct label *labtab = ltab;
61
62 char ETMES[] = "Extra text at end of command: %s";
63 char SMMES[] = "Space missing before filename: %s";
64 char TMMES[] = "Too much command text: %s";
65 char LTL[] = "Label too long: %s";
66 char AD0MES[] = "No addresses allowed: %s";
67 char AD1MES[] = "Only one address allowed: %s";
68 char TOOBIG[] = "Suffix too large - 512 max: %s";
69
70 extern int sed; /* IMPORTANT flag !!! */
71 extern char *comple();
72
73 extern char *malloc();
74
75 static void dechain(void);
76 static void fcomp(void);
77
78 int
main(int argc,char * argv[])79 main(int argc, char *argv[])
80 {
81 int flag_found = 0;
82
83 sed = 1;
84 eargc = argc;
85 eargv = argv;
86
87 aptr = abuf;
88 lab = labtab + 1; /* 0 reserved for end-pointer */
89 rep = ptrspace;
90 rep->r1.ad1 = respace;
91 lcomend = &genbuf[71];
92 ptrend = &ptrspace[PTRSIZE];
93 labend = &labtab[LABSIZE];
94 lnum = 0;
95 pending = 0;
96 depth = 0;
97 spend = linebuf;
98 hspend = holdsp; /* Avoid "bus error" under "H" cmd. */
99 fcode[0] = stdout;
100 fname[0] = "";
101 nfiles = 1;
102
103 if(eargc == 1)
104 exit(0);
105
106
107 setlocale(LC_ALL, ""); /* get locale environment */
108
109 while (--eargc > 0 && (++eargv)[0][0] == '-')
110 switch (eargv[0][1]) {
111
112 case 'n':
113 nflag++;
114 continue;
115
116 case 'f':
117 flag_found = 1;
118 if(eargc-- <= 0) exit(2);
119
120 if((fin = fopen(*++eargv, "r")) == NULL) {
121 (void) fprintf(stderr, "sed: ");
122 perror(*eargv);
123 exit(2);
124 }
125
126 fcomp();
127 (void) fclose(fin);
128 continue;
129
130 case 'e':
131 flag_found = 1;
132 eflag++;
133 fcomp();
134 eflag = 0;
135 continue;
136
137 case 'g':
138 gflag++;
139 continue;
140
141 default:
142 (void) fprintf(stderr, "sed: Unknown flag: %c\n", eargv[0][1]);
143 exit(2);
144 }
145
146
147 if(rep == ptrspace && !flag_found) {
148 eargv--;
149 eargc++;
150 eflag++;
151 fcomp();
152 eargv++;
153 eargc--;
154 eflag = 0;
155 }
156
157 if(depth)
158 comperr("Too many {'s");
159
160 labtab->address = rep;
161
162 dechain();
163
164 if(eargc <= 0)
165 execute((char *)NULL);
166 else while(--eargc >= 0) {
167 execute(*eargv++);
168 }
169 (void) fclose(stdout);
170 return (0);
171 }
172
173 static void
fcomp(void)174 fcomp(void)
175 {
176
177 char *p, *op, *tp;
178 char *address();
179 union reptr *pt, *pt1;
180 int i, ii;
181 struct label *lpt;
182 char fnamebuf[MAXPATHLEN];
183
184 op = lastre;
185
186 if(rline(linebuf, &linebuf[LBSIZE+1]) < 0) return;
187 if(*linebuf == '#') {
188 if(linebuf[1] == 'n')
189 nflag = 1;
190 }
191 else {
192 cp = linebuf;
193 goto comploop;
194 }
195
196 for(;;) {
197 if(rline(linebuf, &linebuf[LBSIZE+1]) < 0) break;
198
199 cp = linebuf;
200
201 comploop:
202 /* (void) fprintf(stderr, "cp: %s\n", cp); DEBUG */
203 while(*cp == ' ' || *cp == '\t') cp++;
204 if(*cp == '\0' || *cp == '#') continue;
205 if(*cp == ';') {
206 cp++;
207 goto comploop;
208 }
209
210 p = address(rep->r1.ad1);
211
212 if(p == rep->r1.ad1) {
213 if(op)
214 rep->r1.ad1 = op;
215 else
216 comperr("First RE may not be null: %s");
217 } else if(p == 0) {
218 p = rep->r1.ad1;
219 rep->r1.ad1 = 0;
220 } else {
221 op = rep->r1.ad1;
222 if(*cp == ',' || *cp == ';') {
223 cp++;
224 rep->r1.ad2 = p;
225 p = address(rep->r1.ad2);
226 if(p == 0)
227 comperr("Illegal line number: %s");
228 if(p == rep->r1.ad2)
229 rep->r1.ad2 = op;
230 else
231 op = rep->r1.ad2;
232
233 } else
234 rep->r1.ad2 = 0;
235 }
236
237 if(p > &respace[RESIZE-1])
238 comperr(TMMES);
239
240 while(*cp == ' ' || *cp == '\t') cp++;
241
242 swit:
243 switch(*cp++) {
244
245 default:
246 comperr("Unrecognized command: %s");
247
248 case '!':
249 rep->r1.negfl = 1;
250 goto swit;
251
252 case '{':
253 rep->r1.command = BCOM;
254 rep->r1.negfl = !(rep->r1.negfl);
255 cmpend[depth++] = &rep->r2.lb1;
256 if(++rep >= ptrend)
257 comperr("Too many commands: %s");
258 rep->r1.ad1 = p;
259 if(*cp == '\0') continue;
260
261 goto comploop;
262
263 case '}':
264 if(rep->r1.ad1)
265 comperr(AD0MES);
266
267 if(--depth < 0)
268 comperr("Too many }'s");
269 *cmpend[depth] = rep;
270
271 rep->r1.ad1 = p;
272 continue;
273
274 case '=':
275 rep->r1.command = EQCOM;
276 if(rep->r1.ad2)
277 comperr(AD1MES);
278 break;
279
280 case ':':
281 if(rep->r1.ad1)
282 comperr(AD0MES);
283
284 while(*cp++ == ' ');
285 cp--;
286
287
288 tp = lab->asc;
289 while((*tp++ = *cp++))
290 if(tp >= &(lab->asc[9]))
291 comperr(LTL);
292 *--tp = '\0';
293
294 if(lpt = search(lab)) {
295 if(lpt->address)
296 comperr("Duplicate labels: %s");
297 } else {
298 lab->chain = 0;
299 lpt = lab;
300 if(++lab >= labend)
301 comperr("Too many labels: %s");
302 }
303 lpt->address = rep;
304 rep->r1.ad1 = p;
305
306 continue;
307
308 case 'a':
309 rep->r1.command = ACOM;
310 if(rep->r1.ad2)
311 comperr(AD1MES);
312 if(*cp == '\\') cp++;
313 if(*cp++ != '\n')
314 comperr(ETMES);
315 rep->r1.re1 = p;
316 if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
317 comperr(TMMES);
318 break;
319 case 'c':
320 rep->r1.command = CCOM;
321 if(*cp == '\\') cp++;
322 if(*cp++ != ('\n'))
323 comperr(ETMES);
324 rep->r1.re1 = p;
325 if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
326 comperr(TMMES);
327 break;
328 case 'i':
329 rep->r1.command = ICOM;
330 if(rep->r1.ad2)
331 comperr(AD1MES);
332 if(*cp == '\\') cp++;
333 if(*cp++ != ('\n'))
334 comperr(ETMES);
335 rep->r1.re1 = p;
336 if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
337 comperr(TMMES);
338 break;
339
340 case 'g':
341 rep->r1.command = GCOM;
342 break;
343
344 case 'G':
345 rep->r1.command = CGCOM;
346 break;
347
348 case 'h':
349 rep->r1.command = HCOM;
350 break;
351
352 case 'H':
353 rep->r1.command = CHCOM;
354 break;
355
356 case 't':
357 rep->r1.command = TCOM;
358 goto jtcommon;
359
360 case 'b':
361 rep->r1.command = BCOM;
362 jtcommon:
363 while(*cp++ == ' ');
364 cp--;
365
366 if(*cp == '\0') {
367 if(pt = labtab->chain) {
368 while(pt1 = pt->r2.lb1)
369 pt = pt1;
370 pt->r2.lb1 = rep;
371 } else
372 labtab->chain = rep;
373 break;
374 }
375 tp = lab->asc;
376 while((*tp++ = *cp++))
377 if(tp >= &(lab->asc[9]))
378 comperr(LTL);
379 cp--;
380 *--tp = '\0';
381
382 if(lpt = search(lab)) {
383 if(lpt->address) {
384 rep->r2.lb1 = lpt->address;
385 } else {
386 pt = lpt->chain;
387 while(pt1 = pt->r2.lb1)
388 pt = pt1;
389 pt->r2.lb1 = rep;
390 }
391 } else {
392 lab->chain = rep;
393 lab->address = 0;
394 if(++lab >= labend)
395 comperr("Too many labels: %s");
396 }
397 break;
398
399 case 'n':
400 rep->r1.command = NCOM;
401 break;
402
403 case 'N':
404 rep->r1.command = CNCOM;
405 break;
406
407 case 'p':
408 rep->r1.command = PCOM;
409 break;
410
411 case 'P':
412 rep->r1.command = CPCOM;
413 break;
414
415 case 'r':
416 rep->r1.command = RCOM;
417 if(rep->r1.ad2)
418 comperr(AD1MES);
419 if(*cp++ != ' ')
420 comperr(SMMES);
421 rep->r1.re1 = p;
422 if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL)
423 comperr(TMMES);
424 break;
425
426 case 'd':
427 rep->r1.command = DCOM;
428 break;
429
430 case 'D':
431 rep->r1.command = CDCOM;
432 rep->r2.lb1 = ptrspace;
433 break;
434
435 case 'q':
436 rep->r1.command = QCOM;
437 if(rep->r1.ad2)
438 comperr(AD1MES);
439 break;
440
441 case 'l':
442 rep->r1.command = LCOM;
443 break;
444
445 case 's':
446 rep->r1.command = SCOM;
447 sseof = *cp++;
448 rep->r1.re1 = p;
449 p = comple((char *) 0, rep->r1.re1, &respace[RESIZE-1], sseof);
450 if(p == rep->r1.re1) {
451 if(op)
452 rep->r1.re1 = op;
453 else
454 comperr("First RE may not be null: %s");
455 } else
456 op = rep->r1.re1;
457 rep->r1.rhs = p;
458
459 p = compsub(rep->r1.rhs);
460
461 if(*cp == 'g') {
462 cp++;
463 rep->r1.gfl = 999;
464 } else if(gflag)
465 rep->r1.gfl = 999;
466
467 if(*cp >= '1' && *cp <= '9')
468 {i = *cp - '0';
469 cp++;
470 while(1)
471 {ii = *cp;
472 if(ii < '0' || ii > '9') break;
473 i = i*10 + ii - '0';
474 if(i > 512)
475 comperr(TOOBIG);
476 cp++;
477 }
478 rep->r1.gfl = i;
479 }
480
481 if(*cp == 'p') {
482 cp++;
483 rep->r1.pfl = 1;
484 }
485
486 if(*cp == 'P') {
487 cp++;
488 rep->r1.pfl = 2;
489 }
490
491 if(*cp == 'w') {
492 cp++;
493 if(*cp++ != ' ')
494 comperr(SMMES);
495 if (text(fnamebuf, &fnamebuf[MAXPATHLEN]) == NULL)
496 comperr("File name too long: %s");
497 for(i = nfiles - 1; i >= 0; i--)
498 if(strcmp(fnamebuf,fname[i]) == 0) {
499 rep->r1.fcode = fcode[i];
500 goto done;
501 }
502 if(nfiles >= NWFILES)
503 comperr("Too many files in w commands: %s");
504
505 i = strlen(fnamebuf) + 1;
506 if ((fname[nfiles] = malloc((unsigned)i)) == NULL) {
507 (void) fprintf(stderr, "sed: Out of memory\n");
508 exit(2);
509 }
510 (void) strcpy(fname[nfiles], fnamebuf);
511 if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
512 (void) fprintf(stderr, "sed: Cannot open ");
513 perror(fname[nfiles]);
514 exit(2);
515 }
516 fcode[nfiles++] = rep->r1.fcode;
517 }
518 break;
519
520 case 'w':
521 rep->r1.command = WCOM;
522 if(*cp++ != ' ')
523 comperr(SMMES);
524 if (text(fnamebuf, &fnamebuf[MAXPATHLEN]) == NULL)
525 comperr("File name too long: %s");
526 for(i = nfiles - 1; i >= 0; i--)
527 if(strcmp(fnamebuf, fname[i]) == 0) {
528 rep->r1.fcode = fcode[i];
529 goto done;
530 }
531 if(nfiles >= NWFILES)
532 comperr("Too many files in w commands: %s");
533
534 i = strlen(fnamebuf) + 1;
535 if ((fname[nfiles] = malloc((unsigned)i)) == NULL) {
536 (void) fprintf(stderr, "sed: Out of memory\n");
537 exit(2);
538 }
539 (void) strcpy(fname[nfiles], fnamebuf);
540 if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
541 (void) fprintf(stderr, "sed: Cannot create ");
542 perror(fname[nfiles]);
543 exit(2);
544 }
545 fcode[nfiles++] = rep->r1.fcode;
546 break;
547
548 case 'x':
549 rep->r1.command = XCOM;
550 break;
551
552 case 'y':
553 rep->r1.command = YCOM;
554 sseof = *cp++;
555 rep->r1.re1 = p;
556 p = ycomp(rep->r1.re1);
557 break;
558
559 }
560 done:
561 if(++rep >= ptrend)
562 comperr("Too many commands, last: %s");
563
564 rep->r1.ad1 = p;
565
566 if(*cp++ != '\0') {
567 if(cp[-1] == ';')
568 goto comploop;
569 comperr(ETMES);
570 }
571 }
572 rep->r1.command = 0;
573 lastre = op;
574 }
575
compsub(rhsbuf)576 char *compsub(rhsbuf)
577 char *rhsbuf;
578 {
579 char *p, *q;
580
581 p = rhsbuf;
582 q = cp;
583 for(;;) {
584 if(p > &respace[RESIZE-1])
585 comperr(TMMES);
586 if((*p = *q++) == '\\') {
587 p++;
588 if(p > &respace[RESIZE-1])
589 comperr(TMMES);
590 *p = *q++;
591 if(*p > nbra + '0' && *p <= '9')
592 comperr("``\\digit'' out of range: %s");
593 p++;
594 continue;
595 }
596 if(*p == sseof) {
597 *p++ = '\0';
598 cp = q;
599 return(p);
600 }
601 if(*p++ == '\0')
602 comperr("Ending delimiter missing on substitution: %s");
603
604 }
605 }
606
607 int
rline(lbuf,lbend)608 rline(lbuf, lbend)
609 char *lbuf;
610 char *lbend;
611 {
612 char *p, *q;
613 int t;
614 static char *saveq;
615
616 p = lbuf;
617
618 if(eflag) {
619 if(eflag > 0) {
620 eflag = -1;
621 if(--eargc <= 0)
622 exit(2);
623 q = *++eargv;
624 while((t = *q++) != '\0') {
625 if(t == '\n') {
626 saveq = q;
627 goto out1;
628 }
629 if (p < lbend)
630 *p++ = t;
631 if(t == '\\') {
632 if((t = *q++) == '\0') {
633 saveq = 0;
634 return(-1);
635 }
636 if (p < lbend)
637 *p++ = t;
638 }
639 }
640 saveq = 0;
641
642 out1:
643 if (p == lbend)
644 comperr("Command line too long");
645 *p = '\0';
646 return(1);
647 }
648 if((q = saveq) == 0) return(-1);
649
650 while((t = *q++) != '\0') {
651 if(t == '\n') {
652 saveq = q;
653 goto out2;
654 }
655 if(p < lbend)
656 *p++ = t;
657 if(t == '\\') {
658 if((t = *q++) == '\0') {
659 saveq = 0;
660 return(-1);
661 }
662 if (p < lbend)
663 *p++ = t;
664 }
665 }
666 saveq = 0;
667
668 out2:
669 if (p == lbend)
670 comperr("Command line too long");
671 *p = '\0';
672 return(1);
673 }
674
675 while((t = getc(fin)) != EOF) {
676 if(t == '\n') {
677 if (p == lbend)
678 comperr("Command line too long");
679 *p = '\0';
680 return(1);
681 }
682 if (p < lbend)
683 *p++ = t;
684 if(t == '\\') {
685 if((t = getc(fin)) == EOF)
686 break;
687 if(p < lbend)
688 *p++ = t;
689 }
690 }
691 if(ferror(fin)) {
692 perror("sed: Error reading pattern file");
693 exit(2);
694 }
695 return(-1);
696 }
697
address(expbuf)698 char *address(expbuf)
699 char *expbuf;
700 {
701 char *rcp;
702 long long lno;
703
704 if(*cp == '$') {
705 if (expbuf > &respace[RESIZE-2])
706 comperr(TMMES);
707 cp++;
708 *expbuf++ = CEND;
709 *expbuf++ = CCEOF;
710 return(expbuf);
711 }
712 if (*cp == '/' || *cp == '\\' ) {
713 if ( *cp == '\\' )
714 cp++;
715 sseof = *cp++;
716 return(comple((char *) 0, expbuf, &respace[RESIZE-1], sseof));
717 }
718
719 rcp = cp;
720 lno = 0;
721
722 while(*rcp >= '0' && *rcp <= '9')
723 lno = lno*10 + *rcp++ - '0';
724
725 if(rcp > cp) {
726 if (expbuf > &respace[RESIZE-3])
727 comperr(TMMES);
728 *expbuf++ = CLNUM;
729 *expbuf++ = nlno;
730 tlno[nlno++] = lno;
731 if(nlno >= NLINES)
732 comperr("Too many line numbers: %s");
733 *expbuf++ = CCEOF;
734 cp = rcp;
735 return(expbuf);
736 }
737 return(0);
738 }
739
text(textbuf,tbend)740 char *text(textbuf, tbend)
741 char *textbuf;
742 char *tbend;
743 {
744 char *p, *q;
745
746 p = textbuf;
747 q = cp;
748 #ifndef S5EMUL
749 /*
750 * Strip off indentation from text to be inserted.
751 */
752 while(*q == '\t' || *q == ' ') q++;
753 #endif
754 for(;;) {
755
756 if(p > tbend)
757 return(NULL); /* overflowed the buffer */
758 if((*p = *q++) == '\\')
759 *p = *q++;
760 if(*p == '\0') {
761 cp = --q;
762 return(++p);
763 }
764 #ifndef S5EMUL
765 /*
766 * Strip off indentation from text to be inserted.
767 */
768 if(*p == '\n') {
769 while(*q == '\t' || *q == ' ') q++;
770 }
771 #endif
772 p++;
773 }
774 }
775
776
search(ptr)777 struct label *search(ptr)
778 struct label *ptr;
779 {
780 struct label *rp;
781
782 rp = labtab;
783 while(rp < ptr) {
784 if(strcmp(rp->asc, ptr->asc) == 0)
785 return(rp);
786 rp++;
787 }
788
789 return(0);
790 }
791
792
793 static void
dechain(void)794 dechain(void)
795 {
796 struct label *lptr;
797 union reptr *rptr, *trptr;
798
799 for(lptr = labtab; lptr < lab; lptr++) {
800
801 if(lptr->address == 0) {
802 (void) fprintf(stderr, "sed: Undefined label: %s\n", lptr->asc);
803 exit(2);
804 }
805
806 if(lptr->chain) {
807 rptr = lptr->chain;
808 while(trptr = rptr->r2.lb1) {
809 rptr->r2.lb1 = lptr->address;
810 rptr = trptr;
811 }
812 rptr->r2.lb1 = lptr->address;
813 }
814 }
815 }
816
ycomp(expbuf)817 char *ycomp(expbuf)
818 char *expbuf;
819 {
820 char c;
821 char *ep, *tsp;
822 int i;
823 char *sp;
824
825 ep = expbuf;
826 if(ep + 0377 > &respace[RESIZE-1])
827 comperr(TMMES);
828 sp = cp;
829 for(tsp = cp; (c = *tsp) != sseof; tsp++) {
830 if(c == '\\')
831 tsp++;
832 if(c == '\0' || c == '\n')
833 comperr("Ending delimiter missing on string: %s");
834 }
835 tsp++;
836
837 while((c = *sp++) != sseof) {
838 c &= 0377;
839 if(c == '\\' && *sp == 'n') {
840 sp++;
841 c = '\n';
842 }
843 if((ep[c] = *tsp++) == '\\' && *tsp == 'n') {
844 ep[c] = '\n';
845 tsp++;
846 }
847 if(ep[c] == sseof || ep[c] == '\0')
848 comperr("Transform strings not the same size: %s");
849 }
850 if(*tsp != sseof) {
851 if(*tsp == '\0')
852 comperr("Ending delimiter missing on string: %s");
853 else
854 comperr("Transform strings not the same size: %s");
855 }
856 cp = ++tsp;
857
858 for(i = 0; i < 0400; i++)
859 if(ep[i] == 0)
860 ep[i] = i;
861
862 return(ep + 0400);
863 }
864
865 void
comperr(char * msg)866 comperr(char *msg)
867 {
868 (void) fprintf(stderr, "sed: ");
869 (void) fprintf(stderr, msg, linebuf);
870 (void) putc('\n', stderr);
871 exit(2);
872 }
873