1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)ed.c 5.1.1.1 (Berkeley) 12/03/92"; 16 #endif /* not lint */ 17 18 /* 19 * Editor 20 */ 21 #include <sys/param.h> 22 #include <sys/wait.h> 23 #include <signal.h> 24 #include <sgtty.h> 25 #undef CEOF 26 #include <fcntl.h> 27 #include <time.h> 28 #include <setjmp.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include "pathnames.h" 33 34 #define NULL 0 35 #define LBSIZE 512 36 #define ESIZE 128 37 #define GBSIZE 256 38 #define NBRA 5 39 #define EOF -1 40 41 #define CBRA 1 42 #define CCHR 2 43 #define CDOT 4 44 #define CCL 6 45 #define NCCL 8 46 #define CDOL 10 47 #define CEOF 11 48 #define CKET 12 49 #define CBACK 14 50 51 #define STAR 01 52 53 char Q[] = ""; 54 char T[] = "TMP"; 55 #define READ 0 56 #define WRITE 1 57 58 int peekc; 59 int lastc; 60 char savedfile[MAXPATHLEN]; 61 char file[MAXPATHLEN]; 62 char linebuf[LBSIZE]; 63 char rhsbuf[LBSIZE/2]; 64 char expbuf[ESIZE+4]; 65 int circfl; 66 int *zero; 67 int *dot; 68 int *dol; 69 int *addr1; 70 int *addr2; 71 char genbuf[LBSIZE]; 72 long count; 73 char *nextip; 74 char *linebp; 75 int ninbuf; 76 int io; 77 int pflag; 78 sig_t oldhup; 79 sig_t oldquit; 80 int vflag = 1; 81 82 83 int listf; 84 int col; 85 char *globp; 86 int tfile = -1; 87 int tline; 88 char tfname[sizeof(_PATH_TMP) + 20]; 89 char *loc1; 90 char *loc2; 91 char *locs; 92 char ibuff[512]; 93 int iblock = -1; 94 char obuff[512]; 95 int oblock = -1; 96 int ichanged; 97 int nleft; 98 char WRERR[] = "WRITE ERROR"; 99 int names[26]; 100 int anymarks; 101 char *braslist[NBRA]; 102 char *braelist[NBRA]; 103 int nbra; 104 int subnewa; 105 int subolda; 106 int fchange; 107 int wrapp; 108 unsigned nlall = 128; 109 110 int *address(); 111 char *getline(); 112 char *getblock(); 113 char *place(); 114 jmp_buf savej; 115 116 void onintr(), quit(), onhup(); 117 118 main(argc, argv) 119 int argc; 120 char **argv; 121 { 122 register char *p1, *p2; 123 sig_t oldintr; 124 125 oldquit = signal(SIGQUIT, SIG_IGN); 126 oldhup = signal(SIGHUP, SIG_IGN); 127 oldintr = signal(SIGINT, SIG_IGN); 128 if ((int)signal(SIGTERM, SIG_IGN) == 0) 129 signal(SIGTERM, quit); 130 argv++; 131 while (argc > 1 && **argv=='-') { 132 switch((*argv)[1]) { 133 134 case '\0': 135 vflag = 0; 136 break; 137 138 case 'q': 139 signal(SIGQUIT, SIG_DFL); 140 vflag = 1; 141 break; 142 143 } 144 argv++; 145 argc--; 146 } 147 148 if (argc>1) { 149 p1 = *argv; 150 p2 = savedfile; 151 while (*p2++ = *p1++) 152 ; 153 globp = "r"; 154 } 155 zero = (int *)malloc(nlall*sizeof(int)); 156 (void)strcpy(tfname, _PATH_TMP); 157 (void)strcat(tfname, "_edXXXXXX"); 158 (void)mktemp(tfname); 159 init(); 160 if (((int)oldintr&01) == 0) 161 signal(SIGINT, onintr); 162 if (((int)oldhup&01) == 0) 163 signal(SIGHUP, onhup); 164 setjmp(savej); 165 commands(); 166 quit(); 167 } 168 169 commands() 170 { 171 int getfile(), gettty(); 172 register *a1, c; 173 174 for (;;) { 175 if (pflag) { 176 pflag = 0; 177 addr1 = addr2 = dot; 178 goto print; 179 } 180 addr1 = 0; 181 addr2 = 0; 182 do { 183 addr1 = addr2; 184 if ((a1 = address())==0) { 185 c = getchr(); 186 break; 187 } 188 addr2 = a1; 189 if ((c=getchr()) == ';') { 190 c = ','; 191 dot = a1; 192 } 193 } while (c==','); 194 if (addr1==0) 195 addr1 = addr2; 196 switch(c) { 197 198 case 'a': 199 setdot(); 200 newline(); 201 append(gettty, addr2); 202 continue; 203 204 case 'c': 205 delete(); 206 append(gettty, addr1-1); 207 continue; 208 209 case 'd': 210 delete(); 211 continue; 212 213 case 'E': 214 fchange = 0; 215 c = 'e'; 216 case 'e': 217 setnoaddr(); 218 if (vflag && fchange) { 219 fchange = 0; 220 error(Q); 221 } 222 filename(c); 223 init(); 224 addr2 = zero; 225 goto caseread; 226 227 case 'f': 228 setnoaddr(); 229 filename(c); 230 puts(savedfile); 231 continue; 232 233 case 'g': 234 global(1); 235 continue; 236 237 case 'i': 238 setdot(); 239 nonzero(); 240 newline(); 241 append(gettty, addr2-1); 242 continue; 243 244 245 case 'j': 246 if (addr2==0) { 247 addr1 = dot; 248 addr2 = dot+1; 249 } 250 setdot(); 251 newline(); 252 nonzero(); 253 join(); 254 continue; 255 256 case 'k': 257 if ((c = getchr()) < 'a' || c > 'z') 258 error(Q); 259 newline(); 260 setdot(); 261 nonzero(); 262 names[c-'a'] = *addr2 & ~01; 263 anymarks |= 01; 264 continue; 265 266 case 'm': 267 move(0); 268 continue; 269 270 case '\n': 271 if (addr2==0) 272 addr2 = dot+1; 273 addr1 = addr2; 274 goto print; 275 276 case 'l': 277 listf++; 278 case 'p': 279 case 'P': 280 newline(); 281 print: 282 setdot(); 283 nonzero(); 284 a1 = addr1; 285 do { 286 puts(getline(*a1++)); 287 } while (a1 <= addr2); 288 dot = addr2; 289 listf = 0; 290 continue; 291 292 case 'Q': 293 fchange = 0; 294 case 'q': 295 setnoaddr(); 296 newline(); 297 quit(); 298 299 case 'r': 300 filename(c); 301 caseread: 302 if ((io = open(file, 0)) < 0) { 303 lastc = '\n'; 304 error(file); 305 } 306 setall(); 307 ninbuf = 0; 308 c = zero != dol; 309 append(getfile, addr2); 310 exfile(); 311 fchange = c; 312 continue; 313 314 case 's': 315 setdot(); 316 nonzero(); 317 substitute(globp!=0); 318 continue; 319 320 case 't': 321 move(1); 322 continue; 323 324 case 'u': 325 setdot(); 326 nonzero(); 327 newline(); 328 if ((*addr2&~01) != subnewa) 329 error(Q); 330 *addr2 = subolda; 331 dot = addr2; 332 continue; 333 334 case 'v': 335 global(0); 336 continue; 337 338 case 'W': 339 wrapp++; 340 case 'w': 341 setall(); 342 nonzero(); 343 filename(c); 344 if(!wrapp || 345 ((io = open(file,1)) == -1) || 346 ((lseek(io, 0L, 2)) == -1)) 347 if ((io = creat(file, 0666)) < 0) 348 error(file); 349 wrapp = 0; 350 putfile(); 351 exfile(); 352 if (addr1==zero+1 && addr2==dol) 353 fchange = 0; 354 continue; 355 356 357 358 case '=': 359 setall(); 360 newline(); 361 count = (addr2-zero)&077777; 362 putd(); 363 putchr('\n'); 364 continue; 365 366 case '!': 367 callunix(); 368 continue; 369 370 case EOF: 371 return; 372 373 } 374 error(Q); 375 } 376 } 377 378 int * 379 address() 380 { 381 register *a1, minus, c; 382 int n, relerr; 383 384 minus = 0; 385 a1 = 0; 386 for (;;) { 387 c = getchr(); 388 if ('0'<=c && c<='9') { 389 n = 0; 390 do { 391 n *= 10; 392 n += c - '0'; 393 } while ((c = getchr())>='0' && c<='9'); 394 peekc = c; 395 if (a1==0) 396 a1 = zero; 397 if (minus<0) 398 n = -n; 399 a1 += n; 400 minus = 0; 401 continue; 402 } 403 relerr = 0; 404 if (a1 || minus) 405 relerr++; 406 switch(c) { 407 case ' ': 408 case '\t': 409 continue; 410 411 case '+': 412 minus++; 413 if (a1==0) 414 a1 = dot; 415 continue; 416 417 case '-': 418 case '^': 419 minus--; 420 if (a1==0) 421 a1 = dot; 422 continue; 423 424 case '?': 425 case '/': 426 compile(c); 427 a1 = dot; 428 for (;;) { 429 if (c=='/') { 430 a1++; 431 if (a1 > dol) 432 a1 = zero; 433 } else { 434 a1--; 435 if (a1 < zero) 436 a1 = dol; 437 } 438 if (execute(0, a1)) 439 break; 440 if (a1==dot) 441 error(Q); 442 } 443 break; 444 445 case '$': 446 a1 = dol; 447 break; 448 449 case '.': 450 a1 = dot; 451 break; 452 453 case '\'': 454 if ((c = getchr()) < 'a' || c > 'z') 455 error(Q); 456 for (a1=zero; a1<=dol; a1++) 457 if (names[c-'a'] == (*a1 & ~01)) 458 break; 459 break; 460 461 default: 462 peekc = c; 463 if (a1==0) 464 return(0); 465 a1 += minus; 466 if (a1<zero || a1>dol) 467 error(Q); 468 return(a1); 469 } 470 if (relerr) 471 error(Q); 472 } 473 } 474 475 setdot() 476 { 477 if (addr2 == 0) 478 addr1 = addr2 = dot; 479 if (addr1 > addr2) 480 error(Q); 481 } 482 483 setall() 484 { 485 if (addr2==0) { 486 addr1 = zero+1; 487 addr2 = dol; 488 if (dol==zero) 489 addr1 = zero; 490 } 491 setdot(); 492 } 493 494 setnoaddr() 495 { 496 if (addr2) 497 error(Q); 498 } 499 500 nonzero() 501 { 502 if (addr1<=zero || addr2>dol) 503 error(Q); 504 } 505 506 newline() 507 { 508 register c; 509 510 if ((c = getchr()) == '\n') 511 return; 512 if (c=='p' || c=='l') { 513 pflag++; 514 if (c=='l') 515 listf++; 516 if (getchr() == '\n') 517 return; 518 } 519 error(Q); 520 } 521 522 filename(comm) 523 { 524 register char *p1, *p2; 525 register c; 526 527 count = 0; 528 c = getchr(); 529 if (c=='\n' || c==EOF) { 530 p1 = savedfile; 531 if (*p1==0 && comm!='f') 532 error(Q); 533 p2 = file; 534 while (*p2++ = *p1++) 535 ; 536 return; 537 } 538 if (c!=' ') 539 error(Q); 540 while ((c = getchr()) == ' ') 541 ; 542 if (c=='\n') 543 error(Q); 544 p1 = file; 545 do { 546 *p1++ = c; 547 if (c==' ' || c==EOF) 548 error(Q); 549 } while ((c = getchr()) != '\n'); 550 *p1++ = 0; 551 if (savedfile[0]==0 || comm=='e' || comm=='f') { 552 p1 = savedfile; 553 p2 = file; 554 while (*p1++ = *p2++) 555 ; 556 } 557 } 558 559 exfile() 560 { 561 close(io); 562 io = -1; 563 if (vflag) { 564 putd(); 565 putchr('\n'); 566 } 567 } 568 569 void 570 onintr() 571 { 572 /* not necessary: (void)signal(SIGINT, onintr); */ 573 putchr('\n'); 574 lastc = '\n'; 575 error(Q); 576 } 577 578 void 579 onhup() 580 { 581 /* not necessary: (void)signal(SIGINT, SIG_IGN); */ 582 /* not necessary: (void)signal(SIGHUP, SIG_IGN); */ 583 if (dol > zero) { 584 addr1 = zero+1; 585 addr2 = dol; 586 io = creat("ed.hup", 0666); 587 if (io > 0) 588 putfile(); 589 } 590 fchange = 0; 591 quit(); 592 } 593 594 error(s) 595 char *s; 596 { 597 register c; 598 599 wrapp = 0; 600 listf = 0; 601 putchr('?'); 602 puts(s); 603 count = 0; 604 lseek(0, (long)0, 2); 605 pflag = 0; 606 if (globp) 607 lastc = '\n'; 608 globp = 0; 609 peekc = lastc; 610 if(lastc) 611 while ((c = getchr()) != '\n' && c != EOF) 612 ; 613 if (io > 0) { 614 close(io); 615 io = -1; 616 } 617 longjmp(savej, 1); 618 } 619 620 getchr() 621 { 622 char c; 623 if (lastc=peekc) { 624 peekc = 0; 625 return(lastc); 626 } 627 if (globp) { 628 if ((lastc = *globp++) != 0) 629 return(lastc); 630 globp = 0; 631 return(EOF); 632 } 633 if (read(0, &c, 1) <= 0) 634 return(lastc = EOF); 635 lastc = c&0177; 636 return(lastc); 637 } 638 639 gettty() 640 { 641 register c; 642 register char *gf; 643 register char *p; 644 645 p = linebuf; 646 gf = globp; 647 while ((c = getchr()) != '\n') { 648 if (c==EOF) { 649 if (gf) 650 peekc = c; 651 return(c); 652 } 653 if ((c &= 0177) == 0) 654 continue; 655 *p++ = c; 656 if (p >= &linebuf[LBSIZE-2]) 657 error(Q); 658 } 659 *p++ = 0; 660 if (linebuf[0]=='.' && linebuf[1]==0) 661 return(EOF); 662 return(0); 663 } 664 665 getfile() 666 { 667 register c; 668 register char *lp, *fp; 669 670 lp = linebuf; 671 fp = nextip; 672 do { 673 if (--ninbuf < 0) { 674 if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0) 675 return(EOF); 676 fp = genbuf; 677 while(fp < &genbuf[ninbuf]) { 678 if (*fp++ & 0200) { 679 break; 680 } 681 } 682 fp = genbuf; 683 } 684 c = *fp++; 685 if (c=='\0') 686 continue; 687 if (c&0200 || lp >= &linebuf[LBSIZE]) { 688 lastc = '\n'; 689 error(Q); 690 } 691 *lp++ = c; 692 count++; 693 } while (c != '\n'); 694 *--lp = 0; 695 nextip = fp; 696 return(0); 697 } 698 699 putfile() 700 { 701 int *a1, n; 702 register char *fp, *lp; 703 register nib; 704 705 nib = 512; 706 fp = genbuf; 707 a1 = addr1; 708 do { 709 lp = getline(*a1++); 710 for (;;) { 711 if (--nib < 0) { 712 n = fp-genbuf; 713 if(write(io, genbuf, n) != n) { 714 puts(WRERR); 715 error(Q); 716 } 717 nib = 511; 718 fp = genbuf; 719 } 720 count++; 721 if ((*fp++ = *lp++) == 0) { 722 fp[-1] = '\n'; 723 break; 724 } 725 } 726 } while (a1 <= addr2); 727 n = fp-genbuf; 728 if(write(io, genbuf, n) != n) { 729 puts(WRERR); 730 error(Q); 731 } 732 } 733 734 append(f, a) 735 int *a; 736 int (*f)(); 737 { 738 register *a1, *a2, *rdot; 739 int nline, tl; 740 741 nline = 0; 742 dot = a; 743 while ((*f)() == 0) { 744 if ((dol-zero)+1 >= nlall) { 745 int *ozero = zero; 746 nlall += 512; 747 if ((zero = (int *)realloc((char *)zero, nlall*sizeof(int)))==NULL) { 748 lastc = '\n'; 749 zero = ozero; 750 error("MEM?"); 751 } 752 dot += zero - ozero; 753 dol += zero - ozero; 754 } 755 tl = putline(); 756 nline++; 757 a1 = ++dol; 758 a2 = a1+1; 759 rdot = ++dot; 760 while (a1 > rdot) 761 *--a2 = *--a1; 762 *rdot = tl; 763 } 764 return(nline); 765 } 766 767 callunix() 768 { 769 register sig_t savint; 770 register int pid, rpid; 771 int retcode; 772 773 setnoaddr(); 774 if ((pid = fork()) == 0) { 775 signal(SIGHUP, oldhup); 776 signal(SIGQUIT, oldquit); 777 execl(_PATH_BSHELL, "sh", "-t", 0); 778 exit(0100); 779 } 780 savint = signal(SIGINT, SIG_IGN); 781 while ((rpid = wait(&retcode)) != pid && rpid != -1) 782 ; 783 signal(SIGINT, savint); 784 puts("!"); 785 } 786 787 void 788 quit() 789 { 790 if (vflag && fchange && dol!=zero) { 791 fchange = 0; 792 error(Q); 793 } 794 unlink(tfname); 795 exit(0); 796 } 797 798 delete() 799 { 800 setdot(); 801 newline(); 802 nonzero(); 803 rdelete(addr1, addr2); 804 } 805 806 rdelete(ad1, ad2) 807 int *ad1, *ad2; 808 { 809 register *a1, *a2, *a3; 810 811 a1 = ad1; 812 a2 = ad2+1; 813 a3 = dol; 814 dol -= a2 - a1; 815 do { 816 *a1++ = *a2++; 817 } while (a2 <= a3); 818 a1 = ad1; 819 if (a1 > dol) 820 a1 = dol; 821 dot = a1; 822 fchange = 1; 823 } 824 825 gdelete() 826 { 827 register *a1, *a2, *a3; 828 829 a3 = dol; 830 for (a1=zero+1; (*a1&01)==0; a1++) 831 if (a1>=a3) 832 return; 833 for (a2=a1+1; a2<=a3;) { 834 if (*a2&01) { 835 a2++; 836 dot = a1; 837 } else 838 *a1++ = *a2++; 839 } 840 dol = a1-1; 841 if (dot>dol) 842 dot = dol; 843 fchange = 1; 844 } 845 846 char * 847 getline(tl) 848 { 849 register char *bp, *lp; 850 register nl; 851 852 lp = linebuf; 853 bp = getblock(tl, READ); 854 nl = nleft; 855 tl &= ~0377; 856 while (*lp++ = *bp++) 857 if (--nl == 0) { 858 bp = getblock(tl+=0400, READ); 859 nl = nleft; 860 } 861 return(linebuf); 862 } 863 864 putline() 865 { 866 register char *bp, *lp; 867 register nl; 868 int tl; 869 870 fchange = 1; 871 lp = linebuf; 872 tl = tline; 873 bp = getblock(tl, WRITE); 874 nl = nleft; 875 tl &= ~0377; 876 while (*bp = *lp++) { 877 if (*bp++ == '\n') { 878 *--bp = 0; 879 linebp = lp; 880 break; 881 } 882 if (--nl == 0) { 883 bp = getblock(tl+=0400, WRITE); 884 nl = nleft; 885 } 886 } 887 nl = tline; 888 tline += (((lp-linebuf)+03)>>1)&077776; 889 return(nl); 890 } 891 892 char * 893 getblock(atl, iof) 894 { 895 extern read(), write(); 896 register bno, off; 897 register char *p1, *p2; 898 register int n; 899 900 bno = (atl>>8)&0377; 901 off = (atl<<1)&0774; 902 if (bno >= 255) { 903 lastc = '\n'; 904 error(T); 905 } 906 nleft = 512 - off; 907 if (bno==iblock) { 908 ichanged |= iof; 909 return(ibuff+off); 910 } 911 if (bno==oblock) 912 return(obuff+off); 913 if (iof==READ) { 914 if (ichanged) { 915 blkio(iblock, ibuff, write); 916 } 917 ichanged = 0; 918 iblock = bno; 919 blkio(bno, ibuff, read); 920 return(ibuff+off); 921 } 922 if (oblock>=0) { 923 blkio(oblock, obuff, write); 924 } 925 oblock = bno; 926 return(obuff+off); 927 } 928 929 blkio(b, buf, iofcn) 930 char *buf; 931 int (*iofcn)(); 932 { 933 lseek(tfile, (long)b<<9, 0); 934 if ((*iofcn)(tfile, buf, 512) != 512) { 935 error(T); 936 } 937 } 938 939 init() 940 { 941 register *markp; 942 943 close(tfile); 944 tline = 2; 945 for (markp = names; markp < &names[26]; ) 946 *markp++ = 0; 947 subnewa = 0; 948 anymarks = 0; 949 iblock = -1; 950 oblock = -1; 951 ichanged = 0; 952 close(creat(tfname, 0600)); 953 tfile = open(tfname, 2); 954 dot = dol = zero; 955 } 956 957 global(k) 958 { 959 register char *gp; 960 register c; 961 register int *a1; 962 char globuf[GBSIZE]; 963 964 if (globp) 965 error(Q); 966 setall(); 967 nonzero(); 968 if ((c=getchr())=='\n') 969 error(Q); 970 compile(c); 971 gp = globuf; 972 while ((c = getchr()) != '\n') { 973 if (c==EOF) 974 error(Q); 975 if (c=='\\') { 976 c = getchr(); 977 if (c!='\n') 978 *gp++ = '\\'; 979 } 980 *gp++ = c; 981 if (gp >= &globuf[GBSIZE-2]) 982 error(Q); 983 } 984 *gp++ = '\n'; 985 *gp++ = 0; 986 for (a1=zero; a1<=dol; a1++) { 987 *a1 &= ~01; 988 if (a1>=addr1 && a1<=addr2 && execute(0, a1)==k) 989 *a1 |= 01; 990 } 991 /* 992 * Special case: g/.../d (avoid n^2 algorithm) 993 */ 994 if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') { 995 gdelete(); 996 return; 997 } 998 for (a1=zero; a1<=dol; a1++) { 999 if (*a1 & 01) { 1000 *a1 &= ~01; 1001 dot = a1; 1002 globp = globuf; 1003 commands(); 1004 a1 = zero; 1005 } 1006 } 1007 } 1008 1009 join() 1010 { 1011 register char *gp, *lp; 1012 register *a1; 1013 1014 gp = genbuf; 1015 for (a1=addr1; a1<=addr2; a1++) { 1016 lp = getline(*a1); 1017 while (*gp = *lp++) 1018 if (gp++ >= &genbuf[LBSIZE-2]) 1019 error(Q); 1020 } 1021 lp = linebuf; 1022 gp = genbuf; 1023 while (*lp++ = *gp++) 1024 ; 1025 *addr1 = putline(); 1026 if (addr1<addr2) 1027 rdelete(addr1+1, addr2); 1028 dot = addr1; 1029 } 1030 1031 substitute(inglob) 1032 { 1033 register *markp, *a1, nl; 1034 int gsubf; 1035 int getsub(); 1036 1037 gsubf = compsub(); 1038 for (a1 = addr1; a1 <= addr2; a1++) { 1039 int *ozero; 1040 if (execute(0, a1)==0) 1041 continue; 1042 inglob |= 01; 1043 dosub(); 1044 if (gsubf) { 1045 while (*loc2) { 1046 if (execute(1, (int *)0)==0) 1047 break; 1048 dosub(); 1049 } 1050 } 1051 subnewa = putline(); 1052 *a1 &= ~01; 1053 if (anymarks) { 1054 for (markp = names; markp < &names[26]; markp++) 1055 if (*markp == *a1) 1056 *markp = subnewa; 1057 } 1058 subolda = *a1; 1059 *a1 = subnewa; 1060 ozero = zero; 1061 nl = append(getsub, a1); 1062 nl += zero-ozero; 1063 a1 += nl; 1064 addr2 += nl; 1065 } 1066 if (inglob==0) 1067 error(Q); 1068 } 1069 1070 compsub() 1071 { 1072 register seof, c; 1073 register char *p; 1074 1075 if ((seof = getchr()) == '\n' || seof == ' ') 1076 error(Q); 1077 compile(seof); 1078 p = rhsbuf; 1079 for (;;) { 1080 c = getchr(); 1081 if (c=='\\') 1082 c = getchr() | 0200; 1083 if (c=='\n') { 1084 if (globp) 1085 c |= 0200; 1086 else 1087 error(Q); 1088 } 1089 if (c==seof) 1090 break; 1091 *p++ = c; 1092 if (p >= &rhsbuf[LBSIZE/2]) 1093 error(Q); 1094 } 1095 *p++ = 0; 1096 if ((peekc = getchr()) == 'g') { 1097 peekc = 0; 1098 newline(); 1099 return(1); 1100 } 1101 newline(); 1102 return(0); 1103 } 1104 1105 getsub() 1106 { 1107 register char *p1, *p2; 1108 1109 p1 = linebuf; 1110 if ((p2 = linebp) == 0) 1111 return(EOF); 1112 while (*p1++ = *p2++) 1113 ; 1114 linebp = 0; 1115 return(0); 1116 } 1117 1118 dosub() 1119 { 1120 register char *lp, *sp, *rp; 1121 int c; 1122 1123 lp = linebuf; 1124 sp = genbuf; 1125 rp = rhsbuf; 1126 while (lp < loc1) 1127 *sp++ = *lp++; 1128 while (c = *rp++&0377) { 1129 if (c=='&') { 1130 sp = place(sp, loc1, loc2); 1131 continue; 1132 } else if (c&0200 && (c &= 0177) >='1' && c < nbra+'1') { 1133 sp = place(sp, braslist[c-'1'], braelist[c-'1']); 1134 continue; 1135 } 1136 *sp++ = c&0177; 1137 if (sp >= &genbuf[LBSIZE]) 1138 error(Q); 1139 } 1140 lp = loc2; 1141 loc2 = sp - genbuf + linebuf; 1142 while (*sp++ = *lp++) 1143 if (sp >= &genbuf[LBSIZE]) 1144 error(Q); 1145 lp = linebuf; 1146 sp = genbuf; 1147 while (*lp++ = *sp++) 1148 ; 1149 } 1150 1151 char * 1152 place(sp, l1, l2) 1153 register char *sp, *l1, *l2; 1154 { 1155 1156 while (l1 < l2) { 1157 *sp++ = *l1++; 1158 if (sp >= &genbuf[LBSIZE]) 1159 error(Q); 1160 } 1161 return(sp); 1162 } 1163 1164 move(cflag) 1165 { 1166 register int *adt, *ad1, *ad2; 1167 int getcopy(); 1168 1169 setdot(); 1170 nonzero(); 1171 if ((adt = address())==0) 1172 error(Q); 1173 newline(); 1174 if (cflag) { 1175 int *ozero, delta; 1176 ad1 = dol; 1177 ozero = zero; 1178 append(getcopy, ad1++); 1179 ad2 = dol; 1180 delta = zero - ozero; 1181 ad1 += delta; 1182 adt += delta; 1183 } else { 1184 ad2 = addr2; 1185 for (ad1 = addr1; ad1 <= ad2;) 1186 *ad1++ &= ~01; 1187 ad1 = addr1; 1188 } 1189 ad2++; 1190 if (adt<ad1) { 1191 dot = adt + (ad2-ad1); 1192 if ((++adt)==ad1) 1193 return; 1194 reverse(adt, ad1); 1195 reverse(ad1, ad2); 1196 reverse(adt, ad2); 1197 } else if (adt >= ad2) { 1198 dot = adt++; 1199 reverse(ad1, ad2); 1200 reverse(ad2, adt); 1201 reverse(ad1, adt); 1202 } else 1203 error(Q); 1204 fchange = 1; 1205 } 1206 1207 reverse(a1, a2) 1208 register int *a1, *a2; 1209 { 1210 register int t; 1211 1212 for (;;) { 1213 t = *--a2; 1214 if (a2 <= a1) 1215 return; 1216 *a2 = *a1; 1217 *a1++ = t; 1218 } 1219 } 1220 1221 getcopy() 1222 { 1223 if (addr1 > addr2) 1224 return(EOF); 1225 getline(*addr1++); 1226 return(0); 1227 } 1228 1229 compile(aeof) 1230 { 1231 register eof, c; 1232 register char *ep; 1233 char *lastep; 1234 char bracket[NBRA], *bracketp; 1235 int cclcnt; 1236 1237 ep = expbuf; 1238 eof = aeof; 1239 bracketp = bracket; 1240 if ((c = getchr()) == eof) { 1241 if (*ep==0) 1242 error(Q); 1243 return; 1244 } 1245 circfl = 0; 1246 nbra = 0; 1247 if (c=='^') { 1248 c = getchr(); 1249 circfl++; 1250 } 1251 peekc = c; 1252 lastep = 0; 1253 for (;;) { 1254 if (ep >= &expbuf[ESIZE]) 1255 goto cerror; 1256 c = getchr(); 1257 if (c==eof) { 1258 if (bracketp != bracket) 1259 goto cerror; 1260 *ep++ = CEOF; 1261 return; 1262 } 1263 if (c!='*') 1264 lastep = ep; 1265 switch (c) { 1266 1267 case '\\': 1268 if ((c = getchr())=='(') { 1269 if (nbra >= NBRA) 1270 goto cerror; 1271 *bracketp++ = nbra; 1272 *ep++ = CBRA; 1273 *ep++ = nbra++; 1274 continue; 1275 } 1276 if (c == ')') { 1277 if (bracketp <= bracket) 1278 goto cerror; 1279 *ep++ = CKET; 1280 *ep++ = *--bracketp; 1281 continue; 1282 } 1283 if (c>='1' && c<'1'+NBRA) { 1284 *ep++ = CBACK; 1285 *ep++ = c-'1'; 1286 continue; 1287 } 1288 *ep++ = CCHR; 1289 if (c=='\n') 1290 goto cerror; 1291 *ep++ = c; 1292 continue; 1293 1294 case '.': 1295 *ep++ = CDOT; 1296 continue; 1297 1298 case '\n': 1299 goto cerror; 1300 1301 case '*': 1302 if (lastep==0 || *lastep==CBRA || *lastep==CKET) 1303 goto defchar; 1304 *lastep |= STAR; 1305 continue; 1306 1307 case '$': 1308 if ((peekc=getchr()) != eof) 1309 goto defchar; 1310 *ep++ = CDOL; 1311 continue; 1312 1313 case '[': 1314 *ep++ = CCL; 1315 *ep++ = 0; 1316 cclcnt = 1; 1317 if ((c=getchr()) == '^') { 1318 c = getchr(); 1319 ep[-2] = NCCL; 1320 } 1321 do { 1322 if (c=='\n') 1323 goto cerror; 1324 if (c=='-' && ep[-1]!=0) { 1325 if ((c=getchr())==']') { 1326 *ep++ = '-'; 1327 cclcnt++; 1328 break; 1329 } 1330 while (ep[-1]<c) { 1331 *ep = ep[-1]+1; 1332 ep++; 1333 cclcnt++; 1334 if (ep>=&expbuf[ESIZE]) 1335 goto cerror; 1336 } 1337 } 1338 *ep++ = c; 1339 cclcnt++; 1340 if (ep >= &expbuf[ESIZE]) 1341 goto cerror; 1342 } while ((c = getchr()) != ']'); 1343 lastep[1] = cclcnt; 1344 continue; 1345 1346 defchar: 1347 default: 1348 *ep++ = CCHR; 1349 *ep++ = c; 1350 } 1351 } 1352 cerror: 1353 expbuf[0] = 0; 1354 nbra = 0; 1355 error(Q); 1356 } 1357 1358 execute(gf, addr) 1359 int *addr; 1360 { 1361 register char *p1, *p2, c; 1362 1363 for (c=0; c<NBRA; c++) { 1364 braslist[c] = 0; 1365 braelist[c] = 0; 1366 } 1367 if (gf) { 1368 if (circfl) 1369 return(0); 1370 p1 = linebuf; 1371 p2 = genbuf; 1372 while (*p1++ = *p2++) 1373 ; 1374 locs = p1 = loc2; 1375 } else { 1376 if (addr==zero) 1377 return(0); 1378 p1 = getline(*addr); 1379 locs = 0; 1380 } 1381 p2 = expbuf; 1382 if (circfl) { 1383 loc1 = p1; 1384 return(advance(p1, p2)); 1385 } 1386 /* fast check for first character */ 1387 if (*p2==CCHR) { 1388 c = p2[1]; 1389 do { 1390 if (*p1!=c) 1391 continue; 1392 if (advance(p1, p2)) { 1393 loc1 = p1; 1394 return(1); 1395 } 1396 } while (*p1++); 1397 return(0); 1398 } 1399 /* regular algorithm */ 1400 do { 1401 if (advance(p1, p2)) { 1402 loc1 = p1; 1403 return(1); 1404 } 1405 } while (*p1++); 1406 return(0); 1407 } 1408 1409 advance(lp, ep) 1410 register char *ep, *lp; 1411 { 1412 register char *curlp; 1413 int i; 1414 1415 for (;;) switch (*ep++) { 1416 1417 case CCHR: 1418 if (*ep++ == *lp++) 1419 continue; 1420 return(0); 1421 1422 case CDOT: 1423 if (*lp++) 1424 continue; 1425 return(0); 1426 1427 case CDOL: 1428 if (*lp==0) 1429 continue; 1430 return(0); 1431 1432 case CEOF: 1433 loc2 = lp; 1434 return(1); 1435 1436 case CCL: 1437 if (cclass(ep, *lp++, 1)) { 1438 ep += *ep; 1439 continue; 1440 } 1441 return(0); 1442 1443 case NCCL: 1444 if (cclass(ep, *lp++, 0)) { 1445 ep += *ep; 1446 continue; 1447 } 1448 return(0); 1449 1450 case CBRA: 1451 braslist[*ep++] = lp; 1452 continue; 1453 1454 case CKET: 1455 braelist[*ep++] = lp; 1456 continue; 1457 1458 case CBACK: 1459 if (braelist[i = *ep++]==0) 1460 error(Q); 1461 if (backref(i, lp)) { 1462 lp += braelist[i] - braslist[i]; 1463 continue; 1464 } 1465 return(0); 1466 1467 case CBACK|STAR: 1468 if (braelist[i = *ep++] == 0) 1469 error(Q); 1470 curlp = lp; 1471 while (backref(i, lp)) 1472 lp += braelist[i] - braslist[i]; 1473 while (lp >= curlp) { 1474 if (advance(lp, ep)) 1475 return(1); 1476 lp -= braelist[i] - braslist[i]; 1477 } 1478 continue; 1479 1480 case CDOT|STAR: 1481 curlp = lp; 1482 while (*lp++) 1483 ; 1484 goto star; 1485 1486 case CCHR|STAR: 1487 curlp = lp; 1488 while (*lp++ == *ep) 1489 ; 1490 ep++; 1491 goto star; 1492 1493 case CCL|STAR: 1494 case NCCL|STAR: 1495 curlp = lp; 1496 while (cclass(ep, *lp++, ep[-1]==(CCL|STAR))) 1497 ; 1498 ep += *ep; 1499 goto star; 1500 1501 star: 1502 do { 1503 lp--; 1504 if (lp==locs) 1505 break; 1506 if (advance(lp, ep)) 1507 return(1); 1508 } while (lp > curlp); 1509 return(0); 1510 1511 default: 1512 error(Q); 1513 } 1514 } 1515 1516 backref(i, lp) 1517 register i; 1518 register char *lp; 1519 { 1520 register char *bp; 1521 1522 bp = braslist[i]; 1523 while (*bp++ == *lp++) 1524 if (bp >= braelist[i]) 1525 return(1); 1526 return(0); 1527 } 1528 1529 cclass(set, c, af) 1530 register char *set, c; 1531 { 1532 register n; 1533 1534 if (c==0) 1535 return(0); 1536 n = *set++; 1537 while (--n) 1538 if (*set++ == c) 1539 return(af); 1540 return(!af); 1541 } 1542 1543 putd() 1544 { 1545 register r; 1546 1547 r = count%10; 1548 count /= 10; 1549 if (count) 1550 putd(); 1551 putchr(r + '0'); 1552 } 1553 1554 puts(sp) 1555 register char *sp; 1556 { 1557 col = 0; 1558 while (*sp) 1559 putchr(*sp++); 1560 putchr('\n'); 1561 } 1562 1563 char line[70]; 1564 char *linp = line; 1565 1566 putchr(ac) 1567 { 1568 register char *lp; 1569 register c; 1570 1571 lp = linp; 1572 c = ac; 1573 if (listf) { 1574 col++; 1575 if (col >= 72) { 1576 col = 0; 1577 *lp++ = '\\'; 1578 *lp++ = '\n'; 1579 } 1580 if (c=='\t') { 1581 c = '>'; 1582 goto esc; 1583 } 1584 if (c=='\b') { 1585 c = '<'; 1586 esc: 1587 *lp++ = '-'; 1588 *lp++ = '\b'; 1589 *lp++ = c; 1590 goto out; 1591 } 1592 if (c<' ' && c!= '\n') { 1593 *lp++ = '\\'; 1594 *lp++ = (c>>3)+'0'; 1595 *lp++ = (c&07)+'0'; 1596 col += 2; 1597 goto out; 1598 } 1599 } 1600 *lp++ = c; 1601 out: 1602 if(c == '\n' || lp >= &line[64]) { 1603 linp = line; 1604 write(1, line, lp-line); 1605 return; 1606 } 1607 linp = lp; 1608 } 1609 1610