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