|
|
1.1 root 1: static char *SCCS_ID = "@(#)more.c 4.1 (Berkeley) 10/16/80";
2: /*
3: ** more.c - General purpose tty output filter and file perusal program
4: **
5: ** by Eric Shienbrood, UC Berkeley
6: */
7:
8: #include <whoami.h>
9: #ifdef V6
10: #include <retrofit.h>
11: #endif
12: #include <stdio.h>
13: #include <ctype.h>
14: #include <signal.h>
15: #include <errno.h>
16: #include <sgtty.h>
17: #include <setjmp.h>
18: #include <sys/types.h>
19: #include <sys/dir.h>
20: #include <sys/stat.h>
21: #include <local/uparm.h>
22:
23: /* Help file will eventually go in libpath(more.help) on all systems */
24:
25: #ifdef INGRES
26: #define VI "/usr/bin/vi"
27: #define HELPFILE "/mntp/doucette/more/more.help"
28: #endif
29:
30: #ifndef INGRES
31: #ifndef HELPFILE
32: #define HELPFILE libpath(more.help)
33: #endif
34: #define VI binpath(vi)
35: #endif
36:
37: #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m))
38: #define Ftell(f) file_pos
39: #define Fseek(f,off) (file_pos=off,fseek(f,off,0))
40: #define Getc(f) (++file_pos, getc(f))
41: #define Ungetc(c,f) (--file_pos, ungetc(c,f))
42:
43: #ifdef V6
44: #define MBIT RAW
45: #define CBREAK ~RAW
46: #else
47: #define MBIT CBREAK
48: #define stty(fd,argp) ioctl(fd,TIOCSETN,argp)
49: #endif
50:
51: #define TBUFSIZ 1024
52: #define LINSIZ 256
53: #define ctrl(letter) ('letter' & 077)
54: #define RUBOUT '\177'
55: #define ESC '\033'
56: #define QUIT '\034'
57:
58: struct sgttyb otty;
59: long file_pos, file_size;
60: int fnum, no_intty, no_tty, slow_tty;
61: int dum_opt, dlines, onquit(), end_it();
62: #ifdef SIGTSTP
63: int onsusp();
64: #endif
65: int nscroll = 11; /* Number of lines scrolled by 'd' */
66: int fold_opt = 1; /* Fold long lines */
67: int stop_opt = 1; /* Stop after form feeds */
68: int promptlen;
69: int Currline; /* Line we are currently at */
70: int startup = 1;
71: int firstf = 1;
72: int notell = 1;
73: int bad_so; /* True if overwriting does not turn off standout */
74: int inwait, Pause, errors;
75: int within; /* true if we are within a file,
76: false if we are between files */
77: int hard, dumb, noscroll, hardtabs;
78: int catch_susp; /* We should catch the SIGTSTP signal */
79: char **fnames; /* The list of file names */
80: int nfiles; /* Number of files left to process */
81: char *shell; /* The name of the shell to use */
82: int shellp; /* A previous shell command exists */
83: char ch;
84: jmp_buf restore;
85: char obuf[BUFSIZ]; /* stdout buffer */
86: char Line[LINSIZ]; /* Line buffer */
87: int Lpp = 24; /* lines per page */
88: char *Clear; /* clear screen */
89: char *eraseln; /* erase line */
90: char *Senter, *Sexit;/* enter and exit standout mode */
91: char *tgetstr();
92: int Mcol = 80; /* number of columns */
93: int Wrap = 1; /* set if automargins */
94: long fseek();
95: struct {
96: long chrctr, line;
97: } context, screen_start;
98: extern char PC; /* pad character */
99: extern short ospeed;
100:
101:
102: main(argc, argv)
103: int argc;
104: char *argv[];
105: {
106: register FILE *f;
107: register char *s;
108: register char *p;
109: register char ch;
110: register int left;
111: int prnames = 0;
112: int initopt = 0;
113: int srchopt = 0;
114: int clearit = 0;
115: int initline;
116: char initbuf[80];
117: FILE *checkf();
118:
119: nfiles = argc;
120: fnames = argv;
121: initterm ();
122: while (--nfiles > 0) {
123: if ((ch = (*++fnames)[0]) == '-') {
124: for (s = fnames[0] + 1, dlines = 0; *s != '\0'; s++)
125: if (isdigit(*s))
126: dlines = dlines*10 + *s - '0';
127: else if (*s == 'd')
128: dum_opt = 1;
129: else if (*s == 'l')
130: stop_opt = 0;
131: else if (*s == 'f')
132: fold_opt = 0;
133: }
134: else if (ch == '+') {
135: s = *fnames;
136: if (*++s == '/') {
137: srchopt++;
138: for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';)
139: *p++ = *s++;
140: *p = '\0';
141: }
142: else {
143: initopt++;
144: for (initline = 0; *s != '\0'; s++)
145: if (isdigit (*s))
146: initline = initline*10 + *s -'0';
147: --initline;
148: }
149: }
150: else break;
151: }
152: if (dlines == 0)
153: dlines = Lpp - (noscroll ? 1 : 2);
154: left = dlines;
155: if (nfiles > 1)
156: prnames++;
157: if (!no_intty && nfiles == 0) {
158: fputs("Usage: ",stderr);
159: fputs(argv[0],stderr);
160: fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr);
161: exit(1);
162: }
163: else
164: f = stdin;
165: if (!no_tty) {
166: signal(SIGQUIT, onquit);
167: signal(SIGINT, end_it);
168: #ifdef SIGTSTP
169: if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) {
170: signal(SIGTSTP, onsusp);
171: catch_susp++;
172: }
173: #endif
174: stty (2, &otty);
175: }
176: if (no_intty) {
177: if (no_tty)
178: copy_file (stdin);
179: else {
180: if ((ch = Getc (f)) == '\f')
181: doclear ();
182: else {
183: Ungetc (ch, f);
184: if (noscroll)
185: doclear ();
186: }
187: if (srchopt)
188: search (initbuf, stdin, 1);
189: else if (initopt)
190: skiplns (initline, stdin);
191: screen (stdin, left);
192: }
193: no_intty = 0;
194: prnames++;
195: firstf = 0;
196: }
197:
198: while (fnum < nfiles) {
199: if ((f = checkf (fnames[fnum], &clearit)) != NULL) {
200: context.line = context.chrctr = 0;
201: Currline = 0;
202: if (firstf) setjmp (restore);
203: if (firstf) {
204: firstf = 0;
205: if (srchopt)
206: search (initbuf, f, 1);
207: else if (initopt)
208: skiplns (initline, f);
209: }
210: else if (fnum < nfiles && !no_tty) {
211: setjmp (restore);
212: left = command (fnames[fnum], f);
213: }
214: if (left != 0) {
215: if (noscroll || clearit)
216: doclear ();
217: if (prnames) {
218: if (bad_so)
219: erase (0);
220: pr("::::::::::::::");
221: if (promptlen > 14)
222: erase (14);
223: printf ("\n%s\n::::::::::::::\n", fnames[fnum]);
224: if (left > Lpp - 4)
225: left = Lpp - 4;
226: }
227: if (no_tty)
228: copy_file (f);
229: else {
230: within++;
231: screen(f, left);
232: within = 0;
233: }
234: }
235: setjmp (restore);
236: fflush(stdout);
237: fclose(f);
238: screen_start.line = screen_start.chrctr = 0L;
239: context.line = context.chrctr = 0L;
240: }
241: fnum++;
242: firstf = 0;
243: }
244: reset_tty ();
245: exit(0);
246: }
247:
248: /*
249: ** Check whether the file named by fs is an ASCII file which the user may
250: ** access. If it is, return the opened file. Otherwise return NULL.
251: */
252:
253: FILE *
254: checkf (fs, clearfirst)
255: register char *fs;
256: int *clearfirst;
257: {
258: struct stat stbuf;
259: register FILE *f;
260: char c;
261:
262: if (stat (fs, &stbuf) == -1) {
263: fflush(stdout);
264: perror(fs);
265: return (NULL);
266: }
267: if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
268: printf("\n*** %s: directory ***\n\n", fs);
269: return (NULL);
270: }
271: if ((f=Fopen(fs, "r")) == NULL) {
272: fflush(stdout);
273: perror(fs);
274: return (NULL);
275: }
276: c = Getc(f);
277:
278: /* Try to see whether it is an ASCII file */
279:
280: switch ((c | *f->_ptr << 8) & 0177777) {
281: case 0405:
282: case 0407:
283: case 0410:
284: case 0411:
285: case 0413:
286: case 0177545:
287: printf("\n******** %s: Not a text file ********\n\n", fs);
288: fclose (f);
289: return (NULL);
290: default:
291: break;
292: }
293: if (c == '\f')
294: *clearfirst = 1;
295: else {
296: *clearfirst = 0;
297: Ungetc (c, f);
298: }
299: if ((file_size = stbuf.st_size) == 0)
300: file_size = 0x7fffffffffffffffL;
301: return (f);
302: }
303:
304: /*
305: ** A real function, for the tputs routine in termlib
306: */
307:
308: putch (ch)
309: char ch;
310: {
311: putchar (ch);
312: }
313:
314: /*
315: ** Print out the contents of the file f, one screenful at a time.
316: */
317:
318: #define STOP -10
319:
320: screen (f, num_lines)
321: register FILE *f;
322: register int num_lines;
323: {
324: register int c;
325: register int nchars;
326: int length;
327:
328: for (;;) {
329: while (num_lines > 0 && !Pause) {
330: if ((nchars = getline (f, &length)) == EOF)
331: return;
332: if (bad_so || (Senter && *Senter == ' ') && promptlen > 0)
333: erase (0);
334: prbuf (Line, length);
335: if (nchars < promptlen)
336: erase (nchars); /* erase () sets promptlen to 0 */
337: else promptlen = 0;
338: if (nchars < Mcol || !fold_opt)
339: putchar('\n');
340: if (nchars == STOP)
341: break;
342: num_lines--;
343: }
344: fflush(stdout);
345: if ((c = Getc(f)) == EOF)
346: return;
347: Ungetc (c, f);
348: setjmp (restore);
349: Pause = 0; startup = 0;
350: if ((num_lines = command (NULL, f)) == 0)
351: return;
352: if (hard && promptlen > 0)
353: erase (0);
354: if (noscroll && num_lines == dlines)
355: doclear ();
356: screen_start.line = Currline;
357: screen_start.chrctr = Ftell (f);
358: }
359: }
360:
361: /*
362: ** Come here if a quit signal is received
363: */
364:
365: onquit()
366: {
367: signal(SIGQUIT, SIG_IGN);
368: if (!inwait) {
369: putchar ('\n');
370: if (!startup) {
371: signal(SIGQUIT, onquit);
372: longjmp (restore, 1);
373: }
374: else
375: Pause++;
376: }
377: else if (!dum_opt && notell) {
378: write (2, "[Use q or Q to quit]", 20);
379: promptlen += 20;
380: notell = 0;
381: }
382: signal(SIGQUIT, onquit);
383: }
384:
385: /*
386: ** Clean up terminal state and exit. Also come here if interrupt signal received
387: */
388:
389: end_it ()
390: {
391:
392: reset_tty ();
393: if (promptlen > 0) {
394: kill_line ();
395: fflush (stdout);
396: }
397: else
398: write (2, "\n", 1);
399: _exit(0);
400: }
401:
402: copy_file(f)
403: register FILE *f;
404: {
405: register int c;
406:
407: while ((c = getc(f)) != EOF)
408: putchar(c);
409: }
410:
411: /* Simplified printf function */
412:
413: printf (fmt, args)
414: register char *fmt;
415: int args;
416: {
417: register int *argp;
418: register char ch;
419: register int ccount;
420:
421: ccount = 0;
422: argp = &args;
423: while (*fmt) {
424: while ((ch = *fmt++) != '%') {
425: if (ch == '\0')
426: return (ccount);
427: ccount++;
428: putchar (ch);
429: }
430: switch (*fmt++) {
431: case 'd':
432: ccount += printd (*argp);
433: break;
434: case 's':
435: ccount += pr ((char *)*argp);
436: break;
437: case '%':
438: ccount++;
439: argp--;
440: putchar ('%');
441: break;
442: case '0':
443: return (ccount);
444: default:
445: break;
446: }
447: ++argp;
448: }
449: return (ccount);
450:
451: }
452:
453: /*
454: ** Print an integer as a string of decimal digits,
455: ** returning the length of the print representation.
456: */
457:
458: printd (n)
459: int n;
460: {
461: int a, nchars;
462:
463: if (a = n/10)
464: nchars = 1 + printd(a);
465: else
466: nchars = 1;
467: putchar (n % 10 + '0');
468: return (nchars);
469: }
470:
471: /* Put the print representation of an integer into a string */
472: static char *sptr;
473:
474: scanstr (n, str)
475: int n;
476: char *str;
477: {
478: sptr = str;
479: sprintf (n);
480: *sptr = '\0';
481: }
482:
483: sprintf (n)
484: {
485: int a;
486:
487: if (a = n/10)
488: sprintf (a);
489: *sptr++ = n % 10 + '0';
490: }
491:
492: static char bell = ctrl(G);
493:
494: strlen (s)
495: char *s;
496: {
497: register char *p;
498:
499: p = s;
500: while (*p++)
501: ;
502: return (p - s - 1);
503: }
504:
505: /* See whether the last component of the path name "path" is equal to the
506: ** string "string"
507: */
508:
509: tailequ (path, string)
510: char *path;
511: register char *string;
512: {
513: register char *tail;
514:
515: tail = path + strlen(path);
516: while (tail >= path)
517: if (*(--tail) == '/')
518: break;
519: ++tail;
520: while (*tail++ == *string++)
521: if (*tail == '\0')
522: return(1);
523: return(0);
524: }
525:
526: prompt (filename)
527: char *filename;
528: {
529: if (promptlen > 0)
530: kill_line ();
531: if (!hard) {
532: promptlen = 8;
533: if (Senter && Sexit)
534: tputs (Senter, 1, putch);
535: pr("--More--");
536: if (filename != NULL) {
537: promptlen += printf ("(Next file: %s)", filename);
538: }
539: else if (!no_intty) {
540: promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size));
541: }
542: if (dum_opt) {
543: promptlen += pr("[Hit space to continue, Rubout to abort]");
544: }
545: if (Senter && Sexit)
546: tputs (Sexit, 1, putch);
547: fflush(stdout);
548: }
549: else
550: write (2, &bell, 1);
551: inwait++;
552: }
553:
554: /*
555: ** Get a logical line
556: */
557:
558: getline(f, length)
559: register FILE *f;
560: int *length;
561: {
562: register int c;
563: register char *p;
564: register int column;
565: static int colflg;
566:
567: p = Line;
568: column = 0;
569: c = Getc (f);
570: if (colflg && c == '\n') {
571: Currline++;
572: c = Getc (f);
573: }
574: while (p < &Line[LINSIZ - 1]) {
575: if (c == EOF) {
576: if (p > Line) {
577: *p = '\0';
578: *length = p - Line;
579: return (column);
580: }
581: *length = p - Line;
582: return (EOF);
583: }
584: if (c == '\n') {
585: Currline++;
586: break;
587: }
588: *p++ = c;
589: if (c == '\t')
590: if (hardtabs && column < promptlen && !hard) {
591: if (eraseln && !dumb) {
592: column = 1 + (column | 7);
593: tputs (eraseln, 1, putch);
594: promptlen = 0;
595: }
596: else {
597: for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) {
598: *p++ = ' ';
599: }
600: if (column >= promptlen) promptlen = 0;
601: }
602: }
603: else
604: column = 1 + (column | 7);
605: else if (c == '\b')
606: column--;
607: else if (c == '\r')
608: column = 0;
609: else if (c == '\f' && stop_opt) {
610: p[-1] = '^';
611: *p++ = 'L';
612: column += 2;
613: Pause++;
614: }
615: else if (c == EOF) {
616: *length = p - Line;
617: return (column);
618: }
619: else if (c >= ' ' && c != RUBOUT)
620: column++;
621: if (column >= Mcol && fold_opt) break;
622: c = Getc (f);
623: }
624: if (column >= Mcol && Mcol > 0) {
625: if (!Wrap) {
626: *p++ = '\n';
627: }
628: }
629: colflg = column == Mcol && fold_opt;
630: *length = p - Line;
631: *p = 0;
632: return (column);
633: }
634:
635: /*
636: ** Erase the rest of the prompt, assuming we are starting at column col.
637: */
638:
639: erase (col)
640: register int col;
641: {
642:
643: if (promptlen == 0)
644: return;
645: if (hard) {
646: putchar ('\n');
647: }
648: else {
649: if (col == 0)
650: putchar ('\r');
651: if (!dumb && eraseln)
652: tputs (eraseln, 1, putch);
653: else
654: for (col = promptlen - col; col > 0; col--)
655: putchar (' ');
656: }
657: promptlen = 0;
658: }
659:
660: /*
661: ** Erase the current line entirely
662: */
663:
664: kill_line ()
665: {
666: erase (0);
667: if (!eraseln || dumb) putchar ('\r');
668: }
669:
670: /*
671: ** Print string and return number of characters
672: */
673:
674: pr(s1)
675: char *s1;
676: {
677: register char *s;
678: register char c;
679:
680: for (s = s1; c = *s++; )
681: putchar(c);
682: return (s - s1 - 1);
683: }
684:
685:
686: /* Print a buffer of n characters */
687:
688: prbuf (s, n)
689: register char *s;
690: register int n;
691: {
692: while (n-- > 0)
693: putchar (*s++);
694: }
695:
696: /*
697: ** Clear the screen
698: */
699:
700: doclear()
701: {
702: if (Clear && !hard) {
703: tputs(Clear, 1, putch);
704:
705: /* Put out carriage return so that system doesn't
706: ** get confused by escape sequences when expanding tabs
707: */
708: putchar ('\r');
709: promptlen = 0;
710: }
711: }
712:
713: static int lastcmd, lastarg, lastp;
714: static int lastcolon;
715: char shell_line[132];
716:
717: /*
718: ** Read a command and do it. A command consists of an optional integer
719: ** argument followed by the command character. Return the number of lines
720: ** to display in the next screenful. If there is nothing more to display
721: ** in the current file, zero is returned.
722: */
723:
724: command (filename, f)
725: char *filename;
726: register FILE *f;
727: {
728: register int nlines;
729: register int retval;
730: register char c;
731: char colonch;
732: FILE *helpf;
733: int done;
734: char comchar, cmdbuf[80], *p;
735:
736: #define ret(val) retval=val;done++;break
737:
738: done = 0;
739: if (!errors)
740: prompt (filename);
741: else
742: errors = 0;
743: if (MBIT == RAW && slow_tty) {
744: otty.sg_flags |= MBIT;
745: stty(2, &otty);
746: }
747: for (;;) {
748: nlines = number (&comchar);
749: lastp = colonch = 0;
750: if (comchar == '.') { /* Repeat last command */
751: lastp++;
752: comchar = lastcmd;
753: nlines = lastarg;
754: if (lastcmd == ':')
755: colonch = lastcolon;
756: }
757: lastcmd = comchar;
758: lastarg = nlines;
759: if (comchar == otty.sg_erase) {
760: kill_line ();
761: prompt (filename);
762: continue;
763: }
764: switch (comchar) {
765: case ':':
766: retval = colon (filename, colonch, nlines);
767: if (retval >= 0)
768: done++;
769: break;
770: case ' ':
771: case 'z':
772: if (nlines == 0) nlines = dlines;
773: else if (comchar == 'z') dlines = nlines;
774: ret (nlines);
775: case 'd':
776: case ctrl(D):
777: if (nlines != 0) nscroll = nlines;
778: ret (nscroll);
779: case RUBOUT:
780: case 'q':
781: case 'Q':
782: end_it ();
783: case 's':
784: case 'f':
785: if (nlines == 0) nlines++;
786: if (comchar == 'f')
787: nlines *= dlines;
788: putchar ('\r');
789: erase (0);
790: printf("\n...skipping %d line", nlines);
791: if (nlines > 1)
792: pr("s\n\n");
793: else
794: pr("\n\n");
795: while (nlines > 0) {
796: while ((c = Getc (f)) != '\n')
797: if (c == EOF) {
798: retval = 0;
799: done++;
800: goto endsw;
801: }
802: Currline++;
803: nlines--;
804: }
805: ret (dlines);
806: case '\n':
807: if (nlines != 0)
808: dlines = nlines;
809: else
810: nlines = 1;
811: ret (nlines);
812: case '\f':
813: if (!no_intty) {
814: doclear ();
815: Fseek (f, screen_start.chrctr);
816: Currline = screen_start.line;
817: ret (dlines);
818: }
819: else {
820: write (2, &bell, 1);
821: break;
822: }
823: case '\'':
824: if (!no_intty) {
825: kill_line ();
826: pr ("\n***Back***\n\n");
827: Fseek (f, context.chrctr);
828: Currline = context.line;
829: ret (dlines);
830: }
831: else {
832: write (2, &bell, 1);
833: break;
834: }
835: case '=':
836: kill_line ();
837: promptlen = printd (Currline);
838: fflush (stdout);
839: break;
840: case 'n':
841: lastp++;
842: case '/':
843: if (nlines == 0) nlines++;
844: kill_line ();
845: pr ("/");
846: promptlen = 1;
847: fflush (stdout);
848: if (lastp) {
849: write (2,"\r", 1);
850: search (NULL, f, nlines); /* Use previous r.e. */
851: }
852: else {
853: ttyin (cmdbuf, 78, '/');
854: write (2, "\r", 1);
855: search (cmdbuf, f, nlines);
856: }
857: ret (dlines);
858: case '!':
859: do_shell (filename);
860: break;
861: case 'h':
862: if ((helpf = fopen (HELPFILE, "r")) == NULL)
863: error ("Can't open help file");
864: if (noscroll) doclear ();
865: copy_file (helpf);
866: close (helpf);
867: prompt (filename);
868: break;
869: case 'v': /* This case should go right before default */
870: if (!no_intty) {
871: kill_line ();
872: cmdbuf[0] = '+';
873: scanstr (Currline, &cmdbuf[1]);
874: pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
875: execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0);
876: break;
877: }
878: default:
879: write (2, &bell, 1);
880: break;
881: }
882: if (done) break;
883: }
884: putchar ('\r');
885: endsw:
886: inwait = 0;
887: notell++;
888: if (MBIT == RAW && slow_tty) {
889: otty.sg_flags &= ~MBIT;
890: stty(2, &otty);
891: }
892: return (retval);
893: }
894:
895: char ch;
896:
897: /*
898: * Execute a colon-prefixed command.
899: * Returns <0 if not a command that should cause
900: * more of the file to be printed.
901: */
902:
903: colon (filename, cmd, nlines)
904: char *filename;
905: int cmd;
906: int nlines;
907: {
908: if (cmd == 0)
909: ch = readch ();
910: else
911: ch = cmd;
912: lastcolon = ch;
913: switch (ch) {
914: case 'f':
915: kill_line ();
916: if (!no_intty)
917: promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline);
918: else
919: promptlen = printf ("[Not a file] line %d", Currline);
920: fflush (stdout);
921: return (-1);
922: case 'n':
923: if (nlines == 0) {
924: if (fnum >= nfiles - 1)
925: end_it ();
926: nlines++;
927: }
928: putchar ('\r');
929: erase (0);
930: skipf (nlines);
931: return (0);
932: case 'p':
933: if (no_intty) {
934: write (2, &bell, 1);
935: return (-1);
936: }
937: putchar ('\r');
938: erase (0);
939: if (nlines == 0)
940: nlines++;
941: skipf (-nlines);
942: return (0);
943: case '!':
944: do_shell (filename);
945: return (-1);
946: case 'q':
947: case 'Q':
948: end_it ();
949: default:
950: write (2, &bell, 1);
951: return (-1);
952: }
953: }
954:
955: /*
956: ** Read a decimal number from the terminal. Set cmd to the non-digit which
957: ** terminates the number.
958: */
959:
960: number(cmd)
961: char *cmd;
962: {
963: register int i;
964:
965: i = 0; ch = otty.sg_kill;
966: for (;;) {
967: ch = readch ();
968: if (ch >= '0' && ch <= '9')
969: i = i*10 + ch - '0';
970: else if (ch == otty.sg_kill)
971: i = 0;
972: else {
973: *cmd = ch;
974: break;
975: }
976: }
977: return (i);
978: }
979:
980: do_shell (filename)
981: char *filename;
982: {
983: char cmdbuf[80];
984:
985: kill_line ();
986: pr ("!");
987: fflush (stdout);
988: promptlen = 1;
989: if (lastp)
990: pr (shell_line);
991: else {
992: ttyin (cmdbuf, 78, '!');
993: if (expand (shell_line, cmdbuf)) {
994: kill_line ();
995: promptlen = printf ("!%s", shell_line);
996: }
997: }
998: fflush (stdout);
999: write (2, "\n", 1);
1000: promptlen = 0;
1001: shellp = 1;
1002: execute (filename, shell, shell, "-c", shell_line, 0);
1003: }
1004:
1005: /*
1006: ** Search for nth ocurrence of regular expression contained in buf in the file
1007: */
1008:
1009: search (buf, file, n)
1010: char buf[];
1011: FILE *file;
1012: register int n;
1013: {
1014: long startline = Ftell (file);
1015: register long line1 = startline;
1016: register long line2 = startline;
1017: register long line3 = startline;
1018: register int lncount;
1019: int saveln, rv, re_exec();
1020: char *s, *re_comp();
1021:
1022: context.line = saveln = Currline;
1023: context.chrctr = startline;
1024: lncount = 0;
1025: if ((s = re_comp (buf)) != 0)
1026: error (s);
1027: while (!feof (file)) {
1028: line3 = line2;
1029: line2 = line1;
1030: line1 = Ftell (file);
1031: rdline (file);
1032: lncount++;
1033: if ((rv = re_exec (Line)) == 1)
1034: if (--n == 0) {
1035: if (lncount > 3 || (lncount > 1 && no_intty))
1036: pr ("\n...skipping\n");
1037: if (!no_intty) {
1038: Currline -= (lncount >= 3 ? 3 : lncount);
1039: Fseek (file, line3);
1040: }
1041: else {
1042: kill_line ();
1043: pr (Line);
1044: putchar ('\n');
1045: }
1046: break;
1047: }
1048: else if (rv == -1)
1049: error ("Regular expression botch");
1050: }
1051: if (feof (file)) {
1052: if (!no_intty) {
1053: #ifdef V6
1054: file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */
1055: #endif
1056: Currline = saveln;
1057: Fseek (file, startline);
1058: }
1059: else {
1060: pr ("\nPattern not found\n");
1061: end_it ();
1062: }
1063: error ("Pattern not found");
1064: }
1065: }
1066:
1067: execute (filename, cmd, args)
1068: char *filename;
1069: char *cmd, *args;
1070: {
1071: int id;
1072:
1073: fflush (stdout);
1074: reset_tty ();
1075: while ((id = fork ()) < 0)
1076: sleep (5);
1077: if (id == 0) {
1078: execv (cmd, &args);
1079: write (2, "exec failed\n", 12);
1080: exit (1);
1081: }
1082: signal (SIGINT, SIG_IGN);
1083: signal (SIGQUIT, SIG_IGN);
1084: #ifdef SIGTSTP
1085: if (catch_susp)
1086: signal(SIGTSTP, SIG_DFL);
1087: #endif
1088: wait (0);
1089: signal (SIGINT, end_it);
1090: signal (SIGQUIT, onquit);
1091: #ifdef SIGTSTP
1092: if (catch_susp)
1093: signal(SIGTSTP, onsusp);
1094: #endif
1095: set_tty ();
1096: pr ("------------------------\n");
1097: prompt (filename);
1098: }
1099: /*
1100: ** Skip n lines in the file f
1101: */
1102:
1103: skiplns (n, f)
1104: register int n;
1105: register FILE *f;
1106: {
1107: register char c;
1108:
1109: while (n > 0) {
1110: while ((c = Getc (f)) != '\n')
1111: if (c == EOF)
1112: return;
1113: n--;
1114: Currline++;
1115: }
1116: }
1117:
1118: /*
1119: ** Skip nskip files in the file list (from the command line). Nskip may be
1120: ** negative.
1121: */
1122:
1123: skipf (nskip)
1124: register int nskip;
1125: {
1126: if (nskip == 0) return;
1127: if (nskip > 0) {
1128: if (fnum + nskip > nfiles - 1)
1129: nskip = nfiles - fnum - 1;
1130: }
1131: else if (within)
1132: ++fnum;
1133: fnum += nskip;
1134: if (fnum < 0)
1135: fnum = 0;
1136: pr ("\n...Skipping ");
1137: pr (nskip > 0 ? "to file " : "back to file ");
1138: pr (fnames[fnum]);
1139: pr ("\n\n");
1140: --fnum;
1141: }
1142:
1143: /*----------------------------- Terminal I/O -------------------------------*/
1144:
1145: initterm ()
1146: {
1147: char buf[TBUFSIZ];
1148: char clearbuf[100];
1149: char *clearptr, *padstr;
1150: char *getenv();
1151: int ldisc;
1152:
1153: setbuf(stdout, obuf);
1154: if (!(no_tty = gtty(1, &otty))) {
1155: if (tgetent(buf, getenv("TERM")) <= 0) {
1156: dumb++;
1157: }
1158: else {
1159: if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) {
1160: hard++; /* Hard copy terminal */
1161: Lpp = 24;
1162: }
1163: if (tailequ (fnames[0], "page") || !hard && tgetflag("ns"))
1164: noscroll++;
1165: if ((Mcol = tgetnum("co")) < 0)
1166: Mcol = 80;
1167: Wrap = tgetflag("am");
1168: bad_so = tgetflag ("xs");
1169: clearptr = clearbuf;
1170: eraseln = tgetstr("ce",&clearptr);
1171: Clear = tgetstr("cl", &clearptr);
1172: Senter = tgetstr("so", &clearptr);
1173: Sexit = tgetstr("se", &clearptr);
1174: if (padstr = tgetstr("pc", &clearptr))
1175: PC = *padstr;
1176: }
1177: if ((shell = getenv("SHELL")) == NULL)
1178: shell = "/bin/sh";
1179: }
1180: no_intty = gtty(0, &otty);
1181: gtty(2, &otty);
1182: ospeed = otty.sg_ospeed;
1183: slow_tty = ospeed < B1200;
1184: hardtabs = !(otty.sg_flags & XTABS);
1185: if (!no_tty) {
1186: otty.sg_flags &= ~ECHO;
1187: if (MBIT == CBREAK || !slow_tty)
1188: otty.sg_flags |= MBIT;
1189: }
1190: }
1191:
1192: readch ()
1193: {
1194: char ch;
1195: extern int errno;
1196:
1197: if (read (2, &ch, 1) <= 0)
1198: if (errno != EINTR)
1199: exit(0);
1200: else
1201: ch = otty.sg_kill;
1202: return (ch);
1203: }
1204:
1205: static char BS = '\b';
1206: static char CARAT = '^';
1207:
1208: ttyin (buf, nmax, pchar)
1209: char buf[];
1210: register int nmax;
1211: char pchar;
1212: {
1213: register char *sptr;
1214: register char ch;
1215: register int slash = 0;
1216: int maxlen;
1217: char cbuf;
1218:
1219: sptr = buf;
1220: maxlen = 0;
1221: while (sptr - buf < nmax) {
1222: if (promptlen > maxlen) maxlen = promptlen;
1223: ch = readch ();
1224: if (ch == '\\') {
1225: slash++;
1226: }
1227: else if ((ch == otty.sg_erase) && !slash) {
1228: if (sptr > buf) {
1229: --promptlen;
1230: write (2, &BS, 1);
1231: --sptr;
1232: if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
1233: --promptlen;
1234: write (2, &BS, 1);
1235: }
1236: continue;
1237: }
1238: else {
1239: if (!eraseln) promptlen = maxlen;
1240: longjmp (restore, 1);
1241: }
1242: }
1243: else if ((ch == otty.sg_kill) && !slash) {
1244: if (hard) {
1245: show (ch);
1246: putchar ('\n');
1247: putchar (pchar);
1248: }
1249: else {
1250: putchar ('\r');
1251: putchar (pchar);
1252: if (eraseln)
1253: erase (1);
1254: promptlen = 1;
1255: }
1256: sptr = buf;
1257: fflush (stdout);
1258: continue;
1259: }
1260: if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
1261: write (2, &BS, 1);
1262: --sptr;
1263: }
1264: if (ch != '\\')
1265: slash = 0;
1266: *sptr++ = ch;
1267: if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1268: ch += ch == RUBOUT ? -0100 : 0100;
1269: write (2, &CARAT, 1);
1270: promptlen++;
1271: }
1272: cbuf = ch;
1273: if (ch != '\n' && ch != ESC) {
1274: write (2, &cbuf, 1);
1275: promptlen++;
1276: }
1277: else
1278: break;
1279: }
1280: *--sptr = '\0';
1281: if (!eraseln) promptlen = maxlen;
1282: if (sptr - buf >= nmax - 1)
1283: error ("Line too long");
1284: }
1285:
1286: expand (outbuf, inbuf)
1287: char *outbuf;
1288: char *inbuf;
1289: {
1290: register char *instr;
1291: register char *outstr;
1292: register char ch;
1293: char temp[200];
1294: int changed = 0;
1295:
1296: instr = inbuf;
1297: outstr = temp;
1298: while ((ch = *instr++) != '\0')
1299: switch (ch) {
1300: case '%':
1301: if (!no_intty) {
1302: strcpy (outstr, fnames[fnum]);
1303: outstr += strlen (fnames[fnum]);
1304: changed++;
1305: }
1306: else
1307: *outstr++ = ch;
1308: break;
1309: case '!':
1310: if (!shellp)
1311: error ("No previous command to substitute for");
1312: strcpy (outstr, shell_line);
1313: outstr += strlen (shell_line);
1314: changed++;
1315: break;
1316: case '\\':
1317: if (*instr == '%' || *instr == '!') {
1318: *outstr++ = *instr++;
1319: break;
1320: }
1321: default:
1322: *outstr++ = ch;
1323: }
1324: *outstr++ = '\0';
1325: strcpy (outbuf, temp);
1326: return (changed);
1327: }
1328:
1329: show (ch)
1330: register char ch;
1331: {
1332: char cbuf;
1333:
1334: if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1335: ch += ch == RUBOUT ? -0100 : 0100;
1336: write (2, &CARAT, 1);
1337: promptlen++;
1338: }
1339: cbuf = ch;
1340: write (2, &cbuf, 1);
1341: promptlen++;
1342: }
1343:
1344: error (mess)
1345: char *mess;
1346: {
1347: kill_line ();
1348: promptlen += strlen (mess);
1349: if (Senter && Sexit) {
1350: tputs (Senter, 1, putch);
1351: pr(mess);
1352: tputs (Sexit, 1, putch);
1353: }
1354: else
1355: pr (mess);
1356: fflush(stdout);
1357: errors++;
1358: longjmp (restore, 1);
1359: }
1360:
1361:
1362: set_tty ()
1363: {
1364: otty.sg_flags |= MBIT;
1365: otty.sg_flags &= ~ECHO;
1366: stty(2, &otty);
1367: }
1368:
1369: reset_tty ()
1370: {
1371: otty.sg_flags |= ECHO;
1372: otty.sg_flags &= ~MBIT;
1373: stty(2, &otty);
1374: }
1375:
1376: rdline (f)
1377: register FILE *f;
1378: {
1379: register char c;
1380: register char *p;
1381:
1382: p = Line;
1383: while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
1384: *p++ = c;
1385: if (c == '\n')
1386: Currline++;
1387: *p = '\0';
1388: }
1389:
1390: /* Come here when we get a suspend signal from the terminal */
1391:
1392: #ifdef SIGTSTP
1393: onsusp ()
1394: {
1395: reset_tty ();
1396: fflush (stdout);
1397: /* Send the TSTP signal to suspend our process group */
1398: kill (0, SIGTSTP);
1399: /* Pause for station break */
1400:
1401: /* We're back */
1402: signal (SIGTSTP, onsusp);
1403: set_tty ();
1404: if (inwait)
1405: longjmp (restore);
1406: }
1407: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.