/* $Id$ */ /* * Copyright (c) 2008 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "libmdocml.h" #define BUFFER_IN_DEF BUFSIZ /* See begin_bufs. */ #define BUFFER_OUT_DEF BUFSIZ /* See begin_bufs. */ #ifdef DEBUG #define CSS "mdocml.css" #else #define CSS "/usr/local/share/mdocml/mdocml.css" #endif static void usage(void); static int begin_io(const struct md_args *, char *, char *); static int leave_io(const struct md_buf *, const struct md_buf *, int); static int begin_bufs(const struct md_args *, struct md_buf *, struct md_buf *); static int leave_bufs(const struct md_buf *, const struct md_buf *, int); int main(int argc, char *argv[]) { int c; char *out, *in, *opts, *v; struct md_args args; #define ALL 0 #define ERROR 1 char *toks[] = { "all", "error", NULL }; extern char *optarg; extern int optind; out = in = NULL; (void)memset(&args, 0, sizeof(struct md_args)); args.type = MD_XML; while (-1 != (c = getopt(argc, argv, "c:ef:o:vW:"))) switch (c) { case ('c'): if (args.type != MD_HTML) errx(1, "-c only valid for -fhtml"); args.params.html.css = optarg; break; case ('e'): if (args.type != MD_HTML) errx(1, "-e only valid for -fhtml"); args.params.html.flags |= HTML_CSS_EMBED; break; case ('f'): if (0 == strcmp(optarg, "html")) args.type = MD_HTML; else if (0 == strcmp(optarg, "xml")) args.type = MD_XML; else errx(1, "invalid filter type"); break; case ('o'): out = optarg; break; case ('v'): args.verbosity++; break; case ('W'): opts = optarg; while (*opts) switch (getsubopt(&opts, toks, &v)) { case (ALL): args.warnings |= MD_WARN_ALL; break; case (ERROR): args.warnings |= MD_WARN_ERROR; break; default: usage(); return(1); } break; default: usage(); return(1); } if (MD_HTML == args.type) if (NULL == args.params.html.css) args.params.html.css = CSS; argv += optind; argc -= optind; if (1 == argc) in = *argv++; return(begin_io(&args, out ? out : "-", in ? in : "-")); } /* * Close out file descriptors opened in begin_io. If the descriptor * refers to stdin/stdout, then do nothing. */ static int leave_io(const struct md_buf *out, const struct md_buf *in, int c) { assert(out); assert(in); if (-1 != in->fd && -1 == close(in->fd)) { assert(in->name); warn("%s", in->name); c = 1; } if (-1 != out->fd && STDOUT_FILENO != out->fd && -1 == close(out->fd)) { assert(out->name); warn("%s", out->name); c = 1; } if (1 == c && STDOUT_FILENO != out->fd) if (-1 == unlink(out->name)) warn("%s", out->name); return(c); } /* * Open file descriptors or assign stdin/stdout, if dictated by the "-" * token instead of a filename. */ static int begin_io(const struct md_args *args, char *out, char *in) { struct md_buf fi; struct md_buf fo; #define FI_FL O_RDONLY #define FO_FL O_WRONLY|O_CREAT|O_TRUNC assert(args); assert(out); assert(in); bzero(&fi, sizeof(struct md_buf)); bzero(&fo, sizeof(struct md_buf)); fi.fd = STDIN_FILENO; fo.fd = STDOUT_FILENO; fi.name = in; fo.name = out; if (0 != strncmp(fi.name, "-", 1)) if (-1 == (fi.fd = open(fi.name, FI_FL, 0))) { warn("%s", fi.name); return(leave_io(&fo, &fi, 1)); } if (0 != strncmp(fo.name, "-", 1)) if (-1 == (fo.fd = open(fo.name, FO_FL, 0644))) { warn("%s", fo.name); return(leave_io(&fo, &fi, 1)); } return(leave_io(&fo, &fi, begin_bufs(args, &fo, &fi))); } /* * Free buffers allocated in begin_bufs. */ static int leave_bufs(const struct md_buf *out, const struct md_buf *in, int c) { assert(out); assert(in); if (out->buf) free(out->buf); if (in->buf) free(in->buf); return(c); } /* * Allocate buffers to the maximum of either the input file's blocksize * or BUFFER_IN_DEF/BUFFER_OUT_DEF, which should be around BUFSIZE. */ static int begin_bufs(const struct md_args *args, struct md_buf *out, struct md_buf *in) { struct stat stin, stout; int c; assert(args); assert(in); assert(out); if (-1 == fstat(in->fd, &stin)) { warn("%s", in->name); return(1); } else if (STDIN_FILENO != in->fd && 0 == stin.st_size) { warnx("%s: empty file", in->name); return(1); } else if (-1 == fstat(out->fd, &stout)) { warn("%s", out->name); return(1); } in->bufsz = MAX(stin.st_blksize, BUFFER_IN_DEF); out->bufsz = MAX(stout.st_blksize, BUFFER_OUT_DEF); if (NULL == (in->buf = malloc(in->bufsz))) { warn("malloc"); return(leave_bufs(out, in, 1)); } else if (NULL == (out->buf = malloc(out->bufsz))) { warn("malloc"); return(leave_bufs(out, in, 1)); } c = md_run(args, out, in); return(leave_bufs(out, in, -1 == c ? 1 : 0)); } static void usage(void) { extern char *__progname; (void)printf("usage: %s [-v] [-Wwarn...] [-f filter] " "[-o outfile] [infile]\n", __progname); }