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 }