t* sacc + cursorline and uri preview
URI git clone git://git.codevoid.de/sacc-sdk
DIR Log
DIR Files
DIR Refs
DIR LICENSE
---
tui_txt.c (6527B)
---
1 #include <ctype.h>
2 #include <errno.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <termios.h>
8 #include <sys/ioctl.h>
9 #include <sys/types.h>
10
11 #include "common.h"
12
13 static char bufout[256];
14 static Item *curentry;
15 static char cmd;
16 int lines, columns;
17
18 static void
19 viewsize(int *ln, int *col)
20 {
21 struct winsize ws;
22
23 if (ioctl(1, TIOCGWINSZ, &ws) < 0) {
24 die("Could not get terminal resolution: %s",
25 strerror(errno));
26 }
27
28 if (ln)
29 *ln = ws.ws_row-1; /* one off for status bar */
30 if (col)
31 *col = ws.ws_col;
32 }
33
34 void
35 uisetup(void)
36 {
37 viewsize(&lines, &columns);
38 }
39
40 void
41 uicleanup(void)
42 {
43 return;
44 }
45
46 void
47 help(void)
48 {
49 puts("Commands:\n"
50 "N = [1-9]...: browse item N.\n"
51 "uN...: print item N uri.\n"
52 "0: browse previous item.\n"
53 "n: show next page.\n"
54 "p: show previous page.\n"
55 "t: go to the top of the page\n"
56 "b: go to the bottom of the page\n"
57 "/foo: search for string \"foo\"\n"
58 "!: refetch failed item.\n"
59 "^D, q: quit.\n"
60 "h, ?: this help.");
61 }
62
63 static int
64 ndigits(size_t n)
65 {
66 return (n < 10) ? 1 : (n < 100) ? 2 : 3;
67 }
68
69 void
70 uistatus(char *fmt, ...)
71 {
72 va_list arg;
73 int n;
74
75 va_start(arg, fmt);
76 n = vsnprintf(bufout, sizeof(bufout), fmt, arg);
77 va_end(arg);
78
79 if (n < sizeof(bufout)-1) {
80 n += snprintf(bufout + n, sizeof(bufout) - n,
81 " [Press Enter to continue \xe2\x98\x83]");
82 }
83 if (n >= sizeof(bufout))
84 bufout[sizeof(bufout)-1] = '\0';
85
86 mbsprint(bufout, columns);
87 fflush(stdout);
88
89 getchar();
90 }
91
92 static void
93 printstatus(Item *item, char c)
94 {
95 Dir *dir = item->dat;
96 char *fmt;
97 size_t nitems = dir ? dir->nitems : 0;
98 unsigned long long printoff = dir ? dir->printoff : 0;
99
100 fmt = (strcmp(item->port, "70") && strcmp(item->port, "gopher")) ?
101 "%1$3lld%%%*2$3$c %4$s:%8$s/%5$c%6$s [%7$c]: " :
102 "%3lld%%%*c %s/%c%s [%c]: ";
103 if (snprintf(bufout, sizeof(bufout), fmt,
104 (printoff + lines-1 >= nitems) ? 100 :
105 (printoff + lines) * 100 / nitems, ndigits(nitems)+2, '|',
106 item->host, item->type, item->selector, c, item->port)
107 >= sizeof(bufout))
108 bufout[sizeof(bufout)-1] = '\0';
109 mbsprint(bufout, columns);
110 }
111
112 char *
113 uiprompt(char *fmt, ...)
114 {
115 va_list ap;
116 char *input = NULL;
117 size_t n = 0;
118 ssize_t r;
119
120 va_start(ap, fmt);
121 if (vsnprintf(bufout, sizeof(bufout), fmt, ap) >= sizeof(bufout))
122 bufout[sizeof(bufout)-1] = '\0';
123 va_end(ap);
124
125 mbsprint(bufout, columns);
126 fflush(stdout);
127
128 if ((r = getline(&input, &n, stdin)) < 0) {
129 clearerr(stdin);
130 clear(&input);
131 putchar('\n');
132 } else if (input[r - 1] == '\n') {
133 input[--r] = '\0';
134 }
135
136 return input;
137 }
138
139 void
140 uidisplay(Item *entry)
141 {
142 Item *items;
143 Dir *dir;
144 size_t i, nlines, nitems;
145 int nd;
146
147 if (!entry ||
148 !(entry->type == '1' || entry->type == '+' || entry->type == '7') ||
149 !(dir = entry->dat))
150 return;
151
152 curentry = entry;
153
154 items = dir->items;
155 nitems = dir->nitems;
156 nlines = dir->printoff + lines;
157 nd = ndigits(nitems);
158
159 for (i = dir->printoff; i < nitems && i < nlines; ++i) {
160 if (snprintf(bufout, sizeof(bufout), "%*zu %s %s",
161 nd, i+1, typedisplay(items[i].type),
162 items[i].username)
163 >= sizeof(bufout))
164 bufout[sizeof(bufout)-1] = '\0';
165 mbsprint(bufout, columns);
166 putchar('\n');
167 }
168
169 fflush(stdout);
170 }
171
172 void
173 printuri(Item *item, size_t i)
174 {
175 char *fmt;
176 int n;
177
178 if (!item)
179 return;
180
181 switch (item->type) {
182 case 0:
183 return;
184 case '8':
185 n = snprintf(bufout, sizeof(bufout), "telnet://%s@%s:%s",
186 item->selector, item->host, item->port);
187 break;
188 case 'i':
189 n = snprintf(bufout, sizeof(bufout), "%zu: %s",
190 i, item->username);
191 break;
192 case 'h':
193 n = snprintf(bufout, sizeof(bufout), "%zu: %s: %s",
194 i, item->username, item->selector);
195 break;
196 case 'T':
197 n = snprintf(bufout, sizeof(bufout), "tn3270://%s@%s:%s",
198 item->selector, item->host, item->port);
199 break;
200 default:
201 fmt = strcmp(item->port, "70") ?
202 "%1$zu: %2$s: gopher://%3$s:%6$s/%4$c%5$s" :
203 "%zu: %s: gopher://%s/%c%s";
204 n = snprintf(bufout, sizeof(bufout), fmt, i, item->username,
205 item->host, item->type, item->selector, item->port);
206 break;
207 }
208
209 if (n >= sizeof(bufout))
210 bufout[sizeof(bufout)-1] = '\0';
211
212 mbsprint(bufout, columns);
213 putchar('\n');
214 }
215
216 void
217 searchinline(const char *searchstr, Item *entry)
218 {
219 Dir *dir;
220 size_t i;
221
222 if (!searchstr || !*searchstr || !(dir = entry->dat))
223 return;
224
225 for (i = 0; i < dir->nitems; ++i)
226 if (strcasestr(dir->items[i].username, searchstr))
227 printuri(&(dir->items[i]), i + 1);
228 }
229
230 Item *
231 uiselectitem(Item *entry)
232 {
233 Dir *dir;
234 char buf[BUFSIZ], *sstr, nl;
235 int item, nitems;
236
237 if (!entry || !(dir = entry->dat))
238 return NULL;
239
240 nitems = dir ? dir->nitems : 0;
241
242 for (;;) {
243 if (!cmd)
244 cmd = 'h';
245 printstatus(entry, cmd);
246 fflush(stdout);
247
248 if (!fgets(buf, sizeof(buf), stdin)) {
249 putchar('\n');
250 return NULL;
251 }
252 if (isdigit(*buf)) {
253 cmd = '\0';
254 nl = '\0';
255 if (sscanf(buf, "%d%c", &item, &nl) != 2 || nl != '\n')
256 item = -1;
257 } else if (!strcmp(buf+1, "\n")) {
258 item = -1;
259 cmd = *buf;
260 } else if (*buf == '/') {
261 for (sstr = buf+1; *sstr && *sstr != '\n'; ++sstr)
262 ;
263 *sstr = '\0';
264 sstr = buf+1;
265 cmd = *buf;
266 } else if (isdigit(*(buf+1))) {
267 nl = '\0';
268 if (sscanf(buf+1, "%d%c", &item, &nl) != 2 || nl != '\n')
269 item = -1;
270 else
271 cmd = *buf;
272 }
273
274 switch (cmd) {
275 case '\0':
276 break;
277 case 'q':
278 return NULL;
279 case 'n':
280 if (lines < nitems - dir->printoff &&
281 lines < (size_t)-1 - dir->printoff)
282 dir->printoff += lines;
283 return entry;
284 case 'p':
285 if (lines <= dir->printoff)
286 dir->printoff -= lines;
287 else
288 dir->printoff = 0;
289 return entry;
290 case 'b':
291 if (nitems > lines)
292 dir->printoff = nitems - lines;
293 else
294 dir->printoff = 0;
295 return entry;
296 case 't':
297 dir->printoff = 0;
298 return entry;
299 case '!':
300 if (entry->raw)
301 continue;
302 return entry;
303 case 'u':
304 if (item > 0 && item <= nitems)
305 printuri(&dir->items[item-1], item);
306 continue;
307 case '/':
308 if (*sstr)
309 searchinline(sstr, entry);
310 continue;
311 case 'h':
312 case '?':
313 help();
314 continue;
315 default:
316 cmd = 'h';
317 continue;
318 }
319
320 if (item >= 0 && item <= nitems)
321 break;
322 }
323
324 if (item > 0)
325 return &dir->items[item-1];
326
327 return entry->entry;
328 }
329
330 void
331 uisigwinch(int signal)
332 {
333 uisetup();
334 putchar('\n');
335 uidisplay(curentry);
336 printstatus(curentry, cmd);
337 fflush(stdout);
338 }