author | Olivier Brunel
<jjk@jjacky.com> 2022-12-26 13:46:15 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2022-12-26 13:46:15 UTC |
parent | 988eb058c45d0d598bc27da4579358ade900dba4 |
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 */