Welcome to little lamb

Code » qmdoc » commit a137a25

Start using skalibs

author Olivier Brunel
2022-12-26 13:46:15 UTC
committer Olivier Brunel
2022-12-26 13:46:15 UTC
parent 988eb058c45d0d598bc27da4579358ade900dba4

Start using skalibs

Makefile +3 -3
main.c +43 -28
output.c +27 -0
output.h +24 -0

diff --git a/Makefile b/Makefile
index 0411b1a..c83bc74 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,14 @@
-SRCS = main.c md4c.c
+SRCS = main.c output.c md4c.c
 OBJS = $(SRCS:.c=.o)
 DEPS = $(SRCS:.c=.d)
 
 CFLAGS = -g -O3 -Wall
-LDFLAGS =
+LDFLAGS = -L/lib/skalibs -lskarnet
 
 all: qmdoc
 
 qmdoc: $(OBJS)
-	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS)
+	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $@
 
 -include $(DEPS)
 
diff --git a/main.c b/main.c
index bf55092..c59bab1 100644
--- a/main.c
+++ b/main.c
@@ -8,23 +8,18 @@
 #include <sys/stat.h>
 #include <getopt.h>
 #include <errno.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/buffer.h>
 #include <err.h>
+#include "qmdoc.h"
+#include "output.h"
 #include "md4c.h"
 
-const char *progname;
+const char *PROG = "qmdoc";
+
 #define ret(r,...)      { warn(__VA_ARGS__);  return r; }
 #define retx(r,...)     { warnx(__VA_ARGS__); return r; }
 
-enum {
-    ERR_NONE        =  0,
-    ERR_USAGE       = -1,
-    ERR_IO          = -5,
-    ERR_PARSER      = -6,
-    ERR_MEM         = -7,
-    ERR_NOTSUPP     = -8,
-    ERR_INVALID     = -9,
-};
-
 enum {
     OPT_NO_CSS      = (1 << 0),
     OPT_INLINE_CSS  = (1 << 1),
@@ -750,19 +745,28 @@ load_page_from_file(const char *file, struct page *page)
     return 0;
 }
 
+static void
+help(void)
+{
+    outh(" -C, --no-css                 Do not use CSS\n"
+         " -d, --destdir DIR            Write files into DIR\n"
+         " -h, --help                   Show this help screen and exit\n"
+         " -I, --inline-css             Use inline CSS instead of external files\n"
+        );
+}
+
 static void
 usage(int err)
 {
-    printf("usage: %s [OPTION..] FILE...\n", progname);
-    _exit((err) ? -ERR_USAGE : ERR_NONE);
+    strerr_dieusage((err) ? -ERR_USAGE : -ERR_NONE, "[OPTION..] FILE...");
 }
 
 int
 main (int argc, char *argv[])
 {
-    progname = strrchr(argv[0], '/');
-    if (progname) ++progname;
-    else progname = argv[0];
+    PROG = strrchr(argv[0], '/');
+    if (PROG) ++PROG;
+    else PROG = argv[0];
 
     int options = 0;
     char *destdir = ".";
@@ -771,16 +775,19 @@ main (int argc, char *argv[])
     struct option opts[] = {
         { "no-css",         no_argument,        NULL,   'C' },
         { "destdir",        required_argument,  NULL,   'd' },
+        { "help",           no_argument,        NULL,   'h' },
         { "inline-css",     no_argument,        NULL,   'I' },
         { NULL,             0,                  NULL,    0  },
     };
-    while ((c = getopt_long(argc, argv, "Cd:I", opts, NULL)) != -1) switch (c) {
+    while ((c = getopt_long(argc, argv, "Cd:hI", opts, NULL)) != -1) switch (c) {
         case 'C':
             options |= OPT_NO_CSS;
             break;
         case 'd':
             destdir = optarg;
             break;
+        case 'h':
+            help();
         case 'I':
             options |= OPT_INLINE_CSS;
             break;
@@ -789,22 +796,24 @@ main (int argc, char *argv[])
     }
     if (optind == argc) usage(1);
     if ((options & (OPT_NO_CSS | OPT_INLINE_CSS)) == (OPT_NO_CSS | OPT_INLINE_CSS))
-        retx(-ERR_USAGE, "cannot use '%s' and '%s' together", "--no-css", "--inline-css");
+        strerr_dief1x(-ERR_USAGE, "cannot use '--no-css' and '--inline-css' together");
 
     int fddest = open(destdir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
-    if (fddest < 0) err(ERR_IO, "cannot open '%s'", destdir);
+    if (fddest < 0) strerr_diefu3sys(-ERR_IO, "open '", destdir, "'");
 
     int r;
     struct page pages[argc - optind];
 
     if (argc > optind + 1) {
-        printf("Scanning files...\n");
+        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")) {
-                printf("Skipping '%s': File must be a markdown file (*.md)\n", file);
+                outs("Skipping '");
+                outs(file);
+                outse("': File must be a markdown file (*.md)");
                 continue;
             }
 
@@ -814,7 +823,8 @@ main (int argc, char *argv[])
     }
 
     if (!(options & OPT_NO_CSS)) {
-        printf("%s CSS files...\n", (options & OPT_INLINE_CSS) ? "Loading" : "Copying");
+        outs((options & OPT_INLINE_CSS) ? "Loading" : "Copying");
+        outse(" CSS files...");
         for (int i = 0; i < NB_CSS; ++i) {
             r = load_file(css[i].file, &css[i].buf);
             if (r < 0) return -r;
@@ -837,8 +847,11 @@ main (int argc, char *argv[])
         size_t scelen = strlen(sce);
 
         if (strcmp(sce + scelen - 3, ".md")) {
-            if (argc == optind + 1)
-                printf("Skipping '%s': File must be a markdown file (*.md)\n", sce);
+            if (argc == optind + 1) {
+                outs("Skipping '");
+                outs(sce);
+                outse("': File must be a markdown file (*.md)\n");
+            }
             continue;
         }
 
@@ -846,13 +859,15 @@ main (int argc, char *argv[])
         memcpy(dst, sce, scelen - 2);
         memcpy(dst + scelen - 2, "html", 5);
 
-        printf("Converting %s...\n", sce);
+        outs("Converting ");
+        outs(sce);
+        outse("...");
 
         int fd = openat(fddest, dst, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC | O_NONBLOCK, 0644);
-        if (fd < 0) err(-ERR_IO, "cannot create '%s/%s'", destdir, dst);
+        if (fd < 0) strerr_diefu5sys(-ERR_IO, "create '", destdir, "/", dst, "'");
 
         ctx.out = fdopen(fd, "we");
-        if (!ctx.out) err(-ERR_IO, "cannot open '%s/%s'", destdir, dst);
+        if (!ctx.out) strerr_diefu5sys(-ERR_IO, "open '", destdir, "/", dst, "'");
 
         r = convert_file(sce, &ctx);
         if (r < 0) return -r;
@@ -860,6 +875,6 @@ main (int argc, char *argv[])
         fclose(ctx.out);
     }
 
-    printf("done.\n");
+    outse("done.");
     return 0;
 }
diff --git a/output.c b/output.c
new file mode 100644
index 0000000..8aca0ac
--- /dev/null
+++ b/output.c
@@ -0,0 +1,27 @@
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <unistd.h> /* _exit() */
+#include "qmdoc.h" /* ERR_* */
+#include "output.h"
+
+void
+putb(int opts, const char *str, size_t len)
+{
+    buffer_t *b = (opts & PUT_ERR) ? buffer_2 : buffer_1;
+    if (buffer_put(b, str, len) < 0)
+        strerr_dief2x(ERR_MISC, "cannot print to ", (opts & PUT_ERR) ? "stderr" : "stdout");
+    if ((opts & PUT_NEWLINE) && buffer_put(b, "\n", 1) < 0)
+        strerr_dief2x(ERR_MISC, "cannot print to ", (opts & PUT_ERR) ? "stderr" : "stdout");
+    if ((opts & PUT_FLUSH) && !buffer_flush(b))
+        strerr_dief2x(ERR_MISC, "cannot flush to ", (opts & PUT_ERR) ? "stderr" : "stdout");
+}
+
+void
+outh(const char *help)
+{
+    outs("usage: ");
+    outs(PROG);
+    outs(" [OPTION..] FILE...\n\n");
+    outse(help);
+    _exit(ERR_NONE);
+}
diff --git a/output.h b/output.h
new file mode 100644
index 0000000..a640a01
--- /dev/null
+++ b/output.h
@@ -0,0 +1,24 @@
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+enum {
+    PUT_OUT     =  0, /* implied default else PUT_ERR is set */
+    PUT_ERR     = (1 << 0),
+    PUT_FLUSH   = (1 << 1),
+    PUT_NEWLINE = (1 << 2),
+};
+
+void putb(int opts, const char *str, size_t len);
+
+#define outb(s,l)       putb(PUT_OUT, s, l)
+#define outs(s)         outb(s, strlen(s))
+#define outbe(s,l)      putb(PUT_OUT | PUT_FLUSH | PUT_NEWLINE, s, l)
+#define outse(s)        outbe(s, strlen(s))
+void outh(const char *help);
+
+#define errb(s,l)       putb(PUT_ERR, s, l)
+#define errs(s)         errb(s, strlen(s))
+#define errbe(s,l)      putb(PUT_ERR | PUT_FLUSH | PUT_NEWLINE, s, l)
+#define errse(s)        errbe(s, strlen(s))
+
+#endif /* OUTPUT_H */