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