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