1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2009 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 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 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 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 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 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