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