Introduction
Introduction Statistics Contact Development Disclaimer Help
ui_ti.c - sacc - sacc - sacc(omys), simple console gopher client (config)
git clone git://git.codemadness.org/sacc
Log
Files
Refs
LICENSE
---
ui_ti.c (11696B)
---
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <term.h>
6 #include <termios.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9
10 #include "common.h"
11 #include "config.h"
12
13 #define C(c) #c
14 #define S(c) C(c)
15
16 /* ncurses doesn't define those in term.h, where they're used */
17 #ifndef OK
18 #define OK (0)
19 #endif
20 #ifndef ERR
21 #define ERR (-1)
22 #endif
23
24 static char bufout[256];
25 static struct termios tsave;
26 static struct termios tsacc;
27 static Item *curentry;
28 static int termset = ERR;
29
30 void
31 uisetup(void)
32 {
33 tcgetattr(0, &tsave);
34 tsacc = tsave;
35 tsacc.c_lflag &= ~(ECHO|ICANON);
36 tsacc.c_cc[VMIN] = 1;
37 tsacc.c_cc[VTIME] = 0;
38 tcsetattr(0, TCSANOW, &tsacc);
39
40 if (termset != OK)
41 /* setupterm call exits on error */
42 termset = setupterm(NULL, 1, NULL);
43 putp(tiparm(clear_screen));
44 putp(tiparm(save_cursor));
45 putp(tiparm(change_scroll_region, 0, lines-2));
46 putp(tiparm(restore_cursor, 0));
47 fflush(stdout);
48 }
49
50 void
51 uicleanup(void)
52 {
53 tcsetattr(0, TCSANOW, &tsave);
54
55 if (termset != OK)
56 return;
57
58 putp(tiparm(change_scroll_region, 0, lines-1));
59 putp(tiparm(clear_screen));
60 fflush(stdout);
61 }
62
63 char *
64 uiprompt(char *fmt, ...)
65 {
66 va_list ap;
67 char *input = NULL;
68 size_t n;
69 ssize_t r;
70
71 putp(tiparm(save_cursor));
72
73 putp(tiparm(cursor_address, lines-1, 0));
74 putp(tiparm(clr_eol));
75 putp(tiparm(enter_standout_mode));
76
77 va_start(ap, fmt);
78 vsnprintf(bufout, sizeof(bufout), fmt, ap);
79 va_end(ap);
80
81 n = mbsprint(bufout, columns);
82
83 putp(tiparm(exit_standout_mode));
84 putp(tiparm(clr_eol));
85
86 putp(tiparm(cursor_address, lines-1, n));
87
88 tsacc.c_lflag |= (ECHO|ICANON);
89 tcsetattr(0, TCSANOW, &tsacc);
90 fflush(stdout);
91
92 n = 0;
93 r = getline(&input, &n, stdin);
94
95 tsacc.c_lflag &= ~(ECHO|ICANON);
96 tcsetattr(0, TCSANOW, &tsacc);
97 putp(tiparm(restore_cursor));
98 fflush(stdout);
99
100 if (r == -1 || feof(stdin)) {
101 clearerr(stdin);
102 clear(&input);
103 } else if (input[r - 1] == '\n') {
104 input[--r] = '\0';
105 }
106
107 return input;
108 }
109
110 static void
111 printitem(Item *item)
112 {
113 snprintf(bufout, sizeof(bufout), "%s %s",
114 typedisplay(item->type), item->username);
115
116 mbsprint(bufout, columns);
117 putchar('\r');
118 }
119
120 static Item *
121 help(Item *entry)
122 {
123 static Item item = {
124 .type = '0',
125 .raw = "Commands:\n"
126 "Down, " S(_key_lndown) ": move one line down.\n"
127 S(_key_entrydown) ": move to next link.\n"
128 "Up, " S(_key_lnup) ": move one line up.\n"
129 S(_key_entryup) ": move to previous link.\n"
130 "PgDown, " S(_key_pgdown) ": move one page down.\…
131 "PgUp, " S(_key_pgup) ": move one page up.\n"
132 "Home, " S(_key_home) ": move to top of the page.…
133 "End, " S(_key_end) ": move to end of the page.\n"
134 "Right, " S(_key_pgnext) ": view highlighted item…
135 "Left, " S(_key_pgprev) ": view previous item.\n"
136 S(_key_search) ": search current page.\n"
137 S(_key_searchnext) ": search string forward.\n"
138 S(_key_searchprev) ": search string backward.\n"
139 S(_key_cururi) ": print page URI.\n"
140 S(_key_seluri) ": print item URI.\n"
141 S(_key_yankcur) ": yank page URI to external prog…
142 S(_key_yanksel) ": yank item URI to external prog…
143 S(_key_help) ": show this help.\n"
144 "^D, " S(_key_quit) ": exit sacc.\n"
145 };
146
147 item.entry = entry;
148
149 return &item;
150 }
151
152 void
153 uistatus(char *fmt, ...)
154 {
155 va_list ap;
156 size_t n;
157
158 putp(tiparm(save_cursor));
159
160 putp(tiparm(cursor_address, lines-1, 0));
161 putp(tiparm(enter_standout_mode));
162
163 va_start(ap, fmt);
164 n = vsnprintf(bufout, sizeof(bufout), fmt, ap);
165 va_end(ap);
166
167 if (n < sizeof(bufout)-1) {
168 snprintf(bufout+n, sizeof(bufout)-n,
169 " [Press a key to continue \xe2\x98\x83]");
170 }
171
172 mbsprint(bufout, columns);
173
174 putp(tiparm(exit_standout_mode));
175 putp(tiparm(clr_eol));
176
177 putp(tiparm(restore_cursor));
178 fflush(stdout);
179
180 getchar();
181 }
182
183 static void
184 displaystatus(Item *item)
185 {
186 Dir *dir = item->dat;
187 char *fmt;
188 size_t nitems = dir ? dir->nitems : 0;
189 unsigned long long printoff = dir ? dir->printoff : 0;
190
191 putp(tiparm(save_cursor));
192
193 putp(tiparm(cursor_address, lines-1, 0));
194 putp(tiparm(enter_standout_mode));
195
196 fmt = (strcmp(item->port, "70") && strcmp(item->port, "gopher"))…
197 "%1$3lld%%| %2$s:%5$s/%3$c%4$s" : "%3lld%%| %s/%c%s";
198 snprintf(bufout, sizeof(bufout), fmt,
199 (printoff + lines-1 >= nitems) ? 100 :
200 (printoff + lines-1) * 100 / nitems,
201 item->host, item->type, item->selector, item->port);
202
203 mbsprint(bufout, columns);
204
205 putp(tiparm(exit_standout_mode));
206 putp(tiparm(clr_eol));
207
208 putp(tiparm(restore_cursor));
209 fflush(stdout);
210 }
211
212 static void
213 displayuri(Item *item)
214 {
215 if (item->type == 0 || item->type == 'i')
216 return;
217
218 putp(tiparm(save_cursor));
219
220 putp(tiparm(cursor_address, lines-1, 0));
221 putp(tiparm(enter_standout_mode));
222
223 itemuri(item, bufout, sizeof(bufout));
224
225 mbsprint(bufout, columns);
226
227 putp(tiparm(exit_standout_mode));
228 putp(tiparm(clr_eol));
229
230 putp(tiparm(restore_cursor));
231 fflush(stdout);
232 }
233
234 void
235 uidisplay(Item *entry)
236 {
237 Item *items;
238 Dir *dir;
239 size_t i, curln, lastln, nitems, printoff;
240
241 if (!entry ||
242 !(entry->type == '1' || entry->type == '+' || entry->type ==…
243 return;
244
245 curentry = entry;
246
247 putp(tiparm(clear_screen));
248 displaystatus(entry);
249
250 if (!(dir = entry->dat))
251 return;
252
253 putp(tiparm(save_cursor));
254
255 items = dir->items;
256 nitems = dir->nitems;
257 printoff = dir->printoff;
258 curln = dir->curline;
259 lastln = printoff + lines-1; /* one off for status bar */
260
261 for (i = printoff; i < nitems && i < lastln; ++i) {
262 if (i != printoff)
263 putp(tiparm(cursor_down));
264 if (i == curln) {
265 putp(tiparm(save_cursor));
266 putp(tiparm(enter_standout_mode));
267 }
268 printitem(&items[i]);
269 putp(tiparm(column_address, 0));
270 if (i == curln)
271 putp(tiparm(exit_standout_mode));
272 }
273
274 putp(tiparm(restore_cursor));
275 fflush(stdout);
276 }
277
278 static void
279 movecurline(Item *item, int l)
280 {
281 Dir *dir = item->dat;
282 size_t nitems;
283 ssize_t curline, offline;
284 int plines = lines-2;
285
286 if (dir == NULL)
287 return;
288
289 curline = dir->curline + l;
290 nitems = dir->nitems;
291 if (curline < 0 || curline >= nitems)
292 return;
293
294 printitem(&dir->items[dir->curline]);
295 dir->curline = curline;
296
297 if (l > 0) {
298 offline = dir->printoff + lines-1;
299 if (curline - dir->printoff >= plines / 2 && offline < n…
300 putp(tiparm(save_cursor));
301
302 putp(tiparm(cursor_address, plines, 0));
303 putp(tiparm(scroll_forward));
304 printitem(&dir->items[offline]);
305
306 putp(tiparm(restore_cursor));
307 dir->printoff += l;
308 }
309 } else {
310 offline = dir->printoff + l;
311 if (curline - offline <= plines / 2 && offline >= 0) {
312 putp(tiparm(save_cursor));
313
314 putp(tiparm(cursor_address, 0, 0));
315 putp(tiparm(scroll_reverse));
316 printitem(&dir->items[offline]);
317 putchar('\n');
318
319 putp(tiparm(restore_cursor));
320 dir->printoff += l;
321 }
322 }
323
324 putp(tiparm(cursor_address, curline - dir->printoff, 0));
325 putp(tiparm(enter_standout_mode));
326 printitem(&dir->items[curline]);
327 putp(tiparm(exit_standout_mode));
328 displaystatus(item);
329 fflush(stdout);
330 }
331
332 static void
333 jumptoline(Item *entry, ssize_t line, int absolute)
334 {
335 Dir *dir = entry->dat;
336 size_t lastitem;
337 int lastpagetop, plines = lines-2;
338
339 if (!dir)
340 return;
341 lastitem = dir->nitems-1;
342
343 if (line < 0)
344 line = 0;
345 if (line > lastitem)
346 line = lastitem;
347
348 if (dir->curline == line)
349 return;
350
351 if (lastitem <= plines) { /* all items fit on one p…
352 dir->curline = line;
353 } else if (line == 0) { /* jump to top */
354 if (absolute || dir->curline > plines || dir->printoff =…
355 dir->curline = 0;
356 dir->printoff = 0;
357 } else if (line + plines < lastitem) { /* jump before last page …
358 dir->curline = line;
359 dir->printoff = line;
360 } else { /* jump within the last p…
361 lastpagetop = lastitem - plines;
362 if (dir->printoff == lastpagetop || absolute)
363 dir->curline = line;
364 else if (dir->curline < lastpagetop)
365 dir->curline = lastpagetop;
366 dir->printoff = lastpagetop;
367 }
368
369 uidisplay(entry);
370 return;
371 }
372
373 static void
374 searchinline(const char *searchstr, Item *entry, int pos)
375 {
376 Dir *dir;
377 int i;
378
379 if (!searchstr || !(dir = entry->dat))
380 return;
381
382 if (pos > 0) {
383 for (i = dir->curline + 1; i < dir->nitems; ++i) {
384 if (strcasestr(dir->items[i].username, searchstr…
385 jumptoline(entry, i, 1);
386 break;
387 }
388 }
389 } else {
390 for (i = dir->curline - 1; i > -1; --i) {
391 if (strcasestr(dir->items[i].username, searchstr…
392 jumptoline(entry, i, 1);
393 break;
394 }
395 }
396 }
397 }
398
399 static ssize_t
400 nearentry(Item *entry, int direction)
401 {
402 Dir *dir = entry->dat;
403 size_t item, lastitem;
404
405 if (!dir)
406 return -1;
407 lastitem = dir->nitems;
408 item = dir->curline + direction;
409
410 for (; item < lastitem; item += direction) {
411 if (dir->items[item].type != 'i')
412 return item;
413 }
414
415 return dir->curline;
416 }
417
418 Item *
419 uiselectitem(Item *entry)
420 {
421 Dir *dir;
422 char *searchstr = NULL;
423 int c, plines = lines-2;
424
425 if (!entry || !(dir = entry->dat))
426 return NULL;
427
428 for (;;) {
429 switch (getchar()) {
430 case 0x1b: /* ESC */
431 switch (getchar()) {
432 case 0x1b:
433 goto quit;
434 case 'O': /* application key */
435 case '[': /* DEC */
436 break;
437 default:
438 continue;
439 }
440 c = getchar();
441 switch (c) {
442 case '1':
443 case '4':
444 case '5':
445 case '6':
446 case '7': /* urxvt */
447 case '8': /* urxvt */
448 if (getchar() != '~')
449 continue;
450 switch (c) {
451 case '1':
452 goto home;
453 case '4':
454 goto end;
455 case '5':
456 goto pgup;
457 case '6':
458 goto pgdown;
459 case '7':
460 goto home;
461 case '8':
462 goto end;
463 }
464 case 'A':
465 goto lnup;
466 case 'B':
467 goto lndown;
468 case 'C':
469 goto pgnext;
470 case 'D':
471 goto pgprev;
472 case 'H':
473 goto home;
474 case 0x1b:
475 goto quit;
476 }
477 continue;
478 case _key_pgprev:
479 pgprev:
480 return entry->entry;
481 case _key_pgnext:
482 case '\n':
483 pgnext:
484 if (dir)
485 return &dir->items[dir->curline];
486 continue;
487 case _key_lndown:
488 lndown:
489 movecurline(entry, 1);
490 continue;
491 case _key_entrydown:
492 jumptoline(entry, nearentry(entry, 1), 1);
493 continue;
494 case _key_pgdown:
495 pgdown:
496 jumptoline(entry, dir->printoff + plines, 0);
497 continue;
498 case _key_end:
499 end:
500 jumptoline(entry, dir->nitems, 0);
501 continue;
502 case _key_lnup:
503 lnup:
504 movecurline(entry, -1);
505 continue;
506 case _key_entryup:
507 jumptoline(entry, nearentry(entry, -1), 1);
508 continue;
509 case _key_pgup:
510 pgup:
511 jumptoline(entry, dir->printoff - plines, 0);
512 continue;
513 case _key_home:
514 home:
515 jumptoline(entry, 0, 0);
516 continue;
517 case _key_search:
518 free(searchstr);
519 if (!((searchstr = uiprompt("Search for: ")) &&
520 searchstr[0])) {
521 clear(&searchstr);
522 continue;
523 }
524 case _key_searchnext:
525 searchinline(searchstr, entry, +1);
526 continue;
527 case _key_searchprev:
528 searchinline(searchstr, entry, -1);
529 continue;
530 case EOF:
531 case 0x04:
532 case _key_quit:
533 quit:
534 return NULL;
535 case _key_fetch:
536 if (entry->raw)
537 continue;
538 return entry;
539 case _key_cururi:
540 if (dir)
541 displayuri(entry);
542 continue;
543 case _key_seluri:
544 if (dir)
545 displayuri(&dir->items[dir->curline]);
546 continue;
547 case _key_yankcur:
548 if (dir)
549 yankitem(entry);
550 continue;
551 case _key_yanksel:
552 if (dir)
553 yankitem(&dir->items[dir->curline]);
554 continue;
555 case _key_help: /* FALLTHROUGH */
556 return help(entry);
557 default:
558 continue;
559 }
560 }
561 }
562
563 void
564 uisigwinch(int signal)
565 {
566 Dir *dir;
567
568 if (termset == OK)
569 del_curterm(cur_term);
570 termset = setupterm(NULL, 1, NULL);
571 putp(tiparm(change_scroll_region, 0, lines-2));
572
573 if (!curentry || !(dir = curentry->dat))
574 return;
575
576 if (dir->curline - dir->printoff > lines-2)
577 dir->printoff = dir->curline - (lines-2);
578
579 uidisplay(curentry);
580 }
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.