comparison pager.c @ 18:1e39a251cbe9

Use libtecla for interactive input
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Thu, 24 Aug 2017 13:10:56 +0200
parents a08ef0674d8e
children 5c6155c8e9b6
comparison
equal deleted inserted replaced
17:a08ef0674d8e 18:1e39a251cbe9
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>
31 #include <limits.h> 32 #include <limits.h>
32 #include <signal.h> 33 #include <signal.h>
33 #include <stdio.h> 34 #include <stdio.h>
34 #include <string.h> 35 #include <string.h>
35 #include <sys/ioctl.h> 36 #include <sys/ioctl.h>
44 45
45 #include "pwm.h" 46 #include "pwm.h"
46 #include "pager.h" 47 #include "pager.h"
47 #include "util.h" 48 #include "util.h"
48 49
49 #ifndef TCSASOFT
50 #define TCSASOFT 0
51 #endif /* !TCSASOFT */
52
53 #ifndef _NSIG
54 #ifdef NSIG
55 #define _NSIG NSIG
56 #else /* NSIG */
57 #define _NSIG 128
58 #endif /* NSIG */
59 #endif /* !_NSIG */
60
61 #ifndef _PATH_TTY
62 #define _PATH_TTY "/dev/tty"
63 #endif
64
65 struct pager { 50 struct pager {
66 TAILQ_HEAD(lines_head, lines_entry) lines_head; 51 TAILQ_HEAD(lines_head, lines_entry) lines_head;
67 FILE *fp; 52 FILE *fp;
68 size_t buf_size; 53 size_t buf_size;
69 char *buf; 54 char *buf;
72 struct lines_entry { 57 struct lines_entry {
73 TAILQ_ENTRY(lines_entry) entry; 58 TAILQ_ENTRY(lines_entry) entry;
74 char *line; 59 char *line;
75 }; 60 };
76 61
77 static volatile sig_atomic_t signals[_NSIG];
78
79 static void
80 sig_handler(int signo)
81 {
82 signals[signo] = 1;
83 }
84
85 static int 62 static int
86 getch_prompt(const char *prompt) 63 getch_prompt(GetLine *gl, const char *prompt)
87 { 64 {
88 int retval = -1; 65 int c;
89 int signo; 66 int saved_echo_mode;
90 int fd; 67
91 struct termios saved_term; 68 /* prompt with echo off */
92 struct termios term; 69 saved_echo_mode = gl_echo_mode(gl, -1);
93 struct sigaction sa; 70 gl_echo_mode(gl, 0);
94 struct sigaction saved_sa_hup; 71 c = gl_query_char(gl, prompt, '\0');
95 struct sigaction saved_sa_int; 72 gl_echo_mode(gl, saved_echo_mode);
96 struct sigaction saved_sa_quit;
97 struct sigaction saved_sa_pipe;
98 struct sigaction saved_sa_alrm;
99 struct sigaction saved_sa_term;
100 struct sigaction saved_sa_tstp;
101 struct sigaction saved_sa_ttin;
102 struct sigaction saved_sa_ttou;
103 char c;
104 int need_restart = 0;
105
106 printf("%s", prompt);
107 fflush(stdout);
108
109 restart:
110 for (signo = 0; signo < _NSIG; signo++) {
111 signals[signo] = 0;
112 }
113
114 fd = open(_PATH_TTY, O_RDONLY);
115 if (fd < 0) {
116 return (-1);
117 }
118
119 if (tcgetattr(fd, &saved_term) != 0) {
120 close(fd);
121 return (-1);
122 }
123 memcpy(&term, &saved_term, sizeof (struct termios));
124
125 /* enter raw mode and turn echo off */
126 term.c_lflag &= ~(ICANON | ECHO);
127 while ((tcsetattr(fd, TCSAFLUSH | TCSASOFT, &term) < 0) &&
128 (errno != EINTR)) {
129 continue;
130 }
131
132 /* install temporary signal handler */
133 sigemptyset(&sa.sa_mask);
134 sa.sa_flags = 0;
135 sa.sa_handler = sig_handler;
136 sigaction(SIGHUP, &sa, &saved_sa_hup);
137 sigaction(SIGINT, &sa, &saved_sa_int);
138 sigaction(SIGQUIT, &sa, &saved_sa_quit);
139 sigaction(SIGPIPE, &sa, &saved_sa_pipe);
140 sigaction(SIGALRM, &sa, &saved_sa_alrm);
141 sigaction(SIGTERM, &sa, &saved_sa_term);
142 sigaction(SIGTSTP, &sa, &saved_sa_tstp);
143 sigaction(SIGTTIN, &sa, &saved_sa_ttin);
144 sigaction(SIGTTOU, &sa, &saved_sa_ttou);
145
146 /* read key */
147 if (read(fd, &c, 1) == sizeof (c)) {
148 retval = c;
149 }
150
151 /* restore previous mode and echo setting */
152 do {
153 while ((tcsetattr(fd, TCSAFLUSH | TCSASOFT,
154 &saved_term) < 0) && (errno != EINTR)) {
155 continue;
156 }
157 } while ((tcgetattr(fd, &term) == 0) &&
158 (term.c_lflag != saved_term.c_lflag));
159
160 /* restore previous signal handlers */
161 sigaction(SIGHUP, &saved_sa_hup, &sa);
162 sigaction(SIGINT, &saved_sa_int, &sa);
163 sigaction(SIGQUIT, &saved_sa_quit, &sa);
164 sigaction(SIGPIPE, &saved_sa_pipe, &sa);
165 sigaction(SIGALRM, &saved_sa_alrm, &sa);
166 sigaction(SIGTERM, &saved_sa_term, &sa);
167 sigaction(SIGTSTP, &saved_sa_tstp, &sa);
168 sigaction(SIGTTIN, &saved_sa_ttin, &sa);
169 sigaction(SIGTTOU, &saved_sa_ttou, &sa);
170 73
171 /* erase prompt */ 74 /* erase prompt */
172 printf("\r%*s\r", (int)strlen(prompt), ""); 75 printf("\r%*s\r", (int)strlen(prompt), "");
173 fflush(stdout); 76
174 77 return (c);
175 while ((close(fd) < 0) && (errno != EINTR)) {
176 continue;
177 }
178
179 /* re-raise signals received */
180 for (signo = 0; signo < _NSIG; signo++) {
181 if (signals[signo]) {
182 raise(signo);
183 if ((signo == SIGTSTP) || (signo == SIGTTIN) ||
184 (signo == SIGTTOU)) {
185 need_restart = 1;
186 }
187 }
188 }
189 if (need_restart) {
190 goto restart;
191 }
192
193 return (retval);
194 } 78 }
195 79
196 struct pager * 80 struct pager *
197 pager_create(FILE *fp) 81 pager_create(FILE *fp)
198 { 82 {
368 unsigned int cols = 80; 252 unsigned int cols = 80;
369 #ifdef TIOCGWINSZ 253 #ifdef TIOCGWINSZ
370 struct winsize ws; 254 struct winsize ws;
371 #endif /* TIOCGWINSZ */ 255 #endif /* TIOCGWINSZ */
372 unsigned int row = 0; 256 unsigned int row = 0;
257 GetLine *gl;
373 struct lines_entry *entry; 258 struct lines_entry *entry;
374 259
375 is_interactive = (isatty(STDIN_FILENO) && (pager->fp == stdout)); 260 is_interactive = (isatty(STDIN_FILENO) && (pager->fp == stdout));
376 261
377 #ifdef TIOCGWINSZ 262 #ifdef TIOCGWINSZ
382 cols = (ws.ws_col > 0) ? ws.ws_col : cols; 267 cols = (ws.ws_col > 0) ? ws.ws_col : cols;
383 } 268 }
384 } 269 }
385 #endif /* TIOCGWINSZ */ 270 #endif /* TIOCGWINSZ */
386 271
272 gl = new_GetLine(10, 0);
273 if (gl == NULL) {
274 err(1, "new_GetLine");
275 }
276
387 TAILQ_FOREACH(entry, &pager->lines_head, entry) { 277 TAILQ_FOREACH(entry, &pager->lines_head, entry) {
388 if (is_interactive) { 278 if (is_interactive) {
389 mbsnprint(cols, entry->line, pager->fp); 279 mbsnprint(cols, entry->line, pager->fp);
390 row++; 280 row++;
391 if (row == rows - 1) { 281 if ((TAILQ_NEXT(entry, entry) != NULL) &&
392 getch_prompt("--More--"); 282 (row == rows - 1)) {
283 getch_prompt(gl, "--More--");
393 row = 0; 284 row = 0;
394 } 285 }
395 } else { 286 } else {
396 fprintf(pager->fp, "%s", entry->line); 287 fprintf(pager->fp, "%s", entry->line);
397 fflush(pager->fp); 288 fflush(pager->fp);
398 } 289 }
399 } 290 }
400 } 291
292 del_GetLine(gl);
293 }