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