Welcome to little lamb

Code » qmdoc » commit f74f0f5

More refactorng to skalibs

author Olivier Brunel
2022-12-26 19:25:16 UTC
committer Olivier Brunel
2022-12-26 19:39:02 UTC
parent 083d8979d23c0a9a32104f2efaece990086c172a

More refactorng to skalibs

main.c +112 -88

diff --git a/main.c b/main.c
index 6523780..6e74073 100644
--- a/main.c
+++ b/main.c
@@ -42,7 +42,7 @@ enum {
 };
 static struct css {
     const char *file;
-    off_t offset;
+    size_t offset;
 } css[NB_CSS] = {
     { "struct.css" },
     { "common.css" },
@@ -51,14 +51,16 @@ static struct css {
 };
 
 struct page {
-    char *file;
-    char *title;
+    size_t fileoff;
+    size_t titleoff;
+    int fd;
+    size_t size;
 };
 
 struct ctx {
     int options;
     FILE *out;
-    stralloc sa_css;
+    stralloc sa_names;
     struct css *css;
     struct page *pages;
     int nb_pages;
@@ -191,10 +193,17 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
             {
                 int r = raw_str(f, "<!DOCTYPE html>\n<html><head>");
                 if (r < 0) return r;
+                r = raw_str(f, "<title>");
+                if (r < 0) return r;
+                r = escape_text(f, ctx->sa_names.s + ctx->pages[0].titleoff,
+                                strlen(ctx->sa_names.s + ctx->pages[0].titleoff));
+                if (r < 0) return r;
+                r = raw_str(f, "</title>");
+                if (r < 0) return r;
                 if (ctx->options & OPT_INLINE_CSS) {
                     for (int i = 0; i < NB_CSS; ++i) {
                         if (raw_str(f, "<style>") < 0
-                                || raw_str(f, ctx->sa_css.s + ctx->css[i].offset) < 0
+                                || raw_str(f, ctx->sa_names.s + ctx->css[i].offset) < 0
                                 || raw_str(f, "</style>") < 0)
                             return ERR_IO;
                     }
@@ -209,7 +218,8 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
 
                 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);
+                                   ctx->sa_names.s + ctx->pages[i].fileoff,
+                                   ctx->sa_names.s + ctx->pages[i].titleoff);
                     if (r < 0) return r;
                 }
 
@@ -626,7 +636,7 @@ convert_file(const char *file, struct ctx *ctx)
         .leave_span = leave_span,
         .text = text,
     };
-    int r = md_parse(b, done, &parser, ctx);
+    int r = md_parse(b, done - (b - buf), &parser, ctx);
     if (r < 0) {
         retx(ERR_PARSER, "parser internal error %d", -r);
     } else if (r > 0) {
@@ -636,55 +646,78 @@ convert_file(const char *file, struct ctx *ctx)
     return 0;
 }
 
-static int
-load_page_from_file(const char *file, struct page *page)
+static void
+load_page_from_file(const char *file, struct page *page, stralloc *sa_names)
 {
-    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;
-    }
+    page->fd = open_read(file);
+    if (page->fd < 0) strerr_diefu3sys(-ERR_IO, "open '", file, "'");
 
     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';
+    page->fileoff = sa_names->len;
+    if (!stralloc_catb(sa_names, file, l - 2)
+            || !stralloc_catb(sa_names, "html", 5))
+        strerr_diefu3sys(-ERR_MEM, "load page title from '", file, "'");
+
+    char buf_[256], buf[sizeof(buf_)];
+    buffer_t buffer = BUFFER_INIT(&fd_readv, page->fd, buf_, sizeof(buf_));
+
+    ssize_t left = buffer_get(&buffer, buf, sizeof(buf));
+    if (left <= 0)
+        strerr_diefu3sys(-ERR_IO, "load page title from '", file, "'");
+
+    page->titleoff = page->fileoff;
+
+    char *b = buf;
+    int line = 1, begin = 1, is_hdr = 0;
+    int done = 0, warned = 0;
+    while (left > 0) {
+        char *e = memchr(b + 2, '\n', left - 2);
+        if (begin) is_hdr = (b[0] == '%' && b[1] == ' ');
+        if (begin && !is_hdr)
+            break;
+        switch (line) {
+            case 1:
+                if (begin && is_hdr) page->titleoff = sa_names->len;
+                if (is_hdr
+                        && (!stralloc_catb(sa_names, b + ((is_hdr) ? 2 : 0),
+                                           ((e) ? e - b : left) - ((is_hdr) ? 2 : 0))
+                            || (e && !stralloc_0(sa_names))))
+                    strerr_diefu3sys(-ERR_MEM, "load page title from '", file, "'");
+                break;
+            case 2:
+            case 3:
+                break;
+            default:
+                if (begin && is_hdr && !warned) {
+                    errs("warning: header too long in '");
+                    errs(file);
+                    errse("': Only 3 lines supported");
+                    warned = 1;
+                }
+        }
+        if (e) {
+            int l = e - b + 1;
+            done += l;
+            b += l;
+            left -= l;
+            begin = 1;
+            is_hdr = 0;
+            ++line;
+        }
+        if (!e || left == 0) {
+            done += left;
+            b = buf;
+            left = buffer_get(&buffer, buf, sizeof(buf));
+            if (left <= 0)
+                strerr_diefu3sys(-ERR_IO, "load page title from '", file, "'");
+            if (!e) begin = 0;
         }
-        break;
     }
 
-    fclose(f);
-    return 0;
+    page->size = lseek(page->fd, 0, SEEK_END);
+    if (page->size == (off_t) -1 || lseek(page->fd, done, SEEK_SET) < 0)
+        strerr_diefu3sys(-ERR_MEM, "seek into '", file, "'");
+    page->size -= done;
 }
 
 static void
@@ -743,51 +776,47 @@ main (int argc, char *argv[])
     int fddest = open(destdir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
     if (fddest < 0) strerr_diefu3sys(-ERR_IO, "open '", destdir, "'");
 
-    int r;
     struct page pages[argc - optind];
-
-    if (argc > optind + 1) {
-        outse("Scanning files...");
-        for (int i = optind; i < argc; ++i) {
-            const char *file = argv[i];
-            size_t len = strlen(file);
-
-            if (strcmp(file + len - 3, ".md")) {
-                outs("Skipping '");
-                outs(file);
-                outse("': File must be a markdown file (*.md)");
-                continue;
-            }
-
-            r = load_page_from_file(file, &pages[i - optind]);
-            if (r < 0) return -r;
-        }
-    }
-
     struct ctx ctx = {
         .options = options,
-        .sa_css = STRALLOC_ZERO,
+        .sa_names = STRALLOC_ZERO,
         .css = css,
         .pages = pages,
         .nb_pages = sizeof(pages) / sizeof(*pages),
     };
 
+    outse("Scanning files...");
+    for (int i = optind; i < argc; ++i) {
+        const char *file = argv[i];
+        size_t len = strlen(file);
+
+        if (strcmp(file + len - 3, ".md")) {
+            outs("Skipping '");
+            outs(file);
+            outse("': File must be a markdown file (*.md)");
+            pages[i - optind].fd = -1;
+            continue;
+        }
+
+        load_page_from_file(file, &pages[i - optind], &ctx.sa_names);
+    }
+
     if (!(options & OPT_NO_CSS)) {
         outs((options & OPT_INLINE_CSS) ? "Loading" : "Copying");
         outse(" CSS files...");
         for (int i = 0; i < NB_CSS; ++i) {
-            if ((options & OPT_INLINE_CSS)) {
-                css[i].offset = ctx.sa_css.len;
-                if (!openreadfileclose(css[i].file, &ctx.sa_css, 0))
-                    strerr_diefu3sys(ERR_IO, "load CSS from '", css[i].file, "'");
+            if (options & OPT_INLINE_CSS) {
+                css[i].offset = ctx.sa_names.len;
+                if (!openreadfileclose(css[i].file, &ctx.sa_names, 0))
+                    strerr_diefu3sys(-ERR_IO, "load CSS from '", css[i].file, "'");
             } else {
                 int from, to;
                 from = open_read(css[i].file);
-                if (from < 0) strerr_diefu3sys(ERR_IO, "open '", css[i].file, "'");
+                if (from < 0) strerr_diefu3sys(-ERR_IO, "open '", css[i].file, "'");
                 to = openat_excl(fddest, css[i].file);
-                if (to < 0) strerr_diefu5sys(ERR_IO, "create '", destdir, "/", css[i].file, "'");
+                if (to < 0) strerr_diefu5sys(-ERR_IO, "create '", destdir, "/", css[i].file, "'");
                 if (fd_cat(from, to) < 0)
-                    strerr_diefu5sys(ERR_IO, "copy CSS to '", destdir, "/", css[i].file, "'");
+                    strerr_diefu5sys(-ERR_IO, "copy CSS to '", destdir, "/", css[i].file, "'");
                 fd_close(from);
                 fd_close(to);
             }
@@ -798,14 +827,7 @@ main (int argc, char *argv[])
         const char *sce = argv[i];
         size_t scelen = strlen(sce);
 
-        if (strcmp(sce + scelen - 3, ".md")) {
-            if (argc == optind + 1) {
-                outs("Skipping '");
-                outs(sce);
-                outse("': File must be a markdown file (*.md)\n");
-            }
-            continue;
-        }
+        if (pages[i - optind].fd < 0) continue;
 
         char dst[scelen + 3];
         memcpy(dst, sce, scelen - 2);
@@ -815,18 +837,20 @@ main (int argc, char *argv[])
         outs(sce);
         outse("...");
 
-        int fd = openat(fddest, dst, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC | O_NONBLOCK, 0644);
+        int fd = openat_excl(fddest, dst);
         if (fd < 0) strerr_diefu5sys(-ERR_IO, "create '", destdir, "/", dst, "'");
 
         ctx.out = fdopen(fd, "we");
         if (!ctx.out) strerr_diefu5sys(-ERR_IO, "open '", destdir, "/", dst, "'");
 
-        r = convert_file(sce, &ctx);
+        int r = convert_file(sce, &ctx);
         if (r < 0) return -r;
 
         fclose(ctx.out);
     }
 
+    stralloc_free(&ctx.sa_names);
+
     outse("done.");
     return 0;
 }