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