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