author | Olivier Brunel
<jjk@jjacky.com> 2022-12-28 08:46:02 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2022-12-28 08:46:05 UTC |
parent | 04eefb2681026187c8603c500ffb1bbd5509f930 |
main.c | +49 | -25 |
diff --git a/main.c b/main.c index 7dfe740..8a32d45 100644 --- a/main.c +++ b/main.c @@ -55,6 +55,10 @@ struct page { size_t size; }; +enum { + DOC_HAS_TITLE = (1 << 0), +}; + enum { BUF_OFF = 0, BUF_WAITING, @@ -65,23 +69,30 @@ struct ctx { int options; stralloc sa; size_t otoc; - size_t otitle; stralloc sa_out; int toc_lvl; struct css *css; struct page *pages; int nb_pages; int cur_page; - const char *title; struct { + const char *title; int flags; - int from; - } code; + } doc; struct { stralloc sa; size_t salen; int state; } buf; + union { + struct { + int level; + } title; + struct { + int flags; + int from; + } code; + }; }; enum { @@ -282,7 +293,7 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_) } } if (!raw_str(ctx, "</head><body><header><section><h1>") - || !escape_text(ctx, ctx->title, strlen(ctx->title)) + || !escape_text(ctx, ctx->doc.title, strlen(ctx->doc.title)) || !raw_str(ctx, "</h1></section><nav><ul>")) return ERR_PARSER_ENTER_BLOCK; @@ -345,13 +356,15 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_) case MD_BLOCK_H: { MD_BLOCK_H_DETAIL *d = details; - char buf[UINT32_FMT]; - buf[uint32_fmt(buf, (uint32) d->level)] = '\0'; - if (!raw_str(ctx, "<h") || !raw_str(ctx, buf) || !raw_str(ctx, ">")) + ctx->title.level = d->level; + + if ((ctx->doc.flags & DOC_HAS_TITLE) && !raw_str(ctx, "</section>")) return ERR_PARSER_ENTER_BLOCK; + ctx->doc.flags |= DOC_HAS_TITLE; - /* TOC */ ctx->buf.state = BUF_ON; + + /* TOC */ for ( ; ctx->toc_lvl < d->level; ++ctx->toc_lvl) { if (!raw_str(ctx, "<ul>")) return ERR_PARSER_TOC; @@ -360,8 +373,7 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_) if (!raw_str(ctx, "</ul>")) return ERR_PARSER_TOC; } - ctx->buf.state = BUF_OFF; - ctx->otitle = ctx->sa_out.len; + ctx->buf.salen = ctx->buf.sa.len; } break; @@ -369,8 +381,7 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_) { MD_BLOCK_CODE_DETAIL *d = details; - if (ctx->code.flags) - return ERR_INVALID; + ctx->code.flags = 0; if (!d->info.text || !strncmp(d->info.text, "pre\n", 4)) { return (raw_str(ctx, "<pre>")) ? 0 : ERR_PARSER_ENTER_BLOCK; @@ -451,7 +462,8 @@ leave_block(MD_BLOCKTYPE type, void *details, void *ctx_) switch (type) { case MD_BLOCK_DOC: - if (!raw_str(ctx, "</body></html>")) + if (((ctx->doc.flags & DOC_HAS_TITLE) && !raw_str(ctx, "</section>")) + || !raw_str(ctx, "</body></html>")) return ERR_PARSER_LEAVE_BLOCK; break; @@ -480,28 +492,40 @@ leave_block(MD_BLOCKTYPE type, void *details, void *ctx_) case MD_BLOCK_H: { - /* TOC */ - const char *s = ctx->sa_out.s + ctx->otitle; - size_t l = ctx->sa_out.len - ctx->otitle; - MD_BLOCK_H_DETAIL *d = details; + if (d->level != ctx->title.level) + return ERR_INVALID; + + const char *s = ctx->buf.sa.s + ctx->buf.salen; + size_t l = ctx->buf.sa.len - ctx->buf.salen; + ctx->buf.sa.len = ctx->buf.salen; + ctx->buf.state = BUF_OFF; + char buf[UINT32_FMT]; - buf[uint32_fmt(buf, (uint32) d->level)] = '\0'; - if (!raw_str(ctx, "<span id=\"") + buf[uint32_fmt(buf, (uint32) ctx->title.level)] = '\0'; + + if (!raw_str(ctx, "<section id=\"") || !anchor(ctx, s, l) - || !raw_str(ctx, "\"><a href=\"#") + || !raw_str(ctx, "\">") + || !raw_str(ctx, "<h") + || !raw_str(ctx, buf) + || !raw_str(ctx, ">") + || !raw_text(ctx, s, l) + || !raw_str(ctx, "<a href=\"#") || !anchor(ctx, s, l) - || !raw_str(ctx, "\"></a></span></h") + || !raw_str(ctx, "\"></a></h") || !raw_str(ctx, buf) || !raw_str(ctx, ">")) return ERR_PARSER_LEAVE_BLOCK; /* TOC */ + char toc[l]; + memcpy(toc, s, l); ctx->buf.state = BUF_ON; if (!raw_str(ctx, "<li><a href=\"#") - || !anchor(ctx, s, l) + || !anchor(ctx, toc, l) || !raw_str(ctx, "\">") - || !strip_tags(ctx, s, l) + || !strip_tags(ctx, toc, l) || !raw_str(ctx, "</a></li>")) return ERR_PARSER_TOC; ctx->buf.state = BUF_OFF; @@ -977,7 +1001,7 @@ main (int argc, char *argv[]) .css = css, .pages = pages, .nb_pages = sizeof(pages) / sizeof(*pages), - .title = title, + .doc.title = title, .buf.sa = STRALLOC_ZERO, };