author | Olivier Brunel
<jjk@jjacky.com> 2022-12-27 16:50:39 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2022-12-27 16:50:39 UTC |
parent | d1b996b5902a8afd356d1e8befb1b317537659c6 |
main.c | +67 | -41 |
diff --git a/main.c b/main.c index 482c875..cb37f88 100644 --- a/main.c +++ b/main.c @@ -64,7 +64,10 @@ enum { struct ctx { int options; stralloc sa; + size_t otoc; stralloc sa_out; + size_t ootoc; + int toc_lvl; struct css *css; struct page *pages; int nb_pages; @@ -86,6 +89,7 @@ enum { ERR_PARSER_LEAVE_SPAN = -103, ERR_PARSER_TEXT = -104, ERR_PARSER_BUFFERED = -105, + ERR_PARSER_TOC = -106, }; static int @@ -236,6 +240,23 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_) || !escape_text(ctx, str_title(i), strlen(str_title(i))) || !raw_str(ctx, "</a></li>")) return ERR_PARSER_ENTER_BLOCK; + + /* remember positions for TOC */ + if (i == ctx->cur_page) { + /* where to include it */ + ctx->ootoc = ctx->sa_out.len; + /* where it is being created */ + ctx->otoc = ctx->sa.len; + + /* open it */ + ctx->buf.state = BUF_ON; + if (!raw_str(ctx, "<ul>")) { + ctx->buf.state = BUF_OFF; + return ERR_PARSER_TOC; + } + ctx->toc_lvl = 1; + ctx->buf.state = BUF_OFF; + } } #undef str_title #undef str_file @@ -663,24 +684,21 @@ text(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *ctx_) } static int -convert_page(struct ctx *ctx) +convert_page(struct ctx *ctx, int fddest) { - size_t size = ctx->pages[ctx->cur_page].size; - size_t salen = ctx->sa.len; + struct page *p = &ctx->pages[ctx->cur_page]; - if (!stralloc_readyplus(&ctx->sa, size)) + const char *dst = ctx->sa.s + p->fileoff; + int fd = openat_excl(fddest, dst); + if (fd < 0) ret_strerr_warnwu1sys(ERR_IO, "create destination"); + + size_t salen = ctx->sa.len; + if (!stralloc_readyplus(&ctx->sa, p->size)) return ERR_MEM; - if (allread(ctx->pages[ctx->cur_page].fd, ctx->sa.s + salen, size) != size) { - int e = errno; - ctx->sa.len = salen; - errs(PROG); - errs(": unable to read '"); - errs(ctx->sa.s + ctx->pages[ctx->cur_page].fileoff); - errs("': "); - errse(strerror(e)); - return ERR_IO; - } + if (allread(p->fd, ctx->sa.s + salen, p->size) != p->size) + ret_strerr_warnwu1sys(ERR_IO, "read source file"); + ctx->sa.len += p->size; const MD_PARSER parser = { .flags = MD_FLAG_COLLAPSEWHITESPACE | MD_FLAG_PERMISSIVEAUTOLINKS @@ -691,18 +709,42 @@ convert_page(struct ctx *ctx) .leave_span = leave_span, .text = text, }; - int r = md_parse(ctx->sa.s + salen, size, &parser, ctx); + int r = md_parse(ctx->sa.s + salen, p->size, &parser, ctx); if (r != 0) { char buf[UINT32_FMT]; buf[uint32_fmt(buf, (uint32) (r < 0) ? -r : r)] = '\0'; + ret_strerr_warnw2x(ERR_PARSER, (r < 0) ? "parser internal error " : "parser error ", + buf); + } - errs(PROG); - errs(": "); - errs((r < 0) ? "parser internal error " : "parser error "); - errse(buf); - - return ERR_PARSER; + /* close TOC */ + ctx->buf.state = BUF_ON; + for ( ; ctx->toc_lvl > 0; --ctx->toc_lvl) { + if (!raw_str(ctx, "</ul>")) { + char buf[UINT32_FMT]; + buf[uint32_fmt(buf, (uint32) ERR_PARSER_TOC)] = '\0'; + ret_strerr_warnwu2x(ERR_PARSER, "parser internal error ", buf); + } } + ctx->buf.state = BUF_OFF; + + /* write output : */ + if ( /* up to TOC position */ + allwrite(fd, ctx->sa_out.s, ctx->ootoc) != ctx->ootoc + /* then the actual TOC */ + || allwrite(fd, ctx->sa.s + ctx->otoc, ctx->sa.len - ctx->otoc) + != ctx->sa.len - ctx->otoc + /* and the rest of the page */ + || allwrite(fd, ctx->sa_out.s + ctx->ootoc, ctx->sa_out.len - ctx->ootoc) + != ctx->sa_out.len - ctx->ootoc + ) + ret_strerr_warnwu1sys(ERR_IO, "write destination"); + fd_close(fd); + + /* reset TOC/buffer positions */ + ctx->ootoc = ctx->otoc = ctx->sa_out.len = 0; + + fd_close(p->fd); ctx->sa.len = salen; return 0; @@ -888,32 +930,16 @@ main (int argc, char *argv[]) } for (int i = optind; i < argc; ++i) { - const char *sce = argv[i]; - size_t scelen = strlen(sce); - if (pages[i - optind].fd < 0) continue; - char dst[scelen + 3]; - memcpy(dst, sce, scelen - 2); - memcpy(dst + scelen - 2, "html", 5); - outs("Converting "); - outs(sce); + outs(argv[i]); outse("..."); - int fd = openat_excl(fddest, dst); - if (fd < 0) strerr_diefu5sys(-ERR_IO, "create '", destdir, "/", dst, "'"); - ctx.cur_page = i - optind; - int r = convert_page(&ctx); - if (r < 0) return -r; - - if (allwrite(fd, ctx.sa_out.s, ctx.sa_out.len) != ctx.sa_out.len) - strerr_diefu5sys(ERR_IO, "write '", destdir, "/", dst, "'"); - ctx.sa_out.len = 0; - fd_close(fd); - - fd_close(pages[ctx.cur_page].fd); + int r = convert_page(&ctx, fddest); + if (r < 0) strerr_diefu7x(-r, "convert '", argv[i], "' to '", destdir, "/", + ctx.sa.s + pages[i - optind].fileoff, "'"); } stralloc_free(&ctx.sa_out);