Mercurial > projects > pwm
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 } |