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