Welcome to little lamb

Code » qmdoc » commit ff81ff2

Start implementing TOC

author Olivier Brunel
2022-12-27 16:50:39 UTC
committer Olivier Brunel
2022-12-27 16:50:39 UTC
parent d1b996b5902a8afd356d1e8befb1b317537659c6

Start implementing TOC

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);