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