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