diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 218 |
1 files changed, 163 insertions, 55 deletions
diff --git a/main.c b/main.c index e749d58..0cddf91 100644 --- a/main.c +++ b/main.c @@ -12,6 +12,19 @@ #include "arena.h" #include "args.h" +typedef struct { + int standalone; + int from_stdin; + Str stylesheet; + int inlinep; + int csslink; + Str hvarv[1024]; + Str title; + int hvarc; +} Options; + +Options opts = { 0 }; + #define ARENA(n, sz) Arena n; { static char arena_backarr[sz];\ n.beg = arena_backarr; n.end = arena_backarr + sizeof(arena_backarr);\ __asm("":"+r"(n.beg)); __asm("":"+r"(n.end)); } @@ -65,15 +78,18 @@ void str_cat_uri(Str *s, Str uri, Arena *a) { str_catc(s, '\'', a); } +void str_catc_html(Str *s, char c, Arena *a) { + switch (c) { + case '&': str_cat(s, S("&"), a); break; + case '<': str_cat(s, S("<"), a); break; + case '>': str_cat(s, S(">"), a); break; + default: str_catc(s, c, a); break; + } +} + void str_cat_html(Str *s, Str uri, Arena *a) { for (isize i = 0; i < uri.n; i++) { - char c = uri.s[i]; - switch (c) { - case '&': str_cat(s, S("&"), a); break; - case '<': str_cat(s, S("<"), a); break; - case '>': str_cat(s, S(">"), a); break; - default: str_catc(s, c, a); break; - } + str_catc_html(s, uri.s[i], a); } } @@ -214,25 +230,24 @@ BlockList blk_gather(Str src, Arena *perm) { Line *lptr = NULL; while (next_line(&src, &line)) { LineType t = classify_line(line, last); - if (last == LN_CODE) { - if (t == LN_CODE) last = LN_NONE; - } else if (t == LN_CODE) { - last = LN_CODE; - } else { - Block *b = blk.len > 0 ? &blk.data[blk.len-1] : NULL; - if (!b || t != b->type) { - b = blk_push(&blk, &lptr, t, perm); - } - Line *l = new(perm, Line); - LineType nt = line_init(l, line, t); - if (b->type != nt) { - if (b->lines) b = blk_push(&blk, &lptr, nt, perm); - else b->type = nt; - } - if (lptr) lptr->next = l; - lptr = l; - if (!b->lines) b->lines = lptr; + if (t == LN_CODE) { + last = last == LN_CODE ? LN_NONE : LN_CODE; + continue; + } + if (last == LN_CODE) t = LN_CODE; + Block *b = blk.len > 0 ? &blk.data[blk.len-1] : NULL; + if (!b || t != b->type) { + b = blk_push(&blk, &lptr, t, perm); + } + Line *l = new(perm, Line); + LineType nt = line_init(l, line, t); + if (b->type != nt) { + if (b->lines) b = blk_push(&blk, &lptr, nt, perm); + else b->type = nt; } + if (lptr) lptr->next = l; + lptr = l; + if (!b->lines) b->lines = lptr; last = t; } for (size_t i = 0; i < blk.len; i++) { @@ -247,11 +262,103 @@ BlockList blk_gather(Str src, Arena *perm) { } #define O(s) str_cat_html(out, s, perm) +#define Oi(s) markup_inline(&ist, out, s, scratch, perm) #define Os(s) str_cat(out, S(s), perm) -#define Ot(a, s, b) Os(a), O(s), Os(b) +#define Ot(a, s, b) Os(a), Oi(s), Os(b) #define Otl(a, f, b) for (Line *l = blk->lines; l; l = l->next) Ot(a, f, b) -void str_cat_blk(Str *out, Block *blk, Arena *perm, Arena *scratch) { +typedef enum { + IM_NONE, + IM_ITAL, + IM_CODE +} InlineMarkup; + +typedef struct { + int stkc; + InlineMarkup *stkv; +} InlineState; + +InlineMarkup im_last(InlineState *ms) { + if (ms->stkc > 0) { + return ms->stkv[ms->stkc - 1]; + } else { + return IM_NONE; + } +} + +void im_cat_op(Str *out, InlineMarkup mu, Arena *perm) { + switch (mu) { + case IM_ITAL: str_cat(out, S("<em>"), perm); break; + case IM_CODE: str_cat(out, S("<code>"), perm); break; + default: break; + } +} + +void im_cat_cl(Str *out, InlineMarkup mu, Arena *perm) { + switch (mu) { + case IM_ITAL: str_cat(out, S("</em>"), perm); break; + case IM_CODE: str_cat(out, S("</code>"), perm); break; + default: break; + } +} + +InlineMarkup im_pop(InlineState *ms) { + if (ms->stkc > 0) return ms->stkv[--ms->stkc]; + return IM_NONE; +} + +InlineMarkup im_push(InlineState *ms, InlineMarkup mu, Arena *scratch) { + if (ms->stkc > 0) { + ms->stkv = resize(scratch, ms->stkv, ms->stkc, ms->stkc + 1); + } else { + ms->stkv = new(scratch, InlineMarkup); + } + ms->stkv[ms->stkc++] = mu; + return mu; +} + +void im_op(InlineState *ms, Str *out, InlineMarkup mu, Arena *scratch, Arena *perm) { + im_cat_op(out, im_push(ms, mu, scratch), perm); +} + +void im_cl(InlineState *ms, Str *out, Arena *perm) { + im_cat_cl(out, im_pop(ms), perm); +} + +void markup_inline(InlineState *ms, Str *out, Str src, Arena *scratch, Arena *perm) { + if (!opts.inlinep) { + str_cat_html(out, src, perm); + return; + } + for (int i = 0; i < src.n; i++) { + char c = src.s[i]; + if (im_last(ms) == IM_CODE) { + if (c == '`') { + im_cl(ms, out, perm); + } else { + str_catc_html(out, src.s[i], perm); + } + } else { + if (c == '`') { + im_op(ms, out, IM_CODE, scratch, perm); + } else if (c == '*') { + if (im_last(ms) == IM_ITAL) { + im_cl(ms, out, perm); + } else { + im_op(ms, out, IM_ITAL, scratch, perm); + } + } else if (str_starts(str_skip(src, i), S("---"))) { + str_cat(out, S("—"), perm); + i += 2; + } else { + str_catc_html(out, src.s[i], perm); + } + } + } +} + +void markup_block(Str *out, Block *blk, Arena *perm, Arena *scratch) { + InlineState ist = { 0 }; switch (blk->type) { case LN_CODE: Os("<pre><code>"); @@ -270,7 +377,13 @@ void str_cat_blk(Str *out, Block *blk, Arena *perm, Arena *scratch) { : str_replace_end(l->url, S(".gmi"), S(".html"), scratch), perm); - Ot(">", l->txt.n > 0 ? l->txt : l->url, "</a></li>\n"); + str_catc(out, '>', perm); + if (l->txt.n > 0) { + markup_inline(&ist, out, l->txt, scratch, perm); + } else { + str_cat_html(out, l->url, perm); + } + str_cat(out, S("</a></li>\n"), perm); } Os("</ul>"); break; @@ -315,13 +428,14 @@ void str_cat_blk(Str *out, Block *blk, Arena *perm, Arena *scratch) { case LN_PAR: Os("<p>"); for (Line *l = blk->lines; l; l = l->next) { - O(l->txt); + Oi(l->txt); if (l->next) Os("<br>\n"); } Os("</p>"); break; } Os("\n"); + while (ist.stkc > 0) im_cl(&ist, out, perm); } int wdoc(FILE *f, Doc **dp, Arena *perm, Arena *scratch) { @@ -333,7 +447,7 @@ int wdoc(FILE *f, Doc **dp, Arena *perm, Arena *scratch) { if (blk.data[i].type == LN_HDR1 && !d->title.s) { d->title = blk.data[i].lines->txt; } - str_cat_blk(&d->html, &blk.data[i], perm, scratch); + markup_block(&d->html, &blk.data[i], perm, scratch); if (i + 1 < blk.len) str_cat(&d->html, S("\n"), perm); } *dp = d; @@ -369,7 +483,7 @@ int hvar_calc(Str param, Str *name, Str *val, Str filename) { void usage(const char *cmd) { fprintf(stderr, "usage: %s -?\n" - " %s [-s] [[-l] -c FILE] [-t TITLE] [-h NAME:ARG1[,ARG2,ARG3...]] [FILES...]\n" + " %s [-s] [-i] [[-l] -c FILE] [-t TITLE] [-h NAME:ARG1[,ARG2,ARG3...]] [FILES...]\n" "\n" " -? --help show this help text\n" " -s --standalone prefix with html metadata\n" @@ -378,37 +492,28 @@ void usage(const char *cmd) { " -c --css embed the given file within a <style> element\n" " -l --link when combined with --css, link to an external stylehseet\n" " instead of reading from a file locally\n" + " -i --inline enable inline formatting (*italics*, `code`, ---dashes)\n" " -t --title set the document title (does nothing without --standalone)\n", cmd, cmd); } -typedef struct { - int standalone; - int from_stdin; - Str stylesheet; - int csslink; - Str hvarv[1024]; - Str title; - int hvarc; -} Options; - -Str html_head(Options *o, Arena *m, Arena *l) { +Str html_head(Arena *m, Arena *l) { Str h = S("<!DOCTYPE html>\n" "<meta charset=utf-8>\n" "<meta name=viewport content='width=device-width,initial-scale=1'>\n"); - if (o->title.s) { + if (opts.title.s) { str_cat(&h, S("<title>"), m); - str_cat_html(&h, o->title, m); + str_cat_html(&h, opts.title, m); str_cat(&h, S("</title>\n"), m); } - if (o->hvarc > 0) { + if (opts.hvarc > 0) { str_cat(&h, S("<style>\n"), m); str_cat(&h, S(":root {"), m); - for (int i = 0; i < o->hvarc; i++) { + for (int i = 0; i < opts.hvarc; i++) { Str name, val; - if (hvar_calc(o->hvarv[i], &name, &val, o->title)) { + if (hvar_calc(opts.hvarv[i], &name, &val, opts.title)) { fprintf(stderr, "invalid argument given to --hvar\n"); exit(1); } @@ -422,15 +527,15 @@ Str html_head(Options *o, Arena *m, Arena *l) { str_cat(&h, S("</style>\n"), m); } - if (o->stylesheet.s) { - if (o->csslink) { + if (opts.stylesheet.s) { + if (opts.csslink) { str_cat(&h, S("<link rel='stylesheet' href="), m); - str_cat_uri(&h, o->stylesheet, m); + str_cat_uri(&h, opts.stylesheet, m); str_cat(&h, S(">"), m); } else { - FILE *f = fopen(str_to_cstr(o->stylesheet, m), "r/o"); + FILE *f = fopen(str_to_cstr(opts.stylesheet, m), "r/o"); if (!f) { - str_putf(o->stylesheet, stderr); + str_putf(opts.stylesheet, stderr); fprintf(stderr, ": %s\n", strerror(errno)); exit(1); } @@ -455,16 +560,16 @@ int main(int argc, const char **argv) { ARENA(scratch, 1 << 20) Doc *doc = 0; - Options opts = { 0 }; int r; ArgsState a = args_begin(argv); Str param = { 0 }; opts.from_stdin = 1; - while ((r = arg_get(&a, "?slc:h:t:", ¶m, + while ((r = arg_get(&a, "?slic:h:t:", ¶m, "help", '?', "standalone", 's', + "inline", 'i', ":title", 't', ":css", 'c', "link", 'l', @@ -478,6 +583,9 @@ int main(int argc, const char **argv) { case 's': opts.standalone = 1; break; + case 'i': + opts.inlinep = 1; + break; case 'c': opts.stylesheet = param; break; @@ -546,7 +654,7 @@ int main(int argc, const char **argv) { } if (opts.standalone) { - str_put(html_head(&opts, &perm, &scratch)); + str_put(html_head(&perm, &scratch)); str_put(S("\n")); } |