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