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