xref: /onnv-gate/usr/src/lib/libast/common/disc/sfdcmore.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #include "sfdchdr.h"
234887Schin 
244887Schin #if _PACKAGE_ast
254887Schin #include <ast_tty.h>
264887Schin #include <signal.h>
274887Schin #endif
284887Schin 
294887Schin /*
304887Schin  * a simple but fast more style pager discipline
314887Schin  * if on sfstdout then sfstdin ops reset the page state
324887Schin  *
334887Schin  * Glenn Fowler
344887Schin  * AT&T Research
354887Schin  *
364887Schin  * @(#)$Id: sfdcmore (AT&T Research) 1998-06-25 $
374887Schin  */
384887Schin 
394887Schin typedef struct
404887Schin {
414887Schin 	Sfdisc_t	disc;		/* sfio discipline		*/
424887Schin 	Sfio_t*		input;		/* tied with this input stream	*/
434887Schin 	Sfio_t*		error;		/* tied with this error stream	*/
444887Schin 	int		rows;		/* max rows			*/
454887Schin 	int		cols;		/* max cols			*/
464887Schin 	int		row;		/* current row			*/
474887Schin 	int		col;		/* current col			*/
484887Schin 	int		match;		/* match length, 0 if none	*/
494887Schin 	char		pattern[128];	/* match pattern		*/
504887Schin 	char		prompt[1];	/* prompt string		*/
514887Schin } More_t;
524887Schin 
534887Schin /*
544887Schin  * more read
554887Schin  * we assume line-at-a-time input
564887Schin  */
574887Schin 
584887Schin #if __STD_C
moreread(Sfio_t * f,void * buf,size_t n,Sfdisc_t * dp)594887Schin static ssize_t moreread(Sfio_t* f, void* buf, size_t n, Sfdisc_t* dp)
604887Schin #else
614887Schin static ssize_t moreread(f, buf, n, dp)
624887Schin Sfio_t*		f;
634887Schin void*		buf;
644887Schin size_t		n;
654887Schin Sfdisc_t*	dp;
664887Schin #endif
674887Schin {
684887Schin 	register More_t*	more = (More_t*)dp;
694887Schin 
704887Schin 	more->match = 0;
714887Schin 	more->row = 2;
724887Schin 	more->col = 1;
734887Schin 	return sfrd(f, buf, n, dp);
744887Schin }
754887Schin 
764887Schin /*
774887Schin  * output label on wfd and return next char on rfd with no echo
784887Schin  * return < -1 is -(signal + 1)
794887Schin  */
804887Schin 
814887Schin #if __STD_C
ttyquery(Sfio_t * rp,Sfio_t * wp,const char * label,Sfdisc_t * dp)824887Schin static int ttyquery(Sfio_t* rp, Sfio_t* wp, const char* label, Sfdisc_t* dp)
834887Schin #else
844887Schin static int ttyquery(rp, wp, label, dp)
854887Schin Sfio_t*		rp;
864887Schin Sfio_t*		wp;
874887Schin char*		label;
884887Schin Sfdisc_t*	dp;
894887Schin #endif
904887Schin {
914887Schin 	register int	r;
924887Schin 	int		n;
934887Schin 
944887Schin #ifdef TCSADRAIN
954887Schin 	unsigned char	c;
964887Schin 	struct termios	old;
974887Schin 	struct termios	tty;
984887Schin 	int		rfd = sffileno(rp);
994887Schin 	int		wfd = sffileno(rp);
1004887Schin 
1014887Schin 	if (!label)
1024887Schin 		n = 0;
1034887Schin 	else if (n = strlen(label))
1044887Schin 		write(wfd, label, n);
1054887Schin 	tcgetattr(rfd, &old);
1064887Schin 	tty = old;
1074887Schin 	tty.c_cc[VTIME] = 0;
1084887Schin 	tty.c_cc[VMIN] = 1;
1094887Schin 	tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);
1104887Schin 	tcsetattr(rfd, TCSADRAIN, &tty);
1114887Schin 	if ((r = read(rfd, &c, 1)) == 1)
1124887Schin 	{
1134887Schin 		if (c == old.c_cc[VEOF])
1144887Schin 			r = -1;
1154887Schin 		else if (c == old.c_cc[VINTR])
1164887Schin 			r = -(SIGINT + 1);
1174887Schin 		else if (c == old.c_cc[VQUIT])
1184887Schin 			r = -(SIGQUIT + 1);
1194887Schin 		else if (c == '\r')
1204887Schin 			r = '\n';
1214887Schin 		else
1224887Schin 			r = c;
1234887Schin 	}
1244887Schin 	tcsetattr(rfd, TCSADRAIN, &old);
1254887Schin 	if (n)
1264887Schin 	{
1274887Schin 		write(wfd, "\r", 1);
1284887Schin 		while (n-- > 0)
1294887Schin 			write(wfd, " ", 1);
1304887Schin 		write(wfd, "\r", 1);
1314887Schin 	}
1324887Schin #else
1334887Schin 	register char*	s;
1344887Schin 
1354887Schin 	if (label && (n = strlen(label)))
1364887Schin 		sfwr(wp, label, n, dp);
1374887Schin 	r = (s = sfgetr(rp, '\n', 0)) ? *s : -1;
1384887Schin #endif
1394887Schin 	return r;
1404887Schin }
1414887Schin 
1424887Schin /*
1434887Schin  * more write
1444887Schin  */
1454887Schin 
1464887Schin #if __STD_C
morewrite(Sfio_t * f,const Void_t * buf,register size_t n,Sfdisc_t * dp)1474887Schin static ssize_t morewrite(Sfio_t* f, const Void_t* buf, register size_t n, Sfdisc_t* dp)
1484887Schin #else
1494887Schin static ssize_t morewrite(f, buf, n, dp)
1504887Schin Sfio_t* 	f;
1514887Schin Void_t*		buf;
1524887Schin register size_t	n;
1534887Schin Sfdisc_t*	dp;
1544887Schin #endif
1554887Schin {
1564887Schin 	register More_t*	more = (More_t*)dp;
1574887Schin 	register char*		b;
1584887Schin 	register char*		s;
1594887Schin 	register char*		e;
1604887Schin 	register ssize_t	w;
1614887Schin 	register int		r;
1624887Schin 
1634887Schin 	if (!more->row)
1644887Schin 		return n;
1654887Schin 	if (!more->col)
1664887Schin 		return sfwr(f, buf, n, dp);
1674887Schin 	w = 0;
1684887Schin 	b = (char*)buf;
1694887Schin 	s = b;
1704887Schin 	e = s + n;
1714887Schin 	if (more->match)
1724887Schin 	{
1734887Schin  match:
1744887Schin 		for (r = more->pattern[0];; s++)
1754887Schin 		{
1764887Schin 			if (s >= e)
1774887Schin 				return n;
1784887Schin 			if (*s == '\n')
1794887Schin 				b = s + 1;
1804887Schin 			else if (*s == r && (e - s) >= more->match && !strncmp(s, more->pattern, more->match))
1814887Schin 				break;
1824887Schin 		}
1834887Schin 		s = b;
1844887Schin 		w += b - (char*)buf;
1854887Schin 		more->match = 0;
1864887Schin 	}
1874887Schin 	while (s < e)
1884887Schin 	{
1894887Schin 		switch (*s++)
1904887Schin 		{
1914887Schin 		case '\t':
1924887Schin 			more->col = ((more->col + 8) & ~7) - 1;
1934887Schin 			/*FALLTHROUGH*/
1944887Schin 		default:
1954887Schin 			if (++more->col <= more->cols || s < e && *s == '\n')
1964887Schin 				continue;
1974887Schin 			/*FALLTHROUGH*/
1984887Schin 		case '\n':
1994887Schin 			more->col = 1;
2004887Schin 			if (++more->row < more->rows)
2014887Schin 				continue;
2024887Schin 			break;
2034887Schin 		case '\b':
2044887Schin 			if (more->col > 1)
2054887Schin 				more->col--;
2064887Schin 			continue;
2074887Schin 		case '\r':
2084887Schin 			more->col = 1;
2094887Schin 			continue;
2104887Schin 		}
2114887Schin 		w += sfwr(f, b, s - b, dp);
2124887Schin 		b = s;
2134887Schin 		r = ttyquery(sfstdin, f, more->prompt, dp);
2144887Schin 		if (r == '/' || r == 'n')
2154887Schin 		{
2164887Schin 			if (r == '/')
2174887Schin 			{
2184887Schin 				sfwr(f, "/", 1, dp);
2194887Schin 				if ((s = sfgetr(sfstdin, '\n', 1)) && (n = sfvalue(sfstdin) - 1) > 0)
2204887Schin 				{
2214887Schin 					if (n >= sizeof(more->pattern))
2224887Schin 						n = sizeof(more->pattern) - 1;
2234887Schin 					memcpy(more->pattern, s, n);
2244887Schin 					more->pattern[n] = 0;
2254887Schin 				}
2264887Schin 			}
2274887Schin 			if (more->match = strlen(more->pattern))
2284887Schin 			{
2294887Schin 				more->row = 1;
2304887Schin 				more->col = 1;
2314887Schin 				goto match;
2324887Schin 			}
2334887Schin 		}
2344887Schin 		switch (r)
2354887Schin 		{
2364887Schin 		case '\n':
2374887Schin 		case '\r':
2384887Schin 			more->row--;
2394887Schin 			more->col = 1;
2404887Schin 			break;
2414887Schin 		case ' ':
2424887Schin 			more->row = 2;
2434887Schin 			more->col = 1;
2444887Schin 			break;
2454887Schin 		default:
2464887Schin 			more->row = 0;
2474887Schin 			return n;
2484887Schin 		}
2494887Schin 	}
2504887Schin 	if (s > b)
2514887Schin 		w += sfwr(f, b, s - b, dp);
2524887Schin 	return w;
2534887Schin }
2544887Schin 
2554887Schin /*
2564887Schin  * remove the discipline on close
2574887Schin  */
2584887Schin 
2594887Schin #if __STD_C
moreexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * dp)2604887Schin static int moreexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* dp)
2614887Schin #else
2624887Schin static int moreexcept(f, type, data, dp)
2634887Schin Sfio_t*		f;
2644887Schin int		type;
2654887Schin Void_t*		data;
2664887Schin Sfdisc_t*	dp;
2674887Schin #endif
2684887Schin {
2694887Schin 	register More_t*	more = (More_t*)dp;
2704887Schin 
2714887Schin 	if (type == SF_FINAL || type == SF_DPOP)
2724887Schin 	{
2734887Schin 		if (f = more->input)
2744887Schin 		{
2754887Schin 			more->input = 0;
2764887Schin 			sfdisc(f, SF_POPDISC);
2774887Schin 		}
2784887Schin 		else if (f = more->error)
2794887Schin 		{
2804887Schin 			more->error = 0;
2814887Schin 			sfdisc(f, SF_POPDISC);
2824887Schin 		}
2834887Schin 		else
2844887Schin 			free(dp);
2854887Schin 	}
2864887Schin 	else if (type == SF_SYNC)
2874887Schin 	{
2884887Schin 		more->match = 0;
2894887Schin 		more->row = 1;
2904887Schin 		more->col = 1;
2914887Schin 	}
2924887Schin 	return 0;
2934887Schin }
2944887Schin 
2954887Schin /*
2964887Schin  * push the more discipline on f
2974887Schin  * if prompt==0 then a default ansi prompt is used
2984887Schin  * if rows==0 or cols==0 then they are deterimined from the tty
2994887Schin  * if f==sfstdout then input on sfstdin also resets the state
3004887Schin  */
3014887Schin 
3024887Schin #if __STD_C
sfdcmore(Sfio_t * f,const char * prompt,int rows,int cols)3034887Schin int sfdcmore(Sfio_t* f, const char* prompt, int rows, int cols)
3044887Schin #else
3054887Schin int sfdcmore(f, prompt, rows, cols)
3064887Schin Sfio_t*		f;
3074887Schin char*		prompt;
3084887Schin int		rows;
3094887Schin int		cols;
3104887Schin #endif
3114887Schin {
3124887Schin 	register More_t*	more;
3134887Schin 	size_t			n;
3144887Schin 
3154887Schin 	/*
3164887Schin 	 * this is a writeonly discipline for interactive io
3174887Schin 	 */
3184887Schin 
3194887Schin 	if (!(sfset(f, 0, 0) & SF_WRITE) || !isatty(sffileno(sfstdin)) || !isatty(sffileno(sfstdout)))
3204887Schin 		return -1;
3214887Schin 	if (!prompt)
3224887Schin 		prompt = "\033[7m More\033[m";
3234887Schin 	n = strlen(prompt) + 1;
3244887Schin 	if (!(more = (More_t*)malloc(sizeof(More_t) + n)))
3254887Schin 		return -1;
3264887Schin 	memset(more, 0, sizeof(*more));
3274887Schin 
3284887Schin 	more->disc.readf = moreread;
3294887Schin 	more->disc.writef = morewrite;
3304887Schin 	more->disc.exceptf = moreexcept;
3314887Schin 	memcpy(more->prompt, prompt, n);
3324887Schin 	if (!rows || !cols)
3334887Schin 	{
3344887Schin #if _PACKAGE_ast
3354887Schin 		astwinsize(sffileno(sfstdin), &rows, &cols);
3364887Schin #endif
3374887Schin 		if (!rows)
3384887Schin 			rows = 24;
3394887Schin 		if (!cols)
3404887Schin 			cols = 80;
3414887Schin 	}
3424887Schin 	more->rows = rows;
3434887Schin 	more->cols = cols;
3444887Schin 	more->row = 1;
3454887Schin 	more->col = 1;
3464887Schin 
3474887Schin 	if (sfdisc(f, &more->disc) != &more->disc)
3484887Schin 	{
3494887Schin 		free(more);
3504887Schin 		return -1;
3514887Schin 	}
3524887Schin 	if (f == sfstdout)
3534887Schin 	{
3544887Schin 		if (sfdisc(sfstdin, &more->disc) != &more->disc)
3554887Schin 		{
3564887Schin 			sfdisc(f, SF_POPDISC);
3574887Schin 			return -1;
3584887Schin 		}
3594887Schin 		more->input = sfstdin;
3604887Schin 		if (sfdisc(sfstderr, &more->disc) != &more->disc)
3614887Schin 		{
3624887Schin 			sfdisc(f, SF_POPDISC);
3634887Schin 			return -1;
3644887Schin 		}
3654887Schin 		more->error = sfstdin;
3664887Schin 	}
3674887Schin 
3684887Schin 	return 0;
3694887Schin }
370