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