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