| ed.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| 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 comman… | |
| 19 MAXSUB = 9, /* max number of sub reg exp */ | |
| 20 ESCFLG = 0xFFFF, /* escape Rune - user defined cod… | |
| 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 onl… | |
| 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… | |
| 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 R… | |
| 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… | |
| 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 … | |
| 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 } |