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 }