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