ui_txt.c (5790B)
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) { 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 }