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 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 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 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 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 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 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 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 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 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 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