xref: /onnv-gate/usr/src/lib/libast/common/disc/sfdcmore.c (revision 4887:feebf9260c2e)
1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #include "sfdchdr.h"
23*4887Schin 
24*4887Schin #if _PACKAGE_ast
25*4887Schin #include <ast_tty.h>
26*4887Schin #include <signal.h>
27*4887Schin #endif
28*4887Schin 
29*4887Schin /*
30*4887Schin  * a simple but fast more style pager discipline
31*4887Schin  * if on sfstdout then sfstdin ops reset the page state
32*4887Schin  *
33*4887Schin  * Glenn Fowler
34*4887Schin  * AT&T Research
35*4887Schin  *
36*4887Schin  * @(#)$Id: sfdcmore (AT&T Research) 1998-06-25 $
37*4887Schin  */
38*4887Schin 
39*4887Schin typedef struct
40*4887Schin {
41*4887Schin 	Sfdisc_t	disc;		/* sfio discipline		*/
42*4887Schin 	Sfio_t*		input;		/* tied with this input stream	*/
43*4887Schin 	Sfio_t*		error;		/* tied with this error stream	*/
44*4887Schin 	int		rows;		/* max rows			*/
45*4887Schin 	int		cols;		/* max cols			*/
46*4887Schin 	int		row;		/* current row			*/
47*4887Schin 	int		col;		/* current col			*/
48*4887Schin 	int		match;		/* match length, 0 if none	*/
49*4887Schin 	char		pattern[128];	/* match pattern		*/
50*4887Schin 	char		prompt[1];	/* prompt string		*/
51*4887Schin } More_t;
52*4887Schin 
53*4887Schin /*
54*4887Schin  * more read
55*4887Schin  * we assume line-at-a-time input
56*4887Schin  */
57*4887Schin 
58*4887Schin #if __STD_C
59*4887Schin static ssize_t moreread(Sfio_t* f, void* buf, size_t n, Sfdisc_t* dp)
60*4887Schin #else
61*4887Schin static ssize_t moreread(f, buf, n, dp)
62*4887Schin Sfio_t*		f;
63*4887Schin void*		buf;
64*4887Schin size_t		n;
65*4887Schin Sfdisc_t*	dp;
66*4887Schin #endif
67*4887Schin {
68*4887Schin 	register More_t*	more = (More_t*)dp;
69*4887Schin 
70*4887Schin 	more->match = 0;
71*4887Schin 	more->row = 2;
72*4887Schin 	more->col = 1;
73*4887Schin 	return sfrd(f, buf, n, dp);
74*4887Schin }
75*4887Schin 
76*4887Schin /*
77*4887Schin  * output label on wfd and return next char on rfd with no echo
78*4887Schin  * return < -1 is -(signal + 1)
79*4887Schin  */
80*4887Schin 
81*4887Schin #if __STD_C
82*4887Schin static int ttyquery(Sfio_t* rp, Sfio_t* wp, const char* label, Sfdisc_t* dp)
83*4887Schin #else
84*4887Schin static int ttyquery(rp, wp, label, dp)
85*4887Schin Sfio_t*		rp;
86*4887Schin Sfio_t*		wp;
87*4887Schin char*		label;
88*4887Schin Sfdisc_t*	dp;
89*4887Schin #endif
90*4887Schin {
91*4887Schin 	register int	r;
92*4887Schin 	int		n;
93*4887Schin 
94*4887Schin #ifdef TCSADRAIN
95*4887Schin 	unsigned char	c;
96*4887Schin 	struct termios	old;
97*4887Schin 	struct termios	tty;
98*4887Schin 	int		rfd = sffileno(rp);
99*4887Schin 	int		wfd = sffileno(rp);
100*4887Schin 
101*4887Schin 	if (!label)
102*4887Schin 		n = 0;
103*4887Schin 	else if (n = strlen(label))
104*4887Schin 		write(wfd, label, n);
105*4887Schin 	tcgetattr(rfd, &old);
106*4887Schin 	tty = old;
107*4887Schin 	tty.c_cc[VTIME] = 0;
108*4887Schin 	tty.c_cc[VMIN] = 1;
109*4887Schin 	tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);
110*4887Schin 	tcsetattr(rfd, TCSADRAIN, &tty);
111*4887Schin 	if ((r = read(rfd, &c, 1)) == 1)
112*4887Schin 	{
113*4887Schin 		if (c == old.c_cc[VEOF])
114*4887Schin 			r = -1;
115*4887Schin 		else if (c == old.c_cc[VINTR])
116*4887Schin 			r = -(SIGINT + 1);
117*4887Schin 		else if (c == old.c_cc[VQUIT])
118*4887Schin 			r = -(SIGQUIT + 1);
119*4887Schin 		else if (c == '\r')
120*4887Schin 			r = '\n';
121*4887Schin 		else
122*4887Schin 			r = c;
123*4887Schin 	}
124*4887Schin 	tcsetattr(rfd, TCSADRAIN, &old);
125*4887Schin 	if (n)
126*4887Schin 	{
127*4887Schin 		write(wfd, "\r", 1);
128*4887Schin 		while (n-- > 0)
129*4887Schin 			write(wfd, " ", 1);
130*4887Schin 		write(wfd, "\r", 1);
131*4887Schin 	}
132*4887Schin #else
133*4887Schin 	register char*	s;
134*4887Schin 
135*4887Schin 	if (label && (n = strlen(label)))
136*4887Schin 		sfwr(wp, label, n, dp);
137*4887Schin 	r = (s = sfgetr(rp, '\n', 0)) ? *s : -1;
138*4887Schin #endif
139*4887Schin 	return r;
140*4887Schin }
141*4887Schin 
142*4887Schin /*
143*4887Schin  * more write
144*4887Schin  */
145*4887Schin 
146*4887Schin #if __STD_C
147*4887Schin static ssize_t morewrite(Sfio_t* f, const Void_t* buf, register size_t n, Sfdisc_t* dp)
148*4887Schin #else
149*4887Schin static ssize_t morewrite(f, buf, n, dp)
150*4887Schin Sfio_t* 	f;
151*4887Schin Void_t*		buf;
152*4887Schin register size_t	n;
153*4887Schin Sfdisc_t*	dp;
154*4887Schin #endif
155*4887Schin {
156*4887Schin 	register More_t*	more = (More_t*)dp;
157*4887Schin 	register char*		b;
158*4887Schin 	register char*		s;
159*4887Schin 	register char*		e;
160*4887Schin 	register ssize_t	w;
161*4887Schin 	register int		r;
162*4887Schin 
163*4887Schin 	if (!more->row)
164*4887Schin 		return n;
165*4887Schin 	if (!more->col)
166*4887Schin 		return sfwr(f, buf, n, dp);
167*4887Schin 	w = 0;
168*4887Schin 	b = (char*)buf;
169*4887Schin 	s = b;
170*4887Schin 	e = s + n;
171*4887Schin 	if (more->match)
172*4887Schin 	{
173*4887Schin  match:
174*4887Schin 		for (r = more->pattern[0];; s++)
175*4887Schin 		{
176*4887Schin 			if (s >= e)
177*4887Schin 				return n;
178*4887Schin 			if (*s == '\n')
179*4887Schin 				b = s + 1;
180*4887Schin 			else if (*s == r && (e - s) >= more->match && !strncmp(s, more->pattern, more->match))
181*4887Schin 				break;
182*4887Schin 		}
183*4887Schin 		s = b;
184*4887Schin 		w += b - (char*)buf;
185*4887Schin 		more->match = 0;
186*4887Schin 	}
187*4887Schin 	while (s < e)
188*4887Schin 	{
189*4887Schin 		switch (*s++)
190*4887Schin 		{
191*4887Schin 		case '\t':
192*4887Schin 			more->col = ((more->col + 8) & ~7) - 1;
193*4887Schin 			/*FALLTHROUGH*/
194*4887Schin 		default:
195*4887Schin 			if (++more->col <= more->cols || s < e && *s == '\n')
196*4887Schin 				continue;
197*4887Schin 			/*FALLTHROUGH*/
198*4887Schin 		case '\n':
199*4887Schin 			more->col = 1;
200*4887Schin 			if (++more->row < more->rows)
201*4887Schin 				continue;
202*4887Schin 			break;
203*4887Schin 		case '\b':
204*4887Schin 			if (more->col > 1)
205*4887Schin 				more->col--;
206*4887Schin 			continue;
207*4887Schin 		case '\r':
208*4887Schin 			more->col = 1;
209*4887Schin 			continue;
210*4887Schin 		}
211*4887Schin 		w += sfwr(f, b, s - b, dp);
212*4887Schin 		b = s;
213*4887Schin 		r = ttyquery(sfstdin, f, more->prompt, dp);
214*4887Schin 		if (r == '/' || r == 'n')
215*4887Schin 		{
216*4887Schin 			if (r == '/')
217*4887Schin 			{
218*4887Schin 				sfwr(f, "/", 1, dp);
219*4887Schin 				if ((s = sfgetr(sfstdin, '\n', 1)) && (n = sfvalue(sfstdin) - 1) > 0)
220*4887Schin 				{
221*4887Schin 					if (n >= sizeof(more->pattern))
222*4887Schin 						n = sizeof(more->pattern) - 1;
223*4887Schin 					memcpy(more->pattern, s, n);
224*4887Schin 					more->pattern[n] = 0;
225*4887Schin 				}
226*4887Schin 			}
227*4887Schin 			if (more->match = strlen(more->pattern))
228*4887Schin 			{
229*4887Schin 				more->row = 1;
230*4887Schin 				more->col = 1;
231*4887Schin 				goto match;
232*4887Schin 			}
233*4887Schin 		}
234*4887Schin 		switch (r)
235*4887Schin 		{
236*4887Schin 		case '\n':
237*4887Schin 		case '\r':
238*4887Schin 			more->row--;
239*4887Schin 			more->col = 1;
240*4887Schin 			break;
241*4887Schin 		case ' ':
242*4887Schin 			more->row = 2;
243*4887Schin 			more->col = 1;
244*4887Schin 			break;
245*4887Schin 		default:
246*4887Schin 			more->row = 0;
247*4887Schin 			return n;
248*4887Schin 		}
249*4887Schin 	}
250*4887Schin 	if (s > b)
251*4887Schin 		w += sfwr(f, b, s - b, dp);
252*4887Schin 	return w;
253*4887Schin }
254*4887Schin 
255*4887Schin /*
256*4887Schin  * remove the discipline on close
257*4887Schin  */
258*4887Schin 
259*4887Schin #if __STD_C
260*4887Schin static int moreexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* dp)
261*4887Schin #else
262*4887Schin static int moreexcept(f, type, data, dp)
263*4887Schin Sfio_t*		f;
264*4887Schin int		type;
265*4887Schin Void_t*		data;
266*4887Schin Sfdisc_t*	dp;
267*4887Schin #endif
268*4887Schin {
269*4887Schin 	register More_t*	more = (More_t*)dp;
270*4887Schin 
271*4887Schin 	if (type == SF_FINAL || type == SF_DPOP)
272*4887Schin 	{
273*4887Schin 		if (f = more->input)
274*4887Schin 		{
275*4887Schin 			more->input = 0;
276*4887Schin 			sfdisc(f, SF_POPDISC);
277*4887Schin 		}
278*4887Schin 		else if (f = more->error)
279*4887Schin 		{
280*4887Schin 			more->error = 0;
281*4887Schin 			sfdisc(f, SF_POPDISC);
282*4887Schin 		}
283*4887Schin 		else
284*4887Schin 			free(dp);
285*4887Schin 	}
286*4887Schin 	else if (type == SF_SYNC)
287*4887Schin 	{
288*4887Schin 		more->match = 0;
289*4887Schin 		more->row = 1;
290*4887Schin 		more->col = 1;
291*4887Schin 	}
292*4887Schin 	return 0;
293*4887Schin }
294*4887Schin 
295*4887Schin /*
296*4887Schin  * push the more discipline on f
297*4887Schin  * if prompt==0 then a default ansi prompt is used
298*4887Schin  * if rows==0 or cols==0 then they are deterimined from the tty
299*4887Schin  * if f==sfstdout then input on sfstdin also resets the state
300*4887Schin  */
301*4887Schin 
302*4887Schin #if __STD_C
303*4887Schin int sfdcmore(Sfio_t* f, const char* prompt, int rows, int cols)
304*4887Schin #else
305*4887Schin int sfdcmore(f, prompt, rows, cols)
306*4887Schin Sfio_t*		f;
307*4887Schin char*		prompt;
308*4887Schin int		rows;
309*4887Schin int		cols;
310*4887Schin #endif
311*4887Schin {
312*4887Schin 	register More_t*	more;
313*4887Schin 	size_t			n;
314*4887Schin 
315*4887Schin 	/*
316*4887Schin 	 * this is a writeonly discipline for interactive io
317*4887Schin 	 */
318*4887Schin 
319*4887Schin 	if (!(sfset(f, 0, 0) & SF_WRITE) || !isatty(sffileno(sfstdin)) || !isatty(sffileno(sfstdout)))
320*4887Schin 		return -1;
321*4887Schin 	if (!prompt)
322*4887Schin 		prompt = "\033[7m More\033[m";
323*4887Schin 	n = strlen(prompt) + 1;
324*4887Schin 	if (!(more = (More_t*)malloc(sizeof(More_t) + n)))
325*4887Schin 		return -1;
326*4887Schin 	memset(more, 0, sizeof(*more));
327*4887Schin 
328*4887Schin 	more->disc.readf = moreread;
329*4887Schin 	more->disc.writef = morewrite;
330*4887Schin 	more->disc.exceptf = moreexcept;
331*4887Schin 	memcpy(more->prompt, prompt, n);
332*4887Schin 	if (!rows || !cols)
333*4887Schin 	{
334*4887Schin #if _PACKAGE_ast
335*4887Schin 		astwinsize(sffileno(sfstdin), &rows, &cols);
336*4887Schin #endif
337*4887Schin 		if (!rows)
338*4887Schin 			rows = 24;
339*4887Schin 		if (!cols)
340*4887Schin 			cols = 80;
341*4887Schin 	}
342*4887Schin 	more->rows = rows;
343*4887Schin 	more->cols = cols;
344*4887Schin 	more->row = 1;
345*4887Schin 	more->col = 1;
346*4887Schin 
347*4887Schin 	if (sfdisc(f, &more->disc) != &more->disc)
348*4887Schin 	{
349*4887Schin 		free(more);
350*4887Schin 		return -1;
351*4887Schin 	}
352*4887Schin 	if (f == sfstdout)
353*4887Schin 	{
354*4887Schin 		if (sfdisc(sfstdin, &more->disc) != &more->disc)
355*4887Schin 		{
356*4887Schin 			sfdisc(f, SF_POPDISC);
357*4887Schin 			return -1;
358*4887Schin 		}
359*4887Schin 		more->input = sfstdin;
360*4887Schin 		if (sfdisc(sfstderr, &more->disc) != &more->disc)
361*4887Schin 		{
362*4887Schin 			sfdisc(f, SF_POPDISC);
363*4887Schin 			return -1;
364*4887Schin 		}
365*4887Schin 		more->error = sfstdin;
366*4887Schin 	}
367*4887Schin 
368*4887Schin 	return 0;
369*4887Schin }
370