#include #include #include #include #include #include "doc.h" #include "net.h" #include "err.h" /* pagination */ size_t pg_lines() { return 24; } void pg_down(void) { size_t lines = pg_lines(); while (lines--) doc_print_line(); } void pg_up(void) { size_t lines = pg_lines() << 1; while (lines--) doc_back_line(); pg_down(); } void pg_redraw(void) { size_t lines = pg_lines(); while (lines--) doc_back_line(); pg_down(); } /* navigation */ int nav_to(const char *url) { struct addr a; static enum protocol prot_default = PROT_FILE; /* change to gopher later */ if (net_addr(url, &a, prot_default)) { return -1; } prot_default = a.prot; return 0; } int nav_link_nr(unsigned long link_nr) { return 0; } /* commands */ struct cmd { char ch; int (*fn)(const char *); }; /* cmd is mutated when trimming strings * returns whether to quit */ int cmd_do(char *cmd) { switch (*cmd) { case 'q': puts("goodbye!"); return 1; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { errno = 0; unsigned long n = strtoul(cmd, NULL, 10); if (errno) { perr("invalid link number"); } else if (nav_link_nr(n)) { perr("navigation failure"); } } break; case 'b': pg_up(); break; case '\0': pg_down(); break; case 'r': pg_redraw(); break; case 'g': if (nav_to(cmd + 1)) perr("navigation failure"); break; default: perr("?"); break; } return 0; } void cmd_trim(char *buf, size_t max) { size_t n = strlen(buf); while (n > 0 && isspace(buf[n - 1])) { buf[--n] = 0; } while (n > 1 && isspace(buf[1])) { memmove(&buf[0], &buf[1], n--); } } int cmd_get(char *buf, size_t n) { fputs("* ", stdout); return !!fgets(buf, n, stdin); } void init(void) { doc_init(); } void fini(void) { doc_fini(); } int main(void) { char cmd_buf[1024]; init(); atexit(fini); while (cmd_get(cmd_buf, sizeof cmd_buf)) { cmd_trim(cmd_buf, sizeof cmd_buf); if (cmd_do(cmd_buf)) { break; } } return 0; }