ui_txt.c - sacc - sacc(omys), simple console gopher client
HTML git clone git://bitreich.org/sacc/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/sacc/
DIR Log
DIR Files
DIR Refs
DIR Tags
DIR LICENSE
---
ui_txt.c (5805B)
---
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 int lines, columns;
16 static char cmd;
17
18 static void
19 viewsize(int *ln, int *col)
20 {
21 struct winsize ws;
22
23 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
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 static void
47 help(void)
48 {
49 puts("Commands:\n"
50 "#: browse item number #.\n"
51 "U: print page URI.\n"
52 "u#: print item number # URI.\n"
53 "0: browse previous item.\n"
54 "n: show next page.\n"
55 "p: show previous page.\n"
56 "t: go to the top of the page\n"
57 "b: go to the bottom of the page\n"
58 "Y: yank page URI.\n"
59 "y#: yank item number # URI.\n"
60 "/str: search for string \"str\"\n"
61 "!: refetch failed item.\n"
62 "^D, q: quit.\n"
63 "h, ?: this help.");
64 }
65
66 static int
67 ndigits(size_t n)
68 {
69 return (n < 10) ? 1 : (n < 100) ? 2 : 3;
70 }
71
72 void
73 uistatus(char *fmt, ...)
74 {
75 va_list arg;
76 int n;
77
78 va_start(arg, fmt);
79 n = vsnprintf(bufout, sizeof(bufout), fmt, arg);
80 va_end(arg);
81
82 if (n < sizeof(bufout)-1) {
83 snprintf(bufout+n, sizeof(bufout)-n,
84 " [Press Enter to continue \xe2\x98\x83]");
85 }
86
87 mbsprint(bufout, columns);
88 fflush(stdout);
89
90 getchar();
91 }
92
93 static void
94 printstatus(Item *item, char c)
95 {
96 Dir *dir = item->dat;
97 char *fmt;
98 size_t nitems = dir ? dir->nitems : 0;
99 unsigned long long printoff = dir ? dir->printoff : 0;
100
101 fmt = (strcmp(item->port, "70") && strcmp(item->port, "gopher")) ?
102 "%1$3lld%%%*2$3$c %4$s:%8$s/%5$c%6$s [%7$c]: " :
103 "%3lld%% %s/%c%s [%c]: ";
104 snprintf(bufout, sizeof(bufout), fmt,
105 (printoff + lines-1 >= nitems) ? 100 :
106 (printoff + lines) * 100 / nitems,
107 item->host, item->type, item->selector, c, item->port);
108
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 vsnprintf(bufout, sizeof(bufout), fmt, ap);
122 va_end(ap);
123
124 mbsprint(bufout, columns);
125 fflush(stdout);
126
127 if ((r = getline(&input, &n, stdin)) == -1 || feof(stdin)) {
128 clearerr(stdin);
129 clear(&input);
130 putchar('\n');
131 } else if (input[r - 1] == '\n') {
132 input[--r] = '\0';
133 }
134
135 return input;
136 }
137
138 void
139 uidisplay(Item *entry)
140 {
141 Item *items;
142 Dir *dir;
143 size_t i, nlines, nitems;
144 int nd;
145
146 if (!entry ||
147 !(entry->type == '1' || entry->type == '+' || entry->type == '7') ||
148 !(dir = entry->dat))
149 return;
150
151 curentry = entry;
152
153 items = dir->items;
154 nitems = dir->nitems;
155 nlines = dir->printoff + lines;
156 nd = ndigits(nitems);
157
158 for (i = dir->printoff; i < nitems && i < nlines; ++i) {
159 snprintf(bufout, sizeof(bufout), "%*zu %s %s",
160 nd, i+1,typedisplay(items[i].type),
161 items[i].username);
162
163 mbsprint(bufout, columns);
164 putchar('\n');
165 }
166
167 fflush(stdout);
168 }
169
170 static void
171 printuri(Item *item, size_t i)
172 {
173 if (!item || item->type == 0 || item->type == 'i')
174 return;
175
176 itemuri(item, bufout, sizeof(bufout));
177
178 mbsprint(bufout, columns);
179 putchar('\n');
180 }
181
182 static void
183 searchinline(const char *searchstr, Item *entry)
184 {
185 Dir *dir;
186 size_t i;
187
188 if (!searchstr || !*searchstr || !(dir = entry->dat))
189 return;
190
191 for (i = 0; i < dir->nitems; ++i)
192 if (strcasestr(dir->items[i].username, searchstr))
193 printuri(&(dir->items[i]), i + 1);
194 }
195
196 Item *
197 uiselectitem(Item *entry)
198 {
199 Dir *dir;
200 char buf[BUFSIZ], *sstr = NULL, nl;
201 int item, nitems;
202
203 if (!entry || !(dir = entry->dat))
204 return NULL;
205
206 nitems = dir ? dir->nitems : 0;
207
208 for (;;) {
209 if (!cmd)
210 cmd = 'h';
211 printstatus(entry, cmd);
212 fflush(stdout);
213
214 if (!fgets(buf, sizeof(buf), stdin)) {
215 putchar('\n');
216 return NULL;
217 }
218 if (isdigit((unsigned char)*buf)) {
219 cmd = '\0';
220 nl = '\0';
221 if (sscanf(buf, "%d%c", &item, &nl) != 2 || nl != '\n')
222 item = -1;
223 } else if (!strcmp(buf+1, "\n")) {
224 item = -1;
225 cmd = *buf;
226 } else if (*buf == '/') {
227 for (sstr = buf+1; *sstr && *sstr != '\n'; ++sstr)
228 ;
229 *sstr = '\0';
230 sstr = buf+1;
231 cmd = *buf;
232 } else if (isdigit((unsigned char)*(buf+1))) {
233 nl = '\0';
234 if (sscanf(buf+1, "%d%c", &item, &nl) != 2 || nl != '\n')
235 item = -1;
236 else
237 cmd = *buf;
238 }
239
240 switch (cmd) {
241 case '\0':
242 break;
243 case 'q':
244 return NULL;
245 case 'n':
246 if (lines < nitems - dir->printoff &&
247 lines < (size_t)-1 - dir->printoff)
248 dir->printoff += lines;
249 return entry;
250 case 'p':
251 if (lines <= dir->printoff)
252 dir->printoff -= lines;
253 else
254 dir->printoff = 0;
255 return entry;
256 case 'b':
257 if (nitems > lines)
258 dir->printoff = nitems - lines;
259 else
260 dir->printoff = 0;
261 return entry;
262 case 't':
263 dir->printoff = 0;
264 return entry;
265 case '!':
266 if (entry->raw)
267 continue;
268 return entry;
269 case 'U':
270 printuri(entry, 0);
271 continue;
272 case 'u':
273 if (item > 0 && item <= nitems)
274 printuri(&dir->items[item-1], item);
275 continue;
276 case 'Y':
277 yankitem(entry);
278 continue;
279 case 'y':
280 if (item > 0 && item <= nitems)
281 yankitem(&dir->items[item-1]);
282 continue;
283 case '/':
284 if (sstr && *sstr)
285 searchinline(sstr, entry);
286 continue;
287 case 'h':
288 case '?':
289 help();
290 continue;
291 default:
292 cmd = 'h';
293 continue;
294 }
295
296 if (item >= 0 && item <= nitems)
297 break;
298 }
299
300 if (item > 0)
301 return &dir->items[item-1];
302
303 return entry->entry;
304 }
305
306 void
307 uisigwinch(int signal)
308 {
309 uisetup();
310
311 if (!curentry)
312 return;
313
314 putchar('\n');
315 uidisplay(curentry);
316 printstatus(curentry, cmd);
317 fflush(stdout);
318 }