|
|
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.18.1.1 (Berkeley) 10/21/90";
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: i = read(io, (char *)&head, sizeof(head));
420: (void)lseek(io, 0L, L_SET);
421: if (i != sizeof(head))
422: break;
423: #ifndef vms
424: switch ((int)head.a_magic) {
425:
426: case 0405: /* data overlay on exec */
427: case OMAGIC: /* unshared */
428: case NMAGIC: /* shared text */
429: case 0411: /* separate I/D */
430: case ZMAGIC: /* VM/Unix demand paged */
431: case 0430: /* PDP-11 Overlay shared */
432: case 0431: /* PDP-11 Overlay sep I/D */
433: error(" Executable");
434:
435: /*
436: * We do not forbid the editing of portable archives
437: * because it is reasonable to edit them, especially
438: * if they are archives of text files. This is
439: * especially useful if you archive source files together
440: * and copy them to another system with ~%take, since
441: * the files sometimes show up munged and must be fixed.
442: */
443: case 0177545:
444: case 0177555:
445: error(" Archive");
446: case 070707:
447: error(" Cpio file");
448:
449: default:
450: {
451: char *bp = (char *)&head;
452: if ((u_char)bp[0] == (u_char)'\037' &&
453: (u_char)bp[1] == (u_char)'\235')
454: error(" Compressed file");
455: if (!strncmp(bp, "!<arch>\n__.SYMDEF", 17)
456: || !strncmp(bp, "!<arch>\n", 8))
457: error(" Archive");
458: }
459: break;
460: }
461: #endif
462: }
463: if (c != 'r') {
464: if (value(READONLY) && denied) {
465: value(READONLY) = ovro;
466: denied = 0;
467: }
468: if ((stbuf.st_mode & 0222) == 0 || access(file, 2) < 0) {
469: ovro = value(READONLY);
470: denied = 1;
471: value(READONLY) = 1;
472: }
473: }
474: if (value(READONLY)) {
475: ex_printf(" [Read only]");
476: flush();
477: }
478: #ifdef FLOCKFILE
479: /*
480: * Attempt to lock the file. We use an sharable lock if reading
481: * the file, and an exclusive lock if editting a file.
482: * The lock will be released when the file is no longer being
483: * referenced. At any time, the editor can have as many as
484: * three files locked, and with different lock statuses.
485: */
486: /*
487: * if this is either the saved or alternate file or current file,
488: * point to the appropriate descriptor and file lock status.
489: */
490: if (strcmp (file,savedfile) == 0) {
491: if (!io_savedfile) io_savedfile = dup(io) ;
492: lp = &lock_savedfile ; iop = &io_savedfile ;
493: } else if (strcmp (file,altfile) == 0) {
494: if (!io_altfile) io_altfile = dup(io) ;
495: lp = &lock_altfile ; iop = &io_altfile ;
496: } else {
497: /* throw away current lock, accquire new current lock */
498: if (io_curr) close (io_curr) ;
499: io_curr = dup(io) ;
500: lp = &lock_curr ; iop = &io_curr ;
501: lock_curr = 0 ;
502: }
503: if (c == 'r' || value(READONLY) || *lp == 0) {
504: /* if we have a lock already, don't bother */
505: if (!*lp) {
506: /* try for a shared lock */
507: if (flock(*iop, LOCK_SH|LOCK_NB) < 0
508: && errno == EWOULDBLOCK) {
509: ex_printf (
510: " [FILE BEING MODIFIED BY ANOTHER PROCESS]") ;
511: flush();
512: goto fail_lock ;
513: } else *lp = LOCK_SH ;
514: }
515: }
516: if ( c != 'r' && !value(READONLY) && *lp != LOCK_EX) {
517: /* if we are editting the file, upgrade to an exclusive lock. */
518: if (flock(*iop, LOCK_EX|LOCK_NB) < 0 && errno == EWOULDBLOCK) {
519: ex_printf (" [File open by another process]") ;
520: flush();
521: } else *lp = LOCK_EX ;
522: }
523: fail_lock:
524: #endif FLOCKFILE
525: if (c == 'r')
526: setdot();
527: else
528: setall();
529: if (FIXUNDO && inopen && c == 'r')
530: undap1 = undap2 = dot + 1;
531: rop2();
532: rop3(c);
533: }
534:
535: rop2()
536: {
537: line *first, *last, *a;
538: struct stat statb;
539:
540: deletenone();
541: clrstats();
542: first = addr2 + 1;
543: if (fstat(io, &statb) < 0)
544: bsize = LBSIZE;
545: else {
546: bsize = statb.st_blksize;
547: if (bsize <= 0)
548: bsize = LBSIZE;
549: }
550: ignore(append(getfile, addr2));
551: last = dot;
552: /*
553: * if the modeline variable is set,
554: * check the first and last five lines of the file
555: * for a mode line.
556: */
557: if (value(MODELINE)) {
558: for (a=first; a<=last; a++) {
559: if (a==first+5 && last-first > 10)
560: a = last - 4;
561: getline(*a);
562: checkmodeline(linebuf);
563: }
564: }
565: }
566:
567: rop3(c)
568: int c;
569: {
570:
571: if (iostats() == 0 && c == 'e')
572: edited++;
573: if (c == 'e') {
574: if (wasalt || firstpat) {
575: register line *addr = zero + oldadot;
576:
577: if (addr > dol)
578: addr = dol;
579: if (firstpat) {
580: globp = (*firstpat) ? firstpat : "$";
581: commands(1,1);
582: firstpat = 0;
583: } else if (addr >= one) {
584: if (inopen)
585: dot = addr;
586: markpr(addr);
587: } else
588: goto other;
589: } else
590: other:
591: if (dol > zero) {
592: if (inopen)
593: dot = one;
594: markpr(one);
595: }
596: if(FIXUNDO)
597: undkind = UNDNONE;
598: if (inopen) {
599: vcline = 0;
600: vreplace(0, LINES, lineDOL());
601: }
602: }
603: }
604:
605: /*
606: * Are these two really the same inode?
607: */
608: samei(sp, cp)
609: struct stat *sp;
610: char *cp;
611: {
612: struct stat stb;
613:
614: if (stat(cp, &stb) < 0 || sp->st_dev != stb.st_dev)
615: return (0);
616: return (sp->st_ino == stb.st_ino);
617: }
618:
619: /* Returns from edited() */
620: #define EDF 0 /* Edited file */
621: #define NOTEDF -1 /* Not edited file */
622: #define PARTBUF 1 /* Write of partial buffer to Edited file */
623:
624: /*
625: * Write a file.
626: */
627: wop(dofname)
628: bool dofname; /* if 1 call filename, else use savedfile */
629: {
630: register int c, exclam, nonexist;
631: line *saddr1, *saddr2;
632: struct stat stbuf;
633: #ifdef FLOCKFILE
634: int *lp, *iop ;
635: #endif FLOCKFILE
636:
637: c = 0;
638: exclam = 0;
639: if (dofname) {
640: if (peekchar() == '!')
641: exclam++, ignchar();
642: ignore(skipwh());
643: while (peekchar() == '>')
644: ignchar(), c++, ignore(skipwh());
645: if (c != 0 && c != 2)
646: error("Write forms are 'w' and 'w>>'");
647: filename('w');
648: } else {
649: if (savedfile[0] == 0)
650: error("No file|No current filename");
651: saddr1=addr1;
652: saddr2=addr2;
653: addr1=one;
654: addr2=dol;
655: CP(file, savedfile);
656: if (inopen) {
657: vclrech(0);
658: splitw++;
659: }
660: lprintf("\"%s\"", file);
661: }
662: nonexist = stat(file, &stbuf);
663: #ifdef FLOCKFILE
664: /*
665: * if this is either the saved or alternate file or current file,
666: * point to the appropriate descriptor and file lock status.
667: */
668: if (strcmp (file,savedfile) == 0) {
669: lp = &lock_savedfile ; iop = &io_savedfile ;
670: } else if (strcmp (file,altfile) == 0) {
671: lp = &lock_altfile ; iop = &io_altfile ;
672: } else {
673: lp = &lock_curr ; iop = &io_curr ;
674: }
675: if (!*iop && !nonexist){
676: *lp = 0 ;
677: if ((*iop = open(file, 1)) < 0) *iop = 0 ;
678: }
679: #endif FLOCKFILE
680: switch (c) {
681:
682: case 0:
683: if (!exclam && (!value(WRITEANY) || value(READONLY)))
684: switch (edfile()) {
685:
686: case NOTEDF:
687: if (nonexist)
688: break;
689: if ((stbuf.st_mode & S_IFMT) == S_IFCHR) {
690: if (samei(&stbuf, _PATH_DEVNULL))
691: break;
692: if (samei(&stbuf, _PATH_TTY))
693: break;
694: }
695: io = open(file, 1);
696: if (io < 0)
697: syserror();
698: if (!isatty(io))
699: serror(" File exists| File exists - use \"w! %s\" to overwrite", file);
700: close(io);
701: break;
702:
703: case EDF:
704: if (value(READONLY))
705: error(" File is read only");
706: break;
707:
708: case PARTBUF:
709: if (value(READONLY))
710: error(" File is read only");
711: error(" Use \"w!\" to write partial buffer");
712: }
713: cre:
714: /*
715: synctmp();
716: */
717: #ifdef FLOCKFILE
718: if (*iop && !*lp != LOCK_EX && !exclam) {
719: /*
720: * upgrade to a exclusive lock. if can't get, someone else
721: * has the exclusive lock. bitch to the user.
722: */
723: if (flock(*iop, LOCK_EX|LOCK_NB) < 0 && errno == EWOULDBLOCK)
724: error (" File being modified by another process - use \"w!\" to write");
725: else *lp = LOCK_EX ;
726: }
727: #endif FLOCKFILE
728: #ifdef V6
729: io = creat(file, 0644);
730: #else
731: io = creat(file, 0666);
732: #ifdef vms /* to retain file protection modes on newer version of file */
733: if (!nonexist)
734: chmod(file, stbuf.st_mode & 0777);
735: #endif
736: #endif
737: if (io < 0)
738: syserror();
739: writing = 1;
740: if (hush == 0)
741: if (nonexist)
742: ex_printf(" [New file]");
743: else if (value(WRITEANY) && edfile() != EDF)
744: ex_printf(" [Existing file]");
745: #ifdef FLOCKFILE
746: if (!*iop)
747: *iop = dup(io) ;
748: #endif FLOCKFILE
749: break;
750:
751: case 2:
752: io = open(file, 1);
753: if (io < 0) {
754: if (exclam || value(WRITEANY))
755: goto cre;
756: syserror();
757: }
758: lseek(io, 0l, 2);
759: #ifdef FLOCKFILE
760: if (!*iop) *iop = dup(io) ;
761: if (*lp != LOCK_EX && !exclam) {
762: /*
763: * upgrade to a exclusive lock. if can't get,
764: * someone else has the exclusive lock.
765: * bitch to the user.
766: */
767: if (flock(*iop, LOCK_SH|LOCK_NB) < 0
768: && errno == EWOULDBLOCK)
769: error (
770: " File being modified by another process - use \"w!>>\" to write");
771: else *lp = LOCK_EX ;
772: }
773: #endif FLOCKFILE
774: break;
775: }
776: #ifdef FLOCKFILE
777: if (flock(*iop, LOCK_EX|LOCK_NB) >= 0)
778: *lp = LOCK_EX ;
779: #endif FLOCKFILE
780: putfile(0);
781: #ifndef vms
782: (void) fsync(io);
783: #endif
784: ignore(iostats());
785: if (c != 2 && addr1 == one && addr2 == dol) {
786: if (eq(file, savedfile))
787: edited = 1;
788: ex_sync();
789: }
790: if (!dofname) {
791: addr1 = saddr1;
792: addr2 = saddr2;
793: }
794: writing = 0;
795: }
796:
797: /*
798: * Is file the edited file?
799: * Work here is that it is not considered edited
800: * if this is a partial buffer, and distinguish
801: * all cases.
802: */
803: edfile()
804: {
805:
806: if (!edited || !eq(file, savedfile))
807: return (NOTEDF);
808: return (addr1 == one && addr2 == dol ? EDF : PARTBUF);
809: }
810:
811: /*
812: * Extract the next line from the io stream.
813: */
814: char *nextip;
815:
816: getfile()
817: {
818: register short c;
819: register char *lp, *fp;
820:
821: lp = linebuf;
822: fp = nextip;
823: do {
824: if (--ninbuf < 0) {
825: ninbuf = read(io, genbuf, (int) bsize) - 1;
826: if (ninbuf < 0) {
827: if (lp != linebuf) {
828: lp++;
829: ex_printf(" [Incomplete last line]");
830: break;
831: }
832: return (EOF);
833: }
834: fp = genbuf;
835: cntch += ninbuf+1;
836: }
837: if (lp >= &linebuf[LBSIZE]) {
838: error(" Line too long");
839: }
840: c = *fp++;
841: if (c == 0) {
842: cntnull++;
843: continue;
844: }
845: if (c & QUOTE) {
846: cntodd++;
847: c &= TRIM;
848: if (c == 0)
849: continue;
850: }
851: *lp++ = c;
852: } while (c != '\n');
853: *--lp = 0;
854: nextip = fp;
855: cntln++;
856: return (0);
857: }
858:
859: /*
860: * Write a range onto the io stream.
861: */
862: /* ARGSUSED */
863: putfile(isfilter)
864: int isfilter;
865: {
866: line *a1;
867: register char *fp, *lp;
868: register int nib;
869: struct stat statb;
870:
871: a1 = addr1;
872: clrstats();
873: cntln = addr2 - a1 + 1;
874: if (cntln == 0)
875: return;
876: if (fstat(io, &statb) < 0)
877: bsize = LBSIZE;
878: else {
879: bsize = statb.st_blksize;
880: if (bsize <= 0)
881: bsize = LBSIZE;
882: }
883: nib = bsize;
884: fp = genbuf;
885: do {
886: getline(*a1++);
887: lp = linebuf;
888: for (;;) {
889: if (--nib < 0) {
890: nib = fp - genbuf;
891: if (write(io, genbuf, nib) != nib) {
892: wrerror();
893: }
894: cntch += nib;
895: nib = bsize - 1;
896: fp = genbuf;
897: }
898: if ((*fp++ = *lp++) == 0) {
899: fp[-1] = '\n';
900: break;
901: }
902: }
903: } while (a1 <= addr2);
904: nib = fp - genbuf;
905: if (write(io, genbuf, nib) != nib) {
906: wrerror();
907: }
908: cntch += nib;
909: }
910:
911: /*
912: * A write error has occurred; if the file being written was
913: * the edited file then we consider it to have changed since it is
914: * now likely scrambled.
915: */
916: wrerror()
917: {
918:
919: if (eq(file, savedfile) && edited)
920: change();
921: syserror();
922: }
923:
924: /*
925: * Source command, handles nested sources.
926: * Traps errors since it mungs unit 0 during the source.
927: */
928: short slevel;
929: short ttyindes;
930:
931: source(fil, okfail)
932: char *fil;
933: bool okfail;
934: {
935: jmp_buf osetexit;
936: register int saveinp, ointty, oerrno;
937: char *saveglobp;
938: short savepeekc;
939:
940: signal(SIGINT, SIG_IGN);
941: saveinp = dup(0);
942: savepeekc = peekc;
943: saveglobp = globp;
944: peekc = 0; globp = 0;
945: if (saveinp < 0)
946: error("Too many nested sources");
947: if (slevel <= 0)
948: ttyindes = saveinp;
949: close(0);
950: if (open(fil, 0) < 0) {
951: oerrno = errno;
952: setrupt();
953: dup(saveinp);
954: close(saveinp);
955: errno = oerrno;
956: if (!okfail)
957: filioerr(fil);
958: return;
959: }
960: slevel++;
961: ointty = intty;
962: intty = isatty(0);
963: oprompt = value(PROMPT);
964: value(PROMPT) &= intty;
965: getexit(osetexit);
966: setrupt();
967: if (setexit() == 0)
968: commands(1, 1);
969: else if (slevel > 1) {
970: close(0);
971: dup(saveinp);
972: close(saveinp);
973: slevel--;
974: resexit(osetexit);
975: reset();
976: }
977: intty = ointty;
978: value(PROMPT) = oprompt;
979: close(0);
980: dup(saveinp);
981: close(saveinp);
982: globp = saveglobp;
983: peekc = savepeekc;
984: slevel--;
985: resexit(osetexit);
986: }
987:
988: /*
989: * Clear io statistics before a read or write.
990: */
991: clrstats()
992: {
993:
994: ninbuf = 0;
995: cntch = 0;
996: cntln = 0;
997: cntnull = 0;
998: cntodd = 0;
999: }
1000:
1001: /*
1002: * Io is finished, close the unit and print statistics.
1003: */
1004: iostats()
1005: {
1006:
1007: close(io);
1008: io = -1;
1009: if (hush == 0) {
1010: if (value(TERSE))
1011: ex_printf(" %d/%D", cntln, cntch);
1012: else
1013: ex_printf(" %d line%s, %D character%s", cntln, plural((long) cntln),
1014: cntch, plural(cntch));
1015: if (cntnull || cntodd) {
1016: ex_printf(" (");
1017: if (cntnull) {
1018: ex_printf("%D null", cntnull);
1019: if (cntodd)
1020: ex_printf(", ");
1021: }
1022: if (cntodd)
1023: ex_printf("%D non-ASCII", cntodd);
1024: ex_putchar(')');
1025: }
1026: noonl();
1027: flush();
1028: }
1029: return (cntnull != 0 || cntodd != 0);
1030: }
1031:
1032: #ifdef USG
1033: # define index strchr
1034: # define rindex strrchr
1035: #endif
1036: #ifdef USG3TTY
1037: # define index strchr
1038: # define rindex strrchr
1039: #endif
1040: #ifdef vms
1041: # define index strchr
1042: # define rindex strrchr
1043: #endif
1044:
1045: checkmodeline(l)
1046: char *l;
1047: {
1048: char *beg, *end;
1049: char cmdbuf[1024];
1050: char *index(), *rindex(), *strncpy();
1051:
1052: beg = index(l, ':');
1053: if (beg == NULL)
1054: return;
1055: if (&beg[-3] < l)
1056: return;
1057: if (!( ( (beg[-3] == ' ' || beg[-3] == '\t')
1058: && beg[-2] == 'e'
1059: && beg[-1] == 'x')
1060: || ( (beg[-3] == ' ' || beg[-3] == '\t')
1061: && beg[-2] == 'v'
1062: && beg[-1] == 'i'))) return;
1063: strncpy(cmdbuf, beg+1, sizeof cmdbuf);
1064: end = rindex(cmdbuf, ':');
1065: if (end == NULL)
1066: return;
1067: *end = 0;
1068: globp = cmdbuf;
1069: commands(1, 1);
1070: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.