1 /*-
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
11 All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)more.c 5.28 (Berkeley) 03/01/93";
16 #endif /* not lint */
17
18 /*
19 ** more.c - General purpose tty output filter and file perusal program
20 **
21 ** by Eric Shienbrood, UC Berkeley
22 **
23 ** modified by Geoff Peck, UCB to add underlining, single spacing
24 ** modified by John Foderaro, UCB to add -c and MORE environment variable
25 */
26
27 #include <sys/param.h>
28 #include <sys/stat.h>
29 #include <sys/file.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <sgtty.h>
33 #include <setjmp.h>
34 #include <a.out.h>
35 #include <varargs.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include "pathnames.h"
40
41 #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m))
42 #define Ftell(f) file_pos
43 #define Fseek(f,off) (file_pos=off,fseek(f,off,0))
44 #define Getc(f) (++file_pos, getc(f))
45 #define Ungetc(c,f) (--file_pos, ungetc(c,f))
46
47 #define MBIT CBREAK
48 #define stty(fd,argp) ioctl(fd,TIOCSETN,argp)
49
50 #define TBUFSIZ 1024
51 #define LINSIZ 256
52 #define ctrl(letter) (letter & 077)
53 #define RUBOUT '\177'
54 #define ESC '\033'
55 #define QUIT '\034'
56
57 struct sgttyb otty, savetty;
58 long file_pos, file_size;
59 int fnum, no_intty, no_tty, slow_tty;
60 int dum_opt, dlines;
61 void chgwinsz(), end_it(), onquit(), onsusp();
62 int nscroll = 11; /* Number of lines scrolled by 'd' */
63 int fold_opt = 1; /* Fold long lines */
64 int stop_opt = 1; /* Stop after form feeds */
65 int ssp_opt = 0; /* Suppress white space */
66 int ul_opt = 1; /* Underline as best we can */
67 int promptlen;
68 int Currline; /* Line we are currently at */
69 int startup = 1;
70 int firstf = 1;
71 int notell = 1;
72 int docrterase = 0;
73 int docrtkill = 0;
74 int bad_so; /* True if overwriting does not turn off standout */
75 int inwait, Pause, errors;
76 int within; /* true if we are within a file,
77 false if we are between files */
78 int hard, dumb, noscroll, hardtabs, clreol, eatnl;
79 int catch_susp; /* We should catch the SIGTSTP signal */
80 char **fnames; /* The list of file names */
81 int nfiles; /* Number of files left to process */
82 char *shell; /* The name of the shell to use */
83 int shellp; /* A previous shell command exists */
84 char ch;
85 jmp_buf restore;
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 *ULenter, *ULexit; /* enter and exit underline mode */
92 char *chUL; /* underline character */
93 char *chBS; /* backspace character */
94 char *Home; /* go to home */
95 char *cursorm; /* cursor movement */
96 char cursorhome[40]; /* contains cursor movement to home */
97 char *EodClr; /* clear rest of screen */
98 char *tgetstr();
99 int Mcol = 80; /* number of columns */
100 int Wrap = 1; /* set if automargins */
101 int soglitch; /* terminal has standout mode glitch */
102 int ulglitch; /* terminal has underline mode glitch */
103 int pstate = 0; /* current UL state */
104 char *getenv();
105 struct {
106 long chrctr, line;
107 } context, screen_start;
108 extern char PC; /* pad character */
109 extern short ospeed;
110
111
main(argc,argv)112 main(argc, argv)
113 int argc;
114 char *argv[];
115 {
116 register FILE *f;
117 register char *s;
118 register char *p;
119 register char ch;
120 register int left;
121 int prnames = 0;
122 int initopt = 0;
123 int srchopt = 0;
124 int clearit = 0;
125 int initline;
126 char initbuf[80];
127 FILE *checkf();
128
129 nfiles = argc;
130 fnames = argv;
131 initterm ();
132 nscroll = Lpp/2 - 1;
133 if (nscroll <= 0)
134 nscroll = 1;
135 if(s = getenv("MORE")) argscan(s);
136 while (--nfiles > 0) {
137 if ((ch = (*++fnames)[0]) == '-') {
138 argscan(*fnames+1);
139 }
140 else if (ch == '+') {
141 s = *fnames;
142 if (*++s == '/') {
143 srchopt++;
144 for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';)
145 *p++ = *s++;
146 *p = '\0';
147 }
148 else {
149 initopt++;
150 for (initline = 0; *s != '\0'; s++)
151 if (isdigit (*s))
152 initline = initline*10 + *s -'0';
153 --initline;
154 }
155 }
156 else break;
157 }
158 /* allow clreol only if Home and eraseln and EodClr strings are
159 * defined, and in that case, make sure we are in noscroll mode
160 */
161 if(clreol)
162 {
163 if((Home == NULL) || (*Home == '\0') ||
164 (eraseln == NULL) || (*eraseln == '\0') ||
165 (EodClr == NULL) || (*EodClr == '\0') )
166 clreol = 0;
167 else noscroll = 1;
168 }
169 if (dlines == 0)
170 dlines = Lpp - (noscroll ? 1 : 2);
171 left = dlines;
172 if (nfiles > 1)
173 prnames++;
174 if (!no_intty && nfiles == 0) {
175 char *rindex();
176
177 p = rindex(argv[0], '/');
178 fputs("usage: ",stderr);
179 fputs(p ? p + 1 : argv[0],stderr);
180 fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr);
181 exit(1);
182 }
183 else
184 f = stdin;
185 if (!no_tty) {
186 signal(SIGQUIT, onquit);
187 signal(SIGINT, end_it);
188 signal(SIGWINCH, chgwinsz);
189 if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) {
190 signal(SIGTSTP, onsusp);
191 catch_susp++;
192 }
193 stty (fileno(stderr), &otty);
194 }
195 if (no_intty) {
196 if (no_tty)
197 copy_file (stdin);
198 else {
199 if ((ch = Getc (f)) == '\f')
200 doclear();
201 else {
202 Ungetc (ch, f);
203 if (noscroll && (ch != EOF)) {
204 if (clreol)
205 home ();
206 else
207 doclear ();
208 }
209 }
210 if (srchopt)
211 {
212 search (initbuf, stdin, 1);
213 if (noscroll)
214 left--;
215 }
216 else if (initopt)
217 skiplns (initline, stdin);
218 screen (stdin, left);
219 }
220 no_intty = 0;
221 prnames++;
222 firstf = 0;
223 }
224
225 while (fnum < nfiles) {
226 if ((f = checkf (fnames[fnum], &clearit)) != NULL) {
227 context.line = context.chrctr = 0;
228 Currline = 0;
229 if (firstf) setjmp (restore);
230 if (firstf) {
231 firstf = 0;
232 if (srchopt)
233 {
234 search (initbuf, f, 1);
235 if (noscroll)
236 left--;
237 }
238 else if (initopt)
239 skiplns (initline, f);
240 }
241 else if (fnum < nfiles && !no_tty) {
242 setjmp (restore);
243 left = command (fnames[fnum], f);
244 }
245 if (left != 0) {
246 if ((noscroll || clearit) && (file_size != LONG_MAX))
247 if (clreol)
248 home ();
249 else
250 doclear ();
251 if (prnames) {
252 if (bad_so)
253 erase (0);
254 if (clreol)
255 cleareol ();
256 pr("::::::::::::::");
257 if (promptlen > 14)
258 erase (14);
259 prtf ("\n");
260 if(clreol) cleareol();
261 prtf("%s\n", fnames[fnum]);
262 if(clreol) cleareol();
263 prtf("::::::::::::::\n");
264 if (left > Lpp - 4)
265 left = Lpp - 4;
266 }
267 if (no_tty)
268 copy_file (f);
269 else {
270 within++;
271 screen(f, left);
272 within = 0;
273 }
274 }
275 setjmp (restore);
276 fflush(stdout);
277 fclose(f);
278 screen_start.line = screen_start.chrctr = 0L;
279 context.line = context.chrctr = 0L;
280 }
281 fnum++;
282 firstf = 0;
283 }
284 reset_tty ();
285 exit(0);
286 }
287
argscan(s)288 argscan(s)
289 char *s;
290 {
291 int seen_num = 0;
292
293 while (*s != '\0') {
294 switch (*s) {
295 case '0': case '1': case '2':
296 case '3': case '4': case '5':
297 case '6': case '7': case '8':
298 case '9':
299 if (!seen_num) {
300 dlines = 0;
301 seen_num = 1;
302 }
303 dlines = dlines*10 + *s - '0';
304 break;
305 case 'd':
306 dum_opt = 1;
307 break;
308 case 'l':
309 stop_opt = 0;
310 break;
311 case 'f':
312 fold_opt = 0;
313 break;
314 case 'p':
315 noscroll++;
316 break;
317 case 'c':
318 clreol++;
319 break;
320 case 's':
321 ssp_opt = 1;
322 break;
323 case 'u':
324 ul_opt = 0;
325 break;
326 }
327 s++;
328 }
329 }
330
331
332 /*
333 ** Check whether the file named by fs is an ASCII file which the user may
334 ** access. If it is, return the opened file. Otherwise return NULL.
335 */
336
337 FILE *
checkf(fs,clearfirst)338 checkf (fs, clearfirst)
339 register char *fs;
340 int *clearfirst;
341 {
342 struct stat stbuf;
343 register FILE *f;
344 char c;
345
346 if (stat (fs, &stbuf) == -1) {
347 (void)fflush(stdout);
348 if (clreol)
349 cleareol ();
350 perror(fs);
351 return((FILE *)NULL);
352 }
353 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
354 prtf("\n*** %s: directory ***\n\n", fs);
355 return((FILE *)NULL);
356 }
357 if ((f = Fopen(fs, "r")) == NULL) {
358 (void)fflush(stdout);
359 perror(fs);
360 return((FILE *)NULL);
361 }
362 if (magic(f, fs))
363 return((FILE *)NULL);
364 c = Getc(f);
365 *clearfirst = c == '\f';
366 Ungetc (c, f);
367 if ((file_size = stbuf.st_size) == 0)
368 file_size = LONG_MAX;
369 return(f);
370 }
371
372 /*
373 * magic --
374 * check for file magic numbers. This code would best be shared with
375 * the file(1) program or, perhaps, more should not try and be so smart?
376 */
magic(f,fs)377 magic(f, fs)
378 FILE *f;
379 char *fs;
380 {
381 struct exec ex;
382
383 if (fread(&ex, sizeof(ex), 1, f) == 1)
384 switch(ex.a_magic) {
385 case OMAGIC:
386 case NMAGIC:
387 case ZMAGIC:
388 case 0405:
389 case 0411:
390 case 0177545:
391 prtf("\n******** %s: Not a text file ********\n\n", fs);
392 (void)fclose(f);
393 return(1);
394 }
395 (void)fseek(f, 0L, L_SET); /* rewind() not necessary */
396 return(0);
397 }
398
399 /*
400 ** A real function, for the tputs routine in termlib
401 */
402
putch(ch)403 putch (ch)
404 char ch;
405 {
406 putchar (ch);
407 }
408
409 /*
410 ** Print out the contents of the file f, one screenful at a time.
411 */
412
413 #define STOP -10
414
screen(f,num_lines)415 screen (f, num_lines)
416 register FILE *f;
417 register int num_lines;
418 {
419 register int c;
420 register int nchars;
421 int length; /* length of current line */
422 static int prev_len = 1; /* length of previous line */
423
424 for (;;) {
425 while (num_lines > 0 && !Pause) {
426 if ((nchars = getline (f, &length)) == EOF)
427 {
428 if (clreol)
429 clreos();
430 return;
431 }
432 if (ssp_opt && length == 0 && prev_len == 0)
433 continue;
434 prev_len = length;
435 if (bad_so || (Senter && *Senter == ' ') && promptlen > 0)
436 erase (0);
437 /* must clear before drawing line since tabs on some terminals
438 * do not erase what they tab over.
439 */
440 if (clreol)
441 cleareol ();
442 prbuf (Line, length);
443 if (nchars < promptlen)
444 erase (nchars); /* erase () sets promptlen to 0 */
445 else promptlen = 0;
446 /* is this needed?
447 * if (clreol)
448 * cleareol(); /* must clear again in case we wrapped *
449 */
450 if (nchars < Mcol || !fold_opt)
451 prbuf("\n", 1); /* will turn off UL if necessary */
452 if (nchars == STOP)
453 break;
454 num_lines--;
455 }
456 if (pstate) {
457 tputs(ULexit, 1, putch);
458 pstate = 0;
459 }
460 fflush(stdout);
461 if ((c = Getc(f)) == EOF)
462 {
463 if (clreol)
464 clreos ();
465 return;
466 }
467
468 if (Pause && clreol)
469 clreos ();
470 Ungetc (c, f);
471 setjmp (restore);
472 Pause = 0; startup = 0;
473 if ((num_lines = command (NULL, f)) == 0)
474 return;
475 if (hard && promptlen > 0)
476 erase (0);
477 if (noscroll && num_lines >= dlines)
478 {
479 if (clreol)
480 home();
481 else
482 doclear ();
483 }
484 screen_start.line = Currline;
485 screen_start.chrctr = Ftell (f);
486 }
487 }
488
489 /*
490 ** Come here if a quit signal is received
491 */
492
493 void
onquit()494 onquit()
495 {
496 signal(SIGQUIT, SIG_IGN);
497 if (!inwait) {
498 putchar ('\n');
499 if (!startup) {
500 signal(SIGQUIT, onquit);
501 longjmp (restore, 1);
502 }
503 else
504 Pause++;
505 }
506 else if (!dum_opt && notell) {
507 write (2, "[Use q or Q to quit]", 20);
508 promptlen += 20;
509 notell = 0;
510 }
511 signal(SIGQUIT, onquit);
512 }
513
514 /*
515 ** Come here if a signal for a window size change is received
516 */
517
518 void
chgwinsz()519 chgwinsz()
520 {
521 struct winsize win;
522
523 (void) signal(SIGWINCH, SIG_IGN);
524 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) {
525 if (win.ws_row != 0) {
526 Lpp = win.ws_row;
527 nscroll = Lpp/2 - 1;
528 if (nscroll <= 0)
529 nscroll = 1;
530 dlines = Lpp - (noscroll ? 1 : 2);
531 }
532 if (win.ws_col != 0)
533 Mcol = win.ws_col;
534 }
535 (void) signal(SIGWINCH, chgwinsz);
536 }
537
538 /*
539 ** Clean up terminal state and exit. Also come here if interrupt signal received
540 */
541
542 void
end_it()543 end_it ()
544 {
545
546 reset_tty ();
547 if (clreol) {
548 putchar ('\r');
549 clreos ();
550 fflush (stdout);
551 }
552 else if (!clreol && (promptlen > 0)) {
553 kill_line ();
554 fflush (stdout);
555 }
556 else
557 write (2, "\n", 1);
558 _exit(0);
559 }
560
copy_file(f)561 copy_file(f)
562 register FILE *f;
563 {
564 register int c;
565
566 while ((c = getc(f)) != EOF)
567 putchar(c);
568 }
569
570 /* Simplified printf function */
571
prtf(fmt,va_alist)572 prtf (fmt, va_alist)
573 register char *fmt;
574 va_dcl
575 {
576 va_list ap;
577 register char ch;
578 register int ccount;
579
580 ccount = 0;
581 va_start(ap);
582 while (*fmt) {
583 while ((ch = *fmt++) != '%') {
584 if (ch == '\0')
585 return (ccount);
586 ccount++;
587 putchar (ch);
588 }
589 switch (*fmt++) {
590 case 'd':
591 ccount += printd (va_arg(ap, int));
592 break;
593 case 's':
594 ccount += pr (va_arg(ap, char *));
595 break;
596 case '%':
597 ccount++;
598 putchar ('%');
599 break;
600 case '0':
601 return (ccount);
602 default:
603 break;
604 }
605 }
606 va_end(ap);
607 return (ccount);
608
609 }
610
611 /*
612 ** Print an integer as a string of decimal digits,
613 ** returning the length of the print representation.
614 */
615
printd(n)616 printd (n)
617 int n;
618 {
619 int a, nchars;
620
621 if (a = n/10)
622 nchars = 1 + printd(a);
623 else
624 nchars = 1;
625 putchar (n % 10 + '0');
626 return (nchars);
627 }
628
629 /* Put the print representation of an integer into a string */
630 static char *sptr;
631
scanstr(n,str)632 scanstr (n, str)
633 int n;
634 char *str;
635 {
636 sptr = str;
637 Sprintf (n);
638 *sptr = '\0';
639 }
640
Sprintf(n)641 Sprintf (n)
642 {
643 int a;
644
645 if (a = n/10)
646 Sprintf (a);
647 *sptr++ = n % 10 + '0';
648 }
649
650 static char bell = ctrl('G');
651
652 /* See whether the last component of the path name "path" is equal to the
653 ** string "string"
654 */
655
tailequ(path,string)656 tailequ (path, string)
657 char *path;
658 register char *string;
659 {
660 register char *tail;
661
662 tail = path + strlen(path);
663 while (tail >= path)
664 if (*(--tail) == '/')
665 break;
666 ++tail;
667 while (*tail++ == *string++)
668 if (*tail == '\0')
669 return(1);
670 return(0);
671 }
672
prompt(filename)673 prompt (filename)
674 char *filename;
675 {
676 if (clreol)
677 cleareol ();
678 else if (promptlen > 0)
679 kill_line ();
680 if (!hard) {
681 promptlen = 8;
682 if (Senter && Sexit) {
683 tputs (Senter, 1, putch);
684 promptlen += (2 * soglitch);
685 }
686 if (clreol)
687 cleareol ();
688 pr("--More--");
689 if (filename != NULL) {
690 promptlen += prtf ("(Next file: %s)", filename);
691 }
692 else if (!no_intty) {
693 promptlen += prtf ("(%d%%)", (int)((file_pos * 100) / file_size));
694 }
695 if (dum_opt) {
696 promptlen += pr("[Press space to continue, 'q' to quit.]");
697 }
698 if (Senter && Sexit)
699 tputs (Sexit, 1, putch);
700 if (clreol)
701 clreos ();
702 fflush(stdout);
703 }
704 else
705 write (2, &bell, 1);
706 inwait++;
707 }
708
709 /*
710 ** Get a logical line
711 */
712
getline(f,length)713 getline(f, length)
714 register FILE *f;
715 int *length;
716 {
717 register int c;
718 register char *p;
719 register int column;
720 static int colflg;
721
722 p = Line;
723 column = 0;
724 c = Getc (f);
725 if (colflg && c == '\n') {
726 Currline++;
727 c = Getc (f);
728 }
729 while (p < &Line[LINSIZ - 1]) {
730 if (c == EOF) {
731 if (p > Line) {
732 *p = '\0';
733 *length = p - Line;
734 return (column);
735 }
736 *length = p - Line;
737 return (EOF);
738 }
739 if (c == '\n') {
740 Currline++;
741 break;
742 }
743 *p++ = c;
744 if (c == '\t')
745 if (!hardtabs || column < promptlen && !hard) {
746 if (hardtabs && eraseln && !dumb) {
747 column = 1 + (column | 7);
748 tputs (eraseln, 1, putch);
749 promptlen = 0;
750 }
751 else {
752 for (--p; p < &Line[LINSIZ - 1];) {
753 *p++ = ' ';
754 if ((++column & 7) == 0)
755 break;
756 }
757 if (column >= promptlen) promptlen = 0;
758 }
759 }
760 else
761 column = 1 + (column | 7);
762 else if (c == '\b' && column > 0)
763 column--;
764 else if (c == '\r')
765 column = 0;
766 else if (c == '\f' && stop_opt) {
767 p[-1] = '^';
768 *p++ = 'L';
769 column += 2;
770 Pause++;
771 }
772 else if (c == EOF) {
773 *length = p - Line;
774 return (column);
775 }
776 else if (c >= ' ' && c != RUBOUT)
777 column++;
778 if (column >= Mcol && fold_opt) break;
779 c = Getc (f);
780 }
781 if (column >= Mcol && Mcol > 0) {
782 if (!Wrap) {
783 *p++ = '\n';
784 }
785 }
786 colflg = column == Mcol && fold_opt;
787 if (colflg && eatnl && Wrap) {
788 *p++ = '\n'; /* simulate normal wrap */
789 }
790 *length = p - Line;
791 *p = 0;
792 return (column);
793 }
794
795 /*
796 ** Erase the rest of the prompt, assuming we are starting at column col.
797 */
798
erase(col)799 erase (col)
800 register int col;
801 {
802
803 if (promptlen == 0)
804 return;
805 if (hard) {
806 putchar ('\n');
807 }
808 else {
809 if (col == 0)
810 putchar ('\r');
811 if (!dumb && eraseln)
812 tputs (eraseln, 1, putch);
813 else
814 for (col = promptlen - col; col > 0; col--)
815 putchar (' ');
816 }
817 promptlen = 0;
818 }
819
820 /*
821 ** Erase the current line entirely
822 */
823
kill_line()824 kill_line ()
825 {
826 erase (0);
827 if (!eraseln || dumb) putchar ('\r');
828 }
829
830 /*
831 * force clear to end of line
832 */
cleareol()833 cleareol()
834 {
835 tputs(eraseln, 1, putch);
836 }
837
clreos()838 clreos()
839 {
840 tputs(EodClr, 1, putch);
841 }
842
843 /*
844 ** Print string and return number of characters
845 */
846
pr(s1)847 pr(s1)
848 char *s1;
849 {
850 register char *s;
851 register char c;
852
853 for (s = s1; c = *s++; )
854 putchar(c);
855 return (s - s1 - 1);
856 }
857
858
859 /* Print a buffer of n characters */
860
prbuf(s,n)861 prbuf (s, n)
862 register char *s;
863 register int n;
864 {
865 register char c; /* next output character */
866 register int state; /* next output char's UL state */
867 #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_')))
868
869 while (--n >= 0)
870 if (!ul_opt)
871 putchar (*s++);
872 else {
873 if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) {
874 s++;
875 continue;
876 }
877 if (state = wouldul(s, n)) {
878 c = (*s == '_')? s[2] : *s ;
879 n -= 2;
880 s += 3;
881 } else
882 c = *s++;
883 if (state != pstate) {
884 if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1))
885 state = 1;
886 else
887 tputs(state ? ULenter : ULexit, 1, putch);
888 }
889 if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0)
890 putchar(c);
891 if (state && *chUL) {
892 pr(chBS);
893 tputs(chUL, 1, putch);
894 }
895 pstate = state;
896 }
897 }
898
899 /*
900 ** Clear the screen
901 */
902
doclear()903 doclear()
904 {
905 if (Clear && !hard) {
906 tputs(Clear, 1, putch);
907
908 /* Put out carriage return so that system doesn't
909 ** get confused by escape sequences when expanding tabs
910 */
911 putchar ('\r');
912 promptlen = 0;
913 }
914 }
915
916 /*
917 * Go to home position
918 */
home()919 home()
920 {
921 tputs(Home,1,putch);
922 }
923
924 static int lastcmd, lastarg, lastp;
925 static int lastcolon;
926 char shell_line[132];
927
928 /*
929 ** Read a command and do it. A command consists of an optional integer
930 ** argument followed by the command character. Return the number of lines
931 ** to display in the next screenful. If there is nothing more to display
932 ** in the current file, zero is returned.
933 */
934
command(filename,f)935 command (filename, f)
936 char *filename;
937 register FILE *f;
938 {
939 register int nlines;
940 register int retval;
941 register char c;
942 char colonch;
943 FILE *helpf;
944 int done;
945 char comchar, cmdbuf[80], *p;
946
947 #define ret(val) retval=val;done++;break
948
949 done = 0;
950 if (!errors)
951 prompt (filename);
952 else
953 errors = 0;
954 if (MBIT == RAW && slow_tty) {
955 otty.sg_flags |= MBIT;
956 stty(fileno(stderr), &otty);
957 }
958 for (;;) {
959 nlines = number (&comchar);
960 lastp = colonch = 0;
961 if (comchar == '.') { /* Repeat last command */
962 lastp++;
963 comchar = lastcmd;
964 nlines = lastarg;
965 if (lastcmd == ':')
966 colonch = lastcolon;
967 }
968 lastcmd = comchar;
969 lastarg = nlines;
970 if (comchar == otty.sg_erase) {
971 kill_line ();
972 prompt (filename);
973 continue;
974 }
975 switch (comchar) {
976 case ':':
977 retval = colon (filename, colonch, nlines);
978 if (retval >= 0)
979 done++;
980 break;
981 case 'b':
982 case ctrl('B'):
983 {
984 register int initline;
985
986 if (no_intty) {
987 write(2, &bell, 1);
988 return (-1);
989 }
990
991 if (nlines == 0) nlines++;
992
993 putchar ('\r');
994 erase (0);
995 prtf ("\n");
996 if (clreol)
997 cleareol ();
998 prtf ("...back %d page", nlines);
999 if (nlines > 1)
1000 pr ("s\n");
1001 else
1002 pr ("\n");
1003
1004 if (clreol)
1005 cleareol ();
1006 pr ("\n");
1007
1008 initline = Currline - dlines * (nlines + 1);
1009 if (! noscroll)
1010 --initline;
1011 if (initline < 0) initline = 0;
1012 Fseek(f, 0L);
1013 Currline = 0; /* skiplns() will make Currline correct */
1014 skiplns(initline, f);
1015 if (! noscroll) {
1016 ret(dlines + 1);
1017 }
1018 else {
1019 ret(dlines);
1020 }
1021 }
1022 case ' ':
1023 case 'z':
1024 if (nlines == 0) nlines = dlines;
1025 else if (comchar == 'z') dlines = nlines;
1026 ret (nlines);
1027 case 'd':
1028 case ctrl('D'):
1029 if (nlines != 0) nscroll = nlines;
1030 ret (nscroll);
1031 case 'q':
1032 case 'Q':
1033 end_it ();
1034 case 's':
1035 case 'f':
1036 if (nlines == 0) nlines++;
1037 if (comchar == 'f')
1038 nlines *= dlines;
1039 putchar ('\r');
1040 erase (0);
1041 prtf ("\n");
1042 if (clreol)
1043 cleareol ();
1044 prtf ("...skipping %d line", nlines);
1045 if (nlines > 1)
1046 pr ("s\n");
1047 else
1048 pr ("\n");
1049
1050 if (clreol)
1051 cleareol ();
1052 pr ("\n");
1053
1054 while (nlines > 0) {
1055 while ((c = Getc (f)) != '\n')
1056 if (c == EOF) {
1057 retval = 0;
1058 done++;
1059 goto endsw;
1060 }
1061 Currline++;
1062 nlines--;
1063 }
1064 ret (dlines);
1065 case '\n':
1066 if (nlines != 0)
1067 dlines = nlines;
1068 else
1069 nlines = 1;
1070 ret (nlines);
1071 case '\f':
1072 if (!no_intty) {
1073 doclear ();
1074 Fseek (f, screen_start.chrctr);
1075 Currline = screen_start.line;
1076 ret (dlines);
1077 }
1078 else {
1079 write (2, &bell, 1);
1080 break;
1081 }
1082 case '\'':
1083 if (!no_intty) {
1084 kill_line ();
1085 pr ("\n***Back***\n\n");
1086 Fseek (f, context.chrctr);
1087 Currline = context.line;
1088 ret (dlines);
1089 }
1090 else {
1091 write (2, &bell, 1);
1092 break;
1093 }
1094 case '=':
1095 kill_line ();
1096 promptlen = printd (Currline);
1097 fflush (stdout);
1098 break;
1099 case 'n':
1100 lastp++;
1101 case '/':
1102 if (nlines == 0) nlines++;
1103 kill_line ();
1104 pr ("/");
1105 promptlen = 1;
1106 fflush (stdout);
1107 if (lastp) {
1108 write (2,"\r", 1);
1109 search (NULL, f, nlines); /* Use previous r.e. */
1110 }
1111 else {
1112 ttyin (cmdbuf, 78, '/');
1113 write (2, "\r", 1);
1114 search (cmdbuf, f, nlines);
1115 }
1116 ret (dlines-1);
1117 case '!':
1118 do_shell (filename);
1119 break;
1120 case '?':
1121 case 'h':
1122 if ((helpf = fopen (HELPFILE, "r")) == NULL)
1123 error ("Can't open help file");
1124 if (noscroll) doclear ();
1125 copy_file (helpf);
1126 fclose (helpf);
1127 prompt (filename);
1128 break;
1129 case 'v': /* This case should go right before default */
1130 if (!no_intty) {
1131 kill_line ();
1132 cmdbuf[0] = '+';
1133 scanstr (Currline - dlines < 0 ? 0
1134 : Currline - (dlines + 1) / 2, &cmdbuf[1]);
1135 pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
1136 execute (filename, _PATH_VI, "vi", cmdbuf, fnames[fnum], 0);
1137 break;
1138 }
1139 default:
1140 if (dum_opt) {
1141 kill_line ();
1142 if (Senter && Sexit) {
1143 tputs (Senter, 1, putch);
1144 promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch);
1145 tputs (Sexit, 1, putch);
1146 }
1147 else
1148 promptlen = pr ("[Press 'h' for instructions.]");
1149 fflush (stdout);
1150 }
1151 else
1152 write (2, &bell, 1);
1153 break;
1154 }
1155 if (done) break;
1156 }
1157 putchar ('\r');
1158 endsw:
1159 inwait = 0;
1160 notell++;
1161 if (MBIT == RAW && slow_tty) {
1162 otty.sg_flags &= ~MBIT;
1163 stty(fileno(stderr), &otty);
1164 }
1165 return (retval);
1166 }
1167
1168 char ch;
1169
1170 /*
1171 * Execute a colon-prefixed command.
1172 * Returns <0 if not a command that should cause
1173 * more of the file to be printed.
1174 */
1175
colon(filename,cmd,nlines)1176 colon (filename, cmd, nlines)
1177 char *filename;
1178 int cmd;
1179 int nlines;
1180 {
1181 if (cmd == 0)
1182 ch = readch ();
1183 else
1184 ch = cmd;
1185 lastcolon = ch;
1186 switch (ch) {
1187 case 'f':
1188 kill_line ();
1189 if (!no_intty)
1190 promptlen = prtf ("\"%s\" line %d", fnames[fnum], Currline);
1191 else
1192 promptlen = prtf ("[Not a file] line %d", Currline);
1193 fflush (stdout);
1194 return (-1);
1195 case 'n':
1196 if (nlines == 0) {
1197 if (fnum >= nfiles - 1)
1198 end_it ();
1199 nlines++;
1200 }
1201 putchar ('\r');
1202 erase (0);
1203 skipf (nlines);
1204 return (0);
1205 case 'p':
1206 if (no_intty) {
1207 write (2, &bell, 1);
1208 return (-1);
1209 }
1210 putchar ('\r');
1211 erase (0);
1212 if (nlines == 0)
1213 nlines++;
1214 skipf (-nlines);
1215 return (0);
1216 case '!':
1217 do_shell (filename);
1218 return (-1);
1219 case 'q':
1220 case 'Q':
1221 end_it ();
1222 default:
1223 write (2, &bell, 1);
1224 return (-1);
1225 }
1226 }
1227
1228 /*
1229 ** Read a decimal number from the terminal. Set cmd to the non-digit which
1230 ** terminates the number.
1231 */
1232
number(cmd)1233 number(cmd)
1234 char *cmd;
1235 {
1236 register int i;
1237
1238 i = 0; ch = otty.sg_kill;
1239 for (;;) {
1240 ch = readch ();
1241 if (ch >= '0' && ch <= '9')
1242 i = i*10 + ch - '0';
1243 else if (ch == otty.sg_kill)
1244 i = 0;
1245 else {
1246 *cmd = ch;
1247 break;
1248 }
1249 }
1250 return (i);
1251 }
1252
do_shell(filename)1253 do_shell (filename)
1254 char *filename;
1255 {
1256 char cmdbuf[80];
1257
1258 kill_line ();
1259 pr ("!");
1260 fflush (stdout);
1261 promptlen = 1;
1262 if (lastp)
1263 pr (shell_line);
1264 else {
1265 ttyin (cmdbuf, 78, '!');
1266 if (expand (shell_line, cmdbuf)) {
1267 kill_line ();
1268 promptlen = prtf ("!%s", shell_line);
1269 }
1270 }
1271 fflush (stdout);
1272 write (2, "\n", 1);
1273 promptlen = 0;
1274 shellp = 1;
1275 execute (filename, shell, shell, "-c", shell_line, 0);
1276 }
1277
1278 /*
1279 ** Search for nth ocurrence of regular expression contained in buf in the file
1280 */
1281
search(buf,file,n)1282 search (buf, file, n)
1283 char buf[];
1284 FILE *file;
1285 register int n;
1286 {
1287 long startline = Ftell (file);
1288 register long line1 = startline;
1289 register long line2 = startline;
1290 register long line3 = startline;
1291 register int lncount;
1292 int saveln, rv, re_exec();
1293 char *s, *re_comp();
1294
1295 context.line = saveln = Currline;
1296 context.chrctr = startline;
1297 lncount = 0;
1298 if ((s = re_comp (buf)) != 0)
1299 error (s);
1300 while (!feof (file)) {
1301 line3 = line2;
1302 line2 = line1;
1303 line1 = Ftell (file);
1304 rdline (file);
1305 lncount++;
1306 if ((rv = re_exec (Line)) == 1)
1307 if (--n == 0) {
1308 if (lncount > 3 || (lncount > 1 && no_intty))
1309 {
1310 pr ("\n");
1311 if (clreol)
1312 cleareol ();
1313 pr("...skipping\n");
1314 }
1315 if (!no_intty) {
1316 Currline -= (lncount >= 3 ? 3 : lncount);
1317 Fseek (file, line3);
1318 if (noscroll)
1319 if (clreol) {
1320 home ();
1321 cleareol ();
1322 }
1323 else
1324 doclear ();
1325 }
1326 else {
1327 kill_line ();
1328 if (noscroll)
1329 if (clreol) {
1330 home ();
1331 cleareol ();
1332 }
1333 else
1334 doclear ();
1335 pr (Line);
1336 putchar ('\n');
1337 }
1338 break;
1339 }
1340 else if (rv == -1)
1341 error ("Regular expression botch");
1342 }
1343 if (feof (file)) {
1344 if (!no_intty) {
1345 /* file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */
1346 Currline = saveln;
1347 Fseek (file, startline);
1348 }
1349 else {
1350 pr ("\nPattern not found\n");
1351 end_it ();
1352 }
1353 error ("Pattern not found");
1354 }
1355 }
1356
1357 /*VARARGS2*/
execute(filename,cmd,va_alist)1358 execute (filename, cmd, va_alist)
1359 char *filename;
1360 char *cmd;
1361 va_dcl
1362 {
1363 int id;
1364 int n;
1365 va_list argp;
1366
1367 fflush (stdout);
1368 reset_tty ();
1369 for (n = 10; (id = fork ()) < 0 && n > 0; n--)
1370 sleep (5);
1371 if (id == 0) {
1372 if (!isatty(0)) {
1373 close(0);
1374 open("/dev/tty", 0);
1375 }
1376 va_start(argp);
1377 execv (cmd, argp);
1378 write (2, "exec failed\n", 12);
1379 exit (1);
1380 va_end(argp); /* balance {}'s for some UNIX's */
1381 }
1382 if (id > 0) {
1383 signal (SIGINT, SIG_IGN);
1384 signal (SIGQUIT, SIG_IGN);
1385 if (catch_susp)
1386 signal(SIGTSTP, SIG_DFL);
1387 while (wait(0) > 0);
1388 signal (SIGINT, end_it);
1389 signal (SIGQUIT, onquit);
1390 if (catch_susp)
1391 signal(SIGTSTP, onsusp);
1392 } else
1393 write(2, "can't fork\n", 11);
1394 set_tty ();
1395 pr ("------------------------\n");
1396 prompt (filename);
1397 }
1398 /*
1399 ** Skip n lines in the file f
1400 */
1401
skiplns(n,f)1402 skiplns (n, f)
1403 register int n;
1404 register FILE *f;
1405 {
1406 register char c;
1407
1408 while (n > 0) {
1409 while ((c = Getc (f)) != '\n')
1410 if (c == EOF)
1411 return;
1412 n--;
1413 Currline++;
1414 }
1415 }
1416
1417 /*
1418 ** Skip nskip files in the file list (from the command line). Nskip may be
1419 ** negative.
1420 */
1421
skipf(nskip)1422 skipf (nskip)
1423 register int nskip;
1424 {
1425 if (nskip == 0) return;
1426 if (nskip > 0) {
1427 if (fnum + nskip > nfiles - 1)
1428 nskip = nfiles - fnum - 1;
1429 }
1430 else if (within)
1431 ++fnum;
1432 fnum += nskip;
1433 if (fnum < 0)
1434 fnum = 0;
1435 pr ("\n...Skipping ");
1436 pr ("\n");
1437 if (clreol)
1438 cleareol ();
1439 pr ("...Skipping ");
1440 pr (nskip > 0 ? "to file " : "back to file ");
1441 pr (fnames[fnum]);
1442 pr ("\n");
1443 if (clreol)
1444 cleareol ();
1445 pr ("\n");
1446 --fnum;
1447 }
1448
1449 /*----------------------------- Terminal I/O -------------------------------*/
1450
initterm()1451 initterm ()
1452 {
1453 char buf[TBUFSIZ];
1454 static char clearbuf[TBUFSIZ];
1455 char *clearptr, *padstr;
1456 int ldisc;
1457 int lmode;
1458 char *term;
1459 int tgrp;
1460 struct winsize win;
1461 char *tgoto();
1462
1463 retry:
1464 if (!(no_tty = ioctl(fileno(stdout), TIOCGETP, &otty))) {
1465 if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) {
1466 perror("TIOCLGET");
1467 exit(1);
1468 }
1469 docrterase = ((lmode & LCRTERA) != 0);
1470 docrtkill = ((lmode & LCRTKIL) != 0);
1471 /*
1472 * Wait until we're in the foreground before we save the
1473 * the terminal modes.
1474 */
1475 if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) {
1476 perror("TIOCGPGRP");
1477 exit(1);
1478 }
1479 if (tgrp != getpgrp(0)) {
1480 kill(0, SIGTTOU);
1481 goto retry;
1482 }
1483 if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) {
1484 dumb++; ul_opt = 0;
1485 }
1486 else {
1487 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) {
1488 Lpp = tgetnum("li");
1489 Mcol = tgetnum("co");
1490 } else {
1491 if ((Lpp = win.ws_row) == 0)
1492 Lpp = tgetnum("li");
1493 if ((Mcol = win.ws_col) == 0)
1494 Mcol = tgetnum("co");
1495 }
1496 if ((Lpp <= 0) || tgetflag("hc")) {
1497 hard++; /* Hard copy terminal */
1498 Lpp = 24;
1499 }
1500 if (tgetflag("xn"))
1501 eatnl++; /* Eat newline at last column + 1; dec, concept */
1502 if (Mcol <= 0)
1503 Mcol = 80;
1504
1505 if (tailequ (fnames[0], "page") || !hard && tgetflag("ns"))
1506 noscroll++;
1507 Wrap = tgetflag("am");
1508 bad_so = tgetflag ("xs");
1509 clearptr = clearbuf;
1510 eraseln = tgetstr("ce",&clearptr);
1511 Clear = tgetstr("cl", &clearptr);
1512 Senter = tgetstr("so", &clearptr);
1513 Sexit = tgetstr("se", &clearptr);
1514 if ((soglitch = tgetnum("sg")) < 0)
1515 soglitch = 0;
1516
1517 /*
1518 * Set up for underlining: some terminals don't need it;
1519 * others have start/stop sequences, still others have an
1520 * underline char sequence which is assumed to move the
1521 * cursor forward one character. If underline sequence
1522 * isn't available, settle for standout sequence.
1523 */
1524
1525 if (tgetflag("ul") || tgetflag("os"))
1526 ul_opt = 0;
1527 if ((chUL = tgetstr("uc", &clearptr)) == NULL )
1528 chUL = "";
1529 if (((ULenter = tgetstr("us", &clearptr)) == NULL ||
1530 (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) {
1531 if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) {
1532 ULenter = "";
1533 ULexit = "";
1534 } else
1535 ulglitch = soglitch;
1536 } else {
1537 if ((ulglitch = tgetnum("ug")) < 0)
1538 ulglitch = 0;
1539 }
1540
1541 if (padstr = tgetstr("pc", &clearptr))
1542 PC = *padstr;
1543 Home = tgetstr("ho",&clearptr);
1544 if (Home == 0 || *Home == '\0')
1545 {
1546 if ((cursorm = tgetstr("cm", &clearptr)) != NULL) {
1547 strcpy(cursorhome, tgoto(cursorm, 0, 0));
1548 Home = cursorhome;
1549 }
1550 }
1551 EodClr = tgetstr("cd", &clearptr);
1552 if ((chBS = tgetstr("bc", &clearptr)) == NULL)
1553 chBS = "\b";
1554
1555 }
1556 if ((shell = getenv("SHELL")) == NULL)
1557 shell = "/bin/sh";
1558 }
1559 no_intty = ioctl(fileno(stdin), TIOCGETP, &otty);
1560 (void)ioctl(fileno(stderr), TIOCGETP, &otty);
1561 savetty = otty;
1562 ospeed = otty.sg_ospeed;
1563 slow_tty = ospeed < B1200;
1564 hardtabs = (otty.sg_flags & TBDELAY) != XTABS;
1565 if (!no_tty) {
1566 otty.sg_flags &= ~ECHO;
1567 if (MBIT == CBREAK || !slow_tty)
1568 otty.sg_flags |= MBIT;
1569 }
1570 }
1571
readch()1572 readch ()
1573 {
1574 char ch;
1575 extern int errno;
1576
1577 errno = 0;
1578 if (read (2, &ch, 1) <= 0)
1579 if (errno != EINTR)
1580 end_it();
1581 else
1582 ch = otty.sg_kill;
1583 return (ch);
1584 }
1585
1586 static char BS = '\b';
1587 static char *BSB = "\b \b";
1588 static char CARAT = '^';
1589 #define ERASEONECHAR \
1590 if (docrterase) \
1591 write (2, BSB, sizeof(BSB)); \
1592 else \
1593 write (2, &BS, sizeof(BS));
1594
ttyin(buf,nmax,pchar)1595 ttyin (buf, nmax, pchar)
1596 char buf[];
1597 register int nmax;
1598 char pchar;
1599 {
1600 register char *sptr;
1601 register char ch;
1602 register int slash = 0;
1603 int maxlen;
1604 char cbuf;
1605
1606 sptr = buf;
1607 maxlen = 0;
1608 while (sptr - buf < nmax) {
1609 if (promptlen > maxlen) maxlen = promptlen;
1610 ch = readch ();
1611 if (ch == '\\') {
1612 slash++;
1613 }
1614 else if ((ch == otty.sg_erase) && !slash) {
1615 if (sptr > buf) {
1616 --promptlen;
1617 ERASEONECHAR
1618 --sptr;
1619 if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
1620 --promptlen;
1621 ERASEONECHAR
1622 }
1623 continue;
1624 }
1625 else {
1626 if (!eraseln) promptlen = maxlen;
1627 longjmp (restore, 1);
1628 }
1629 }
1630 else if ((ch == otty.sg_kill) && !slash) {
1631 if (hard) {
1632 show (ch);
1633 putchar ('\n');
1634 putchar (pchar);
1635 }
1636 else {
1637 putchar ('\r');
1638 putchar (pchar);
1639 if (eraseln)
1640 erase (1);
1641 else if (docrtkill)
1642 while (promptlen-- > 1)
1643 write (2, BSB, sizeof(BSB));
1644 promptlen = 1;
1645 }
1646 sptr = buf;
1647 fflush (stdout);
1648 continue;
1649 }
1650 if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
1651 ERASEONECHAR
1652 --sptr;
1653 }
1654 if (ch != '\\')
1655 slash = 0;
1656 *sptr++ = ch;
1657 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1658 ch += ch == RUBOUT ? -0100 : 0100;
1659 write (2, &CARAT, 1);
1660 promptlen++;
1661 }
1662 cbuf = ch;
1663 if (ch != '\n' && ch != ESC) {
1664 write (2, &cbuf, 1);
1665 promptlen++;
1666 }
1667 else
1668 break;
1669 }
1670 *--sptr = '\0';
1671 if (!eraseln) promptlen = maxlen;
1672 if (sptr - buf >= nmax - 1)
1673 error ("Line too long");
1674 }
1675
expand(outbuf,inbuf)1676 expand (outbuf, inbuf)
1677 char *outbuf;
1678 char *inbuf;
1679 {
1680 register char *instr;
1681 register char *outstr;
1682 register char ch;
1683 char temp[200];
1684 int changed = 0;
1685
1686 instr = inbuf;
1687 outstr = temp;
1688 while ((ch = *instr++) != '\0')
1689 switch (ch) {
1690 case '%':
1691 if (!no_intty) {
1692 strcpy (outstr, fnames[fnum]);
1693 outstr += strlen (fnames[fnum]);
1694 changed++;
1695 }
1696 else
1697 *outstr++ = ch;
1698 break;
1699 case '!':
1700 if (!shellp)
1701 error ("No previous command to substitute for");
1702 strcpy (outstr, shell_line);
1703 outstr += strlen (shell_line);
1704 changed++;
1705 break;
1706 case '\\':
1707 if (*instr == '%' || *instr == '!') {
1708 *outstr++ = *instr++;
1709 break;
1710 }
1711 default:
1712 *outstr++ = ch;
1713 }
1714 *outstr++ = '\0';
1715 strcpy (outbuf, temp);
1716 return (changed);
1717 }
1718
show(ch)1719 show (ch)
1720 register char ch;
1721 {
1722 char cbuf;
1723
1724 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1725 ch += ch == RUBOUT ? -0100 : 0100;
1726 write (2, &CARAT, 1);
1727 promptlen++;
1728 }
1729 cbuf = ch;
1730 write (2, &cbuf, 1);
1731 promptlen++;
1732 }
1733
error(mess)1734 error (mess)
1735 char *mess;
1736 {
1737 if (clreol)
1738 cleareol ();
1739 else
1740 kill_line ();
1741 promptlen += strlen (mess);
1742 if (Senter && Sexit) {
1743 tputs (Senter, 1, putch);
1744 pr(mess);
1745 tputs (Sexit, 1, putch);
1746 }
1747 else
1748 pr (mess);
1749 fflush(stdout);
1750 errors++;
1751 longjmp (restore, 1);
1752 }
1753
1754
set_tty()1755 set_tty ()
1756 {
1757 otty.sg_flags |= MBIT;
1758 otty.sg_flags &= ~ECHO;
1759 stty(fileno(stderr), &otty);
1760 }
1761
reset_tty()1762 reset_tty ()
1763 {
1764 if (no_tty)
1765 return;
1766 if (pstate) {
1767 tputs(ULexit, 1, putch);
1768 fflush(stdout);
1769 pstate = 0;
1770 }
1771 otty.sg_flags |= ECHO;
1772 otty.sg_flags &= ~MBIT;
1773 stty(fileno(stderr), &savetty);
1774 }
1775
rdline(f)1776 rdline (f)
1777 register FILE *f;
1778 {
1779 register char c;
1780 register char *p;
1781
1782 p = Line;
1783 while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
1784 *p++ = c;
1785 if (c == '\n')
1786 Currline++;
1787 *p = '\0';
1788 }
1789
1790 /* Come here when we get a suspend signal from the terminal */
1791
1792 void
onsusp()1793 onsusp ()
1794 {
1795 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
1796 signal(SIGTTOU, SIG_IGN);
1797 reset_tty ();
1798 fflush (stdout);
1799 signal(SIGTTOU, SIG_DFL);
1800 /* Send the TSTP signal to suspend our process group */
1801 signal(SIGTSTP, SIG_DFL);
1802 sigsetmask(0);
1803 kill (0, SIGTSTP);
1804 /* Pause for station break */
1805
1806 /* We're back */
1807 signal (SIGTSTP, onsusp);
1808 set_tty ();
1809 if (inwait)
1810 longjmp (restore, 1);
1811 }
1812