diff --git a/src/gmnlm.c b/src/gmnlm.c
index 2c2b67e0e56d2e6be04bba6cee96cb4a24ff3b51..3598e3fb1770aca2bd646d7a3f2bf642b54c2ab9 100644
--- a/src/gmnlm.c
+++ b/src/gmnlm.c
@@ -27,9 +27,18 @@ bool pagination;
struct gemini_options opts;
FILE *tty;
+ char *plain_url;
struct Curl_URL *url;
struct link *links;
struct history *history;
+ bool running;
+};
+
+enum prompt_result {
+ PROMPT_AGAIN,
+ PROMPT_MORE,
+ PROMPT_QUIT,
+ PROMPT_ANSWERED,
};
static void
@@ -70,6 +79,63 @@ }
return true;
}
+static enum prompt_result
+do_prompts(const char *prompt, struct browser *browser)
+{
+ fprintf(browser->tty, "%s", prompt);
+
+ size_t l = 0;
+ char *in = NULL;
+ ssize_t n = getline(&in, &l, browser->tty);
+ if (n == -1 && feof(browser->tty)) {
+ return PROMPT_QUIT;
+ }
+ if (strcmp(in, "\n") == 0) {
+ return PROMPT_MORE;
+ }
+ if (strcmp(in, "q\n") == 0) {
+ return PROMPT_QUIT;
+ }
+ if (strcmp(in, "b\n") == 0) {
+ if (!browser->history->prev) {
+ fprintf(stderr, "At beginning of history\n");
+ return PROMPT_AGAIN;
+ }
+ browser->history = browser->history->prev;
+ set_url(browser, browser->history->url, NULL);
+ return PROMPT_ANSWERED;
+ }
+ if (strcmp(in, "f\n") == 0) {
+ if (!browser->history->next) {
+ fprintf(stderr, "At end of history\n");
+ return PROMPT_AGAIN;
+ }
+ browser->history = browser->history->next;
+ set_url(browser, browser->history->url, NULL);
+ return PROMPT_ANSWERED;
+ }
+
+ struct link *link = browser->links;
+ char *endptr;
+ int linksel = (int)strtol(in, &endptr, 10);
+ if (endptr[0] == '\n' && linksel >= 0) {
+ while (linksel > 0 && link) {
+ link = link->next;
+ --linksel;
+ }
+
+ if (!link) {
+ fprintf(stderr, "Error: no such link.\n");
+ } else {
+ set_url(browser, link->url, &browser->history);
+ return PROMPT_ANSWERED;
+ }
+ }
+ free(in);
+
+ return PROMPT_AGAIN;
+}
+
static char *
trim_ws(char *in)
{
@@ -80,7 +146,7 @@ for (; *in && isspace(*in); ++in);
return in;
}
-static void
+static bool
display_gemini(struct browser *browser, struct gemini_response *resp)
{
// TODO: Strip ANSI escape sequences
@@ -136,29 +202,36 @@ }
++row;
col = 0;
- // TODO: It would be nice if we could follow links from this
- // prompt
- if (browser->pagination && row >= ws.ws_row - 1) {
- fprintf(browser->tty, "[Enter for more, or q to stop] ");
+ if (browser->pagination && row >= ws.ws_row - 4) {
+ char prompt[4096];
+ snprintf(prompt, sizeof(prompt), "\n%s at %s\n"
+ "[Enter]: read more; [n]: follow Nth link; [b]ack; [f]orward; [q]uit\n"
+ "(more) => ", resp->meta, browser->plain_url);
+ enum prompt_result result = PROMPT_AGAIN;
+ while (result == PROMPT_AGAIN) {
+ result = do_prompts(prompt, browser);
+ }
- size_t n = 0;
- char *l = NULL;
- if (getline(&l, &n, browser->tty) == -1) {
- return;
- }
- if (strcmp(l, "q\n") == 0) {
- return;
+ switch (result) {
+ case PROMPT_AGAIN:
+ case PROMPT_MORE:
+ break;
+ case PROMPT_QUIT:
+ browser->running = false;
+ return true;
+ case PROMPT_ANSWERED:
+ return true;
}
- free(l);
row = col = 0;
}
}
gemini_parser_finish(&p);
+ return false;
}
-static void
+static bool
display_plaintext(struct browser *browser, struct gemini_response *resp)
{
// TODO: Strip ANSI escape sequences
@@ -175,20 +248,20 @@ }
}
(void)row; (void)col; // TODO: generalize pagination
+ return false;
}
-static void
+static bool
display_response(struct browser *browser, struct gemini_response *resp)
{
if (strcmp(resp->meta, "text/gemini") == 0
|| strncmp(resp->meta, "text/gemini;", 12) == 0) {
- display_gemini(browser, resp);
- return;
+ return display_gemini(browser, resp);
}
if (strncmp(resp->meta, "text/", 5) == 0) {
- display_plaintext(browser, resp);
- return;
+ return display_plaintext(browser, resp);
}
+ assert(0); // TODO: Deal with other mimetypes
}
static char *
@@ -225,19 +298,19 @@ }
return input;
}
-static char *
+// Returns true to skip prompting
+static bool
do_requests(struct browser *browser, struct gemini_response *resp)
{
- char *plain_url;
int nredir = 0;
bool requesting = true;
while (requesting) {
CURLUcode uc = curl_url_get(browser->url,
- CURLUPART_URL, &plain_url, 0);
+ CURLUPART_URL, &browser->plain_url, 0);
assert(uc == CURLUE_OK); // Invariant
- enum gemini_result res = gemini_request(
- plain_url, &browser->opts, resp);
+ enum gemini_result res = gemini_request(browser->plain_url,
+ &browser->opts, resp);
if (res != GEMINI_OK) {
fprintf(stderr, "Error: %s\n", gemini_strerr(res, resp));
requesting = false;
@@ -253,7 +326,8 @@ requesting = false;
break;
}
- char *new_url = gemini_input_url(plain_url, input);
+ char *new_url = gemini_input_url(
+ browser->plain_url, input);
assert(new_url);
set_url(browser, new_url, NULL);
break;
@@ -278,8 +352,7 @@ resp->status, resp->meta);
break;
case GEMINI_STATUS_CLASS_SUCCESS:
requesting = false;
- display_response(browser, resp);
- break;
+ return display_response(browser, resp);
}
if (requesting) {
@@ -287,63 +360,7 @@ gemini_response_finish(resp);
}
}
- return plain_url;
-}
-
-static bool
-do_prompts(const char *prompt, struct browser *browser)
-{
- bool prompting = true;
- while (prompting) {
- fprintf(browser->tty, "%s", prompt);
-
- size_t l = 0;
- char *in = NULL;
- ssize_t n = getline(&in, &l, browser->tty);
- if (n == -1 && feof(browser->tty)) {
- return false;
- }
- if (strcmp(in, "q\n") == 0) {
- return false;
- }
- if (strcmp(in, "b\n") == 0) {
- if (!browser->history->prev) {
- fprintf(stderr, "At beginning of history\n");
- continue;
- }
- browser->history = browser->history->prev;
- set_url(browser, browser->history->url, NULL);
- break;
- }
- if (strcmp(in, "f\n") == 0) {
- if (!browser->history->next) {
- fprintf(stderr, "At end of history\n");
- continue;
- }
- browser->history = browser->history->next;
- set_url(browser, browser->history->url, NULL);
- break;
- }
-
- struct link *link = browser->links;
- char *endptr;
- int linksel = (int)strtol(in, &endptr, 10);
- if (endptr[0] == '\n' && linksel >= 0) {
- while (linksel > 0 && link) {
- link = link->next;
- --linksel;
- }
-
- if (!link) {
- fprintf(stderr, "Error: no such link.\n");
- } else {
- set_url(browser, link->url, &browser->history);
- break;
- }
- }
- free(in);
- }
- return true;
+ return false;
}
int
@@ -381,24 +398,38 @@ SSL_load_error_strings();
ERR_load_crypto_strings();
browser.opts.ssl_ctx = SSL_CTX_new(TLS_method());
- bool run = true;
struct gemini_response resp;
- while (run) {
+ browser.running = true;
+ while (browser.running) {
static char prompt[4096];
- char *plain_url = do_requests(&browser, &resp);
+ if (do_requests(&browser, &resp)) {
+ // Skip prompts
+ goto next;
+ }
- snprintf(prompt, sizeof(prompt), "\n%s%s at %s\n"
- "[n]: follow Nth link; [o <url>]: open URL; "
- "[b]ack; [f]orward; "
- "[q]uit\n"
+ snprintf(prompt, sizeof(prompt), "\n%s at %s\n"
+ "[n]: follow Nth link; [b]ack; [f]orward; [q]uit\n"
"=> ",
- resp.status == GEMINI_STATUS_SUCCESS ? " " : "",
resp.status == GEMINI_STATUS_SUCCESS ? resp.meta : "",
- plain_url);
+ browser.plain_url);
gemini_response_finish(&resp);
- run = do_prompts(prompt, &browser);
+ enum prompt_result result = PROMPT_AGAIN;
+ while (result == PROMPT_AGAIN || result == PROMPT_MORE) {
+ result = do_prompts(prompt, &browser);
+ }
+ switch (result) {
+ case PROMPT_AGAIN:
+ case PROMPT_MORE:
+ assert(0);
+ case PROMPT_QUIT:
+ browser.running = false;
+ break;
+ case PROMPT_ANSWERED:
+ break;
+ }
+next:;
struct link *link = browser.links;
while (link) {
struct link *next = link->next;