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