14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 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 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 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 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 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