comparison pager.c @ 19:5c6155c8e9b6

Handle signals Handled signals are generally blocked and only unblocked when doing blocking I/O, i.e. either when reading commands or printing results. A (possibly queued) signal will then interrupt I/O and can be dealt with in the main loop.
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Fri, 01 Sep 2017 22:33:41 +0200
parents 1e39a251cbe9
children
comparison
equal deleted inserted replaced
18:1e39a251cbe9 19:5c6155c8e9b6
26 #ifdef HAVE_ERR_H 26 #ifdef HAVE_ERR_H
27 #include <err.h> 27 #include <err.h>
28 #endif /* HAVE_ERR_H */ 28 #endif /* HAVE_ERR_H */
29 #include <errno.h> 29 #include <errno.h>
30 #include <fcntl.h> 30 #include <fcntl.h>
31 #include <libtecla.h>
32 #include <limits.h> 31 #include <limits.h>
33 #include <signal.h> 32 #include <signal.h>
34 #include <stdio.h> 33 #include <stdio.h>
35 #include <string.h> 34 #include <string.h>
36 #include <sys/ioctl.h> 35 #include <sys/ioctl.h>
47 #include "pager.h" 46 #include "pager.h"
48 #include "util.h" 47 #include "util.h"
49 48
50 struct pager { 49 struct pager {
51 TAILQ_HEAD(lines_head, lines_entry) lines_head; 50 TAILQ_HEAD(lines_head, lines_entry) lines_head;
52 FILE *fp; 51 int fd;
53 size_t buf_size; 52 size_t buf_size;
54 char *buf; 53 char *buf;
55 }; 54 };
56 55
57 struct lines_entry { 56 struct lines_entry {
58 TAILQ_ENTRY(lines_entry) entry; 57 TAILQ_ENTRY(lines_entry) entry;
59 char *line; 58 char *line;
60 }; 59 };
61 60
62 static int
63 getch_prompt(GetLine *gl, const char *prompt)
64 {
65 int c;
66 int saved_echo_mode;
67
68 /* prompt with echo off */
69 saved_echo_mode = gl_echo_mode(gl, -1);
70 gl_echo_mode(gl, 0);
71 c = gl_query_char(gl, prompt, '\0');
72 gl_echo_mode(gl, saved_echo_mode);
73
74 /* erase prompt */
75 printf("\r%*s\r", (int)strlen(prompt), "");
76
77 return (c);
78 }
79
80 struct pager * 61 struct pager *
81 pager_create(FILE *fp) 62 pager_create(int fd)
82 { 63 {
83 struct pager *pager; 64 struct pager *pager;
84 65
85 pager = xmalloc(sizeof (struct pager)); 66 pager = xmalloc(sizeof (struct pager));
86 TAILQ_INIT(&pager->lines_head); 67 TAILQ_INIT(&pager->lines_head);
87 pager->fp = fp; 68 pager->fd = fd;
88 pager->buf_size = BUFSIZ; 69 pager->buf_size = BUFSIZ;
89 pager->buf = xmalloc(BUFSIZ); 70 pager->buf = xmalloc(BUFSIZ);
90 71
91 return (pager); 72 return (pager);
92 } 73 }
181 va_end(args); 162 va_end(args);
182 163
183 return (len); 164 return (len);
184 } 165 }
185 166
186 static unsigned int 167 static int
187 mbsnprint(unsigned int cols, const char *s, FILE *fp) 168 mbsnprint(unsigned int cols, const char *s, int fd)
188 { 169 {
170 int retval;
189 const char *p = s; 171 const char *p = s;
190 unsigned int col = 0; 172 unsigned int col = 0;
191 int mb_len; 173 int mb_len;
192 wchar_t wc; 174 wchar_t wc;
193 int width; 175 int width;
230 } 212 }
231 213
232 p += mb_len; 214 p += mb_len;
233 col += width; 215 col += width;
234 if (col <= cols) { 216 if (col <= cols) {
235 if (fputs(mb_buf, fp) == EOF) { 217 retval = io_dputs(fd, mb_buf);
236 err(1, "fputs"); 218 if (retval != IO_OK) {
237 } 219 return (retval);
238 } 220 }
239 } 221 }
240 222 }
241 fputc('\n', fp); 223
242 fflush(fp); 224 retval = io_dputs(fd, "\n");
243 225
244 return (col); 226 return (retval);
245 } 227 }
246 228
247 void 229 enum io_status
248 pager_show(struct pager *pager) 230 pager_show(struct pager *pager)
249 { 231 {
232 int retval = IO_OK;
250 int is_interactive; 233 int is_interactive;
251 unsigned int rows = 24; 234 unsigned int rows = 24;
252 unsigned int cols = 80; 235 unsigned int cols = 80;
253 #ifdef TIOCGWINSZ 236 #ifdef TIOCGWINSZ
254 struct winsize ws; 237 struct winsize ws;
255 #endif /* TIOCGWINSZ */ 238 #endif /* TIOCGWINSZ */
256 unsigned int row = 0; 239 unsigned int row = 0;
257 GetLine *gl;
258 struct lines_entry *entry; 240 struct lines_entry *entry;
259 241 int c;
260 is_interactive = (isatty(STDIN_FILENO) && (pager->fp == stdout)); 242
243 is_interactive = (isatty(STDIN_FILENO) && (pager->fd == STDOUT_FILENO));
261 244
262 #ifdef TIOCGWINSZ 245 #ifdef TIOCGWINSZ
263 if (is_interactive) { 246 if (is_interactive) {
264 /* determine terminal size */ 247 /* determine terminal size */
265 if (ioctl(fileno(pager->fp), TIOCGWINSZ, &ws) == 0) { 248 if (ioctl(pager->fd, TIOCGWINSZ, &ws) == 0) {
266 rows = (ws.ws_row > 0) ? ws.ws_row : rows; 249 rows = (ws.ws_row > 0) ? ws.ws_row : rows;
267 cols = (ws.ws_col > 0) ? ws.ws_col : cols; 250 cols = (ws.ws_col > 0) ? ws.ws_col : cols;
268 } 251 }
269 } 252 }
270 #endif /* TIOCGWINSZ */ 253 #endif /* TIOCGWINSZ */
271 254
272 gl = new_GetLine(10, 0);
273 if (gl == NULL) {
274 err(1, "new_GetLine");
275 }
276
277 TAILQ_FOREACH(entry, &pager->lines_head, entry) { 255 TAILQ_FOREACH(entry, &pager->lines_head, entry) {
278 if (is_interactive) { 256 if (is_interactive) {
279 mbsnprint(cols, entry->line, pager->fp); 257 retval = mbsnprint(cols, entry->line, pager->fd);
258 if (retval != IO_OK) {
259 goto out;
260 }
280 row++; 261 row++;
281 if ((TAILQ_NEXT(entry, entry) != NULL) && 262 if ((TAILQ_NEXT(entry, entry) != NULL) &&
282 (row == rows - 1)) { 263 (row == rows - 1)) {
283 getch_prompt(gl, "--More--"); 264 /* prompt for keypress */
265 retval = io_get_char("--More--", &c);
266 if (retval != IO_OK) {
267 goto out;
268 }
284 row = 0; 269 row = 0;
285 } 270 }
286 } else { 271 } else {
287 fprintf(pager->fp, "%s", entry->line); 272 retval = io_dputs(pager->fd, entry->line);
288 fflush(pager->fp); 273 if (retval != IO_OK) {
289 } 274 goto out;
290 } 275 }
291 276 }
292 del_GetLine(gl); 277 }
293 } 278
279 out:
280 return (retval);
281 }