|
|
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.