diff --git a/include/gmni.h b/include/gmni.h

index d78d1c8eb4e94507c363219573691e60d40e8ea8..4240c6231010ebb86aead2d49700fe2e3d00b65c 100644

--- a/include/gmni.h

+++ b/include/gmni.h

@@ -2,6 +2,7 @@ #ifndef GEMINI_CLIENT_H

#define GEMINI_CLIENT_H

#include <netdb.h>

#include <openssl/ssl.h>

+#include <stdbool.h>

#include <sys/socket.h>

enum gemini_result {

@@ -106,7 +107,9 @@

enum gemini_tok {

GEMINI_TEXT,

GEMINI_LINK,

- GEMINI_PREFORMATTED,

+ GEMINI_PREFORMATTED_BEGIN,

+ GEMINI_PREFORMATTED_END,

+ GEMINI_PREFORMATTED_TEXT,

GEMINI_HEADING,

GEMINI_LIST_ITEM,

GEMINI_QUOTE,

@@ -124,10 +127,7 @@ char *text;

char *url; // May be NULL

} link;

- struct {

- char *text;

- char *alt_text; // May be NULL

- } preformatted;

+ char *preformatted;

struct {

char *title;

@@ -144,6 +144,7 @@ BIO *f;

char *buf;

size_t bufsz;

size_t bufln;

+ bool preformatted;

};

// Initializes a text/gemini parser which reads from the specified BIO.

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

index 5e5d828f6f246e0baa3917177acd8cb6482387f8..8841c4613e208e379c6cd768a65a9a3b631d3146 100644

--- a/src/gmnlm.c

+++ b/src/gmnlm.c

@@ -278,8 +278,15 @@ } else {

col += fprintf(out, " ");

}

break;

- case GEMINI_PREFORMATTED:

- continue; // TODO

+ case GEMINI_PREFORMATTED_BEGIN:

+ case GEMINI_PREFORMATTED_END:

+ continue; // Not used

+ case GEMINI_PREFORMATTED_TEXT:

+ col += fprintf(out, "` ");

+ if (text == NULL) {

+ text = tok.text;

+ }

+ break;

case GEMINI_HEADING:

if (text == NULL) {

for (int n = tok.heading.level; n; --n) {

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

index b9db3d2000f1176df4a21300f7b806ed6a5ded75..5b0f01399d934f593cdf987e096dd2cfb134d114 100644

--- a/src/parser.c

+++ b/src/parser.c

@@ -1,6 +1,7 @@

#include <assert.h>

#include <ctype.h>

#include <openssl/bio.h>

+#include <stdbool.h>

#include <stddef.h>

#include <stdlib.h>

#include <string.h>

@@ -15,6 +16,7 @@ p->bufsz = BUFSIZ;

p->buf = malloc(p->bufsz + 1);

p->buf[0] = 0;

BIO_up_ref(p->f);

+ p->preformatted = false;

}

void

@@ -57,7 +59,15 @@ if ((end = strstr(p->buf, "\n")) != NULL) {

*end = 0;

}

- if (strncmp(p->buf, "=>", 2) == 0) {

+ if (p->preformatted) {

+ if (strncmp(p->buf, "```", 3) == 0) {

+ tok->token = GEMINI_PREFORMATTED_END;

+ p->preformatted = false;

+ } else {

+ tok->token = GEMINI_PREFORMATTED_TEXT;

+ tok->preformatted = strdup(p->buf);

+ }

+ } else if (strncmp(p->buf, "=>", 2) == 0) {

tok->token = GEMINI_LINK;

int i = 2;

while (p->buf[i] && isspace(p->buf[i])) ++i;

@@ -76,9 +86,11 @@ }

tok->link.url = strdup(tok->link.url);

} else if (strncmp(p->buf, "```", 3) == 0) {

- tok->token = GEMINI_PREFORMATTED; // TODO

- tok->preformatted.text = strdup("<text>");

- tok->preformatted.alt_text = strdup("<alt-text>");

+ tok->token = GEMINI_PREFORMATTED_BEGIN;

+ if (p->buf[3]) {

+ tok->preformatted = strdup(&p->buf[3]);

+ }

+ p->preformatted = true;

} else if (p->buf[0] == '#') {

tok->token = GEMINI_HEADING;

int level = 1;

@@ -125,9 +137,14 @@ case GEMINI_LINK:

free(tok->link.text);

free(tok->link.url);

break;

- case GEMINI_PREFORMATTED:

- free(tok->preformatted.text);

- free(tok->preformatted.alt_text);

+ case GEMINI_PREFORMATTED_BEGIN:

+ free(tok->preformatted);

+ break;

+ case GEMINI_PREFORMATTED_TEXT:

+ free(tok->preformatted);

+ break;

+ case GEMINI_PREFORMATTED_END:

+ // Nothing to free

break;

case GEMINI_HEADING:

free(tok->heading.title);