xref: /titanic_53/usr/src/cmd/pg/pg.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <signal.h>
34*7c478bd9Sstevel@tonic-gate #include <setjmp.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
38*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
39*7c478bd9Sstevel@tonic-gate #include <ctype.h>
40*7c478bd9Sstevel@tonic-gate #include <stdio.h>
41*7c478bd9Sstevel@tonic-gate #include <wchar.h>
42*7c478bd9Sstevel@tonic-gate #include <curses.h>
43*7c478bd9Sstevel@tonic-gate #include <term.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
46*7c478bd9Sstevel@tonic-gate #include <regexpr.h>
47*7c478bd9Sstevel@tonic-gate #include <limits.h>
48*7c478bd9Sstevel@tonic-gate #include <locale.h>
49*7c478bd9Sstevel@tonic-gate #include <wctype.h> /* iswprint() */
50*7c478bd9Sstevel@tonic-gate #include <string.h>
51*7c478bd9Sstevel@tonic-gate #include <unistd.h>
52*7c478bd9Sstevel@tonic-gate #include <wait.h>
53*7c478bd9Sstevel@tonic-gate #include <libw.h>
54*7c478bd9Sstevel@tonic-gate #include <regexpr.h>
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /*
58*7c478bd9Sstevel@tonic-gate  *	pg -- paginator for crt terminals
59*7c478bd9Sstevel@tonic-gate  *
60*7c478bd9Sstevel@tonic-gate  *	Includes the ability to display pages that have
61*7c478bd9Sstevel@tonic-gate  *	already passed by. Also gives the user the ability
62*7c478bd9Sstevel@tonic-gate  *	to search forward and backwards for regular expressions.
63*7c478bd9Sstevel@tonic-gate  *	This works for piped input by copying to a temporary file,
64*7c478bd9Sstevel@tonic-gate  *	and resolving backreferences from there.
65*7c478bd9Sstevel@tonic-gate  *
66*7c478bd9Sstevel@tonic-gate  *	Note:	The reason that there are so many commands to do
67*7c478bd9Sstevel@tonic-gate  *		the same types of things is to try to accommodate
68*7c478bd9Sstevel@tonic-gate  *		users of other paginators.
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	LINSIZ	1024
72*7c478bd9Sstevel@tonic-gate #define	QUIT	'\034'
73*7c478bd9Sstevel@tonic-gate #define	BOF	(EOF - 1)	/* Begining of File */
74*7c478bd9Sstevel@tonic-gate #define	STOP    (EOF - 2)
75*7c478bd9Sstevel@tonic-gate #define	PROMPTSIZE	256
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate /*
78*7c478bd9Sstevel@tonic-gate  * Function definitions
79*7c478bd9Sstevel@tonic-gate  */
80*7c478bd9Sstevel@tonic-gate static	void	lineset(int);
81*7c478bd9Sstevel@tonic-gate static	char	*setprompt();
82*7c478bd9Sstevel@tonic-gate static	int	set_state(int *, wchar_t, char *);
83*7c478bd9Sstevel@tonic-gate static	void	help();
84*7c478bd9Sstevel@tonic-gate static	void	copy_file(FILE *, FILE *);
85*7c478bd9Sstevel@tonic-gate static	void	re_error(int);
86*7c478bd9Sstevel@tonic-gate static	void	save_input(FILE *);
87*7c478bd9Sstevel@tonic-gate static	void	save_pipe();
88*7c478bd9Sstevel@tonic-gate static	void	newdol(FILE *);
89*7c478bd9Sstevel@tonic-gate static	void	erase_line(int);
90*7c478bd9Sstevel@tonic-gate static	void	kill_line();
91*7c478bd9Sstevel@tonic-gate static	void	doclear();
92*7c478bd9Sstevel@tonic-gate static	void	sopr(char *, int);
93*7c478bd9Sstevel@tonic-gate static	void	prompt(char *);
94*7c478bd9Sstevel@tonic-gate static	void	error(char *);
95*7c478bd9Sstevel@tonic-gate static	void	terminit();
96*7c478bd9Sstevel@tonic-gate static	void	compact();
97*7c478bd9Sstevel@tonic-gate static	off_t	getline(FILE *);
98*7c478bd9Sstevel@tonic-gate static	int	mrdchar();
99*7c478bd9Sstevel@tonic-gate static	off_t	find(int, off_t);
100*7c478bd9Sstevel@tonic-gate static	int	search(char *, off_t);
101*7c478bd9Sstevel@tonic-gate static	FILE	*checkf(char *);
102*7c478bd9Sstevel@tonic-gate static	int	skipf(int);
103*7c478bd9Sstevel@tonic-gate static	int	readch();
104*7c478bd9Sstevel@tonic-gate static	int	ttyin();
105*7c478bd9Sstevel@tonic-gate static	int	number();
106*7c478bd9Sstevel@tonic-gate static	int	command(char *);
107*7c478bd9Sstevel@tonic-gate static	int	screen(char *);
108*7c478bd9Sstevel@tonic-gate static	int	fgetputc();
109*7c478bd9Sstevel@tonic-gate static 	char	*pg_strchr();
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate struct line {			/* how line addresses are stored */
113*7c478bd9Sstevel@tonic-gate 	off_t	l_addr;		/* file offset */
114*7c478bd9Sstevel@tonic-gate 	off_t	l_no;		/* line number in file */
115*7c478bd9Sstevel@tonic-gate };
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate typedef	struct line	LINE;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate static	LINE	*zero = NULL,	/* first line */
120*7c478bd9Sstevel@tonic-gate 		*dot,		/* current line */
121*7c478bd9Sstevel@tonic-gate 		*dol,		/* last line */
122*7c478bd9Sstevel@tonic-gate 		*contig;	/* where contiguous (non-aged) lines start */
123*7c478bd9Sstevel@tonic-gate static	long	nlall;		/* room for how many LINEs in memory */
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate static	FILE	*in_file,	/* current input stream */
126*7c478bd9Sstevel@tonic-gate 		*tmp_fin,	/* pipe temporary file in */
127*7c478bd9Sstevel@tonic-gate 		*tmp_fou;	/* pipe temporary file out */
128*7c478bd9Sstevel@tonic-gate static	char	tmp_name[] = "/tmp/pgXXXXXX";
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate static	short	sign;		/* sign of command input */
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate static	int	fnum,		/* which file argument we're in */
133*7c478bd9Sstevel@tonic-gate 		pipe_in,	/* set when stdin is a pipe */
134*7c478bd9Sstevel@tonic-gate 		out_is_tty;	/* set if stdout is a tty */
135*7c478bd9Sstevel@tonic-gate static	gid_t	my_pgid;
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate static	void	on_brk(),
138*7c478bd9Sstevel@tonic-gate 		end_it();
139*7c478bd9Sstevel@tonic-gate static	short	brk_hit;	/* interrupt handling is pending flag */
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate static	int	window = 0;	/* window size in lines */
142*7c478bd9Sstevel@tonic-gate static	short	eof_pause = 1;	/* pause w/ prompt at end of files */
143*7c478bd9Sstevel@tonic-gate static	short	rmode = 0;	/* deny shell escape in restricted mode */
144*7c478bd9Sstevel@tonic-gate static	short	soflag = 0;	/* output all messages in standout mode */
145*7c478bd9Sstevel@tonic-gate static	short	promptlen;	/* length of the current prompt */
146*7c478bd9Sstevel@tonic-gate static	short	firstf = 1;	/* set before first file has been processed */
147*7c478bd9Sstevel@tonic-gate static	short	inwait,		/* set while waiting for user input */
148*7c478bd9Sstevel@tonic-gate 		errors;		/* set if error message has been printed. */
149*7c478bd9Sstevel@tonic-gate 				/* if so, need to erase it and prompt */
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate static	char	**fnames;
152*7c478bd9Sstevel@tonic-gate static	short	status = 0;	/* set > 0 if error detected */
153*7c478bd9Sstevel@tonic-gate static	short	fflag = 0;	/* set if the f option is used */
154*7c478bd9Sstevel@tonic-gate static	short	nflag = 0;	/* set for "no newline" input option */
155*7c478bd9Sstevel@tonic-gate static	short	clropt = 0;	/* set if the clear option is used */
156*7c478bd9Sstevel@tonic-gate static	int	initopt = 0;	/* set if the line option is used */
157*7c478bd9Sstevel@tonic-gate static	int	srchopt = 0;	/* set if the search option is used */
158*7c478bd9Sstevel@tonic-gate static	int	initline;
159*7c478bd9Sstevel@tonic-gate static	char	initbuf[BUFSIZ];
160*7c478bd9Sstevel@tonic-gate static	wchar_t	leave_search = L't';
161*7c478bd9Sstevel@tonic-gate 				/* where on the page to leave a found string */
162*7c478bd9Sstevel@tonic-gate static	short	nfiles;
163*7c478bd9Sstevel@tonic-gate static	char	*shell;
164*7c478bd9Sstevel@tonic-gate static	char	*promptstr = ":";
165*7c478bd9Sstevel@tonic-gate static  off_t	nchars;			/* return from getline in find() */
166*7c478bd9Sstevel@tonic-gate static	jmp_buf	restore;
167*7c478bd9Sstevel@tonic-gate static	char	Line[LINSIZ+2];
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate static	int	catch_susp;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate static	void	onsusp();
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate struct screen_stat {
174*7c478bd9Sstevel@tonic-gate 	off_t	first_line;
175*7c478bd9Sstevel@tonic-gate 	off_t	last_line;
176*7c478bd9Sstevel@tonic-gate 	short	is_eof;
177*7c478bd9Sstevel@tonic-gate 	};
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate static	struct screen_stat old_ss = { 0, 0, 0 };
180*7c478bd9Sstevel@tonic-gate static	struct screen_stat new_ss;
181*7c478bd9Sstevel@tonic-gate static	struct termio otty;	/* to save old terminal settings */
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate static	short	termflg = 0;	/* set once terminal is initialized */
184*7c478bd9Sstevel@tonic-gate static	short	eoflag;		/* set whenever at end of current file */
185*7c478bd9Sstevel@tonic-gate static	short	doliseof;	/* set when last line of file is known */
186*7c478bd9Sstevel@tonic-gate static	off_t	eofl_no;	/* what the last line of the file is */
187*7c478bd9Sstevel@tonic-gate static	void	usage(void);
188*7c478bd9Sstevel@tonic-gate static FILE	*pg_stdin;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate main(argc, argv)
191*7c478bd9Sstevel@tonic-gate int argc;
192*7c478bd9Sstevel@tonic-gate char *argv[];
193*7c478bd9Sstevel@tonic-gate {
194*7c478bd9Sstevel@tonic-gate 	char	*s;
195*7c478bd9Sstevel@tonic-gate 	char	*p;
196*7c478bd9Sstevel@tonic-gate 	int		prnames = 0;
197*7c478bd9Sstevel@tonic-gate 	int		opt;
198*7c478bd9Sstevel@tonic-gate 	int		i;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
201*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
202*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
203*7c478bd9Sstevel@tonic-gate #endif
204*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	/* check for non-standard "-#" option */
207*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
208*7c478bd9Sstevel@tonic-gate 		if (strcmp(argv[i], "--") == 0)
209*7c478bd9Sstevel@tonic-gate 			break;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 		if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
212*7c478bd9Sstevel@tonic-gate 			if (strlen(&argv[i][1]) !=
213*7c478bd9Sstevel@tonic-gate 			    strspn(&argv[i][1], "0123456789")) {
214*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
215*7c478bd9Sstevel@tonic-gate 				    "pg: Badly formed number\n"));
216*7c478bd9Sstevel@tonic-gate 				usage();
217*7c478bd9Sstevel@tonic-gate 			}
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 			window = (int)strtol(&argv[i][1], (char **)NULL, 10);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 			while (i < argc) {
222*7c478bd9Sstevel@tonic-gate 				argv[i] = argv[i + 1];
223*7c478bd9Sstevel@tonic-gate 				i++;
224*7c478bd9Sstevel@tonic-gate 			}
225*7c478bd9Sstevel@tonic-gate 			i--;
226*7c478bd9Sstevel@tonic-gate 			argc--;
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	/* check for non-standard + option */
231*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
232*7c478bd9Sstevel@tonic-gate 		if (strcmp(argv[i], "--") == 0)
233*7c478bd9Sstevel@tonic-gate 		break;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 		if (argv[i][0] == '+') {
236*7c478bd9Sstevel@tonic-gate 			if (argv[i][1] == '/') {
237*7c478bd9Sstevel@tonic-gate 				srchopt++;
238*7c478bd9Sstevel@tonic-gate 				initopt = 0;
239*7c478bd9Sstevel@tonic-gate 				for (s = &argv[i][2], p = initbuf; *s != '\0'; )
240*7c478bd9Sstevel@tonic-gate 					if (p < initbuf + sizeof (initbuf))
241*7c478bd9Sstevel@tonic-gate 						*p++ = *s++;
242*7c478bd9Sstevel@tonic-gate 					else {
243*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr, gettext(
244*7c478bd9Sstevel@tonic-gate 						    "pg: pattern too long\n"));
245*7c478bd9Sstevel@tonic-gate 						return (1);
246*7c478bd9Sstevel@tonic-gate 					}
247*7c478bd9Sstevel@tonic-gate 				*p = '\0';
248*7c478bd9Sstevel@tonic-gate 			} else {
249*7c478bd9Sstevel@tonic-gate 				initopt++;
250*7c478bd9Sstevel@tonic-gate 				srchopt = 0;
251*7c478bd9Sstevel@tonic-gate 				s = &argv[i][2];
252*7c478bd9Sstevel@tonic-gate 				for (; isdigit(*s); s++)
253*7c478bd9Sstevel@tonic-gate 					initline = initline*10 + *s -'0';
254*7c478bd9Sstevel@tonic-gate 				if (*s != '\0')
255*7c478bd9Sstevel@tonic-gate 					usage();
256*7c478bd9Sstevel@tonic-gate 			}
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 			while (i < argc) {
259*7c478bd9Sstevel@tonic-gate 				argv[i] = argv[i + 1];
260*7c478bd9Sstevel@tonic-gate 				i++;
261*7c478bd9Sstevel@tonic-gate 			}
262*7c478bd9Sstevel@tonic-gate 			i--;
263*7c478bd9Sstevel@tonic-gate 			argc--;
264*7c478bd9Sstevel@tonic-gate 		}
265*7c478bd9Sstevel@tonic-gate 	}
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "cefnrsp:")) != EOF) {
268*7c478bd9Sstevel@tonic-gate 		switch (opt) {
269*7c478bd9Sstevel@tonic-gate 		case 'c':
270*7c478bd9Sstevel@tonic-gate 			clropt = 1;
271*7c478bd9Sstevel@tonic-gate 			break;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		case 'e':
274*7c478bd9Sstevel@tonic-gate 			eof_pause = 0;
275*7c478bd9Sstevel@tonic-gate 			break;
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 		case 'f':
278*7c478bd9Sstevel@tonic-gate 			fflag = 1;
279*7c478bd9Sstevel@tonic-gate 			break;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 		case 'n':
282*7c478bd9Sstevel@tonic-gate 			nflag = 1;
283*7c478bd9Sstevel@tonic-gate 			break;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 		case 'r':
286*7c478bd9Sstevel@tonic-gate 			rmode = 1;	/* restricted mode */
287*7c478bd9Sstevel@tonic-gate 			break;
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 		case 's':
290*7c478bd9Sstevel@tonic-gate 			soflag = 1;	/* standout mode */
291*7c478bd9Sstevel@tonic-gate 			break;
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 		case 'p':
294*7c478bd9Sstevel@tonic-gate 			promptstr = setprompt(optarg);
295*7c478bd9Sstevel@tonic-gate 			break;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 		default:
298*7c478bd9Sstevel@tonic-gate 			usage();
299*7c478bd9Sstevel@tonic-gate 		}
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	nfiles = argc - optind;
303*7c478bd9Sstevel@tonic-gate 	fnames = &argv[optind];
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, end_it);
306*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, end_it);
307*7c478bd9Sstevel@tonic-gate 	out_is_tty = isatty(1);
308*7c478bd9Sstevel@tonic-gate 	my_pgid = getpgrp();
309*7c478bd9Sstevel@tonic-gate 	if (out_is_tty) {
310*7c478bd9Sstevel@tonic-gate 		terminit();
311*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGQUIT, on_brk);
312*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGINT, on_brk);
313*7c478bd9Sstevel@tonic-gate 		if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
314*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGTSTP, onsusp);
315*7c478bd9Sstevel@tonic-gate 			catch_susp++;
316*7c478bd9Sstevel@tonic-gate 		}
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 	if (window == 0)
319*7c478bd9Sstevel@tonic-gate 		window = lines - 1;
320*7c478bd9Sstevel@tonic-gate 	if (window <= 1)
321*7c478bd9Sstevel@tonic-gate 		window = 2;
322*7c478bd9Sstevel@tonic-gate 	if (initline <= 0)
323*7c478bd9Sstevel@tonic-gate 		initline = 1;
324*7c478bd9Sstevel@tonic-gate 	if (nfiles > 1)
325*7c478bd9Sstevel@tonic-gate 		prnames++;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	if (nfiles == 0) {
328*7c478bd9Sstevel@tonic-gate 		fnames[0] = "-";
329*7c478bd9Sstevel@tonic-gate 		nfiles++;
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 	while (fnum < nfiles) {
332*7c478bd9Sstevel@tonic-gate 		if (strcmp(fnames[fnum], "") == 0)
333*7c478bd9Sstevel@tonic-gate 			fnames[fnum] = "-";
334*7c478bd9Sstevel@tonic-gate 		if ((in_file = checkf(fnames[fnum])) == NULL)
335*7c478bd9Sstevel@tonic-gate 		{
336*7c478bd9Sstevel@tonic-gate 			status = 2;
337*7c478bd9Sstevel@tonic-gate 			fnum++;
338*7c478bd9Sstevel@tonic-gate 		} else {
339*7c478bd9Sstevel@tonic-gate 			status = 0;
340*7c478bd9Sstevel@tonic-gate 			if (out_is_tty)
341*7c478bd9Sstevel@tonic-gate 				fnum += screen(fnames[fnum]);
342*7c478bd9Sstevel@tonic-gate 			else {
343*7c478bd9Sstevel@tonic-gate 				if (prnames) {
344*7c478bd9Sstevel@tonic-gate 					(void) fputs("::::::::::::::\n",
345*7c478bd9Sstevel@tonic-gate 					    stdout);
346*7c478bd9Sstevel@tonic-gate 					(void) fputs(fnames[fnum], stdout);
347*7c478bd9Sstevel@tonic-gate 					(void) fputs("\n::::::::::::::\n",
348*7c478bd9Sstevel@tonic-gate 					    stdout);
349*7c478bd9Sstevel@tonic-gate 				}
350*7c478bd9Sstevel@tonic-gate 				copy_file(in_file, stdout);
351*7c478bd9Sstevel@tonic-gate 				fnum++;
352*7c478bd9Sstevel@tonic-gate 			}
353*7c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
354*7c478bd9Sstevel@tonic-gate 			if (pipe_in)
355*7c478bd9Sstevel@tonic-gate 				save_pipe();
356*7c478bd9Sstevel@tonic-gate 			else
357*7c478bd9Sstevel@tonic-gate 			if (in_file != tmp_fin)
358*7c478bd9Sstevel@tonic-gate 				(void) fclose(in_file);
359*7c478bd9Sstevel@tonic-gate 		}
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 	end_it();
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
364*7c478bd9Sstevel@tonic-gate 	return (0);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate static	char *
368*7c478bd9Sstevel@tonic-gate setprompt(s)
369*7c478bd9Sstevel@tonic-gate char *s;
370*7c478bd9Sstevel@tonic-gate {
371*7c478bd9Sstevel@tonic-gate 	int i = 0;
372*7c478bd9Sstevel@tonic-gate 	int pct_d = 0;
373*7c478bd9Sstevel@tonic-gate 	static char pstr[PROMPTSIZE];
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	while (i < PROMPTSIZE - 2)
376*7c478bd9Sstevel@tonic-gate 		switch (pstr[i++] = *s++) {
377*7c478bd9Sstevel@tonic-gate 		case '\0':
378*7c478bd9Sstevel@tonic-gate 			return (pstr);
379*7c478bd9Sstevel@tonic-gate 		case '%':
380*7c478bd9Sstevel@tonic-gate 			if (*s == 'd' && !pct_d) {
381*7c478bd9Sstevel@tonic-gate 				pct_d++;
382*7c478bd9Sstevel@tonic-gate 			} else if (*s != '%')
383*7c478bd9Sstevel@tonic-gate 				pstr[i++] = '%';
384*7c478bd9Sstevel@tonic-gate 			if ((pstr[i++] = *s++) == '\0')
385*7c478bd9Sstevel@tonic-gate 				return (pstr);
386*7c478bd9Sstevel@tonic-gate 			break;
387*7c478bd9Sstevel@tonic-gate 		default:
388*7c478bd9Sstevel@tonic-gate 			break;
389*7c478bd9Sstevel@tonic-gate 		}
390*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("pg: prompt too long\n"));
391*7c478bd9Sstevel@tonic-gate 	exit(1);
392*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate /*
397*7c478bd9Sstevel@tonic-gate  * Print out the contents of the file f, one screenful at a time.
398*7c478bd9Sstevel@tonic-gate  */
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate static int
401*7c478bd9Sstevel@tonic-gate screen(file_name)
402*7c478bd9Sstevel@tonic-gate char *file_name;
403*7c478bd9Sstevel@tonic-gate {
404*7c478bd9Sstevel@tonic-gate 	int cmd_ret = 0;
405*7c478bd9Sstevel@tonic-gate 	off_t start;
406*7c478bd9Sstevel@tonic-gate 	short hadchance = 0;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	old_ss.is_eof = 0;
409*7c478bd9Sstevel@tonic-gate 	old_ss.first_line = 0;
410*7c478bd9Sstevel@tonic-gate 	old_ss.last_line = 0;
411*7c478bd9Sstevel@tonic-gate 	new_ss = old_ss;
412*7c478bd9Sstevel@tonic-gate 	if (!firstf)
413*7c478bd9Sstevel@tonic-gate 		cmd_ret = command(file_name);
414*7c478bd9Sstevel@tonic-gate 	else {
415*7c478bd9Sstevel@tonic-gate 		firstf = 0;
416*7c478bd9Sstevel@tonic-gate 		if (initopt) {
417*7c478bd9Sstevel@tonic-gate 			initopt = 0;
418*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = initline;
419*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = initline + (off_t)window - 1;
420*7c478bd9Sstevel@tonic-gate 		} else if (srchopt) {
421*7c478bd9Sstevel@tonic-gate 			srchopt = 0;
422*7c478bd9Sstevel@tonic-gate 			if (!search(initbuf, (off_t)1))
423*7c478bd9Sstevel@tonic-gate 				cmd_ret = command(file_name);
424*7c478bd9Sstevel@tonic-gate 		} else {
425*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = 1;
426*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = (off_t)window;
427*7c478bd9Sstevel@tonic-gate 		}
428*7c478bd9Sstevel@tonic-gate 	}
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	for (;;) {
431*7c478bd9Sstevel@tonic-gate 		if (cmd_ret)
432*7c478bd9Sstevel@tonic-gate 			return (cmd_ret);
433*7c478bd9Sstevel@tonic-gate 		if (hadchance && new_ss.last_line >= eofl_no)
434*7c478bd9Sstevel@tonic-gate 			return (1);
435*7c478bd9Sstevel@tonic-gate 		hadchance = 0;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		if (new_ss.last_line < (off_t)window)
438*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = (off_t)window;
439*7c478bd9Sstevel@tonic-gate 		if (find(0, new_ss.last_line + 1) != EOF)
440*7c478bd9Sstevel@tonic-gate 			new_ss.is_eof = 0;
441*7c478bd9Sstevel@tonic-gate 		else {
442*7c478bd9Sstevel@tonic-gate 			new_ss.is_eof = 1;
443*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = eofl_no - 1;
444*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = new_ss.last_line -
445*7c478bd9Sstevel@tonic-gate 			    (off_t)window + 1;
446*7c478bd9Sstevel@tonic-gate 		}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 		if (new_ss.first_line < 1)
449*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = 1;
450*7c478bd9Sstevel@tonic-gate 		if (clropt) {
451*7c478bd9Sstevel@tonic-gate 			doclear();
452*7c478bd9Sstevel@tonic-gate 			start = new_ss.first_line;
453*7c478bd9Sstevel@tonic-gate 		} else {
454*7c478bd9Sstevel@tonic-gate 			if (new_ss.first_line == old_ss.last_line)
455*7c478bd9Sstevel@tonic-gate 				start = new_ss.first_line + 1;
456*7c478bd9Sstevel@tonic-gate 			else
457*7c478bd9Sstevel@tonic-gate 			if (new_ss.first_line > old_ss.last_line)
458*7c478bd9Sstevel@tonic-gate 				start = new_ss.first_line;
459*7c478bd9Sstevel@tonic-gate 			else
460*7c478bd9Sstevel@tonic-gate 			if (old_ss.first_line < new_ss.first_line)
461*7c478bd9Sstevel@tonic-gate 				start = old_ss.last_line + 1;
462*7c478bd9Sstevel@tonic-gate 			else
463*7c478bd9Sstevel@tonic-gate 				start = new_ss.first_line;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 			if (start < old_ss.first_line)
466*7c478bd9Sstevel@tonic-gate 				sopr(gettext("...skipping backward\n"), 0);
467*7c478bd9Sstevel@tonic-gate 			else
468*7c478bd9Sstevel@tonic-gate 			if (start > old_ss.last_line + 1)
469*7c478bd9Sstevel@tonic-gate 				sopr(gettext("...skipping forward\n"), 0);
470*7c478bd9Sstevel@tonic-gate 		}
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 		for (; start <= new_ss.last_line; start++) {
473*7c478bd9Sstevel@tonic-gate 			(void) find(0, start);
474*7c478bd9Sstevel@tonic-gate 			(void) fputs(Line, stdout);
475*7c478bd9Sstevel@tonic-gate 			if (brk_hit) {
476*7c478bd9Sstevel@tonic-gate 				new_ss.last_line = find(1, 0);
477*7c478bd9Sstevel@tonic-gate 				new_ss.is_eof = 0;
478*7c478bd9Sstevel@tonic-gate 				break;
479*7c478bd9Sstevel@tonic-gate 			}
480*7c478bd9Sstevel@tonic-gate 		}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 		brk_hit = 0;
483*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
484*7c478bd9Sstevel@tonic-gate 		if (new_ss.is_eof) {
485*7c478bd9Sstevel@tonic-gate 			if (!eof_pause || eofl_no == 1)
486*7c478bd9Sstevel@tonic-gate 				return (1);
487*7c478bd9Sstevel@tonic-gate 			hadchance++;
488*7c478bd9Sstevel@tonic-gate 			error("(EOF)");
489*7c478bd9Sstevel@tonic-gate 		}
490*7c478bd9Sstevel@tonic-gate 		old_ss = new_ss;
491*7c478bd9Sstevel@tonic-gate 		cmd_ret = command((char *)NULL);
492*7c478bd9Sstevel@tonic-gate 	}
493*7c478bd9Sstevel@tonic-gate }
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate static	char	cmdbuf[LINSIZ], *cmdptr;
496*7c478bd9Sstevel@tonic-gate #define	BEEP()		if (bell) { (void) putp(bell); (void) fflush(stdout); }
497*7c478bd9Sstevel@tonic-gate #define	BLANKS(p)	while (*p == ' ' || *p == '\t') p++
498*7c478bd9Sstevel@tonic-gate #define	CHECKEND()	BLANKS(cmdptr); if (*cmdptr) { BEEP(); break; }
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate /*
501*7c478bd9Sstevel@tonic-gate  * Read a command and do it. A command consists of an optional integer
502*7c478bd9Sstevel@tonic-gate  * argument followed by the command character.  Return the number of files
503*7c478bd9Sstevel@tonic-gate  * to skip, 0 if we're still talking about the same file.
504*7c478bd9Sstevel@tonic-gate  */
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate static int
507*7c478bd9Sstevel@tonic-gate command(filename)
508*7c478bd9Sstevel@tonic-gate char *filename;
509*7c478bd9Sstevel@tonic-gate {
510*7c478bd9Sstevel@tonic-gate 	off_t nlines;
511*7c478bd9Sstevel@tonic-gate 	FILE *sf;
512*7c478bd9Sstevel@tonic-gate 	char *cmdend;
513*7c478bd9Sstevel@tonic-gate 	pid_t id;
514*7c478bd9Sstevel@tonic-gate 	int skip;
515*7c478bd9Sstevel@tonic-gate 	int	len;
516*7c478bd9Sstevel@tonic-gate 	wchar_t	wc;
517*7c478bd9Sstevel@tonic-gate 	wchar_t	wc_e;
518*7c478bd9Sstevel@tonic-gate 	wchar_t	wc_e1;
519*7c478bd9Sstevel@tonic-gate 	char	*p;
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	for (;;) {
522*7c478bd9Sstevel@tonic-gate 		/*
523*7c478bd9Sstevel@tonic-gate 		 * Wait for output to drain before going on.
524*7c478bd9Sstevel@tonic-gate 		 * This is done so that the user will not hit
525*7c478bd9Sstevel@tonic-gate 		 * break and quit before he has seen the prompt.
526*7c478bd9Sstevel@tonic-gate 		 */
527*7c478bd9Sstevel@tonic-gate 		(void) ioctl(1, TCSBRK, 1);
528*7c478bd9Sstevel@tonic-gate 		if (setjmp(restore) > 0)
529*7c478bd9Sstevel@tonic-gate 			end_it();
530*7c478bd9Sstevel@tonic-gate 		inwait = 1;
531*7c478bd9Sstevel@tonic-gate 		brk_hit = 0;
532*7c478bd9Sstevel@tonic-gate 		if (errors)
533*7c478bd9Sstevel@tonic-gate 			errors = 0;
534*7c478bd9Sstevel@tonic-gate 		else {
535*7c478bd9Sstevel@tonic-gate 			kill_line();
536*7c478bd9Sstevel@tonic-gate 			prompt(filename);
537*7c478bd9Sstevel@tonic-gate 		}
538*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
539*7c478bd9Sstevel@tonic-gate 		if (ttyin())
540*7c478bd9Sstevel@tonic-gate 			continue;
541*7c478bd9Sstevel@tonic-gate 		cmdptr = cmdbuf;
542*7c478bd9Sstevel@tonic-gate 		nlines = number();
543*7c478bd9Sstevel@tonic-gate 		BLANKS(cmdptr);
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 		if ((len = mbtowc(&wc, cmdptr, MB_CUR_MAX)) <= 0) {
546*7c478bd9Sstevel@tonic-gate 			wc = *cmdptr;
547*7c478bd9Sstevel@tonic-gate 			len = 1;
548*7c478bd9Sstevel@tonic-gate 		}
549*7c478bd9Sstevel@tonic-gate 		cmdptr += len;
550*7c478bd9Sstevel@tonic-gate 		switch (wc) {
551*7c478bd9Sstevel@tonic-gate 		case 'h':
552*7c478bd9Sstevel@tonic-gate 			CHECKEND();
553*7c478bd9Sstevel@tonic-gate 			help();
554*7c478bd9Sstevel@tonic-gate 			break;
555*7c478bd9Sstevel@tonic-gate 		case '\014': /* ^L */
556*7c478bd9Sstevel@tonic-gate 		case '.':	/* redisplay current window */
557*7c478bd9Sstevel@tonic-gate 			CHECKEND();
558*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = old_ss.first_line;
559*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = old_ss.last_line;
560*7c478bd9Sstevel@tonic-gate 			inwait = 0;
561*7c478bd9Sstevel@tonic-gate 			return (0);
562*7c478bd9Sstevel@tonic-gate 		case 'w':	/* set window size */
563*7c478bd9Sstevel@tonic-gate 		case 'z':
564*7c478bd9Sstevel@tonic-gate 			if (sign == -1) {
565*7c478bd9Sstevel@tonic-gate 				BEEP();
566*7c478bd9Sstevel@tonic-gate 				break;
567*7c478bd9Sstevel@tonic-gate 			}
568*7c478bd9Sstevel@tonic-gate 			CHECKEND();
569*7c478bd9Sstevel@tonic-gate 			if (nlines == 0)
570*7c478bd9Sstevel@tonic-gate 				nlines = (off_t)window;
571*7c478bd9Sstevel@tonic-gate 			else
572*7c478bd9Sstevel@tonic-gate 			if (nlines > 1)
573*7c478bd9Sstevel@tonic-gate 				window = (int)nlines;
574*7c478bd9Sstevel@tonic-gate 			else {
575*7c478bd9Sstevel@tonic-gate 				BEEP();
576*7c478bd9Sstevel@tonic-gate 				break;
577*7c478bd9Sstevel@tonic-gate 			}
578*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = old_ss.last_line;
579*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = new_ss.first_line +
580*7c478bd9Sstevel@tonic-gate 			    (off_t)window - 1;
581*7c478bd9Sstevel@tonic-gate 			inwait = 0;
582*7c478bd9Sstevel@tonic-gate 			return (0);
583*7c478bd9Sstevel@tonic-gate 		case '\004': /* ^D */
584*7c478bd9Sstevel@tonic-gate 		case 'd':
585*7c478bd9Sstevel@tonic-gate 			CHECKEND();
586*7c478bd9Sstevel@tonic-gate 			if (sign == 0)
587*7c478bd9Sstevel@tonic-gate 				sign = 1;
588*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = old_ss.last_line +
589*7c478bd9Sstevel@tonic-gate 			    (off_t)sign*window/2;
590*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = new_ss.last_line -
591*7c478bd9Sstevel@tonic-gate 			    (off_t)window + 1;
592*7c478bd9Sstevel@tonic-gate 			inwait = 0;
593*7c478bd9Sstevel@tonic-gate 			return (0);
594*7c478bd9Sstevel@tonic-gate 		case 's':
595*7c478bd9Sstevel@tonic-gate 			/*
596*7c478bd9Sstevel@tonic-gate 			 * save input in filename.
597*7c478bd9Sstevel@tonic-gate 			 * Check for filename, access, etc.
598*7c478bd9Sstevel@tonic-gate 			 */
599*7c478bd9Sstevel@tonic-gate 			BLANKS(cmdptr);
600*7c478bd9Sstevel@tonic-gate 			if (!*cmdptr) {
601*7c478bd9Sstevel@tonic-gate 				BEEP();
602*7c478bd9Sstevel@tonic-gate 				break;
603*7c478bd9Sstevel@tonic-gate 			}
604*7c478bd9Sstevel@tonic-gate 			if (setjmp(restore) > 0) {
605*7c478bd9Sstevel@tonic-gate 				BEEP();
606*7c478bd9Sstevel@tonic-gate 			} else {
607*7c478bd9Sstevel@tonic-gate 				char outstr[PROMPTSIZE];
608*7c478bd9Sstevel@tonic-gate 				if ((sf = fopen(cmdptr, "w")) == NULL) {
609*7c478bd9Sstevel@tonic-gate 					error("cannot open save file");
610*7c478bd9Sstevel@tonic-gate 					break;
611*7c478bd9Sstevel@tonic-gate 				}
612*7c478bd9Sstevel@tonic-gate 				kill_line();
613*7c478bd9Sstevel@tonic-gate 				(void) sprintf(outstr, gettext(
614*7c478bd9Sstevel@tonic-gate 				    "saving file %s"), cmdptr);
615*7c478bd9Sstevel@tonic-gate 				sopr(outstr, 1);
616*7c478bd9Sstevel@tonic-gate 				(void) fflush(stdout);
617*7c478bd9Sstevel@tonic-gate 				save_input(sf);
618*7c478bd9Sstevel@tonic-gate 				error("saved");
619*7c478bd9Sstevel@tonic-gate 			}
620*7c478bd9Sstevel@tonic-gate 			(void) fclose(sf);
621*7c478bd9Sstevel@tonic-gate 			break;
622*7c478bd9Sstevel@tonic-gate 		case 'q':
623*7c478bd9Sstevel@tonic-gate 		case 'Q':
624*7c478bd9Sstevel@tonic-gate 			CHECKEND();
625*7c478bd9Sstevel@tonic-gate 			inwait = 0;
626*7c478bd9Sstevel@tonic-gate 			end_it();
627*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 		case 'f':	/* skip forward screenfuls */
630*7c478bd9Sstevel@tonic-gate 			CHECKEND();
631*7c478bd9Sstevel@tonic-gate 			if (sign == 0)
632*7c478bd9Sstevel@tonic-gate 				sign++;	/* skips are always relative */
633*7c478bd9Sstevel@tonic-gate 			if (nlines == 0)
634*7c478bd9Sstevel@tonic-gate 				nlines++;
635*7c478bd9Sstevel@tonic-gate 			nlines = nlines * (window - 1);
636*7c478bd9Sstevel@tonic-gate 			if (sign == 1)
637*7c478bd9Sstevel@tonic-gate 				new_ss.first_line = old_ss.last_line + nlines;
638*7c478bd9Sstevel@tonic-gate 			else
639*7c478bd9Sstevel@tonic-gate 				new_ss.first_line = old_ss.first_line - nlines;
640*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = new_ss.first_line +
641*7c478bd9Sstevel@tonic-gate 			    (off_t)window - 1;
642*7c478bd9Sstevel@tonic-gate 			inwait = 0;
643*7c478bd9Sstevel@tonic-gate 			return (0);
644*7c478bd9Sstevel@tonic-gate 		case 'l':	/* get a line */
645*7c478bd9Sstevel@tonic-gate 			CHECKEND();
646*7c478bd9Sstevel@tonic-gate 			if (nlines == 0) {
647*7c478bd9Sstevel@tonic-gate 				nlines++;
648*7c478bd9Sstevel@tonic-gate 				if (sign == 0)
649*7c478bd9Sstevel@tonic-gate 					sign = 1;
650*7c478bd9Sstevel@tonic-gate 			}
651*7c478bd9Sstevel@tonic-gate 			switch (sign) {
652*7c478bd9Sstevel@tonic-gate 			case 1:
653*7c478bd9Sstevel@tonic-gate 				new_ss.last_line = old_ss.last_line + nlines;
654*7c478bd9Sstevel@tonic-gate 				new_ss.first_line =
655*7c478bd9Sstevel@tonic-gate 				    new_ss.last_line - (off_t)window + 1;
656*7c478bd9Sstevel@tonic-gate 				break;
657*7c478bd9Sstevel@tonic-gate 			case 0:  /* leave addressed line at top */
658*7c478bd9Sstevel@tonic-gate 				new_ss.first_line = nlines;
659*7c478bd9Sstevel@tonic-gate 				new_ss.last_line = nlines + (off_t)window - 1;
660*7c478bd9Sstevel@tonic-gate 				break;
661*7c478bd9Sstevel@tonic-gate 			case -1:
662*7c478bd9Sstevel@tonic-gate 				new_ss.first_line = old_ss.first_line - nlines;
663*7c478bd9Sstevel@tonic-gate 				new_ss.last_line =
664*7c478bd9Sstevel@tonic-gate 				    new_ss.first_line + (off_t)window - 1;
665*7c478bd9Sstevel@tonic-gate 				break;
666*7c478bd9Sstevel@tonic-gate 			}
667*7c478bd9Sstevel@tonic-gate 			inwait = 0;
668*7c478bd9Sstevel@tonic-gate 			return (0);
669*7c478bd9Sstevel@tonic-gate 		case '\0': /* \n or blank */
670*7c478bd9Sstevel@tonic-gate 			if (nlines == 0) {
671*7c478bd9Sstevel@tonic-gate 				nlines++;
672*7c478bd9Sstevel@tonic-gate 				if (sign == 0)
673*7c478bd9Sstevel@tonic-gate 					sign = 1;
674*7c478bd9Sstevel@tonic-gate 			}
675*7c478bd9Sstevel@tonic-gate 			nlines = (nlines - 1) * (window - 1);
676*7c478bd9Sstevel@tonic-gate 			switch (sign) {
677*7c478bd9Sstevel@tonic-gate 			case 1:
678*7c478bd9Sstevel@tonic-gate 				new_ss.first_line = old_ss.last_line + nlines;
679*7c478bd9Sstevel@tonic-gate 				new_ss.last_line =
680*7c478bd9Sstevel@tonic-gate 				    new_ss.first_line + (off_t)window - 1;
681*7c478bd9Sstevel@tonic-gate 				break;
682*7c478bd9Sstevel@tonic-gate 			case 0:
683*7c478bd9Sstevel@tonic-gate 				new_ss.first_line = nlines + 1;
684*7c478bd9Sstevel@tonic-gate 				new_ss.last_line = nlines + (off_t)window;
685*7c478bd9Sstevel@tonic-gate 				/*
686*7c478bd9Sstevel@tonic-gate 				 * This if statement is to fix the obscure bug
687*7c478bd9Sstevel@tonic-gate 				 * where you have a file that has less lines
688*7c478bd9Sstevel@tonic-gate 				 * than a screen holds, and the user types '1',
689*7c478bd9Sstevel@tonic-gate 				 * expecting to have the 1st page (re)displayed.
690*7c478bd9Sstevel@tonic-gate 				 * If we didn't set the new last_line to
691*7c478bd9Sstevel@tonic-gate 				 * eofl_no-1, the screen() routine
692*7c478bd9Sstevel@tonic-gate 				 * would cause pg to exit.
693*7c478bd9Sstevel@tonic-gate 				 */
694*7c478bd9Sstevel@tonic-gate 				if (new_ss.first_line == 1 &&
695*7c478bd9Sstevel@tonic-gate 				    new_ss.last_line >= eofl_no)
696*7c478bd9Sstevel@tonic-gate 					new_ss.last_line = eofl_no - 1;
697*7c478bd9Sstevel@tonic-gate 				break;
698*7c478bd9Sstevel@tonic-gate 			case -1:
699*7c478bd9Sstevel@tonic-gate 				new_ss.last_line = old_ss.first_line - nlines;
700*7c478bd9Sstevel@tonic-gate 				new_ss.first_line =
701*7c478bd9Sstevel@tonic-gate 				    new_ss.last_line - (off_t)window + 1;
702*7c478bd9Sstevel@tonic-gate 				break;
703*7c478bd9Sstevel@tonic-gate 			}
704*7c478bd9Sstevel@tonic-gate 			inwait = 0;
705*7c478bd9Sstevel@tonic-gate 			return (0);
706*7c478bd9Sstevel@tonic-gate 		case 'n':	/* switch to next file in arglist */
707*7c478bd9Sstevel@tonic-gate 			CHECKEND();
708*7c478bd9Sstevel@tonic-gate 			if (sign == 0)
709*7c478bd9Sstevel@tonic-gate 				sign = 1;
710*7c478bd9Sstevel@tonic-gate 			if (nlines == 0)
711*7c478bd9Sstevel@tonic-gate 				nlines++;
712*7c478bd9Sstevel@tonic-gate 			if ((skip = skipf(sign *nlines)) == 0) {
713*7c478bd9Sstevel@tonic-gate 				BEEP();
714*7c478bd9Sstevel@tonic-gate 				break;
715*7c478bd9Sstevel@tonic-gate 			}
716*7c478bd9Sstevel@tonic-gate 			inwait = 0;
717*7c478bd9Sstevel@tonic-gate 			return (skip);
718*7c478bd9Sstevel@tonic-gate 		case 'p':	/* switch to previous file in arglist */
719*7c478bd9Sstevel@tonic-gate 			CHECKEND();
720*7c478bd9Sstevel@tonic-gate 			if (sign == 0)
721*7c478bd9Sstevel@tonic-gate 				sign = 1;
722*7c478bd9Sstevel@tonic-gate 			if (nlines == 0)
723*7c478bd9Sstevel@tonic-gate 				nlines++;
724*7c478bd9Sstevel@tonic-gate 			if ((skip = skipf(-sign * nlines)) == 0) {
725*7c478bd9Sstevel@tonic-gate 				BEEP();
726*7c478bd9Sstevel@tonic-gate 				break;
727*7c478bd9Sstevel@tonic-gate 			}
728*7c478bd9Sstevel@tonic-gate 			inwait = 0;
729*7c478bd9Sstevel@tonic-gate 			return (skip);
730*7c478bd9Sstevel@tonic-gate 		case '$':	/* go to end of file */
731*7c478bd9Sstevel@tonic-gate 			CHECKEND();
732*7c478bd9Sstevel@tonic-gate 			sign = 1;
733*7c478bd9Sstevel@tonic-gate 			while (find(1, (off_t)10000) != EOF)
734*7c478bd9Sstevel@tonic-gate 				/* any large number will do */;
735*7c478bd9Sstevel@tonic-gate 			new_ss.last_line = eofl_no - 1;
736*7c478bd9Sstevel@tonic-gate 			new_ss.first_line = eofl_no - (off_t)window;
737*7c478bd9Sstevel@tonic-gate 			inwait = 0;
738*7c478bd9Sstevel@tonic-gate 			return (0);
739*7c478bd9Sstevel@tonic-gate 		case '/':	/* search forward for r.e. */
740*7c478bd9Sstevel@tonic-gate 		case '?':	/*   "  backwards */
741*7c478bd9Sstevel@tonic-gate 		case '^':	/* this ones a ? for regent100s */
742*7c478bd9Sstevel@tonic-gate 			if (sign < 0) {
743*7c478bd9Sstevel@tonic-gate 				BEEP();
744*7c478bd9Sstevel@tonic-gate 				break;
745*7c478bd9Sstevel@tonic-gate 			}
746*7c478bd9Sstevel@tonic-gate 			if (nlines == 0)
747*7c478bd9Sstevel@tonic-gate 				nlines++;
748*7c478bd9Sstevel@tonic-gate 			cmdptr--;
749*7c478bd9Sstevel@tonic-gate 			cmdend = cmdptr + (strlen(cmdptr) - 1);
750*7c478bd9Sstevel@tonic-gate 			wc_e1 = -1;
751*7c478bd9Sstevel@tonic-gate 			wc_e = -1;
752*7c478bd9Sstevel@tonic-gate 			for (p = cmdptr; p <= cmdend; p += len) {
753*7c478bd9Sstevel@tonic-gate 				wc_e1 = wc_e;
754*7c478bd9Sstevel@tonic-gate 				if ((len = mbtowc(&wc_e, p, MB_CUR_MAX)) <= 0) {
755*7c478bd9Sstevel@tonic-gate 					wc_e = *p;
756*7c478bd9Sstevel@tonic-gate 					len = 1;
757*7c478bd9Sstevel@tonic-gate 				}
758*7c478bd9Sstevel@tonic-gate 			}
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 			if (cmdend > cmdptr + 1) {
761*7c478bd9Sstevel@tonic-gate 				if ((wc_e1 == *cmdptr) &&
762*7c478bd9Sstevel@tonic-gate 				    ((wc_e == L't') ||
763*7c478bd9Sstevel@tonic-gate 					(wc_e == L'm') || (wc_e == L'b'))) {
764*7c478bd9Sstevel@tonic-gate 					leave_search = wc_e;
765*7c478bd9Sstevel@tonic-gate 					wc_e = wc_e1;
766*7c478bd9Sstevel@tonic-gate 					cmdend--;
767*7c478bd9Sstevel@tonic-gate 				}
768*7c478bd9Sstevel@tonic-gate 			}
769*7c478bd9Sstevel@tonic-gate 			if ((cmdptr < cmdend) && (wc_e == *cmdptr))
770*7c478bd9Sstevel@tonic-gate 				*cmdend = '\0';
771*7c478bd9Sstevel@tonic-gate 			if (*cmdptr != '/')  /* signify back search by - */
772*7c478bd9Sstevel@tonic-gate 				nlines = -nlines;
773*7c478bd9Sstevel@tonic-gate 			if (!search(++cmdptr, (off_t)nlines))
774*7c478bd9Sstevel@tonic-gate 				break;
775*7c478bd9Sstevel@tonic-gate 			else {
776*7c478bd9Sstevel@tonic-gate 				inwait = 0;
777*7c478bd9Sstevel@tonic-gate 				return (0);
778*7c478bd9Sstevel@tonic-gate 			}
779*7c478bd9Sstevel@tonic-gate 		case '!':	/* shell escape */
780*7c478bd9Sstevel@tonic-gate 			if (rmode) {	/* restricted mode */
781*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
782*7c478bd9Sstevel@tonic-gate 				"!command not allowed in restricted mode.\n"));
783*7c478bd9Sstevel@tonic-gate 				break;
784*7c478bd9Sstevel@tonic-gate 			}
785*7c478bd9Sstevel@tonic-gate 			if (!hard_copy) { /* redisplay the command */
786*7c478bd9Sstevel@tonic-gate 				(void) fputs(cmdbuf, stdout);
787*7c478bd9Sstevel@tonic-gate 				(void) fputs("\n", stdout);
788*7c478bd9Sstevel@tonic-gate 			}
789*7c478bd9Sstevel@tonic-gate 			if ((id = fork()) < 0) {
790*7c478bd9Sstevel@tonic-gate 				error("cannot fork, try again later");
791*7c478bd9Sstevel@tonic-gate 				break;
792*7c478bd9Sstevel@tonic-gate 			}
793*7c478bd9Sstevel@tonic-gate 			if (id == (pid_t)0) {
794*7c478bd9Sstevel@tonic-gate 				/*
795*7c478bd9Sstevel@tonic-gate 				 * if stdin is a pipe, need to close it so
796*7c478bd9Sstevel@tonic-gate 				 * that the terminal is really stdin for
797*7c478bd9Sstevel@tonic-gate 				 * the command
798*7c478bd9Sstevel@tonic-gate 				 */
799*7c478bd9Sstevel@tonic-gate 				(void) fclose(stdin);
800*7c478bd9Sstevel@tonic-gate 				(void) fclose(pg_stdin);
801*7c478bd9Sstevel@tonic-gate 				(void) dup(fileno(stdout));
802*7c478bd9Sstevel@tonic-gate 				(void) execl(shell, shell, "-c", cmdptr, 0);
803*7c478bd9Sstevel@tonic-gate 				(void) perror("exec");
804*7c478bd9Sstevel@tonic-gate 				exit(1);
805*7c478bd9Sstevel@tonic-gate 			}
806*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGINT, SIG_IGN);
807*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGQUIT, SIG_IGN);
808*7c478bd9Sstevel@tonic-gate 			if (catch_susp)
809*7c478bd9Sstevel@tonic-gate 				(void) signal(SIGTSTP, SIG_DFL);
810*7c478bd9Sstevel@tonic-gate 			while (wait((int *)0) != id);
811*7c478bd9Sstevel@tonic-gate 			{
812*7c478bd9Sstevel@tonic-gate 				if (errno == ECHILD)
813*7c478bd9Sstevel@tonic-gate 					break;
814*7c478bd9Sstevel@tonic-gate 				else
815*7c478bd9Sstevel@tonic-gate 					errno = 0;
816*7c478bd9Sstevel@tonic-gate 			}
817*7c478bd9Sstevel@tonic-gate 			(void) fputs("!\n", stdout);
818*7c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
819*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGINT, on_brk);
820*7c478bd9Sstevel@tonic-gate 			(void) signal(SIGQUIT, on_brk);
821*7c478bd9Sstevel@tonic-gate 			if (catch_susp)
822*7c478bd9Sstevel@tonic-gate 				(void) signal(SIGTSTP, onsusp);
823*7c478bd9Sstevel@tonic-gate 			break;
824*7c478bd9Sstevel@tonic-gate 		default:
825*7c478bd9Sstevel@tonic-gate 			BEEP();
826*7c478bd9Sstevel@tonic-gate 			break;
827*7c478bd9Sstevel@tonic-gate 		}
828*7c478bd9Sstevel@tonic-gate 	}
829*7c478bd9Sstevel@tonic-gate }
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate static int
832*7c478bd9Sstevel@tonic-gate number()
833*7c478bd9Sstevel@tonic-gate {
834*7c478bd9Sstevel@tonic-gate 	int i;
835*7c478bd9Sstevel@tonic-gate 	char *p;
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	i = 0;
838*7c478bd9Sstevel@tonic-gate 	sign = 0;
839*7c478bd9Sstevel@tonic-gate 	p = cmdptr;
840*7c478bd9Sstevel@tonic-gate 	BLANKS(p);
841*7c478bd9Sstevel@tonic-gate 	if (*p == '+') {
842*7c478bd9Sstevel@tonic-gate 		p++;
843*7c478bd9Sstevel@tonic-gate 		sign = 1;
844*7c478bd9Sstevel@tonic-gate 	}
845*7c478bd9Sstevel@tonic-gate 	else
846*7c478bd9Sstevel@tonic-gate 	if (*p == '-') {
847*7c478bd9Sstevel@tonic-gate 		p++;
848*7c478bd9Sstevel@tonic-gate 		sign = -1;
849*7c478bd9Sstevel@tonic-gate 	}
850*7c478bd9Sstevel@tonic-gate 	while (isdigit(*p))
851*7c478bd9Sstevel@tonic-gate 		i = i * 10 + *p++ - '0';
852*7c478bd9Sstevel@tonic-gate 	cmdptr = p;
853*7c478bd9Sstevel@tonic-gate 	return (i);
854*7c478bd9Sstevel@tonic-gate }
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate static int
857*7c478bd9Sstevel@tonic-gate ttyin()
858*7c478bd9Sstevel@tonic-gate {
859*7c478bd9Sstevel@tonic-gate 	char *sptr, *p;
860*7c478bd9Sstevel@tonic-gate 	wchar_t ch;
861*7c478bd9Sstevel@tonic-gate 	int slash = 0;
862*7c478bd9Sstevel@tonic-gate 	int state = 0;
863*7c478bd9Sstevel@tonic-gate 	int width, length;
864*7c478bd9Sstevel@tonic-gate 	char multic[MB_LEN_MAX];
865*7c478bd9Sstevel@tonic-gate 	static	int	readch();
866*7c478bd9Sstevel@tonic-gate 	int 	len;
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	(void) fixterm();
869*7c478bd9Sstevel@tonic-gate 	/* initialize state processing */
870*7c478bd9Sstevel@tonic-gate 	(void) set_state(&state, ' ', (char *)0);
871*7c478bd9Sstevel@tonic-gate 	sptr = cmdbuf;
872*7c478bd9Sstevel@tonic-gate 	while (state != 10) {
873*7c478bd9Sstevel@tonic-gate 		if ((ch = readch()) < 0 || !iswascii(ch) && !iswprint(ch)) {
874*7c478bd9Sstevel@tonic-gate 			BEEP();
875*7c478bd9Sstevel@tonic-gate 			continue;
876*7c478bd9Sstevel@tonic-gate 		}
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 		if ((length = wctomb(multic, ch)) < 0)
879*7c478bd9Sstevel@tonic-gate 			length = 0;
880*7c478bd9Sstevel@tonic-gate 		multic[length] = 0;
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 		if (ch == '\n' && !slash)
883*7c478bd9Sstevel@tonic-gate 			break;
884*7c478bd9Sstevel@tonic-gate 		if (ch == erasechar() && !slash) {
885*7c478bd9Sstevel@tonic-gate 			if (sptr > cmdbuf) {
886*7c478bd9Sstevel@tonic-gate 				char *oldp = cmdbuf;
887*7c478bd9Sstevel@tonic-gate 				wchar_t wchar;
888*7c478bd9Sstevel@tonic-gate 				p = cmdbuf;
889*7c478bd9Sstevel@tonic-gate 				while (p  < sptr) {
890*7c478bd9Sstevel@tonic-gate 					oldp = p;
891*7c478bd9Sstevel@tonic-gate 					len = mbtowc(&wchar, p, MB_CUR_MAX);
892*7c478bd9Sstevel@tonic-gate 					if (len <= 0) {
893*7c478bd9Sstevel@tonic-gate 						wchar = (unsigned char)*p;
894*7c478bd9Sstevel@tonic-gate 						len = 1;
895*7c478bd9Sstevel@tonic-gate 					}
896*7c478bd9Sstevel@tonic-gate 					p += len;
897*7c478bd9Sstevel@tonic-gate 				}
898*7c478bd9Sstevel@tonic-gate 				if ((width = wcwidth(wchar)) <= 0)
899*7c478bd9Sstevel@tonic-gate 					/* ascii control character */
900*7c478bd9Sstevel@tonic-gate 					width = 2;
901*7c478bd9Sstevel@tonic-gate 				promptlen -= width;
902*7c478bd9Sstevel@tonic-gate 				while (width--)
903*7c478bd9Sstevel@tonic-gate 					(void) fputs("\b \b", stdout);
904*7c478bd9Sstevel@tonic-gate 				sptr = oldp;
905*7c478bd9Sstevel@tonic-gate 			}
906*7c478bd9Sstevel@tonic-gate 			(void) set_state(&state, ch, sptr);
907*7c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
908*7c478bd9Sstevel@tonic-gate 			continue;
909*7c478bd9Sstevel@tonic-gate 		}
910*7c478bd9Sstevel@tonic-gate 		else
911*7c478bd9Sstevel@tonic-gate 		if (ch == killchar() && !slash) {
912*7c478bd9Sstevel@tonic-gate 			if (hard_copy)
913*7c478bd9Sstevel@tonic-gate 				(void) putwchar(ch);
914*7c478bd9Sstevel@tonic-gate 			(void) resetterm();
915*7c478bd9Sstevel@tonic-gate 			return (1);
916*7c478bd9Sstevel@tonic-gate 		}
917*7c478bd9Sstevel@tonic-gate 		if (ch < ' ')
918*7c478bd9Sstevel@tonic-gate 			width = 2;
919*7c478bd9Sstevel@tonic-gate 		else
920*7c478bd9Sstevel@tonic-gate 			if ((width = wcwidth(ch)) <= 0)
921*7c478bd9Sstevel@tonic-gate 				width = 0;
922*7c478bd9Sstevel@tonic-gate 		if (slash) {
923*7c478bd9Sstevel@tonic-gate 			slash = 0;
924*7c478bd9Sstevel@tonic-gate 			(void) fputs("\b \b", stdout);
925*7c478bd9Sstevel@tonic-gate 			sptr--;
926*7c478bd9Sstevel@tonic-gate 			promptlen--;
927*7c478bd9Sstevel@tonic-gate 		} else /* is there room to keep this character? */
928*7c478bd9Sstevel@tonic-gate 		if (sptr >= cmdbuf + sizeof (cmdbuf) ||
929*7c478bd9Sstevel@tonic-gate 		    promptlen + width >= columns) {
930*7c478bd9Sstevel@tonic-gate 			BEEP();
931*7c478bd9Sstevel@tonic-gate 			continue;
932*7c478bd9Sstevel@tonic-gate 		}
933*7c478bd9Sstevel@tonic-gate 		else
934*7c478bd9Sstevel@tonic-gate 		if (ch == '\\')
935*7c478bd9Sstevel@tonic-gate 			slash++;
936*7c478bd9Sstevel@tonic-gate 		if (set_state(&state, ch, sptr) == 0) {
937*7c478bd9Sstevel@tonic-gate 			BEEP();
938*7c478bd9Sstevel@tonic-gate 			continue;
939*7c478bd9Sstevel@tonic-gate 		}
940*7c478bd9Sstevel@tonic-gate 		(void) strncpy(sptr, multic, (size_t)length);
941*7c478bd9Sstevel@tonic-gate 		sptr += length;
942*7c478bd9Sstevel@tonic-gate 		if (ch < ' ') {
943*7c478bd9Sstevel@tonic-gate 			ch += 0100;
944*7c478bd9Sstevel@tonic-gate 			multic[0] = '^';
945*7c478bd9Sstevel@tonic-gate 			multic[1] = ch;
946*7c478bd9Sstevel@tonic-gate 			length = 2;
947*7c478bd9Sstevel@tonic-gate 		}
948*7c478bd9Sstevel@tonic-gate 		p = multic;
949*7c478bd9Sstevel@tonic-gate 		while (length--)
950*7c478bd9Sstevel@tonic-gate 			(void) putchar(*p++);
951*7c478bd9Sstevel@tonic-gate 		promptlen += width;
952*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	*sptr = '\0';
956*7c478bd9Sstevel@tonic-gate 	kill_line();
957*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
958*7c478bd9Sstevel@tonic-gate 	(void) resetterm();
959*7c478bd9Sstevel@tonic-gate 	return (0);
960*7c478bd9Sstevel@tonic-gate }
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate static	int
963*7c478bd9Sstevel@tonic-gate set_state(pstate, c, pc)
964*7c478bd9Sstevel@tonic-gate int *pstate;
965*7c478bd9Sstevel@tonic-gate wchar_t c;
966*7c478bd9Sstevel@tonic-gate char *pc;
967*7c478bd9Sstevel@tonic-gate {
968*7c478bd9Sstevel@tonic-gate 	static char *psign;
969*7c478bd9Sstevel@tonic-gate 	static char *pnumber;
970*7c478bd9Sstevel@tonic-gate 	static char *pcommand;
971*7c478bd9Sstevel@tonic-gate 	static int slash;
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	if (*pstate == 0) {
974*7c478bd9Sstevel@tonic-gate 		psign = (char *)NULL;
975*7c478bd9Sstevel@tonic-gate 		pnumber = (char *)NULL;
976*7c478bd9Sstevel@tonic-gate 		pcommand = (char *)NULL;
977*7c478bd9Sstevel@tonic-gate 		*pstate = 1;
978*7c478bd9Sstevel@tonic-gate 		slash = 0;
979*7c478bd9Sstevel@tonic-gate 		return (1);
980*7c478bd9Sstevel@tonic-gate 	}
981*7c478bd9Sstevel@tonic-gate 	if (c == '\\' && !slash) {
982*7c478bd9Sstevel@tonic-gate 		slash++;
983*7c478bd9Sstevel@tonic-gate 		return (1);
984*7c478bd9Sstevel@tonic-gate 	}
985*7c478bd9Sstevel@tonic-gate 	if (c == erasechar() && !slash)
986*7c478bd9Sstevel@tonic-gate 		switch (*pstate) {
987*7c478bd9Sstevel@tonic-gate 		case 4:
988*7c478bd9Sstevel@tonic-gate 			if (pc > pcommand)
989*7c478bd9Sstevel@tonic-gate 				return (1);
990*7c478bd9Sstevel@tonic-gate 			pcommand = (char *)NULL;
991*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 		case 3:
994*7c478bd9Sstevel@tonic-gate 			if (pnumber && pc > pnumber) {
995*7c478bd9Sstevel@tonic-gate 				*pstate = 3;
996*7c478bd9Sstevel@tonic-gate 				return (1);
997*7c478bd9Sstevel@tonic-gate 			}
998*7c478bd9Sstevel@tonic-gate 			pnumber = (char *)NULL;
999*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 		case 2:
1002*7c478bd9Sstevel@tonic-gate 			if (psign && pc > psign) {
1003*7c478bd9Sstevel@tonic-gate 				*pstate = 2;
1004*7c478bd9Sstevel@tonic-gate 				return (1);
1005*7c478bd9Sstevel@tonic-gate 			}
1006*7c478bd9Sstevel@tonic-gate 			psign = (char *)NULL;
1007*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 		case 1:
1010*7c478bd9Sstevel@tonic-gate 			*pstate = 1;
1011*7c478bd9Sstevel@tonic-gate 			return (1);
1012*7c478bd9Sstevel@tonic-gate 		}
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 	slash = 0;
1015*7c478bd9Sstevel@tonic-gate 	switch (*pstate) {
1016*7c478bd9Sstevel@tonic-gate 	case 1: /* before recieving anything interesting */
1017*7c478bd9Sstevel@tonic-gate 		if (c == '\t' || (!nflag && c == ' '))
1018*7c478bd9Sstevel@tonic-gate 			return (1);
1019*7c478bd9Sstevel@tonic-gate 		if (c == '+' || c == '-') {
1020*7c478bd9Sstevel@tonic-gate 			psign = pc;
1021*7c478bd9Sstevel@tonic-gate 			*pstate = 2;
1022*7c478bd9Sstevel@tonic-gate 			return (1);
1023*7c478bd9Sstevel@tonic-gate 		}
1024*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	case 2: /* recieved sign, waiting for digit */
1027*7c478bd9Sstevel@tonic-gate 		if (iswascii(c) && isdigit(c)) {
1028*7c478bd9Sstevel@tonic-gate 			pnumber = pc;
1029*7c478bd9Sstevel@tonic-gate 			*pstate = 3;
1030*7c478bd9Sstevel@tonic-gate 			return (1);
1031*7c478bd9Sstevel@tonic-gate 		}
1032*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 	case 3: /* recieved digit, waiting for the rest of the number */
1035*7c478bd9Sstevel@tonic-gate 		if (iswascii(c) && isdigit(c))
1036*7c478bd9Sstevel@tonic-gate 			return (1);
1037*7c478bd9Sstevel@tonic-gate 		if (iswascii(c) && pg_strchr("h\014.wz\004dqQfl np$", c)) {
1038*7c478bd9Sstevel@tonic-gate 			pcommand = pc;
1039*7c478bd9Sstevel@tonic-gate 			if (nflag)
1040*7c478bd9Sstevel@tonic-gate 				*pstate = 10;
1041*7c478bd9Sstevel@tonic-gate 			else
1042*7c478bd9Sstevel@tonic-gate 				*pstate = 4;
1043*7c478bd9Sstevel@tonic-gate 			return (1);
1044*7c478bd9Sstevel@tonic-gate 		}
1045*7c478bd9Sstevel@tonic-gate 		if (iswascii(c) && pg_strchr("s/^?!", c)) {
1046*7c478bd9Sstevel@tonic-gate 			pcommand = pc;
1047*7c478bd9Sstevel@tonic-gate 			*pstate = 4;
1048*7c478bd9Sstevel@tonic-gate 			return (1);
1049*7c478bd9Sstevel@tonic-gate 		}
1050*7c478bd9Sstevel@tonic-gate 		return (0);
1051*7c478bd9Sstevel@tonic-gate 	case 4:
1052*7c478bd9Sstevel@tonic-gate 		return (1);
1053*7c478bd9Sstevel@tonic-gate 	}
1054*7c478bd9Sstevel@tonic-gate 	return (0);
1055*7c478bd9Sstevel@tonic-gate }
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate static	int
1058*7c478bd9Sstevel@tonic-gate readch()
1059*7c478bd9Sstevel@tonic-gate {
1060*7c478bd9Sstevel@tonic-gate 	return (fgetwc(pg_stdin));
1061*7c478bd9Sstevel@tonic-gate }
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate static void
1064*7c478bd9Sstevel@tonic-gate help()
1065*7c478bd9Sstevel@tonic-gate {
1066*7c478bd9Sstevel@tonic-gate 	if (clropt)
1067*7c478bd9Sstevel@tonic-gate 		doclear();
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	(void) fputs(gettext(
1070*7c478bd9Sstevel@tonic-gate "-------------------------------------------------------\n"
1071*7c478bd9Sstevel@tonic-gate "  h                     help\n"
1072*7c478bd9Sstevel@tonic-gate "  q or Q                quit\n"
1073*7c478bd9Sstevel@tonic-gate "  <blank> or <newline>  next page\n"
1074*7c478bd9Sstevel@tonic-gate "  l                     next line\n"
1075*7c478bd9Sstevel@tonic-gate "  d or <^D>             display half a page more\n"
1076*7c478bd9Sstevel@tonic-gate "  . or <^L>             redisplay current page\n"
1077*7c478bd9Sstevel@tonic-gate "  f                     skip the next page forward\n"
1078*7c478bd9Sstevel@tonic-gate "  n                     next file\n"
1079*7c478bd9Sstevel@tonic-gate "  p                     previous file\n"
1080*7c478bd9Sstevel@tonic-gate "  $                     last page\n"
1081*7c478bd9Sstevel@tonic-gate "  w or z                set window size and display next page\n"
1082*7c478bd9Sstevel@tonic-gate "  s savefile            save current file in savefile\n"
1083*7c478bd9Sstevel@tonic-gate "  /pattern/             search forward for pattern\n"
1084*7c478bd9Sstevel@tonic-gate "  ?pattern? or\n"
1085*7c478bd9Sstevel@tonic-gate "  ^pattern^             search backward for pattern\n"
1086*7c478bd9Sstevel@tonic-gate "  !command              execute command\n"
1087*7c478bd9Sstevel@tonic-gate "\n"
1088*7c478bd9Sstevel@tonic-gate "Most commands can be preceeded by a number, as in:\n"
1089*7c478bd9Sstevel@tonic-gate "+1<newline> (next page); -1<newline> (previous page); 1<newline> (page 1).\n"
1090*7c478bd9Sstevel@tonic-gate "\n"
1091*7c478bd9Sstevel@tonic-gate "See the manual page for more detail.\n"
1092*7c478bd9Sstevel@tonic-gate "-------------------------------------------------------\n"),
1093*7c478bd9Sstevel@tonic-gate 		stdout);
1094*7c478bd9Sstevel@tonic-gate }
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate /*
1097*7c478bd9Sstevel@tonic-gate  * Skip nskip files in the file list (from the command line). Nskip may be
1098*7c478bd9Sstevel@tonic-gate  * negative.
1099*7c478bd9Sstevel@tonic-gate  */
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate static int
1102*7c478bd9Sstevel@tonic-gate skipf(nskip)
1103*7c478bd9Sstevel@tonic-gate int nskip;
1104*7c478bd9Sstevel@tonic-gate {
1105*7c478bd9Sstevel@tonic-gate 	if (fnum + nskip < 0) {
1106*7c478bd9Sstevel@tonic-gate 		nskip = -fnum;
1107*7c478bd9Sstevel@tonic-gate 		if (nskip == 0)
1108*7c478bd9Sstevel@tonic-gate 			error("No previous file");
1109*7c478bd9Sstevel@tonic-gate 	}
1110*7c478bd9Sstevel@tonic-gate 	else
1111*7c478bd9Sstevel@tonic-gate 	if (fnum + nskip > nfiles - 1) {
1112*7c478bd9Sstevel@tonic-gate 		nskip = (nfiles - 1) - fnum;
1113*7c478bd9Sstevel@tonic-gate 		if (nskip == 0)
1114*7c478bd9Sstevel@tonic-gate 			error("No next file");
1115*7c478bd9Sstevel@tonic-gate 	}
1116*7c478bd9Sstevel@tonic-gate 	return (nskip);
1117*7c478bd9Sstevel@tonic-gate }
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate /*
1120*7c478bd9Sstevel@tonic-gate  * Check whether the file named by fs is a file which the user may
1121*7c478bd9Sstevel@tonic-gate  * access.  If it is, return the opened file. Otherwise return NULL.
1122*7c478bd9Sstevel@tonic-gate  */
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate static FILE *
1125*7c478bd9Sstevel@tonic-gate checkf(fs)
1126*7c478bd9Sstevel@tonic-gate char *fs;
1127*7c478bd9Sstevel@tonic-gate {
1128*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
1129*7c478bd9Sstevel@tonic-gate 	FILE *f;
1130*7c478bd9Sstevel@tonic-gate 	int fd;
1131*7c478bd9Sstevel@tonic-gate 	int f_was_opened;
1132*7c478bd9Sstevel@tonic-gate 
1133*7c478bd9Sstevel@tonic-gate 	pipe_in = 0;
1134*7c478bd9Sstevel@tonic-gate 	if (strcmp(fs, "-") == 0) {
1135*7c478bd9Sstevel@tonic-gate 		if (tmp_fin == NULL)
1136*7c478bd9Sstevel@tonic-gate 			f = stdin;
1137*7c478bd9Sstevel@tonic-gate 		else {
1138*7c478bd9Sstevel@tonic-gate 			rewind(tmp_fin);
1139*7c478bd9Sstevel@tonic-gate 			f = tmp_fin;
1140*7c478bd9Sstevel@tonic-gate 		}
1141*7c478bd9Sstevel@tonic-gate 		f_was_opened = 0;
1142*7c478bd9Sstevel@tonic-gate 	} else {
1143*7c478bd9Sstevel@tonic-gate 		if ((f = fopen(fs, "r")) == (FILE *)NULL) {
1144*7c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
1145*7c478bd9Sstevel@tonic-gate 			perror(fs);
1146*7c478bd9Sstevel@tonic-gate 			return ((FILE *)NULL);
1147*7c478bd9Sstevel@tonic-gate 		}
1148*7c478bd9Sstevel@tonic-gate 		f_was_opened = 1;
1149*7c478bd9Sstevel@tonic-gate 	}
1150*7c478bd9Sstevel@tonic-gate 	if (fstat(fileno(f), &stbuf) == -1) {
1151*7c478bd9Sstevel@tonic-gate 		if (f_was_opened)
1152*7c478bd9Sstevel@tonic-gate 			(void) fclose(f);
1153*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
1154*7c478bd9Sstevel@tonic-gate 		perror(fs);
1155*7c478bd9Sstevel@tonic-gate 		return ((FILE *)NULL);
1156*7c478bd9Sstevel@tonic-gate 	}
1157*7c478bd9Sstevel@tonic-gate 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1158*7c478bd9Sstevel@tonic-gate 		if (f_was_opened)
1159*7c478bd9Sstevel@tonic-gate 			(void) fclose(f);
1160*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "pg: ");
1161*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s is a directory\n"), fs);
1162*7c478bd9Sstevel@tonic-gate 		return ((FILE *)NULL);
1163*7c478bd9Sstevel@tonic-gate 	}
1164*7c478bd9Sstevel@tonic-gate 	if ((stbuf.st_mode & S_IFMT) == S_IFREG) {
1165*7c478bd9Sstevel@tonic-gate 		if (f == stdin)		/* It may have been read from */
1166*7c478bd9Sstevel@tonic-gate 			rewind(f);	/* already, and not reopened  */
1167*7c478bd9Sstevel@tonic-gate 	} else {
1168*7c478bd9Sstevel@tonic-gate 		if (f != stdin) {
1169*7c478bd9Sstevel@tonic-gate 			if (f_was_opened)
1170*7c478bd9Sstevel@tonic-gate 				(void) fclose(f);
1171*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "pg: ");
1172*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1173*7c478bd9Sstevel@tonic-gate 			"special files only handled as standard input\n"));
1174*7c478bd9Sstevel@tonic-gate 			return ((FILE *)NULL);
1175*7c478bd9Sstevel@tonic-gate 		} else {
1176*7c478bd9Sstevel@tonic-gate 			if ((fd = mkstemp(tmp_name)) < 0) {
1177*7c478bd9Sstevel@tonic-gate 			    (void) perror(tmp_name);
1178*7c478bd9Sstevel@tonic-gate 			    return ((FILE *)NULL);
1179*7c478bd9Sstevel@tonic-gate 			}
1180*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
1181*7c478bd9Sstevel@tonic-gate 			if ((tmp_fou = fopen(tmp_name, "w")) == NULL) {
1182*7c478bd9Sstevel@tonic-gate 				(void) perror(tmp_name);
1183*7c478bd9Sstevel@tonic-gate 				return ((FILE *)NULL);
1184*7c478bd9Sstevel@tonic-gate 			}
1185*7c478bd9Sstevel@tonic-gate 			if ((tmp_fin = fopen(tmp_name, "r")) == NULL) {
1186*7c478bd9Sstevel@tonic-gate 				(void) perror(tmp_name);
1187*7c478bd9Sstevel@tonic-gate 				return ((FILE *)NULL);
1188*7c478bd9Sstevel@tonic-gate 			}
1189*7c478bd9Sstevel@tonic-gate 			pipe_in = 1;
1190*7c478bd9Sstevel@tonic-gate 		}
1191*7c478bd9Sstevel@tonic-gate 	}
1192*7c478bd9Sstevel@tonic-gate 	lineset(BOF);
1193*7c478bd9Sstevel@tonic-gate 	return (f);
1194*7c478bd9Sstevel@tonic-gate }
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate static void
1197*7c478bd9Sstevel@tonic-gate copy_file(f, out)
1198*7c478bd9Sstevel@tonic-gate FILE *f, *out;
1199*7c478bd9Sstevel@tonic-gate {
1200*7c478bd9Sstevel@tonic-gate 	int c;
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	while ((c = getc(f)) != EOF)
1203*7c478bd9Sstevel@tonic-gate 		(void) putc(c, out);
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate }
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate static void
1208*7c478bd9Sstevel@tonic-gate re_error(i)
1209*7c478bd9Sstevel@tonic-gate int i;
1210*7c478bd9Sstevel@tonic-gate {
1211*7c478bd9Sstevel@tonic-gate 	int j;
1212*7c478bd9Sstevel@tonic-gate 	static struct messages {
1213*7c478bd9Sstevel@tonic-gate 		char *message;
1214*7c478bd9Sstevel@tonic-gate 		int number;
1215*7c478bd9Sstevel@tonic-gate 		} re_errmsg[] = {
1216*7c478bd9Sstevel@tonic-gate 		"Pattern not found",				1,
1217*7c478bd9Sstevel@tonic-gate 		"Range endpoint too large",			11,
1218*7c478bd9Sstevel@tonic-gate 		"Bad number",					16,
1219*7c478bd9Sstevel@tonic-gate 		"`\\digit' out of range",			25,
1220*7c478bd9Sstevel@tonic-gate 		"No remembered search string",  		41,
1221*7c478bd9Sstevel@tonic-gate 		"\\( \\) imbalance",				42,
1222*7c478bd9Sstevel@tonic-gate 		"Too many \\(",					43,
1223*7c478bd9Sstevel@tonic-gate 		"More than two numbers given in \\{ \\}",  	44,
1224*7c478bd9Sstevel@tonic-gate 		"} expected after \\",				45,
1225*7c478bd9Sstevel@tonic-gate 		"First number exceeds second in \\{ \\}",  	46,
1226*7c478bd9Sstevel@tonic-gate 		"[] imbalance",					49,
1227*7c478bd9Sstevel@tonic-gate 		"Regular expression overflow",			50,
1228*7c478bd9Sstevel@tonic-gate 		"Illegal byte sequence",			67,
1229*7c478bd9Sstevel@tonic-gate 		"Bad regular expression",			0
1230*7c478bd9Sstevel@tonic-gate 		};
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	for (j = 0; re_errmsg[j].number != 0; j++)
1233*7c478bd9Sstevel@tonic-gate 		if (re_errmsg[j].number == i)
1234*7c478bd9Sstevel@tonic-gate 			break;
1235*7c478bd9Sstevel@tonic-gate 	error(re_errmsg[j].message);
1236*7c478bd9Sstevel@tonic-gate 	longjmp(restore, 1);  /* restore to search() */
1237*7c478bd9Sstevel@tonic-gate }
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate /*
1240*7c478bd9Sstevel@tonic-gate  * Search for nth ocurrence of regular expression contained in buf in the file
1241*7c478bd9Sstevel@tonic-gate  *	negative n implies backward search
1242*7c478bd9Sstevel@tonic-gate  *	n 'guaranteed' non-zero
1243*7c478bd9Sstevel@tonic-gate  */
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate static int
1247*7c478bd9Sstevel@tonic-gate search(buf, n)
1248*7c478bd9Sstevel@tonic-gate char buf[];
1249*7c478bd9Sstevel@tonic-gate off_t n;
1250*7c478bd9Sstevel@tonic-gate {
1251*7c478bd9Sstevel@tonic-gate 	int direction;
1252*7c478bd9Sstevel@tonic-gate 	static char *expbuf;
1253*7c478bd9Sstevel@tonic-gate 	char *nexpbuf;
1254*7c478bd9Sstevel@tonic-gate 	int END_COND;
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	if (setjmp(restore) <= 0) {
1257*7c478bd9Sstevel@tonic-gate 		nexpbuf = compile(buf, (char *)0, (char *)0);
1258*7c478bd9Sstevel@tonic-gate 		if (regerrno) {
1259*7c478bd9Sstevel@tonic-gate 			if (regerrno != 41 || expbuf == NULL)
1260*7c478bd9Sstevel@tonic-gate 				re_error(regerrno);
1261*7c478bd9Sstevel@tonic-gate 		} else {
1262*7c478bd9Sstevel@tonic-gate 			if (expbuf)
1263*7c478bd9Sstevel@tonic-gate 				free(expbuf);
1264*7c478bd9Sstevel@tonic-gate 			expbuf = nexpbuf;
1265*7c478bd9Sstevel@tonic-gate 		}
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 		if (n < 0) {	/* search back */
1268*7c478bd9Sstevel@tonic-gate 			direction = -1;
1269*7c478bd9Sstevel@tonic-gate 			(void) find(0, old_ss.first_line);
1270*7c478bd9Sstevel@tonic-gate 			END_COND = BOF;
1271*7c478bd9Sstevel@tonic-gate 		} else {
1272*7c478bd9Sstevel@tonic-gate 			direction = 1;
1273*7c478bd9Sstevel@tonic-gate 			(void) find(0, old_ss.last_line);
1274*7c478bd9Sstevel@tonic-gate 			END_COND = EOF;
1275*7c478bd9Sstevel@tonic-gate 		}
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 		while (find(1, direction) != END_COND) {
1278*7c478bd9Sstevel@tonic-gate 			if (brk_hit)
1279*7c478bd9Sstevel@tonic-gate 				break;
1280*7c478bd9Sstevel@tonic-gate 			if (step(Line, expbuf))
1281*7c478bd9Sstevel@tonic-gate 				if ((n -= direction) == 0) {
1282*7c478bd9Sstevel@tonic-gate 					switch (leave_search) {
1283*7c478bd9Sstevel@tonic-gate 					case 't':
1284*7c478bd9Sstevel@tonic-gate 						new_ss.first_line =
1285*7c478bd9Sstevel@tonic-gate 						    find(1, (off_t)0);
1286*7c478bd9Sstevel@tonic-gate 						new_ss.last_line =
1287*7c478bd9Sstevel@tonic-gate 						    new_ss.first_line +
1288*7c478bd9Sstevel@tonic-gate 						    (off_t)window
1289*7c478bd9Sstevel@tonic-gate 						    - 1;
1290*7c478bd9Sstevel@tonic-gate 						break;
1291*7c478bd9Sstevel@tonic-gate 					case 'b':
1292*7c478bd9Sstevel@tonic-gate 						new_ss.last_line =
1293*7c478bd9Sstevel@tonic-gate 						    find(1, (off_t)0);
1294*7c478bd9Sstevel@tonic-gate 						new_ss.first_line =
1295*7c478bd9Sstevel@tonic-gate 						    new_ss.last_line -
1296*7c478bd9Sstevel@tonic-gate 						    (off_t)window
1297*7c478bd9Sstevel@tonic-gate 						    + 1;
1298*7c478bd9Sstevel@tonic-gate 						break;
1299*7c478bd9Sstevel@tonic-gate 					case 'm':
1300*7c478bd9Sstevel@tonic-gate 						new_ss.first_line =
1301*7c478bd9Sstevel@tonic-gate 						    find(1, (off_t)0) -
1302*7c478bd9Sstevel@tonic-gate 						    ((off_t)window - 1)/2;
1303*7c478bd9Sstevel@tonic-gate 						new_ss.last_line =
1304*7c478bd9Sstevel@tonic-gate 						    new_ss.first_line +
1305*7c478bd9Sstevel@tonic-gate 						    (off_t)window
1306*7c478bd9Sstevel@tonic-gate 						    - 1;
1307*7c478bd9Sstevel@tonic-gate 						break;
1308*7c478bd9Sstevel@tonic-gate 					}
1309*7c478bd9Sstevel@tonic-gate 					return (1);
1310*7c478bd9Sstevel@tonic-gate 				}
1311*7c478bd9Sstevel@tonic-gate 		}
1312*7c478bd9Sstevel@tonic-gate 		re_error(1); /* Pattern not found */
1313*7c478bd9Sstevel@tonic-gate 	}
1314*7c478bd9Sstevel@tonic-gate 	BEEP();
1315*7c478bd9Sstevel@tonic-gate 	return (0);
1316*7c478bd9Sstevel@tonic-gate }
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate /*
1319*7c478bd9Sstevel@tonic-gate  *	find -- find line in file f, subject to certain constraints.
1320*7c478bd9Sstevel@tonic-gate  *
1321*7c478bd9Sstevel@tonic-gate  *	This is the reason for all the funny stuff with sign and nlines.
1322*7c478bd9Sstevel@tonic-gate  *	We need to be able to differentiate between relative and abosolute
1323*7c478bd9Sstevel@tonic-gate  *	address specifications.
1324*7c478bd9Sstevel@tonic-gate  *
1325*7c478bd9Sstevel@tonic-gate  *	So...there are basically three cases that this routine
1326*7c478bd9Sstevel@tonic-gate  *	handles. Either line is zero, which  means there is to be
1327*7c478bd9Sstevel@tonic-gate  *	no motion (because line numbers start at one), or
1328*7c478bd9Sstevel@tonic-gate  *	how and line specify a number, or line itself is negative,
1329*7c478bd9Sstevel@tonic-gate  *	which is the same as having how == -1 and line == abs(line).
1330*7c478bd9Sstevel@tonic-gate  *
1331*7c478bd9Sstevel@tonic-gate  *	Then, figure where exactly it is that we are going (an absolute
1332*7c478bd9Sstevel@tonic-gate  *	line number). Find out if it is within what we have read,
1333*7c478bd9Sstevel@tonic-gate  *	if so, go there without further ado. Otherwise, do some
1334*7c478bd9Sstevel@tonic-gate  *	magic to get there, saving all the intervening lines,
1335*7c478bd9Sstevel@tonic-gate  *	in case the user wants to see them some time later.
1336*7c478bd9Sstevel@tonic-gate  *
1337*7c478bd9Sstevel@tonic-gate  *	In any case, return the line number that we end up at.
1338*7c478bd9Sstevel@tonic-gate  *	(This is used by search() and screen()). If we go past EOF,
1339*7c478bd9Sstevel@tonic-gate  *	return EOF.
1340*7c478bd9Sstevel@tonic-gate  *	This EOF will go away eventually, as pg is expanded to
1341*7c478bd9Sstevel@tonic-gate  *	handle multiple files as one huge one. Then EOF will
1342*7c478bd9Sstevel@tonic-gate  *	mean we have run off the file list.
1343*7c478bd9Sstevel@tonic-gate  *	If the requested line number is too far back, return BOF.
1344*7c478bd9Sstevel@tonic-gate  */
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate static off_t
1347*7c478bd9Sstevel@tonic-gate find(how, line)	/* find the line and seek there */
1348*7c478bd9Sstevel@tonic-gate int how;
1349*7c478bd9Sstevel@tonic-gate off_t line;
1350*7c478bd9Sstevel@tonic-gate {
1351*7c478bd9Sstevel@tonic-gate 	/* no compacted memory yet */
1352*7c478bd9Sstevel@tonic-gate 	FILE *f = in_file;
1353*7c478bd9Sstevel@tonic-gate 	off_t where;
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	if (how == 0)
1356*7c478bd9Sstevel@tonic-gate 		where = line;
1357*7c478bd9Sstevel@tonic-gate 	else
1358*7c478bd9Sstevel@tonic-gate 		if (dot == zero - 1)
1359*7c478bd9Sstevel@tonic-gate 			where = how * line;
1360*7c478bd9Sstevel@tonic-gate 		else
1361*7c478bd9Sstevel@tonic-gate 			where = how * line + dot->l_no;
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 	/* now, where is either at, before, or after dol */
1364*7c478bd9Sstevel@tonic-gate 	/* most likely case is after, so do it first */
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate 	eoflag = 0;
1367*7c478bd9Sstevel@tonic-gate 	if (where >= dol->l_no) {
1368*7c478bd9Sstevel@tonic-gate 		if (doliseof) {
1369*7c478bd9Sstevel@tonic-gate 			dot = dol;
1370*7c478bd9Sstevel@tonic-gate 			eoflag++;
1371*7c478bd9Sstevel@tonic-gate 			return (EOF);
1372*7c478bd9Sstevel@tonic-gate 		}
1373*7c478bd9Sstevel@tonic-gate 		if (pipe_in)
1374*7c478bd9Sstevel@tonic-gate 			in_file = f = stdin;
1375*7c478bd9Sstevel@tonic-gate 		else
1376*7c478bd9Sstevel@tonic-gate 			(void) fseeko(f, (off_t)dol->l_addr, SEEK_SET);
1377*7c478bd9Sstevel@tonic-gate 		dot = dol - 1;
1378*7c478bd9Sstevel@tonic-gate 		while ((nchars = getline(f)) != EOF) {
1379*7c478bd9Sstevel@tonic-gate 			dot++;
1380*7c478bd9Sstevel@tonic-gate 			newdol(f);
1381*7c478bd9Sstevel@tonic-gate 			if (where == dot->l_no || brk_hit)
1382*7c478bd9Sstevel@tonic-gate 				break;
1383*7c478bd9Sstevel@tonic-gate 		}
1384*7c478bd9Sstevel@tonic-gate 		if (nchars != EOF)
1385*7c478bd9Sstevel@tonic-gate 			return (dot->l_no);
1386*7c478bd9Sstevel@tonic-gate 		else { /* EOF */
1387*7c478bd9Sstevel@tonic-gate 			dot = dol;
1388*7c478bd9Sstevel@tonic-gate 			eoflag++;
1389*7c478bd9Sstevel@tonic-gate 			doliseof++;
1390*7c478bd9Sstevel@tonic-gate 			eofl_no = dol->l_no;
1391*7c478bd9Sstevel@tonic-gate 			return (EOF);
1392*7c478bd9Sstevel@tonic-gate 		}
1393*7c478bd9Sstevel@tonic-gate 	} else { /* where < dol->l_no */
1394*7c478bd9Sstevel@tonic-gate 		if (pipe_in) {
1395*7c478bd9Sstevel@tonic-gate 			(void) fflush(tmp_fou);
1396*7c478bd9Sstevel@tonic-gate 			in_file = f = tmp_fin;
1397*7c478bd9Sstevel@tonic-gate 		}
1398*7c478bd9Sstevel@tonic-gate 		if (where < zero->l_no) {
1399*7c478bd9Sstevel@tonic-gate 			(void) fseeko(f, (off_t)zero->l_addr, SEEK_SET);
1400*7c478bd9Sstevel@tonic-gate 			dot = zero - 1;
1401*7c478bd9Sstevel@tonic-gate 			return (BOF);
1402*7c478bd9Sstevel@tonic-gate 		} else {
1403*7c478bd9Sstevel@tonic-gate 			dot = zero + where - 1;
1404*7c478bd9Sstevel@tonic-gate 			(void) fseeko(f, (off_t)dot->l_addr, SEEK_SET);
1405*7c478bd9Sstevel@tonic-gate 			nchars = getline(f);
1406*7c478bd9Sstevel@tonic-gate 			return (dot->l_no);
1407*7c478bd9Sstevel@tonic-gate 		}
1408*7c478bd9Sstevel@tonic-gate 	}
1409*7c478bd9Sstevel@tonic-gate }
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate static FILE *fileptr;
1412*7c478bd9Sstevel@tonic-gate static int (*rdchar)();
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate static int
1415*7c478bd9Sstevel@tonic-gate mrdchar()
1416*7c478bd9Sstevel@tonic-gate {
1417*7c478bd9Sstevel@tonic-gate 	return (rdchar(fileptr));
1418*7c478bd9Sstevel@tonic-gate }
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate /*
1421*7c478bd9Sstevel@tonic-gate  * Get a logical line
1422*7c478bd9Sstevel@tonic-gate  */
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate static off_t
1425*7c478bd9Sstevel@tonic-gate getline(f)
1426*7c478bd9Sstevel@tonic-gate FILE *f;
1427*7c478bd9Sstevel@tonic-gate {
1428*7c478bd9Sstevel@tonic-gate 	char	*p;
1429*7c478bd9Sstevel@tonic-gate 	int	column;
1430*7c478bd9Sstevel@tonic-gate 	static char multic[MB_LEN_MAX];
1431*7c478bd9Sstevel@tonic-gate 	static int savlength;
1432*7c478bd9Sstevel@tonic-gate 	wchar_t c;
1433*7c478bd9Sstevel@tonic-gate 	int length, width;
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	if (pipe_in && f == stdin)
1436*7c478bd9Sstevel@tonic-gate 		rdchar = fgetputc;
1437*7c478bd9Sstevel@tonic-gate 	else
1438*7c478bd9Sstevel@tonic-gate 		rdchar = (int (*)())fgetwc;
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate 	fileptr = f;
1441*7c478bd9Sstevel@tonic-gate 	/* copy overlap from previous call to getline */
1442*7c478bd9Sstevel@tonic-gate 	if (savlength)
1443*7c478bd9Sstevel@tonic-gate 		(void) strncpy(Line, multic, (size_t)savlength);
1444*7c478bd9Sstevel@tonic-gate 	for (column = 0, p = Line + savlength; ; ) {
1445*7c478bd9Sstevel@tonic-gate 		if ((c = mrdchar()) <= 0) {
1446*7c478bd9Sstevel@tonic-gate 			clearerr(f);
1447*7c478bd9Sstevel@tonic-gate 			if (p > Line) {	/* last line doesn't have '\n', */
1448*7c478bd9Sstevel@tonic-gate 				*p++ = '\n';
1449*7c478bd9Sstevel@tonic-gate 				*p = '\0';	/* print it any way */
1450*7c478bd9Sstevel@tonic-gate 				return (column);
1451*7c478bd9Sstevel@tonic-gate 			}
1452*7c478bd9Sstevel@tonic-gate 			return (EOF);
1453*7c478bd9Sstevel@tonic-gate 		}
1454*7c478bd9Sstevel@tonic-gate 		length = wctomb(multic, c);
1455*7c478bd9Sstevel@tonic-gate 		if (length < 0) {
1456*7c478bd9Sstevel@tonic-gate 			length = -length;
1457*7c478bd9Sstevel@tonic-gate 			c = 0;
1458*7c478bd9Sstevel@tonic-gate 		}
1459*7c478bd9Sstevel@tonic-gate 		if ((width = wcwidth(c)) < 0)
1460*7c478bd9Sstevel@tonic-gate 			width = 0;
1461*7c478bd9Sstevel@tonic-gate 		if (column + width > columns && !fflag)
1462*7c478bd9Sstevel@tonic-gate 			break;
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate 		if (p + length > &Line[LINSIZ - 2] && c != '\n')
1465*7c478bd9Sstevel@tonic-gate 			break;
1466*7c478bd9Sstevel@tonic-gate 		(void) strncpy(p, multic, (size_t)length);
1467*7c478bd9Sstevel@tonic-gate 		p += length;
1468*7c478bd9Sstevel@tonic-gate 		column += width;
1469*7c478bd9Sstevel@tonic-gate 		/* don't have any overlap here */
1470*7c478bd9Sstevel@tonic-gate 		length = 0;
1471*7c478bd9Sstevel@tonic-gate 		switch (c) {
1472*7c478bd9Sstevel@tonic-gate 		case '\t': /* just a guess */
1473*7c478bd9Sstevel@tonic-gate 			column = 1 + (column | 7);
1474*7c478bd9Sstevel@tonic-gate 			break;
1475*7c478bd9Sstevel@tonic-gate 		case '\b':
1476*7c478bd9Sstevel@tonic-gate 			if (column > 0)
1477*7c478bd9Sstevel@tonic-gate 				column--;
1478*7c478bd9Sstevel@tonic-gate 			break;
1479*7c478bd9Sstevel@tonic-gate 		case '\r':
1480*7c478bd9Sstevel@tonic-gate 			column = 0;
1481*7c478bd9Sstevel@tonic-gate 			break;
1482*7c478bd9Sstevel@tonic-gate 		}
1483*7c478bd9Sstevel@tonic-gate 		if (c == '\n')
1484*7c478bd9Sstevel@tonic-gate 			break;
1485*7c478bd9Sstevel@tonic-gate 		if (column >= columns && !fflag)
1486*7c478bd9Sstevel@tonic-gate 			break;
1487*7c478bd9Sstevel@tonic-gate 	}
1488*7c478bd9Sstevel@tonic-gate 	if (c != '\n') { /* We're stopping in the middle of the line */
1489*7c478bd9Sstevel@tonic-gate 		if (column != columns || !auto_right_margin)
1490*7c478bd9Sstevel@tonic-gate 			*p++ = '\n';	/* for the display */
1491*7c478bd9Sstevel@tonic-gate 		/* save overlap for next call to getline */
1492*7c478bd9Sstevel@tonic-gate 		savlength = length;
1493*7c478bd9Sstevel@tonic-gate 		if (savlength == 0) {
1494*7c478bd9Sstevel@tonic-gate 			/*
1495*7c478bd9Sstevel@tonic-gate 			 * check if following byte is newline and get
1496*7c478bd9Sstevel@tonic-gate 			 * it if it is
1497*7c478bd9Sstevel@tonic-gate 			 */
1498*7c478bd9Sstevel@tonic-gate 			c = fgetwc(f);
1499*7c478bd9Sstevel@tonic-gate 			if (c == '\n') {
1500*7c478bd9Sstevel@tonic-gate 				/* gobble and copy (if necessary) newline */
1501*7c478bd9Sstevel@tonic-gate 				(void) ungetwc(c, f);
1502*7c478bd9Sstevel@tonic-gate 				(void) (*rdchar)(f);
1503*7c478bd9Sstevel@tonic-gate 			} else if (c == EOF)
1504*7c478bd9Sstevel@tonic-gate 				clearerr(f);
1505*7c478bd9Sstevel@tonic-gate 			else
1506*7c478bd9Sstevel@tonic-gate 				(void) ungetwc(c, f);
1507*7c478bd9Sstevel@tonic-gate 		}
1508*7c478bd9Sstevel@tonic-gate 	} else
1509*7c478bd9Sstevel@tonic-gate 		savlength = 0;
1510*7c478bd9Sstevel@tonic-gate 	*p = 0;
1511*7c478bd9Sstevel@tonic-gate 	return (column);
1512*7c478bd9Sstevel@tonic-gate }
1513*7c478bd9Sstevel@tonic-gate 
1514*7c478bd9Sstevel@tonic-gate static void
1515*7c478bd9Sstevel@tonic-gate save_input(f)
1516*7c478bd9Sstevel@tonic-gate FILE *f;
1517*7c478bd9Sstevel@tonic-gate {
1518*7c478bd9Sstevel@tonic-gate 	if (pipe_in) {
1519*7c478bd9Sstevel@tonic-gate 		save_pipe();
1520*7c478bd9Sstevel@tonic-gate 		in_file = tmp_fin;
1521*7c478bd9Sstevel@tonic-gate 		pipe_in = 0;
1522*7c478bd9Sstevel@tonic-gate 	}
1523*7c478bd9Sstevel@tonic-gate 	(void) fseeko(in_file, (off_t)0, SEEK_SET);
1524*7c478bd9Sstevel@tonic-gate 	copy_file(in_file, f);
1525*7c478bd9Sstevel@tonic-gate }
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate static void
1528*7c478bd9Sstevel@tonic-gate save_pipe()
1529*7c478bd9Sstevel@tonic-gate {
1530*7c478bd9Sstevel@tonic-gate 	if (!doliseof)
1531*7c478bd9Sstevel@tonic-gate 		while (fgetputc(stdin) != EOF)
1532*7c478bd9Sstevel@tonic-gate 			if (brk_hit) {
1533*7c478bd9Sstevel@tonic-gate 				brk_hit = 0;
1534*7c478bd9Sstevel@tonic-gate 				error("Piped input only partially saved");
1535*7c478bd9Sstevel@tonic-gate 				break;
1536*7c478bd9Sstevel@tonic-gate 			}
1537*7c478bd9Sstevel@tonic-gate 	(void) fclose(tmp_fou);
1538*7c478bd9Sstevel@tonic-gate }
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate static int
1541*7c478bd9Sstevel@tonic-gate fgetputc(f)	/* copy anything read from a pipe to tmp_fou */
1542*7c478bd9Sstevel@tonic-gate FILE *f;
1543*7c478bd9Sstevel@tonic-gate {
1544*7c478bd9Sstevel@tonic-gate 	int c;
1545*7c478bd9Sstevel@tonic-gate 
1546*7c478bd9Sstevel@tonic-gate 	if ((c = fgetwc(f)) != EOF)
1547*7c478bd9Sstevel@tonic-gate 		(void) fputwc(c, tmp_fou);
1548*7c478bd9Sstevel@tonic-gate 	return (c);
1549*7c478bd9Sstevel@tonic-gate }
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate static	void
1552*7c478bd9Sstevel@tonic-gate lineset(how)	/* initialize line memory */
1553*7c478bd9Sstevel@tonic-gate int how;
1554*7c478bd9Sstevel@tonic-gate {
1555*7c478bd9Sstevel@tonic-gate 	if (zero == NULL) {
1556*7c478bd9Sstevel@tonic-gate 		nlall = 128;
1557*7c478bd9Sstevel@tonic-gate 		zero = (LINE *) malloc(nlall * sizeof (LINE));
1558*7c478bd9Sstevel@tonic-gate 	}
1559*7c478bd9Sstevel@tonic-gate 	dol = contig = zero;
1560*7c478bd9Sstevel@tonic-gate 	zero->l_no = 1;
1561*7c478bd9Sstevel@tonic-gate 	zero->l_addr = 0l;
1562*7c478bd9Sstevel@tonic-gate 	if (how == BOF) {
1563*7c478bd9Sstevel@tonic-gate 		dot = zero - 1;
1564*7c478bd9Sstevel@tonic-gate 		eoflag = 0;
1565*7c478bd9Sstevel@tonic-gate 		doliseof = 0;
1566*7c478bd9Sstevel@tonic-gate 		eofl_no = -1;
1567*7c478bd9Sstevel@tonic-gate 	} else {
1568*7c478bd9Sstevel@tonic-gate 		dot = dol;
1569*7c478bd9Sstevel@tonic-gate 		eoflag = 1;
1570*7c478bd9Sstevel@tonic-gate 		doliseof = 1;
1571*7c478bd9Sstevel@tonic-gate 		eofl_no = 1;
1572*7c478bd9Sstevel@tonic-gate 	}
1573*7c478bd9Sstevel@tonic-gate }
1574*7c478bd9Sstevel@tonic-gate 
1575*7c478bd9Sstevel@tonic-gate static void
1576*7c478bd9Sstevel@tonic-gate newdol(f)	/* add address of new 'dol' */
1577*7c478bd9Sstevel@tonic-gate 		/* assumes that f is currently at beginning of said line */
1578*7c478bd9Sstevel@tonic-gate 		/* updates dol */
1579*7c478bd9Sstevel@tonic-gate FILE *f;
1580*7c478bd9Sstevel@tonic-gate {
1581*7c478bd9Sstevel@tonic-gate 	int diff;
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate 	if ((dol - zero) + 1 >= nlall) {
1584*7c478bd9Sstevel@tonic-gate 		LINE *ozero = zero;
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate 		nlall += 512;
1587*7c478bd9Sstevel@tonic-gate 		if ((zero = (LINE *)realloc((char *)zero,
1588*7c478bd9Sstevel@tonic-gate 		    (unsigned)(nlall * sizeof (LINE)))) == NULL) {
1589*7c478bd9Sstevel@tonic-gate 			zero = ozero;
1590*7c478bd9Sstevel@tonic-gate 			compact();
1591*7c478bd9Sstevel@tonic-gate 		}
1592*7c478bd9Sstevel@tonic-gate 		diff = (int)((int)zero - (int)ozero);
1593*7c478bd9Sstevel@tonic-gate 		dot = (LINE *)((int)dot + diff);
1594*7c478bd9Sstevel@tonic-gate 		dol = (LINE *)((int)dol + diff);
1595*7c478bd9Sstevel@tonic-gate 		contig = (LINE *)((int)contig + diff);
1596*7c478bd9Sstevel@tonic-gate 	}
1597*7c478bd9Sstevel@tonic-gate 	dol++;
1598*7c478bd9Sstevel@tonic-gate 	if (!pipe_in)
1599*7c478bd9Sstevel@tonic-gate 		dol->l_addr = (off_t)ftello(f);
1600*7c478bd9Sstevel@tonic-gate 	else {
1601*7c478bd9Sstevel@tonic-gate 		(void) fflush(tmp_fou);
1602*7c478bd9Sstevel@tonic-gate 		dol->l_addr = (off_t)ftello(tmp_fou);
1603*7c478bd9Sstevel@tonic-gate 	}
1604*7c478bd9Sstevel@tonic-gate 	dol->l_no = (dol-1)->l_no + 1;
1605*7c478bd9Sstevel@tonic-gate }
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate static void
1608*7c478bd9Sstevel@tonic-gate compact()
1609*7c478bd9Sstevel@tonic-gate {
1610*7c478bd9Sstevel@tonic-gate 	(void) perror("realloc");
1611*7c478bd9Sstevel@tonic-gate 	end_it();
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate }
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate static void
1616*7c478bd9Sstevel@tonic-gate terminit()	/* set up terminal dependencies from termlib */
1617*7c478bd9Sstevel@tonic-gate {
1618*7c478bd9Sstevel@tonic-gate 	int err_ret;
1619*7c478bd9Sstevel@tonic-gate 	struct termio ntty;
1620*7c478bd9Sstevel@tonic-gate 
1621*7c478bd9Sstevel@tonic-gate 	for (;;) {
1622*7c478bd9Sstevel@tonic-gate 		gid_t my_tgid;
1623*7c478bd9Sstevel@tonic-gate 		my_tgid = (gid_t)tcgetpgrp(1);
1624*7c478bd9Sstevel@tonic-gate 		if (my_tgid < (gid_t)0 || my_tgid == my_pgid)
1625*7c478bd9Sstevel@tonic-gate 			break;
1626*7c478bd9Sstevel@tonic-gate 		(void) kill(-my_pgid, SIGTTOU);
1627*7c478bd9Sstevel@tonic-gate 	}
1628*7c478bd9Sstevel@tonic-gate 
1629*7c478bd9Sstevel@tonic-gate 	if ((freopen("/dev/tty", "r+", stdout)) == NULL) {
1630*7c478bd9Sstevel@tonic-gate 		(void) perror("open");
1631*7c478bd9Sstevel@tonic-gate 		exit(1);
1632*7c478bd9Sstevel@tonic-gate 	}
1633*7c478bd9Sstevel@tonic-gate 	(void) ioctl(fileno(stdout), TCGETA, &otty);
1634*7c478bd9Sstevel@tonic-gate 	termflg = 1;
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 	(void) setupterm(0, fileno(stdout), &err_ret);
1637*7c478bd9Sstevel@tonic-gate 	(void) ioctl(fileno(stdout), TCGETA, &ntty);
1638*7c478bd9Sstevel@tonic-gate 	ntty.c_lflag &= ~(ECHONL | ECHO | ICANON);
1639*7c478bd9Sstevel@tonic-gate 	ntty.c_cc[VMIN] = 1;
1640*7c478bd9Sstevel@tonic-gate 	ntty.c_cc[VTIME] = 1;
1641*7c478bd9Sstevel@tonic-gate 	(void) ioctl(fileno(stdout), TCSETAW, &ntty);
1642*7c478bd9Sstevel@tonic-gate 	pg_stdin = fdopen(dup(fileno(stdout)), "r");
1643*7c478bd9Sstevel@tonic-gate 	(void) saveterm();
1644*7c478bd9Sstevel@tonic-gate 	(void) resetterm();
1645*7c478bd9Sstevel@tonic-gate 	if (lines <= 0 || hard_copy) {
1646*7c478bd9Sstevel@tonic-gate 		hard_copy = 1;
1647*7c478bd9Sstevel@tonic-gate 		lines = 24;
1648*7c478bd9Sstevel@tonic-gate 	}
1649*7c478bd9Sstevel@tonic-gate 	if (columns <= 0)
1650*7c478bd9Sstevel@tonic-gate 		columns = 80;
1651*7c478bd9Sstevel@tonic-gate 	if (clropt && !clear_screen)
1652*7c478bd9Sstevel@tonic-gate 		clropt = 0;
1653*7c478bd9Sstevel@tonic-gate 	if ((shell = getenv("SHELL")) == (char *)NULL)
1654*7c478bd9Sstevel@tonic-gate 			shell = "/usr/bin/sh";
1655*7c478bd9Sstevel@tonic-gate }
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate static void
1658*7c478bd9Sstevel@tonic-gate error(mess)
1659*7c478bd9Sstevel@tonic-gate char *mess;
1660*7c478bd9Sstevel@tonic-gate {
1661*7c478bd9Sstevel@tonic-gate 	kill_line();
1662*7c478bd9Sstevel@tonic-gate 	sopr(gettext(mess), 1);
1663*7c478bd9Sstevel@tonic-gate 	prompt((char *)NULL);
1664*7c478bd9Sstevel@tonic-gate 	errors++;
1665*7c478bd9Sstevel@tonic-gate }
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate static void
1668*7c478bd9Sstevel@tonic-gate prompt(filename)
1669*7c478bd9Sstevel@tonic-gate char *filename;
1670*7c478bd9Sstevel@tonic-gate {
1671*7c478bd9Sstevel@tonic-gate 	char outstr[PROMPTSIZE+6];
1672*7c478bd9Sstevel@tonic-gate 	int pagenum;
1673*7c478bd9Sstevel@tonic-gate 	if (filename != NULL) {
1674*7c478bd9Sstevel@tonic-gate 		/*
1675*7c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
1676*7c478bd9Sstevel@tonic-gate 		 * 	%s is a filename.
1677*7c478bd9Sstevel@tonic-gate 		 */
1678*7c478bd9Sstevel@tonic-gate 		(void) sprintf(outstr, gettext("(Next file: %s)"), filename);
1679*7c478bd9Sstevel@tonic-gate 	} else {
1680*7c478bd9Sstevel@tonic-gate 		if ((pagenum = (int)((new_ss.last_line-2)/(window-1)+1))
1681*7c478bd9Sstevel@tonic-gate 						> 999999)
1682*7c478bd9Sstevel@tonic-gate 			pagenum = 999999;
1683*7c478bd9Sstevel@tonic-gate 		(void) sprintf(outstr, promptstr, pagenum);
1684*7c478bd9Sstevel@tonic-gate 	}
1685*7c478bd9Sstevel@tonic-gate 	sopr(outstr, 1);
1686*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
1687*7c478bd9Sstevel@tonic-gate }
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate /*
1690*7c478bd9Sstevel@tonic-gate  *  sopr puts out the message (please no \n's) surrounded by standout
1691*7c478bd9Sstevel@tonic-gate  *  begins and ends
1692*7c478bd9Sstevel@tonic-gate  */
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate static void
1695*7c478bd9Sstevel@tonic-gate sopr(m, count)
1696*7c478bd9Sstevel@tonic-gate 	char *m;
1697*7c478bd9Sstevel@tonic-gate 	int count;
1698*7c478bd9Sstevel@tonic-gate {
1699*7c478bd9Sstevel@tonic-gate 	wchar_t	wc;
1700*7c478bd9Sstevel@tonic-gate 	int	len, n;
1701*7c478bd9Sstevel@tonic-gate 	char	*p;
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate 	if (count) {
1704*7c478bd9Sstevel@tonic-gate 		p = m;
1705*7c478bd9Sstevel@tonic-gate 		for (; *p; p += len) {
1706*7c478bd9Sstevel@tonic-gate 			if ((len = mbtowc(&wc, p, MB_CUR_MAX)) <= 0) {
1707*7c478bd9Sstevel@tonic-gate 				len = 1;
1708*7c478bd9Sstevel@tonic-gate 				continue;
1709*7c478bd9Sstevel@tonic-gate 			}
1710*7c478bd9Sstevel@tonic-gate 			if ((n = wcwidth(wc)) > 0)
1711*7c478bd9Sstevel@tonic-gate 				promptlen += n;
1712*7c478bd9Sstevel@tonic-gate 		}
1713*7c478bd9Sstevel@tonic-gate 	}
1714*7c478bd9Sstevel@tonic-gate 	if (soflag && enter_standout_mode && exit_standout_mode) {
1715*7c478bd9Sstevel@tonic-gate 		(void) putp(enter_standout_mode);
1716*7c478bd9Sstevel@tonic-gate 		(void) fputs(m, stdout);
1717*7c478bd9Sstevel@tonic-gate 		(void) putp(exit_standout_mode);
1718*7c478bd9Sstevel@tonic-gate 	}
1719*7c478bd9Sstevel@tonic-gate 	else
1720*7c478bd9Sstevel@tonic-gate 		(void) fputs(m, stdout);
1721*7c478bd9Sstevel@tonic-gate }
1722*7c478bd9Sstevel@tonic-gate 
1723*7c478bd9Sstevel@tonic-gate static void
1724*7c478bd9Sstevel@tonic-gate doclear()
1725*7c478bd9Sstevel@tonic-gate {
1726*7c478bd9Sstevel@tonic-gate 	if (clear_screen)
1727*7c478bd9Sstevel@tonic-gate 		(void) putp(clear_screen);
1728*7c478bd9Sstevel@tonic-gate 	(void) putchar('\r');  /* this resets the terminal drivers character */
1729*7c478bd9Sstevel@tonic-gate 			/* count in case it is trying to expand tabs  */
1730*7c478bd9Sstevel@tonic-gate 
1731*7c478bd9Sstevel@tonic-gate }
1732*7c478bd9Sstevel@tonic-gate 
1733*7c478bd9Sstevel@tonic-gate static void
1734*7c478bd9Sstevel@tonic-gate kill_line()
1735*7c478bd9Sstevel@tonic-gate {
1736*7c478bd9Sstevel@tonic-gate 	erase_line(0);
1737*7c478bd9Sstevel@tonic-gate 	if (!clr_eol) (void) putchar('\r');
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate }
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate /* erase from after col to end of prompt */
1742*7c478bd9Sstevel@tonic-gate static void
1743*7c478bd9Sstevel@tonic-gate erase_line(col)
1744*7c478bd9Sstevel@tonic-gate int col;
1745*7c478bd9Sstevel@tonic-gate {
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 	if (promptlen == 0)
1748*7c478bd9Sstevel@tonic-gate 		return;
1749*7c478bd9Sstevel@tonic-gate 	if (hard_copy)
1750*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1751*7c478bd9Sstevel@tonic-gate 	else {
1752*7c478bd9Sstevel@tonic-gate 		if (col == 0)
1753*7c478bd9Sstevel@tonic-gate 			(void) putchar('\r');
1754*7c478bd9Sstevel@tonic-gate 		if (clr_eol) {
1755*7c478bd9Sstevel@tonic-gate 			(void) putp(clr_eol);
1756*7c478bd9Sstevel@tonic-gate 			/* for the terminal driver again */
1757*7c478bd9Sstevel@tonic-gate 			(void) putchar('\r');
1758*7c478bd9Sstevel@tonic-gate 		}
1759*7c478bd9Sstevel@tonic-gate 		else
1760*7c478bd9Sstevel@tonic-gate 			for (col = promptlen - col; col > 0; col--)
1761*7c478bd9Sstevel@tonic-gate 				(void) putchar(' ');
1762*7c478bd9Sstevel@tonic-gate 	}
1763*7c478bd9Sstevel@tonic-gate 	promptlen = 0;
1764*7c478bd9Sstevel@tonic-gate }
1765*7c478bd9Sstevel@tonic-gate 
1766*7c478bd9Sstevel@tonic-gate /*
1767*7c478bd9Sstevel@tonic-gate  * Come here if a quit or interrupt signal is received
1768*7c478bd9Sstevel@tonic-gate  */
1769*7c478bd9Sstevel@tonic-gate 
1770*7c478bd9Sstevel@tonic-gate static void
1771*7c478bd9Sstevel@tonic-gate on_brk(sno)
1772*7c478bd9Sstevel@tonic-gate 	int sno;	/* signal number generated */
1773*7c478bd9Sstevel@tonic-gate {
1774*7c478bd9Sstevel@tonic-gate 	(void) signal(sno, on_brk);
1775*7c478bd9Sstevel@tonic-gate 	if (!inwait) {
1776*7c478bd9Sstevel@tonic-gate 		BEEP();
1777*7c478bd9Sstevel@tonic-gate 		brk_hit = 1;
1778*7c478bd9Sstevel@tonic-gate 	} else {
1779*7c478bd9Sstevel@tonic-gate 		brk_hit = 0;
1780*7c478bd9Sstevel@tonic-gate 		longjmp(restore, 1);
1781*7c478bd9Sstevel@tonic-gate 	}
1782*7c478bd9Sstevel@tonic-gate }
1783*7c478bd9Sstevel@tonic-gate 
1784*7c478bd9Sstevel@tonic-gate /*
1785*7c478bd9Sstevel@tonic-gate  * Clean up terminal state and exit.
1786*7c478bd9Sstevel@tonic-gate  */
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate void
1789*7c478bd9Sstevel@tonic-gate end_it()
1790*7c478bd9Sstevel@tonic-gate {
1791*7c478bd9Sstevel@tonic-gate 
1792*7c478bd9Sstevel@tonic-gate 	if (out_is_tty) {
1793*7c478bd9Sstevel@tonic-gate 		kill_line();
1794*7c478bd9Sstevel@tonic-gate 		(void) resetterm();
1795*7c478bd9Sstevel@tonic-gate 		if (termflg)
1796*7c478bd9Sstevel@tonic-gate 			(void) ioctl(fileno(stdout), TCSETAW, &otty);
1797*7c478bd9Sstevel@tonic-gate 	}
1798*7c478bd9Sstevel@tonic-gate 	if (tmp_fin)
1799*7c478bd9Sstevel@tonic-gate 		(void) fclose(tmp_fin);
1800*7c478bd9Sstevel@tonic-gate 	if (tmp_fou)
1801*7c478bd9Sstevel@tonic-gate 		(void) fclose(tmp_fou);
1802*7c478bd9Sstevel@tonic-gate 	if (tmp_fou || tmp_fin)
1803*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_name);
1804*7c478bd9Sstevel@tonic-gate 	exit(status);
1805*7c478bd9Sstevel@tonic-gate }
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate void
1808*7c478bd9Sstevel@tonic-gate onsusp()
1809*7c478bd9Sstevel@tonic-gate {
1810*7c478bd9Sstevel@tonic-gate 	int ttou_is_dfl;
1811*7c478bd9Sstevel@tonic-gate 
1812*7c478bd9Sstevel@tonic-gate 	/* ignore SIGTTOU so following resetterm and flush works */
1813*7c478bd9Sstevel@tonic-gate 	ttou_is_dfl = (signal(SIGTTOU, SIG_IGN) == SIG_DFL);
1814*7c478bd9Sstevel@tonic-gate 	(void) resetterm();
1815*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
1816*7c478bd9Sstevel@tonic-gate 	if (ttou_is_dfl)
1817*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGTTOU, SIG_DFL);
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate 	/* send SIGTSTP to stop this process group */
1820*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGTSTP, SIG_DFL);
1821*7c478bd9Sstevel@tonic-gate 	(void) kill(-my_pgid, SIGTSTP);
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 	/* continued - reset the terminal */
1824*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1825*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGTSTP, (void (*)(int))onsusp);
1826*7c478bd9Sstevel@tonic-gate #else
1827*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGTSTP, (void (*))onsusp);
1828*7c478bd9Sstevel@tonic-gate #endif
1829*7c478bd9Sstevel@tonic-gate 	(void) resetterm();
1830*7c478bd9Sstevel@tonic-gate 	if (inwait)
1831*7c478bd9Sstevel@tonic-gate 		longjmp(restore, -1);
1832*7c478bd9Sstevel@tonic-gate 
1833*7c478bd9Sstevel@tonic-gate }
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate static char *
1836*7c478bd9Sstevel@tonic-gate pg_strchr(str, c)
1837*7c478bd9Sstevel@tonic-gate char	*str;
1838*7c478bd9Sstevel@tonic-gate wchar_t	c;
1839*7c478bd9Sstevel@tonic-gate {
1840*7c478bd9Sstevel@tonic-gate 	while (*str) {
1841*7c478bd9Sstevel@tonic-gate 		if (c == *str)
1842*7c478bd9Sstevel@tonic-gate 			return (str);
1843*7c478bd9Sstevel@tonic-gate 		str++;
1844*7c478bd9Sstevel@tonic-gate 	}
1845*7c478bd9Sstevel@tonic-gate 	return (0);
1846*7c478bd9Sstevel@tonic-gate }
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate void
1849*7c478bd9Sstevel@tonic-gate usage()
1850*7c478bd9Sstevel@tonic-gate {
1851*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1852*7c478bd9Sstevel@tonic-gate "Usage: pg [-number] [-p string] [-cefnrs] [+line] [+/pattern/] files\n"));
1853*7c478bd9Sstevel@tonic-gate 	exit(1);
1854*7c478bd9Sstevel@tonic-gate }
1855