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