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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1996, by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 #ident "%Z%%M% %I% %E% SMI" /* from S5R3.1 1.10 */ 32 33 #include <stdio.h> 34 #include <sys/param.h> 35 #include "sed.h" 36 #define NWFILES 11 /* 10 plus one for standard output */ 37 FILE *fin; 38 FILE *fcode[NWFILES]; 39 char *lastre; 40 char sseof; 41 union reptr *ptrend; 42 int eflag; 43 extern nbra; 44 char linebuf[LBSIZE+1]; 45 int gflag; 46 int nlno; 47 char *fname[NWFILES]; 48 int nfiles; 49 union reptr ptrspace[PTRSIZE]; 50 union reptr *rep; 51 char *cp; 52 char respace[RESIZE]; 53 struct label ltab[LABSIZE]; 54 struct label *lab; 55 struct label *labend; 56 int depth; 57 int eargc; 58 char **eargv; 59 union reptr **cmpend[DEPTH]; 60 61 #define CCEOF 22 62 63 struct label *labtab = ltab; 64 65 char ETMES[] = "Extra text at end of command: %s"; 66 char SMMES[] = "Space missing before filename: %s"; 67 char TMMES[] = "Too much command text: %s"; 68 char LTL[] = "Label too long: %s"; 69 char AD0MES[] = "No addresses allowed: %s"; 70 char AD1MES[] = "Only one address allowed: %s"; 71 char TOOBIG[] = "Suffix too large - 512 max: %s"; 72 73 extern sed; /* IMPORTANT flag !!! */ 74 extern char *comple(); 75 76 extern char *malloc(); 77 78 main(argc, argv) 79 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 exit(0); 171 /*NOTREACHED*/ 172 } 173 174 fcomp() 175 { 176 177 register 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[8])) 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[8])) 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 char *compsub(rhsbuf) 576 char *rhsbuf; 577 { 578 register 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 rline(lbuf, lbend) 607 char *lbuf; 608 char *lbend; 609 { 610 register char *p, *q; 611 register t; 612 static char *saveq; 613 614 p = lbuf; 615 616 if(eflag) { 617 if(eflag > 0) { 618 eflag = -1; 619 if(--eargc <= 0) 620 exit(2); 621 q = *++eargv; 622 while((t = *q++) != '\0') { 623 if(t == '\n') { 624 saveq = q; 625 goto out1; 626 } 627 if (p < lbend) 628 *p++ = t; 629 if(t == '\\') { 630 if((t = *q++) == '\0') { 631 saveq = 0; 632 return(-1); 633 } 634 if (p < lbend) 635 *p++ = t; 636 } 637 } 638 saveq = 0; 639 640 out1: 641 if (p == lbend) 642 comperr("Command line too long"); 643 *p = '\0'; 644 return(1); 645 } 646 if((q = saveq) == 0) return(-1); 647 648 while((t = *q++) != '\0') { 649 if(t == '\n') { 650 saveq = q; 651 goto out2; 652 } 653 if(p < lbend) 654 *p++ = t; 655 if(t == '\\') { 656 if((t = *q++) == '\0') { 657 saveq = 0; 658 return(-1); 659 } 660 if (p < lbend) 661 *p++ = t; 662 } 663 } 664 saveq = 0; 665 666 out2: 667 if (p == lbend) 668 comperr("Command line too long"); 669 *p = '\0'; 670 return(1); 671 } 672 673 while((t = getc(fin)) != EOF) { 674 if(t == '\n') { 675 if (p == lbend) 676 comperr("Command line too long"); 677 *p = '\0'; 678 return(1); 679 } 680 if (p < lbend) 681 *p++ = t; 682 if(t == '\\') { 683 if((t = getc(fin)) == EOF) 684 break; 685 if(p < lbend) 686 *p++ = t; 687 } 688 } 689 if(ferror(fin)) { 690 perror("sed: Error reading pattern file"); 691 exit(2); 692 } 693 return(-1); 694 } 695 696 char *address(expbuf) 697 char *expbuf; 698 { 699 register char *rcp; 700 long long lno; 701 702 if(*cp == '$') { 703 if (expbuf > &respace[RESIZE-2]) 704 comperr(TMMES); 705 cp++; 706 *expbuf++ = CEND; 707 *expbuf++ = CCEOF; 708 return(expbuf); 709 } 710 if (*cp == '/' || *cp == '\\' ) { 711 if ( *cp == '\\' ) 712 cp++; 713 sseof = *cp++; 714 return(comple((char *) 0, expbuf, &respace[RESIZE-1], sseof)); 715 } 716 717 rcp = cp; 718 lno = 0; 719 720 while(*rcp >= '0' && *rcp <= '9') 721 lno = lno*10 + *rcp++ - '0'; 722 723 if(rcp > cp) { 724 if (expbuf > &respace[RESIZE-3]) 725 comperr(TMMES); 726 *expbuf++ = CLNUM; 727 *expbuf++ = nlno; 728 tlno[nlno++] = lno; 729 if(nlno >= NLINES) 730 comperr("Too many line numbers: %s"); 731 *expbuf++ = CCEOF; 732 cp = rcp; 733 return(expbuf); 734 } 735 return(0); 736 } 737 738 char *text(textbuf, tbend) 739 char *textbuf; 740 char *tbend; 741 { 742 register char *p, *q; 743 744 p = textbuf; 745 q = cp; 746 #ifndef S5EMUL 747 /* 748 * Strip off indentation from text to be inserted. 749 */ 750 while(*q == '\t' || *q == ' ') q++; 751 #endif 752 for(;;) { 753 754 if(p > tbend) 755 return(NULL); /* overflowed the buffer */ 756 if((*p = *q++) == '\\') 757 *p = *q++; 758 if(*p == '\0') { 759 cp = --q; 760 return(++p); 761 } 762 #ifndef S5EMUL 763 /* 764 * Strip off indentation from text to be inserted. 765 */ 766 if(*p == '\n') { 767 while(*q == '\t' || *q == ' ') q++; 768 } 769 #endif 770 p++; 771 } 772 } 773 774 775 struct label *search(ptr) 776 struct label *ptr; 777 { 778 struct label *rp; 779 780 rp = labtab; 781 while(rp < ptr) { 782 if(strcmp(rp->asc, ptr->asc) == 0) 783 return(rp); 784 rp++; 785 } 786 787 return(0); 788 } 789 790 791 dechain() 792 { 793 struct label *lptr; 794 union reptr *rptr, *trptr; 795 796 for(lptr = labtab; lptr < lab; lptr++) { 797 798 if(lptr->address == 0) { 799 (void) fprintf(stderr, "sed: Undefined label: %s\n", lptr->asc); 800 exit(2); 801 } 802 803 if(lptr->chain) { 804 rptr = lptr->chain; 805 while(trptr = rptr->r2.lb1) { 806 rptr->r2.lb1 = lptr->address; 807 rptr = trptr; 808 } 809 rptr->r2.lb1 = lptr->address; 810 } 811 } 812 } 813 814 char *ycomp(expbuf) 815 char *expbuf; 816 { 817 register char c; 818 register char *ep, *tsp; 819 register int i; 820 char *sp; 821 822 ep = expbuf; 823 if(ep + 0377 > &respace[RESIZE-1]) 824 comperr(TMMES); 825 sp = cp; 826 for(tsp = cp; (c = *tsp) != sseof; tsp++) { 827 if(c == '\\') 828 tsp++; 829 if(c == '\0' || c == '\n') 830 comperr("Ending delimiter missing on string: %s"); 831 } 832 tsp++; 833 834 while((c = *sp++) != sseof) { 835 c &= 0377; 836 if(c == '\\' && *sp == 'n') { 837 sp++; 838 c = '\n'; 839 } 840 if((ep[c] = *tsp++) == '\\' && *tsp == 'n') { 841 ep[c] = '\n'; 842 tsp++; 843 } 844 if(ep[c] == sseof || ep[c] == '\0') 845 comperr("Transform strings not the same size: %s"); 846 } 847 if(*tsp != sseof) { 848 if(*tsp == '\0') 849 comperr("Ending delimiter missing on string: %s"); 850 else 851 comperr("Transform strings not the same size: %s"); 852 } 853 cp = ++tsp; 854 855 for(i = 0; i < 0400; i++) 856 if(ep[i] == 0) 857 ep[i] = i; 858 859 return(ep + 0400); 860 } 861 comperr(msg) 862 char *msg; 863 { 864 (void) fprintf(stderr, "sed: "); 865 (void) fprintf(stderr, msg, linebuf); 866 (void) putc('\n', stderr); 867 exit(2); 868 } 869