1 /* 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /* 27 * Simple paged-output and paged-viewing functions 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 #include <termios.h> 38 #include <unistd.h> 39 #include <stropts.h> 40 41 static int p_maxlines = -1; 42 static int p_freelines; 43 44 static struct termios orig_termios; 45 static char *pager_prompt1 = \ 46 " --more-- <space> page down <enter> line down <q> quit "; 47 static char *pager_blank = \ 48 " "; 49 50 /* 51 * 'open' the pager 52 */ 53 void 54 pager_open(void) 55 { 56 int nlines; 57 char *cp, *lp; 58 struct termios raw; 59 struct winsize ws; 60 61 tcgetattr(0, &orig_termios); 62 raw = orig_termios; 63 raw.c_lflag &= ~(ICANON | ECHO); 64 raw.c_cc[VMIN] = 1; 65 raw.c_cc[VTIME] = 0; 66 (void) tcsetattr(0, TCSAFLUSH, &raw); 67 68 nlines = 24; /* sensible default */ 69 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_row == 0) { 70 if ((cp = getenv("LINES")) != NULL) { 71 nlines = strtol(cp, &lp, 0); 72 } 73 } else 74 nlines = ws.ws_row; 75 76 p_maxlines = nlines - 1; 77 if (p_maxlines < 1) 78 p_maxlines = 1; 79 p_freelines = p_maxlines; 80 } 81 82 /* 83 * 'close' the pager 84 */ 85 void 86 pager_close(void) 87 { 88 (void) fflush(stdout); 89 p_maxlines = -1; 90 (void) tcsetattr(0, TCSAFLUSH, &orig_termios); 91 } 92 93 /* 94 * Emit lines to the pager; may not return until the user 95 * has responded to the prompt. 96 * 97 * Will return nonzero if the user enters 'q' or 'Q' at the prompt. 98 * 99 * XXX note that this watches outgoing newlines (and eats them), but 100 * does not handle wrap detection (req. count of columns). 101 */ 102 int 103 pager_output(const char *cp) 104 { 105 int action; 106 107 if (cp == NULL) 108 return (0); 109 110 for (;;) { 111 if (*cp == 0) 112 return (0); 113 114 putchar(*cp); /* always emit character */ 115 116 if (*(cp++) == '\n') { /* got a newline? */ 117 p_freelines--; 118 if (p_freelines <= 0) { 119 printf("%s", pager_prompt1); 120 action = 0; 121 while (action == 0) { 122 switch (getchar()) { 123 case '\r': 124 case '\n': 125 p_freelines = 1; 126 action = 1; 127 break; 128 case ' ': 129 p_freelines = p_maxlines; 130 action = 1; 131 break; 132 case 'q': 133 case 'Q': 134 action = 2; 135 break; 136 default: 137 break; 138 } 139 } 140 printf("\r%s\r", pager_blank); 141 if (action == 2) 142 return (1); 143 } 144 } 145 } 146 } 147 148 /* 149 * Display from (fd). 150 */ 151 int 152 pager_file(const char *fname) 153 { 154 char buf[80]; 155 size_t hmuch; 156 int fd; 157 int result; 158 159 if ((fd = open(fname, O_RDONLY)) == -1) { 160 printf("can't open '%s': %s\n", fname, strerror(errno)); 161 return (-1); 162 } 163 164 for (;;) { 165 hmuch = read(fd, buf, sizeof (buf) - 1); 166 if (hmuch == -1) { 167 result = -1; 168 break; 169 } 170 if (hmuch == 0) { 171 result = 0; 172 break; 173 } 174 buf[hmuch] = 0; 175 if (pager_output(buf)) { 176 result = 1; 177 break; 178 } 179 } 180 close(fd); 181 return (result); 182 } 183