diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 80 |
1 files changed, 73 insertions, 7 deletions
diff --git a/main.c b/main.c index e65eb9d..8f5a784 100644 --- a/main.c +++ b/main.c @@ -24,6 +24,7 @@ typedef struct { Str title; int hvarc; Str docroot; + Str header_file, footer_file; } Options; Options opts = { 0 }; @@ -66,12 +67,33 @@ char to_xdigit(int x) { } } +int uri_ch_reserved(char c) { + return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']'; +} + +int uri_ch_unreserved(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') || c == '-' || c == '.' + || c == '_' || c == '~'; +} + +int uri_ch_sub_delim(char c) { + return c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' + || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' + || c == '='; +} + +int uri_ch_allowed(char c) { + return uri_ch_reserved(c) || uri_ch_unreserved(c) || uri_ch_sub_delim(c) + || c == '%'; +} + void str_cat_uri_internal(Str *s, Str uri, Arena *a) { for (isize i = 0; i < uri.n; i++) { char c = uri.s[i]; - if (c == '\'' || c == '%') { + if (c == '\'' || !uri_ch_allowed(c)) { str_catc(s, '%', a); - str_catc(s, to_xdigit((c & 0xff) >> 4), a); + str_catc(s, to_xdigit((c >> 4) & 0xf), a); str_catc(s, to_xdigit(c & 0xf), a); } else { str_catc(s, c, a); @@ -379,7 +401,7 @@ void markup_inline(InlineState *ms, Str *out, Str src, Arena *scratch, Arena *pe if (!f.n) break; i = f.s - src.s + 1; } else if (str_starts(skp, S("---"))) { - str_cat(out, S("—"), perm); + str_cat(out, S("—"), perm); i += 2; } else { text_inline(ms, c, out, perm); @@ -498,6 +520,15 @@ uint64_t str_hash(Str s) { return h; } +uint64_t murmur64(uint64_t h) { + h ^= h >> 33; + h *= 0xff51afd7ed558ccdL; + h ^= h >> 33; + h *= 0xc4ceb9fe1a85ec53L; + h ^= h >> 33; + return h; +} + /* --hvar bgcolor:'#fcc,#cfc,#ccf,#cff,#ffc,#fcf' */ int hvar_calc(Str param, Str *name, Str *val, Str filename) { Cut c = str_cut(param, ':'); @@ -506,7 +537,7 @@ int hvar_calc(Str param, Str *name, Str *val, Str filename) { usize n = 0; for (Str h = c.tail; h.n > 0; h = str_cut(h, ',').tail) n++; if (!n) return -1; - usize j = str_hash(filename) % n; + usize j = murmur64(str_hash(filename)) % n; usize i = 0; for (Str h = c.tail; h.n > 0; h = str_cut(h, ',').tail) { if (i == j) { @@ -520,12 +551,13 @@ int hvar_calc(Str param, Str *name, Str *val, Str filename) { void usage(const char *cmd) { fprintf(stderr, "usage: %s -?\n" - " %s [-silq] [-L LANG] [-c FILE] [-t TITLE] [-h NAME:ARG1[,ARG2,ARG3...]] [FILES...]\n" + " %s [OPTIONS] [FILES...]\n" "\n" " -? --help show this help text\n" " -s --standalone prefix with html metadata\n" " -h --hvar define a css variable (--name) with a random value,\n" " selected by a hash of the document's title\n" + " (format: NAME:ARG1[,ARG2,ARG3...])\n" " -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" @@ -533,6 +565,8 @@ void usage(const char *cmd) { " -q --smartq enable smart quotes\n" " -t --title set the document title (does nothing without --standalone)\n" " -R --root set a root url prepended to absolute paths\n" + " -H --header prepend the given file before the document\n" + " -F --footer append the given file after the document\n" " -L --lang set the document's language\n", cmd, cmd); } @@ -609,6 +643,26 @@ Str html_tail(Arena *m, Arena *l) { return h; } +void put_file(Str filename, Arena *scratch) { + Arena t = *scratch; + const char *path = str_to_cstr(filename, scratch); + FILE *f = fopen(path, "r/o"); + if (!f) { + fprintf(stderr, "failed to open file %s: %s\n", path, + strerror(errno)); + return; + } + Str buf; + if (read_all(f, &buf, scratch)) { + fprintf(stderr, "failed to read file %s: %s\n", path, + strerror(errno)); + return; + } + str_put(buf); + fclose(f); + *scratch = t; +} + #define countof(x) (sizeof(x) / sizeof(*x)) int main(int argc, const char **argv) { (void)argc; @@ -623,7 +677,7 @@ int main(int argc, const char **argv) { Str param = { 0 }; opts.from_stdin = 1; - while ((r = arg_get(&a, "?sliqc:h:t:L:R:", ¶m, + while ((r = arg_get(&a, "?sliqc:h:t:L:R:H:F:", ¶m, "help", '?', "standalone", 's', "smartq", 'q', @@ -633,7 +687,9 @@ int main(int argc, const char **argv) { "link", 'l', "lang", 'L', "root", 'R', - ":hvar", 'h')) >= ARG_OK) { + ":hvar", 'h', + "header", 'H', + "footer", 'F')) >= ARG_OK) { Arena reset = scratch; FILE *f; switch (r) { @@ -671,6 +727,12 @@ int main(int argc, const char **argv) { } opts.hvarv[opts.hvarc++] = param; break; + case 'H': + opts.header_file = param; + break; + case 'F': + opts.footer_file = param; + break; default: if (str_eql(param, S("-"))) { if (wdoc(stdin, &doc, &perm, &scratch)) { @@ -727,11 +789,15 @@ int main(int argc, const char **argv) { str_put(S("\n")); } + if (opts.header_file.n) put_file(opts.header_file, &scratch); + while (doc) { str_put(doc->html); doc = doc->next; } + if (opts.footer_file.n) put_file(opts.footer_file, &scratch); + str_put(html_tail(&perm, &scratch)); return 0; |