author | Olivier Brunel
<jjk@jjacky.com> 2022-12-25 21:52:51 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2022-12-25 21:52:51 UTC |
parent | fca14ddf20e8fe3b5b367b795aecf9531c688e53 |
base.md | +1 | -1 |
main.c | +98 | -4 |
diff --git a/base.md b/base.md index e3c0efe..bb90f09 100644 --- a/base.md +++ b/base.md @@ -1,4 +1,4 @@ -:Foobar Documentation +% Foobar Documentation # Welcome to Foobar ! diff --git a/main.c b/main.c index a03cb19..bf55092 100644 --- a/main.c +++ b/main.c @@ -53,10 +53,17 @@ static struct css { { "dark.css" } }; +struct page { + char *file; + char *title; +}; + struct ctx { int options; FILE *out; struct css *css; + struct page *pages; + int nb_pages; struct { int flags; int from; @@ -199,7 +206,16 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_) if (r < 0) return r; } } - r = raw_str(f, "</head><body><main>"); + r = raw_str(f, "</head><body><header><nav><ul>"); + if (r < 0) return r; + + for (int i = 0; i < ctx->nb_pages; ++i) { + r = raw_printf(f, "<li><a href=\"%s\">%s</a></li>", + ctx->pages[i].file, ctx->pages[i].title); + if (r < 0) return r; + } + + r = raw_str(f, "</ul></nav></header><main>"); if (r < 0) return r; } break; @@ -599,6 +615,10 @@ convert_file(const char *file, struct ctx *ctx) } close(fd); + b = buf; + while (b[0] == '%' && b[1] == ' ') + b = strchr(b, '\n') + 1; + const MD_PARSER parser = { .flags = MD_FLAG_COLLAPSEWHITESPACE | MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_NOHTMLBLOCKS | MD_FLAG_STRIKETHROUGH | MD_FLAG_UNDERLINE, @@ -608,7 +628,7 @@ convert_file(const char *file, struct ctx *ctx) .leave_span = leave_span, .text = text, }; - int r = md_parse(buf, done, &parser, ctx); + int r = md_parse(b, done, &parser, ctx); if (r < 0) { retx(ERR_PARSER, "parser internal error %d", -r); } else if (r > 0) { @@ -679,6 +699,57 @@ write_file(int fdp, const char *path, const char *file, const char *data) return 0; } +static int +load_page_from_file(const char *file, struct page *page) +{ + int fd = open(file, O_RDONLY | O_CLOEXEC | O_NONBLOCK); + if (fd < 0) ret(ERR_IO, "cannot open '%s'", file); + + FILE *f = fdopen(fd, "re"); + if (!f) { + warn("cannot open '%s'", file); + close(fd); + return ERR_IO; + } + + size_t l = strlen(file); + page->file = malloc(l + 3); + if (!page->file) { + warn("cannot load title from '%s'", file); + fclose(f); + return ERR_MEM; + } + memcpy(page->file, file, l - 2); + memcpy(page->file + l - 2, "html", 5); + + char buf[256]; + while (fgets(buf, sizeof(buf), f)) { + if (buf[0] != '%' || buf[1] != ' ') { + page->title = strdup(file); + } else { + char *e = memchr(buf + 2, '\n', sizeof(buf) - 2); + if (!e) { + printf("Title too long in '%s'; Truncated\n", file); + e = buf + 512; + } + size_t l = e - buf - 2; + page->title = malloc(l + 1); + if (!page->title) { + warn("cannot load page title from '%s'", file); + fclose(f); + free(page->file); + return ERR_MEM; + } + memcpy(page->title, buf + 2, l); + page->title[l] = '\0'; + } + break; + } + + fclose(f); + return 0; +} + static void usage(int err) { @@ -724,6 +795,23 @@ main (int argc, char *argv[]) if (fddest < 0) err(ERR_IO, "cannot open '%s'", destdir); int r; + struct page pages[argc - optind]; + + if (argc > optind + 1) { + printf("Scanning files...\n"); + for (int i = optind; i < argc; ++i) { + const char *file = argv[i]; + size_t len = strlen(file); + + if (strcmp(file + len - 3, ".md")) { + printf("Skipping '%s': File must be a markdown file (*.md)\n", file); + continue; + } + + r = load_page_from_file(file, &pages[i - optind]); + if (r < 0) return -r; + } + } if (!(options & OPT_NO_CSS)) { printf("%s CSS files...\n", (options & OPT_INLINE_CSS) ? "Loading" : "Copying"); @@ -737,14 +825,20 @@ main (int argc, char *argv[]) } } - struct ctx ctx = { .options = options, .css = css }; + struct ctx ctx = { + .options = options, + .css = css, + .pages = pages, + .nb_pages = sizeof(pages) / sizeof(*pages), + }; for (int i = optind; i < argc; ++i) { const char *sce = argv[i]; size_t scelen = strlen(sce); if (strcmp(sce + scelen - 3, ".md")) { - warn("Skipping '%s': File must be a markdown file (*.md)", sce); + if (argc == optind + 1) + printf("Skipping '%s': File must be a markdown file (*.md)\n", sce); continue; }