|
|
1.1 ! root 1: /* Copyright (c) 1979 Regents of the University of California */ ! 2: #include "ex.h" ! 3: #include "ex_argv.h" ! 4: #include "ex_temp.h" ! 5: #include "ex_tty.h" ! 6: #include "ex_vis.h" ! 7: ! 8: /* ! 9: * File input/output, unix escapes, source, filtering preserve and recover ! 10: */ ! 11: ! 12: /* ! 13: * Following remember where . was in the previous file for return ! 14: * on file switching. ! 15: */ ! 16: int altdot; ! 17: int oldadot; ! 18: bool wasalt; ! 19: ! 20: long cntch; /* Count of characters on unit io */ ! 21: #ifndef VMUNIX ! 22: short cntln; /* Count of lines " */ ! 23: #else ! 24: int cntln; ! 25: #endif ! 26: long cntnull; /* Count of nulls " */ ! 27: long cntodd; /* Count of non-ascii characters " */ ! 28: ! 29: /* ! 30: * Parse file name for command encoded by comm. ! 31: * If comm is E then command is doomed and we are ! 32: * parsing just so user won't have to retype the name. ! 33: */ ! 34: filename(comm) ! 35: int comm; ! 36: { ! 37: register int c = comm, d; ! 38: register int i; ! 39: ! 40: d = getchar(); ! 41: if (endcmd(d)) { ! 42: if (savedfile[0] == 0 && comm != 'f') ! 43: error("No file|No current filename"); ! 44: CP(file, savedfile); ! 45: wasalt = 0; ! 46: oldadot = altdot; ! 47: if (d == EOF) ! 48: ungetchar(d); ! 49: } else { ! 50: ungetchar(d); ! 51: getone(); ! 52: eol(); ! 53: if (savedfile[0] == 0 && c != 'E' && c != 'e') { ! 54: c = 'e'; ! 55: edited = 0; ! 56: } ! 57: wasalt = strcmp(file, altfile) == 0; ! 58: oldadot = altdot; ! 59: switch (c) { ! 60: ! 61: case 'f': ! 62: edited = 0; ! 63: /* fall into ... */ ! 64: ! 65: case 'e': ! 66: if (savedfile[0]) { ! 67: altdot = lineDOT(); ! 68: CP(altfile, savedfile); ! 69: } ! 70: CP(savedfile, file); ! 71: break; ! 72: ! 73: default: ! 74: if (file[0]) { ! 75: if (c != 'E') ! 76: altdot = lineDOT(); ! 77: CP(altfile, file); ! 78: } ! 79: break; ! 80: } ! 81: } ! 82: if (hush && comm != 'f' || comm == 'E') ! 83: return; ! 84: if (file[0] != 0) { ! 85: lprintf("\"%s\"", file); ! 86: if (comm == 'f') { ! 87: if (!edited) ! 88: printf(" [Not edited]"); ! 89: if (tchng) ! 90: printf(" [Modified]"); ! 91: } ! 92: flush(); ! 93: } else ! 94: printf("No file "); ! 95: if (comm == 'f') { ! 96: if (!(i = lineDOL())) ! 97: i++; ! 98: printf(" line %d of %d --%ld%%--", lineDOT(), lineDOL(), ! 99: (long) 100 * lineDOT() / i); ! 100: } ! 101: } ! 102: ! 103: /* ! 104: * Get the argument words for a command into genbuf ! 105: * expanding # and %. ! 106: */ ! 107: getargs() ! 108: { ! 109: register int c; ! 110: register char *cp, *fp; ! 111: static char fpatbuf[32]; /* hence limit on :next +/pat */ ! 112: ! 113: pastwh(); ! 114: if (peekchar() == '+') { ! 115: for (cp = fpatbuf;;) { ! 116: c = *cp++ = getchar(); ! 117: if (cp >= &fpatbuf[sizeof(fpatbuf)]) ! 118: error("Pattern too long"); ! 119: if (c == '\\' && isspace(peekchar())) ! 120: c = getchar(); ! 121: if (c == EOF || isspace(c)) { ! 122: ungetchar(c); ! 123: *--cp = 0; ! 124: firstpat = &fpatbuf[1]; ! 125: break; ! 126: } ! 127: } ! 128: } ! 129: if (skipend()) ! 130: return (0); ! 131: CP(genbuf, "echo "); cp = &genbuf[5]; ! 132: for (;;) { ! 133: c = getchar(); ! 134: if (endcmd(c)) { ! 135: ungetchar(c); ! 136: break; ! 137: } ! 138: switch (c) { ! 139: ! 140: case '\\': ! 141: if (any(peekchar(), "#%")) ! 142: c = getchar(); ! 143: /* fall into... */ ! 144: ! 145: default: ! 146: if (cp > &genbuf[LBSIZE - 2]) ! 147: flong: ! 148: error("Argument buffer overflow"); ! 149: *cp++ = c; ! 150: break; ! 151: ! 152: case '#': ! 153: fp = altfile; ! 154: if (*fp == 0) ! 155: error("No alternate filename@to substitute for #"); ! 156: goto filexp; ! 157: ! 158: case '%': ! 159: fp = savedfile; ! 160: if (*fp == 0) ! 161: error("No current filename@to substitute for %%"); ! 162: filexp: ! 163: while (*fp) { ! 164: if (cp > &genbuf[LBSIZE - 2]) ! 165: goto flong; ! 166: *cp++ = *fp++; ! 167: } ! 168: break; ! 169: } ! 170: } ! 171: *cp = 0; ! 172: return (1); ! 173: } ! 174: ! 175: /* ! 176: * Glob the argument words in genbuf, or if no globbing ! 177: * is implied, just split them up directly. ! 178: */ ! 179: glob(gp) ! 180: struct glob *gp; ! 181: { ! 182: int pvec[2]; ! 183: register char **argv = gp->argv; ! 184: register char *cp = gp->argspac; ! 185: register int c; ! 186: char ch; ! 187: int nleft = NCARGS; ! 188: ! 189: gp->argc0 = 0; ! 190: if (gscan() == 0) { ! 191: register char *v = genbuf + 5; /* strlen("echo ") */ ! 192: ! 193: for (;;) { ! 194: while (isspace(*v)) ! 195: v++; ! 196: if (!*v) ! 197: break; ! 198: *argv++ = cp; ! 199: while (*v && !isspace(*v)) ! 200: *cp++ = *v++; ! 201: *cp++ = 0; ! 202: gp->argc0++; ! 203: } ! 204: *argv = 0; ! 205: return; ! 206: } ! 207: if (pipe(pvec) < 0) ! 208: error("Can't make pipe to glob"); ! 209: pid = fork(); ! 210: io = pvec[0]; ! 211: if (pid < 0) { ! 212: close(pvec[1]); ! 213: error("Can't fork to do glob"); ! 214: } ! 215: if (pid == 0) { ! 216: int oerrno; ! 217: ! 218: close(1); ! 219: dup(pvec[1]); ! 220: close(pvec[0]); ! 221: execl(svalue(SHELL), "sh", "-c", genbuf, 0); ! 222: oerrno = errno; close(1); dup(2); errno = oerrno; ! 223: filioerr(svalue(SHELL)); ! 224: } ! 225: close(pvec[1]); ! 226: do { ! 227: *argv = cp; ! 228: for (;;) { ! 229: if (read(io, &ch, 1) != 1) { ! 230: close(io); ! 231: c = -1; ! 232: } else ! 233: c = ch & TRIM; ! 234: if (c <= 0 || isspace(c)) ! 235: break; ! 236: *cp++ = c; ! 237: if (--nleft <= 0) ! 238: error("Arg list too long"); ! 239: } ! 240: if (cp != *argv) { ! 241: --nleft; ! 242: *cp++ = 0; ! 243: gp->argc0++; ! 244: if (gp->argc0 >= NARGS) ! 245: error("Arg list too long"); ! 246: argv++; ! 247: } ! 248: } while (c >= 0); ! 249: waitfor(); ! 250: if (gp->argc0 == 0) ! 251: error(NOSTR); ! 252: } ! 253: ! 254: /* ! 255: * Scan genbuf for shell metacharacters. ! 256: * Set is union of v7 shell and csh metas. ! 257: */ ! 258: gscan() ! 259: { ! 260: register char *cp; ! 261: ! 262: for (cp = genbuf; *cp; cp++) ! 263: if (any(*cp, "~{[*?$`'\"\\")) ! 264: return (1); ! 265: return (0); ! 266: } ! 267: ! 268: /* ! 269: * Parse one filename into file. ! 270: */ ! 271: getone() ! 272: { ! 273: register char *str; ! 274: struct glob G; ! 275: ! 276: if (getargs() == 0) ! 277: error("Missing filename"); ! 278: glob(&G); ! 279: if (G.argc0 > 1) ! 280: error("Ambiguous|Too many file names"); ! 281: str = G.argv[G.argc0 - 1]; ! 282: if (strlen(str) > FNSIZE - 4) ! 283: error("Filename too long"); ! 284: samef: ! 285: CP(file, str); ! 286: } ! 287: ! 288: /* ! 289: * Read a file from the world. ! 290: * C is command, 'e' if this really an edit (or a recover). ! 291: */ ! 292: rop(c) ! 293: int c; ! 294: { ! 295: register int i; ! 296: struct stat stbuf; ! 297: short magic; ! 298: ! 299: io = open(file, 0); ! 300: if (io < 0) { ! 301: if (c == 'e' && errno == ENOENT) ! 302: edited++; ! 303: syserror(); ! 304: } ! 305: if (fstat(io, &stbuf)) ! 306: syserror(); ! 307: switch (stbuf.st_mode & S_IFMT) { ! 308: ! 309: case S_IFBLK: ! 310: error(" Block special file"); ! 311: ! 312: case S_IFCHR: ! 313: if (isatty(io)) ! 314: error(" Teletype"); ! 315: if (samei(&stbuf, "/dev/null")) ! 316: break; ! 317: error(" Character special file"); ! 318: ! 319: case S_IFDIR: ! 320: error(" Directory"); ! 321: ! 322: case S_IFREG: ! 323: i = read(io, (char *) &magic, sizeof(magic)); ! 324: lseek(io, 0l, 0); ! 325: if (i != sizeof(magic)) ! 326: break; ! 327: switch (magic) { ! 328: ! 329: case 0405: ! 330: case 0407: ! 331: case 0410: ! 332: case 0411: ! 333: error(" Executable"); ! 334: ! 335: case 0177545: ! 336: case 0177555: ! 337: error(" Archive"); ! 338: ! 339: default: ! 340: if (magic & 0100200) ! 341: error(" Non-ascii file"); ! 342: break; ! 343: } ! 344: } ! 345: if (c == 'r') ! 346: setdot(); ! 347: else ! 348: setall(); ! 349: if (inopen && c == 'r') ! 350: undap1 = undap2 = dot + 1; ! 351: rop2(); ! 352: rop3(c); ! 353: } ! 354: ! 355: rop2() ! 356: { ! 357: ! 358: deletenone(); ! 359: clrstats(); ! 360: ignore(append(getfile, addr2)); ! 361: } ! 362: ! 363: rop3(c) ! 364: int c; ! 365: { ! 366: ! 367: if (iostats() == 0 && c == 'e') ! 368: edited++; ! 369: if (c == 'e') { ! 370: if (wasalt || firstpat) { ! 371: register line *addr = zero + oldadot; ! 372: ! 373: if (addr > dol) ! 374: addr = dol; ! 375: if (firstpat) { ! 376: globp = (*firstpat) ? firstpat : "$"; ! 377: commands(1,1); ! 378: firstpat = 0; ! 379: } else if (addr >= one) { ! 380: if (inopen) ! 381: dot = addr; ! 382: markpr(addr); ! 383: } else ! 384: goto other; ! 385: } else ! 386: other: ! 387: if (dol > zero) { ! 388: if (inopen) ! 389: dot = one; ! 390: markpr(one); ! 391: } ! 392: undkind = UNDNONE; ! 393: if (inopen) { ! 394: vcline = 0; ! 395: vreplace(0, LINES, lineDOL()); ! 396: } ! 397: } ! 398: if (laste) { ! 399: laste = 0; ! 400: sync(); ! 401: } ! 402: } ! 403: ! 404: /* ! 405: * Are these two really the same inode? ! 406: */ ! 407: samei(sp, cp) ! 408: struct stat *sp; ! 409: char *cp; ! 410: { ! 411: struct stat stb; ! 412: ! 413: if (stat(cp, &stb) < 0 || sp->st_dev != stb.st_dev) ! 414: return (0); ! 415: return (sp->st_ino == stb.st_ino); ! 416: } ! 417: ! 418: /* Returns from edited() */ ! 419: #define EDF 0 /* Edited file */ ! 420: #define NOTEDF -1 /* Not edited file */ ! 421: #define PARTBUF 1 /* Write of partial buffer to Edited file */ ! 422: ! 423: /* ! 424: * Write a file. ! 425: */ ! 426: wop(dofname) ! 427: bool dofname; /* if 1 call filename, else use savedfile */ ! 428: { ! 429: register int c, exclam, nonexist; ! 430: line *saddr1, *saddr2; ! 431: struct stat stbuf; ! 432: ! 433: c = 0; ! 434: exclam = 0; ! 435: if (dofname) { ! 436: if (peekchar() == '!') ! 437: exclam++, ignchar(); ! 438: ignore(skipwh()); ! 439: while (peekchar() == '>') ! 440: ignchar(), c++, ignore(skipwh()); ! 441: if (c != 0 && c != 2) ! 442: error("Write forms are 'w' and 'w>>'"); ! 443: filename('w'); ! 444: } else { ! 445: saddr1=addr1; ! 446: saddr2=addr2; ! 447: addr1=one; ! 448: addr2=dol; ! 449: CP(file, savedfile); ! 450: if (inopen) { ! 451: vclrech(0); ! 452: splitw++; ! 453: } ! 454: lprintf("\"%s\"", file); ! 455: } ! 456: nonexist = stat(file, &stbuf); ! 457: switch (c) { ! 458: ! 459: case 0: ! 460: if (!exclam && !value(WRITEANY)) switch (edfile()) { ! 461: ! 462: case NOTEDF: ! 463: if (nonexist) ! 464: break; ! 465: if ((stbuf.st_mode & S_IFMT) == S_IFCHR) { ! 466: if (samei(&stbuf, "/dev/null")) ! 467: break; ! 468: if (samei(&stbuf, "/dev/tty")) ! 469: break; ! 470: } ! 471: io = open(file, 1); ! 472: if (io < 0) ! 473: syserror(); ! 474: if (!isatty(io)) ! 475: serror(" File exists| File exists - use \"w! %s\" to overwrite", file); ! 476: close(io); ! 477: break; ! 478: ! 479: case PARTBUF: ! 480: error(" Use \"w!\" to write partial buffer"); ! 481: } ! 482: cre: ! 483: /* ! 484: synctmp(); ! 485: */ ! 486: #ifdef V6 ! 487: io = creat(file, 0644); ! 488: #else ! 489: io = creat(file, 0666); ! 490: #endif ! 491: if (io < 0) ! 492: syserror(); ! 493: if (hush == 0) ! 494: if (nonexist) ! 495: printf(" [New file]"); ! 496: else if (value(WRITEANY) && edfile() != EDF) ! 497: printf(" [Existing file]"); ! 498: break; ! 499: ! 500: case 2: ! 501: io = open(file, 1); ! 502: if (io < 0) { ! 503: if (exclam || value(WRITEANY)) ! 504: goto cre; ! 505: syserror(); ! 506: } ! 507: lseek(io, 0l, 2); ! 508: break; ! 509: } ! 510: putfile(); ! 511: ignore(iostats()); ! 512: if (c != 2 && addr1 == one && addr2 == dol) { ! 513: if (eq(file, savedfile)) ! 514: edited = 1; ! 515: sync(); ! 516: } ! 517: if (!dofname) { ! 518: addr1 = saddr1; ! 519: addr2 = saddr2; ! 520: } ! 521: } ! 522: ! 523: /* ! 524: * Is file the edited file? ! 525: * Work here is that it is not considered edited ! 526: * if this is a partial buffer, and distinguish ! 527: * all cases. ! 528: */ ! 529: edfile() ! 530: { ! 531: ! 532: if (!edited || !eq(file, savedfile)) ! 533: return (NOTEDF); ! 534: return (addr1 == one && addr2 == dol ? EDF : PARTBUF); ! 535: } ! 536: ! 537: /* ! 538: * First part of a shell escape, ! 539: * parse the line, expanding # and % and ! and printing if implied. ! 540: */ ! 541: unix0(warn) ! 542: bool warn; ! 543: { ! 544: register char *up, *fp; ! 545: register short c; ! 546: char printub, puxb[UXBSIZE + sizeof (int)]; ! 547: ! 548: printub = 0; ! 549: CP(puxb, uxb); ! 550: c = getchar(); ! 551: if (c == '\n' || c == EOF) ! 552: error("Incomplete shell escape command@- use 'shell' to get a shell"); ! 553: up = uxb; ! 554: do { ! 555: switch (c) { ! 556: ! 557: case '\\': ! 558: if (any(peekchar(), "%#!")) ! 559: c = getchar(); ! 560: default: ! 561: if (up >= &uxb[UXBSIZE]) { ! 562: tunix: ! 563: uxb[0] = 0; ! 564: error("Command too long"); ! 565: } ! 566: *up++ = c; ! 567: break; ! 568: ! 569: case '!': ! 570: fp = puxb; ! 571: if (*fp == 0) { ! 572: uxb[0] = 0; ! 573: error("No previous command@to substitute for !"); ! 574: } ! 575: printub++; ! 576: while (*fp) { ! 577: if (up >= &uxb[UXBSIZE]) ! 578: goto tunix; ! 579: *up++ = *fp++; ! 580: } ! 581: break; ! 582: ! 583: case '#': ! 584: fp = altfile; ! 585: if (*fp == 0) { ! 586: uxb[0] = 0; ! 587: error("No alternate filename@to substitute for #"); ! 588: } ! 589: goto uexp; ! 590: ! 591: case '%': ! 592: fp = savedfile; ! 593: if (*fp == 0) { ! 594: uxb[0] = 0; ! 595: error("No filename@to substitute for %%"); ! 596: } ! 597: uexp: ! 598: printub++; ! 599: while (*fp) { ! 600: if (up >= &uxb[UXBSIZE]) ! 601: goto tunix; ! 602: *up++ = *fp++ | QUOTE; ! 603: } ! 604: break; ! 605: } ! 606: c = getchar(); ! 607: } while (c == '|' || !endcmd(c)); ! 608: if (c == EOF) ! 609: ungetchar(c); ! 610: *up = 0; ! 611: if (!inopen) ! 612: resetflav(); ! 613: if (warn) ! 614: ckaw(); ! 615: if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) { ! 616: xchng = chng; ! 617: vnfl(); ! 618: printf(mesg("[No write]|[No write since last change]")); ! 619: noonl(); ! 620: flush(); ! 621: } else ! 622: warn = 0; ! 623: if (printub) { ! 624: if (uxb[0] == 0) ! 625: error("No previous command@to repeat"); ! 626: if (inopen) { ! 627: splitw++; ! 628: vclean(); ! 629: vgoto(WECHO, 0); ! 630: } ! 631: if (warn) ! 632: vnfl(); ! 633: if (hush == 0) ! 634: lprintf("!%s", uxb); ! 635: if (inopen) { ! 636: vclreol(); ! 637: vgoto(WECHO, 0); ! 638: } else ! 639: putnl(); ! 640: flush(); ! 641: } ! 642: } ! 643: ! 644: /* ! 645: * Do the real work for execution of a shell escape. ! 646: * Mode is like the number passed to open system calls ! 647: * and indicates filtering. If input is implied, newstdin ! 648: * must have been setup already. ! 649: */ ! 650: unixex(opt, up, newstdin, mode) ! 651: char *opt, *up; ! 652: int newstdin, mode; ! 653: { ! 654: int pvec[2], f; ! 655: ! 656: signal(SIGINT, SIG_IGN); ! 657: if (inopen) ! 658: f = setty(normf); ! 659: if ((mode & 1) && pipe(pvec) < 0) { ! 660: /* Newstdin should be io so it will be closed */ ! 661: if (inopen) ! 662: setty(f); ! 663: error("Can't make pipe for filter"); ! 664: } ! 665: #ifndef VFORK ! 666: pid = fork(); ! 667: #else ! 668: pid = vfork(); ! 669: #endif ! 670: if (pid < 0) { ! 671: if (mode & 1) { ! 672: close(pvec[0]); ! 673: close(pvec[1]); ! 674: } ! 675: setrupt(); ! 676: error("No more processes"); ! 677: } ! 678: if (pid == 0) { ! 679: if (mode & 2) { ! 680: close(0); ! 681: dup(newstdin); ! 682: close(newstdin); ! 683: } ! 684: if (mode & 1) { ! 685: close(pvec[0]); ! 686: close(1); ! 687: dup(pvec[1]); ! 688: if (inopen) { ! 689: close(2); ! 690: dup(1); ! 691: } ! 692: close(pvec[1]); ! 693: } ! 694: if (io) ! 695: close(io); ! 696: if (tfile) ! 697: close(tfile); ! 698: #ifndef VMUNIX ! 699: close(erfile); ! 700: #endif ! 701: signal(SIGHUP, oldhup); ! 702: signal(SIGQUIT, oldquit); ! 703: if (ruptible) ! 704: signal(SIGINT, SIG_DFL); ! 705: execl(svalue(SHELL), "sh", opt, up, (char *) 0); ! 706: printf("No %s!\n", svalue(SHELL)); ! 707: error(NOSTR); ! 708: } ! 709: if (mode & 1) { ! 710: io = pvec[0]; ! 711: close(pvec[1]); ! 712: } ! 713: if (newstdin) ! 714: close(newstdin); ! 715: return (f); ! 716: } ! 717: ! 718: /* ! 719: * Wait for the command to complete. ! 720: * F is for restoration of tty mode if from open/visual. ! 721: * C flags suppression of printing. ! 722: */ ! 723: unixwt(c, f) ! 724: bool c; ! 725: int f; ! 726: { ! 727: ! 728: waitfor(); ! 729: if (inopen) ! 730: setty(f); ! 731: setrupt(); ! 732: if (!inopen && c && hush == 0) { ! 733: printf("!\n"); ! 734: flush(); ! 735: termreset(); ! 736: gettmode(); ! 737: } ! 738: } ! 739: ! 740: /* ! 741: * Setup a pipeline for the filtration implied by mode ! 742: * which is like a open number. If input is required to ! 743: * the filter, then a child editor is created to write it. ! 744: * If output is catch it from io which is created by unixex. ! 745: */ ! 746: filter(mode) ! 747: register int mode; ! 748: { ! 749: static int pvec[2]; ! 750: register int f; ! 751: register int lines = lineDOL(); ! 752: ! 753: mode++; ! 754: if (mode & 2) { ! 755: signal(SIGINT, SIG_IGN); ! 756: if (pipe(pvec) < 0) ! 757: error("Can't make pipe"); ! 758: pid = fork(); ! 759: io = pvec[0]; ! 760: if (pid < 0) { ! 761: setrupt(); ! 762: close(pvec[1]); ! 763: error("No more processes"); ! 764: } ! 765: if (pid == 0) { ! 766: setrupt(); ! 767: io = pvec[1]; ! 768: close(pvec[0]); ! 769: putfile(); ! 770: exit(0); ! 771: } ! 772: close(pvec[1]); ! 773: io = pvec[0]; ! 774: setrupt(); ! 775: } ! 776: f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); ! 777: if (mode == 3) { ! 778: delete(0); ! 779: addr2 = addr1 - 1; ! 780: } ! 781: if (mode & 1) { ! 782: undap1 = undap2 = addr2+1; ! 783: ignore(append(getfile, addr2)); ! 784: } ! 785: close(io); ! 786: io = -1; ! 787: unixwt(!inopen, f); ! 788: netchHAD(lines); ! 789: } ! 790: ! 791: /* ! 792: * Set up to do a recover, getting io to be a pipe from ! 793: * the recover process. ! 794: */ ! 795: recover() ! 796: { ! 797: static int pvec[2]; ! 798: ! 799: if (pipe(pvec) < 0) ! 800: error(" Can't make pipe for recovery"); ! 801: pid = fork(); ! 802: io = pvec[0]; ! 803: if (pid < 0) { ! 804: close(pvec[1]); ! 805: error(" Can't fork to execute recovery"); ! 806: } ! 807: if (pid == 0) { ! 808: close(2); ! 809: dup(1); ! 810: close(1); ! 811: dup(pvec[1]); ! 812: close(pvec[1]); ! 813: execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); ! 814: close(1); ! 815: dup(2); ! 816: error(" No recovery routine"); ! 817: } ! 818: close(pvec[1]); ! 819: } ! 820: ! 821: /* ! 822: * Wait for the process (pid an external) to complete. ! 823: */ ! 824: waitfor() ! 825: { ! 826: ! 827: do ! 828: rpid = wait(&status); ! 829: while (rpid != pid && rpid != -1); ! 830: status = (status >> 8) & 0377; ! 831: } ! 832: ! 833: /* ! 834: * The end of a recover operation. If the process ! 835: * exits non-zero, force not edited; otherwise force ! 836: * a write. ! 837: */ ! 838: revocer() ! 839: { ! 840: ! 841: waitfor(); ! 842: if (pid == rpid && status != 0) ! 843: edited = 0; ! 844: else ! 845: change(); ! 846: } ! 847: ! 848: /* ! 849: * Extract the next line from the io stream. ! 850: */ ! 851: static char *nextip; ! 852: ! 853: getfile() ! 854: { ! 855: register short c; ! 856: register char *lp, *fp; ! 857: ! 858: lp = linebuf; ! 859: fp = nextip; ! 860: do { ! 861: if (--ninbuf < 0) { ! 862: ninbuf = read(io, genbuf, LBSIZE) - 1; ! 863: if (ninbuf < 0) { ! 864: if (lp != linebuf) { ! 865: printf(" [Incomplete last line]"); ! 866: break; ! 867: } ! 868: return (EOF); ! 869: } ! 870: fp = genbuf; ! 871: } ! 872: if (lp >= &linebuf[LBSIZE]) { ! 873: error(" Line too long"); ! 874: } ! 875: c = *fp++; ! 876: if (c == 0) { ! 877: cntnull++; ! 878: continue; ! 879: } ! 880: if (c & QUOTE) { ! 881: cntodd++; ! 882: c &= TRIM; ! 883: if (c == 0) ! 884: continue; ! 885: } ! 886: *lp++ = c; ! 887: } while (c != '\n'); ! 888: cntch += lp - linebuf; ! 889: *--lp = 0; ! 890: nextip = fp; ! 891: cntln++; ! 892: return (0); ! 893: } ! 894: ! 895: /* ! 896: * Write a range onto the io stream. ! 897: */ ! 898: putfile() ! 899: { ! 900: line *a1; ! 901: register char *fp, *lp; ! 902: register int nib; ! 903: ! 904: a1 = addr1; ! 905: clrstats(); ! 906: cntln = addr2 - a1 + 1; ! 907: if (cntln == 0) ! 908: return; ! 909: nib = BUFSIZ; ! 910: fp = genbuf; ! 911: do { ! 912: getline(*a1++); ! 913: lp = linebuf; ! 914: for (;;) { ! 915: if (--nib < 0) { ! 916: nib = fp - genbuf; ! 917: if (write(io, genbuf, nib) != nib) { ! 918: wrerror(); ! 919: } ! 920: cntch += nib; ! 921: nib = BUFSIZ - 1; ! 922: fp = genbuf; ! 923: } ! 924: if ((*fp++ = *lp++) == 0) { ! 925: fp[-1] = '\n'; ! 926: break; ! 927: } ! 928: } ! 929: } while (a1 <= addr2); ! 930: nib = fp - genbuf; ! 931: if (write(io, genbuf, nib) != nib) { ! 932: wrerror(); ! 933: } ! 934: cntch += nib; ! 935: } ! 936: ! 937: /* ! 938: * A write error has occurred; if the file being written was ! 939: * the edited file then we consider it to have changed since it is ! 940: * now likely scrambled. ! 941: */ ! 942: wrerror() ! 943: { ! 944: ! 945: if (eq(file, savedfile) && edited) ! 946: change(); ! 947: syserror(); ! 948: } ! 949: ! 950: /* ! 951: * Source command, handles nested sources. ! 952: * Traps errors since it mungs unit 0 during the source. ! 953: */ ! 954: static short slevel; ! 955: ! 956: source(fil, okfail) ! 957: char *fil; ! 958: bool okfail; ! 959: { ! 960: jmp_buf osetexit; ! 961: register int saveinp, ointty, oerrno; ! 962: int oprompt; ! 963: ! 964: signal(SIGINT, SIG_IGN); ! 965: saveinp = dup(0); ! 966: if (saveinp < 0) ! 967: error("Too many nested sources"); ! 968: close(0); ! 969: if (open(fil, 0) < 0) { ! 970: oerrno = errno; ! 971: setrupt(); ! 972: dup(saveinp); ! 973: close(saveinp); ! 974: errno = oerrno; ! 975: if (!okfail) ! 976: filioerr(fil); ! 977: return; ! 978: } ! 979: slevel++; ! 980: ointty = intty; ! 981: intty = isatty(0); ! 982: oprompt = value(PROMPT); ! 983: value(PROMPT) &= intty; ! 984: getexit(osetexit); ! 985: setrupt(); ! 986: if (setexit() == 0) ! 987: commands(1, 1); ! 988: else if (slevel > 1) { ! 989: close(0); ! 990: dup(saveinp); ! 991: close(saveinp); ! 992: slevel--; ! 993: resexit(osetexit); ! 994: reset(); ! 995: } ! 996: intty = ointty; ! 997: value(PROMPT) = oprompt; ! 998: close(0); ! 999: dup(saveinp); ! 1000: close(saveinp); ! 1001: slevel--; ! 1002: resexit(osetexit); ! 1003: } ! 1004: ! 1005: /* ! 1006: * Clear io statistics before a read or write. ! 1007: */ ! 1008: clrstats() ! 1009: { ! 1010: ! 1011: ninbuf = 0; ! 1012: cntch = 0; ! 1013: cntln = 0; ! 1014: cntnull = 0; ! 1015: cntodd = 0; ! 1016: } ! 1017: ! 1018: /* ! 1019: * Io is finished, close the unit and print statistics. ! 1020: */ ! 1021: iostats() ! 1022: { ! 1023: ! 1024: close(io); ! 1025: io = -1; ! 1026: if (hush == 0) { ! 1027: if (value(TERSE)) ! 1028: printf(" %d/%D", cntln, cntch); ! 1029: else ! 1030: printf(" %d line%s, %D character%s", cntln, plural((long) cntln), ! 1031: cntch, plural(cntch)); ! 1032: if (cntnull || cntodd) { ! 1033: printf(" ("); ! 1034: if (cntnull) { ! 1035: printf("%D null", cntnull); ! 1036: if (cntodd) ! 1037: printf(", "); ! 1038: } ! 1039: if (cntodd) ! 1040: printf("%D non-ASCII", cntodd); ! 1041: putchar(')'); ! 1042: } ! 1043: noonl(); ! 1044: flush(); ! 1045: } ! 1046: return (cntnull != 0 || cntodd != 0); ! 1047: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.