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