diff --git a/src/gmnlm.c b/src/gmnlm.c

index dd8c8d200a949a24d030ce3429a4d20f1430fe97..94e9933e514438c633663ae8871d4fba3e64c349 100644

--- a/src/gmnlm.c

+++ b/src/gmnlm.c

@@ -17,15 +17,42 @@ char *url;

struct link *next;

};

+struct history {

+ char *url;

+ struct history *prev, *next;

+};

+

static void

usage(const char *argv_0)

{

fprintf(stderr, "usage: %s [gemini://...]\n", argv_0);

+}

+

+static void

+history_free(struct history *history)

+{

+ if (!history) {

+ return;

+ }

+ history_free(history->next);

+ free(history);

}

static bool

-set_url(struct Curl_URL *url, char *new_url)

+set_url(struct Curl_URL *url, char *new_url, struct history **history)

{

+ if (history) {

+ struct history *next = calloc(1, sizeof(struct history));

+ next->url = strdup(new_url);

+ next->prev = *history;

+ if (*history) {

+ if ((*history)->next) {

+ history_free((*history)->next);

+ }

+ (*history)->next = next;

+ }

+ *history = next;

+ }

if (curl_url_set(url, CURLUPART_URL, new_url, 0) != CURLUE_OK) {

fprintf(stderr, "Error: invalid URL\n");

return false;

@@ -138,8 +165,9 @@ return 1;

}

}

+ struct history *history;

if (optind == argc - 1) {

- set_url(url, argv[optind]);

+ set_url(url, argv[optind], &history);

} else {

usage(argv[0]);

return 1;

@@ -161,9 +189,10 @@ char *plain_url;

CURLUcode uc = curl_url_get(url, CURLUPART_URL, &plain_url, 0);

assert(uc == CURLUE_OK); // Invariant

- snprintf(prompt, sizeof(prompt), "\n\t%s\n"

- "\tWhere to? [n]: follow Nth link; [o <url>]: open URL; [q]: quit "

- "[b]ack; [f]orward\n"

+ snprintf(prompt, sizeof(prompt), "\nat %s\n"

+ "[n]: follow Nth link; [o <url>]: open URL; "

+ "[b]ack; [f]orward; "

+ "[q]uit\n"

"=> ", plain_url);

enum gemini_result res = gemini_request(plain_url, &opts, &resp);

@@ -201,11 +230,29 @@ size_t l = 0;

char *in = NULL;

ssize_t n = getline(&in, &l, tty);

if (n == -1 && feof(tty)) {

- prompting = run = false;

+ run = false;

break;

}

if (strcmp(in, "q\n") == 0) {

- prompting = run = false;

+ run = false;

+ break;

+ }

+ if (strcmp(in, "b\n") == 0) {

+ if (!history->prev) {

+ fprintf(stderr, "At beginning of history\n");

+ continue;

+ }

+ history = history->prev;

+ set_url(url, history->url, NULL);

+ break;

+ }

+ if (strcmp(in, "f\n") == 0) {

+ if (!history->next) {

+ fprintf(stderr, "At end of history\n");

+ continue;

+ }

+ history = history->next;

+ set_url(url, history->url, NULL);

break;

}

@@ -221,23 +268,24 @@

if (!link) {

fprintf(stderr, "Error: no such link.\n");

} else {

- prompting = false;

- set_url(url, link->url);

+ set_url(url, link->url, &history);

+ break;

}

}

+ free(in);

+ }

- link = links;

- while (link) {

- struct link *next = link->next;

- free(link->url);

- free(link);

- link = next;

- }

-

- free(in);

+ struct link *link = links;

+ while (link) {

+ struct link *next = link->next;

+ free(link->url);

+ free(link);

+ link = next;

}

+ links = NULL;

}

+ history_free(history);

SSL_CTX_free(opts.ssl_ctx);

curl_url_cleanup(url);

return 0;