]> git.cameronkatri.com Git - mandoc.git/blobdiff - mdocml.c
Boolean validation.
[mandoc.git] / mdocml.c
index dc77143164d5e42c4a22c6725e2acce98ed4bc64..2b7c4388fb4f9bde9142d0a3f9ddaddeae43d20f 100644 (file)
--- a/mdocml.c
+++ b/mdocml.c
@@ -1,4 +1,4 @@
-/* $Id: mdocml.c,v 1.2 2008/11/22 16:55:02 kristaps Exp $ */
+/* $Id: mdocml.c,v 1.46 2009/01/16 14:15:12 kristaps Exp $ */
 /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  */
-#include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/param.h>
 
 #include <assert.h>
-#include <err.h>
 #include <fcntl.h>
+#include <err.h>
 #include <getopt.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#include "libmdocml.h"
-
-struct md_file {
-       int              fd;
-       const char      *name;
+#include "mdoc.h"
+
+#define        xfprintf        (void)fprintf
+#define        xprintf         (void)printf
+#define        xvfprintf       (void)fvprintf
+
+#define        MD_LINE_SZ      (256)           /* Max input line size. */
+
+struct md_parse {
+       int              warn;          /* Warning flags. */
+#define        MD_WARN_SYNTAX  (1 << 0)        /* Show syntax warnings. */
+#define        MD_WARN_COMPAT  (1 << 1)        /* Show compat warnings. */
+#define        MD_WARN_ALL     (0x03)          /* Show all warnings. */
+#define        MD_WARN_ERR     (1 << 2)        /* Make warnings->errors. */
+       int              dbg;           /* Debug level. */
+       struct mdoc     *mdoc;          /* Active parser. */
+       char            *buf;           /* Input buffer. */
+       u_long           bufsz;         /* Input buffer size. */
+       char            *name;          /* Input file name. */
+       int              fd;            /* Input file desc. */
 };
 
-struct md_buf {
-       struct md_file  *file;
-       char            *buf;
-       size_t           bufsz;
-       size_t           line;
-};
+extern char            *__progname;
 
-struct md_mbuf {
-       struct md_buf   *buf;
-       size_t           pos;
-};
-
-static void             usage(void);
+static void             usage(void);
 
-static int              md_begin(const char *, const char *);
-static int              md_begin_io(const char *, const char *);
-static int              md_begin_bufs(struct md_file *, struct md_file *);
-static int              md_run(struct md_buf *, struct md_buf *);
-static int              md_line(struct md_mbuf *, const struct md_buf *,
-                               const char *, size_t);
+static int              parse_begin(struct md_parse *);
+static int              parse_leave(struct md_parse *, int);
+static int              io_begin(struct md_parse *);
+static int              io_leave(struct md_parse *, int);
+static int              buf_begin(struct md_parse *);
+static int              buf_leave(struct md_parse *, int);
 
-static ssize_t          md_buf_fill(struct md_buf *);
-static int              md_buf_flush(struct md_mbuf *);
-
-static int              md_buf_putchar(struct md_mbuf *, char);
-static int              md_buf_puts(struct md_mbuf *, 
-                               const char *, size_t);
+static void             msg_msg(void *, int, int, const char *);
+static int              msg_err(void *, int, int, const char *);
+static int              msg_warn(void *, int, int, 
+                               enum mdoc_warn, const char *);
 
+#ifdef __linux__
+extern int              getsubopt(char **, char *const *, char **);
+#endif
 
 int
 main(int argc, char *argv[])
 {
        int              c;
-       char            *out, *in;
+       struct md_parse  parser;
+       char            *opts, *v;
+#define ALL             0
+#define COMPAT          1
+#define SYNTAX          2
+#define ERROR           3
+       char            *toks[] = { "all", "compat", "syntax", 
+                                   "error", NULL };
 
        extern char     *optarg;
        extern int       optind;
 
-       out = NULL;
-       
-       while (-1 != (c = getopt(argc, argv, "o:")))
+       (void)memset(&parser, 0, sizeof(struct md_parse));
+
+       while (-1 != (c = getopt(argc, argv, "vW:")))
                switch (c) {
-               case ('o'):
-                       out = optarg;
+               case ('v'):
+                       parser.dbg++;
+                       break;
+               case ('W'):
+                       opts = optarg;
+                       while (*opts) 
+                               switch (getsubopt(&opts, toks, &v)) {
+                               case (ALL):
+                                       parser.warn |= MD_WARN_ALL;
+                                       break;
+                               case (COMPAT):
+                                       parser.warn |= MD_WARN_COMPAT;
+                                       break;
+                               case (SYNTAX):
+                                       parser.warn |= MD_WARN_SYNTAX;
+                                       break;
+                               case (ERROR):
+                                       parser.warn |= MD_WARN_ERR;
+                                       break;
+                               default:
+                                       usage();
+                                       return(1);
+                               }
                        break;
                default:
                        usage();
@@ -86,276 +120,274 @@ main(int argc, char *argv[])
                }
 
        argv += optind;
-       if (1 != (argc -= optind)) {
-               usage();
-               return(1);
-       }
+       argc -= optind;
 
-       argc--;
-       in = *argv++;
+       parser.name = "-";
+       if (1 == argc)
+               parser.name = *argv++;
 
-       return(md_begin(out, in));
+       if ( ! io_begin(&parser))
+               return(EXIT_FAILURE);
+
+       return(EXIT_SUCCESS);
 }
 
 
 static int
-md_begin(const char *out, const char *in)
+io_leave(struct md_parse *p, int code)
 {
-       char             buf[MAXPATHLEN];
-
-       assert(in);
-       if (out)
-               return(md_begin_io(out, in));
 
-       if (strlcpy(buf, in, MAXPATHLEN) >= MAXPATHLEN)
-               warnx("output filename too long");
-       else if (strlcat(buf, ".html", MAXPATHLEN) >= MAXPATHLEN)
-               warnx("output filename too long");
-       else 
-               return(md_begin_io(buf, in));
+       if (-1 == p->fd || STDIN_FILENO == p->fd)
+               return(code);
 
-       return(1);
+       if (-1 == close(p->fd)) {
+               warn("%s", p->name);
+               code = 0;
+       }
+       return(code);
 }
 
 
 static int
-md_begin_io(const char *out, const char *in)
+io_begin(struct md_parse *p)
 {
-       int              c;
-       struct md_file   fin, fout;
 
-       assert(out);
-       assert(in);
+       p->fd = STDIN_FILENO;
+       if (0 != strncmp(p->name, "-", 1))
+               if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
+                       warn("%s", p->name);
+                       return(io_leave(p, 0));
+               }
+
+       return(io_leave(p, buf_begin(p)));
+}
 
-       /* TODO: accept "-" as both input and output. */
 
-       fin.name = in;
+static int
+buf_leave(struct md_parse *p, int code)
+{
 
-       if (-1 == (fin.fd = open(fin.name, O_RDONLY, 0))) {
-               warn("%s", fin.name);
-               return(1);
-       }
+       if (p->buf)
+               free(p->buf);
+       return(code);
+}
 
-       fout.name = out;
 
-       fout.fd = open(fout.name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-       if (-1 == fout.fd) {
-               warn("%s", fout.name);
-               if (-1 == close(fin.fd))
-                       warn("%s", fin.name);
+static int
+buf_begin(struct md_parse *p)
+{
+       struct stat      st;
+
+       if (-1 == fstat(p->fd, &st)) {
+               warn("%s", p->name);
                return(1);
-       }
+       } 
 
-       c = md_begin_bufs(&fout, &fin);
+       p->bufsz = MAX(st.st_blksize, BUFSIZ);
 
-       if (-1 == close(fin.fd)) {
-               warn("%s", in);
-               c = 1;
-       }
-       if (-1 == close(fout.fd)) {
-               warn("%s", out);
-               c = 1;
+       if (NULL == (p->buf = malloc(p->bufsz))) {
+               warn("malloc");
+               return(buf_leave(p, 0));
        }
 
-       return(c);
+       return(buf_leave(p, parse_begin(p)));
 }
 
 
-static int
-md_begin_bufs(struct md_file *out, struct md_file *in)
+/* TODO: remove this to a print-tree output filter. */
+static void
+print_node(const struct mdoc_node *n, int indent)
 {
-       struct stat      stin, stout;
-       struct md_buf    inbuf, outbuf;
-       int              c;
-
-       assert(in);
-       assert(out);
-
-       if (-1 == fstat(in->fd, &stin)) {
-               warn("fstat: %s", in->name);
-               return(1);
-       } else if (-1 == fstat(out->fd, &stout)) {
-               warn("fstat: %s", out->name);
-               return(1);
+       const char       *p, *t;
+       int               i, j;
+       size_t            argc, sz;
+       char            **params;
+       struct mdoc_arg  *argv;
+
+       argv = NULL;
+       argc = sz = 0;
+       params = NULL;
+
+       t = mdoc_type2a(n->type);
+
+       switch (n->type) {
+       case (MDOC_TEXT):
+               p = n->data.text.string;
+               break;
+       case (MDOC_BODY):
+               p = mdoc_macronames[n->tok];
+               break;
+       case (MDOC_HEAD):
+               p = mdoc_macronames[n->tok];
+               break;
+       case (MDOC_TAIL):
+               p = mdoc_macronames[n->tok];
+               break;
+       case (MDOC_ELEM):
+               p = mdoc_macronames[n->tok];
+               argv = n->data.elem.argv;
+               argc = n->data.elem.argc;
+               break;
+       case (MDOC_BLOCK):
+               p = mdoc_macronames[n->tok];
+               argv = n->data.block.argv;
+               argc = n->data.block.argc;
+               break;
+       case (MDOC_ROOT):
+               p = "root";
+               break;
+       default:
+               abort();
+               /* NOTREACHED */
        }
 
-       inbuf.file = in;
-       inbuf.line = 1;
-       /*inbuf.bufsz = MAX(stin.st_blksize, BUFSIZ);*/
-       inbuf.bufsz = 256;
-
-       outbuf.file = out;
-       outbuf.line = 1;
-       /*outbuf.bufsz = MAX(stout.st_blksize, BUFSIZ);*/
-       outbuf.bufsz = 256;
-
-       if (NULL == (inbuf.buf = malloc(inbuf.bufsz))) {
-               warn("malloc");
-               return(1);
-       } else if (NULL == (outbuf.buf = malloc(outbuf.bufsz))) {
-               warn("malloc");
-               free(inbuf.buf);
-               return(1);
+       for (i = 0; i < indent; i++)
+               xprintf("    ");
+       xprintf("%s (%s)", p, t);
+
+       for (i = 0; i < (int)argc; i++) {
+               xprintf(" -%s", mdoc_argnames[argv[i].arg]);
+               if (argv[i].sz > 0)
+                       xprintf(" [");
+               for (j = 0; j < (int)argv[i].sz; j++)
+                       xprintf(" [%s]", argv[i].value[j]);
+               if (argv[i].sz > 0)
+                       xprintf(" ]");
        }
 
-       c = md_run(&outbuf, &inbuf);
+       for (i = 0; i < (int)sz; i++)
+               xprintf(" [%s]", params[i]);
 
-       free(inbuf.buf);
-       free(outbuf.buf);
+       xprintf(" %d:%d\n", n->line, n->pos);
 
-       return(c);
+       if (n->child)
+               print_node(n->child, indent + 1);
+       if (n->next)
+               print_node(n->next, indent);
 }
 
 
-static ssize_t
-md_buf_fill(struct md_buf *in)
+static int
+parse_leave(struct md_parse *p, int code)
 {
-       ssize_t          ssz;
+       const struct mdoc_node *n;
 
-       assert(in);
-       assert(in->file);
-       assert(in->buf);
-       assert(in->bufsz > 0);
-       assert(in->file->name);
+       if (NULL == p->mdoc)
+               return(code);
 
-       if (-1 == (ssz = read(in->file->fd, in->buf, in->bufsz))) 
-               warn("%s", in->file->name);
-       else
-               (void)printf("%s: filled %zd bytes\n",
-                               in->file->name, ssz);
+       if ( ! mdoc_endparse(p->mdoc))
+               code = 0;
+       if ((n = mdoc_result(p->mdoc)))
+               print_node(n, 0);
 
-       return(ssz);
+       mdoc_free(p->mdoc);
+
+       return(code);
 }
 
 
 static int
-md_run(struct md_buf *out, struct md_buf *in)
+parse_begin(struct md_parse *p)
 {
-       struct md_mbuf   mbuf;
        ssize_t          sz, i;
-       char             line[BUFSIZ];
        size_t           pos;
-
-       assert(in);
-       assert(out); 
-
-       mbuf.buf = out;
-       mbuf.pos = 0;
-
-       /* LINTED */
-       for (pos = 0; ; ) {
-               if (-1 == (sz = md_buf_fill(in)))
-                       return(1);
-               else if (0 == sz)
+       char             line[MD_LINE_SZ];
+       struct mdoc_cb   cb;
+       int              lnn;
+
+       cb.mdoc_err = msg_err;
+       cb.mdoc_warn = msg_warn;
+       cb.mdoc_msg = msg_msg;
+
+       if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
+               return(parse_leave(p, 0));
+
+       for (lnn = 1, pos = 0; ; ) {
+               if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
+                       warn("%s", p->name);
+                       return(parse_leave(p, 0));
+               } else if (0 == sz) 
                        break;
 
                for (i = 0; i < sz; i++) {
-                       if ('\n' == in->buf[i]) {
-                               if (md_line(&mbuf, in, line, pos))
-                                       return(1);
-                               in->line++;
-                               pos = 0;
-                               continue;
-                       }
-
-                       if (pos < BUFSIZ) {
-                               /* LINTED */
-                               line[pos++] = in->buf[i];
-                               continue;
+                       if ('\n' != p->buf[i]) {
+                               if (pos < sizeof(line)) {
+                                       line[(int)pos++] = p->buf[(int)i];
+                                       continue;
+                               }
+                               warnx("%s: line %d too long", 
+                                               p->name, lnn);
+                               return(parse_leave(p, 0));
                        }
+       
+                       line[(int)pos] = 0;
+                       if ( ! mdoc_parseln(p->mdoc, lnn, line))
+                               return(parse_leave(p, 0));
 
-                       warnx("%s: line %zu too long",
-                                       in->file->name, in->line);
-                       return(1);
+                       lnn++;
+                       pos = 0;
                }
        }
 
-       if (0 != pos && md_line(&mbuf, in, line, pos))
-               return(1);
-
-       return(md_buf_flush(&mbuf) ? 0 : 1);
+       return(parse_leave(p, 1));
 }
 
 
 static int
-md_buf_flush(struct md_mbuf *buf)
+msg_err(void *arg, int line, int col, const char *msg)
 {
-       ssize_t          sz;
-
-       assert(buf);
-       assert(buf->buf);
-       assert(buf->buf->file);
-       assert(buf->buf->buf);
-       assert(buf->buf->file->name);
+       struct md_parse  *p;
 
-       (void)printf("%s: flushing %zu bytes\n",
-                       buf->buf->file->name, buf->pos);
-
-       if (0 == buf->pos)
-               return(1);
+       p = (struct md_parse *)arg;
 
-       sz = write(buf->buf->file->fd, buf->buf->buf, buf->pos);
-
-       if (-1 == sz) {
-               warn("%s", buf->buf->file->name);
-               return(0);
-       } else if ((size_t)sz != buf->pos) {
-               warnx("%s: short write", buf->buf->file->name);
-               return(0);
-       }
-
-       buf->pos = 0;
-       return(1);
-}
-
-
-static int
-md_buf_putchar(struct md_mbuf *buf, char c)
-{
-       return(md_buf_puts(buf, &c, 1));
+       xfprintf(stderr, "%s:%d: error: %s (column %d)\n", 
+                       p->name, line, msg, col);
+       return(0);
 }
 
 
-static int
-md_buf_puts(struct md_mbuf *buf, const char *p, size_t sz)
+static void
+msg_msg(void *arg, int line, int col, const char *msg)
 {
-       size_t           ssz;
-
-       assert(p);
-       assert(buf);
-       assert(buf->buf);
+       struct md_parse  *p;
 
-       while (buf->pos + sz > buf->buf->bufsz) {
-               ssz = buf->buf->bufsz - buf->pos;
-               (void)memcpy(buf->buf->buf + buf->pos, p, ssz);
-               p += ssz;
-               sz -= ssz;
-               buf->pos += ssz;
+       p = (struct md_parse *)arg;
 
-               if ( ! md_buf_flush(buf))
-                       return(0);
-       }
+       if (0 == p->dbg)
+               return;
 
-       (void)memcpy(buf->buf->buf + buf->pos, p, sz);
-       buf->pos += sz;
-       return(1);
+       xfprintf(stderr, "%s:%d: debug: %s (column %d)\n", 
+                       p->name, line, msg, col);
 }
 
 
 static int
-md_line(struct md_mbuf *out, const struct md_buf *in,
-               const char *buf, size_t sz)
+msg_warn(void *arg, int line, int col, 
+               enum mdoc_warn type, const char *msg)
 {
+       struct md_parse  *p;
 
-       assert(buf);
-       assert(out);
-       assert(in);
+       p = (struct md_parse *)arg;
 
-       if ( ! md_buf_puts(out, buf, sz))
+       switch (type) {
+       case (WARN_COMPAT):
+               if (p->warn & MD_WARN_COMPAT)
+                       break;
+               return(1);
+       case (WARN_SYNTAX):
+               if (p->warn & MD_WARN_SYNTAX)
+                       break;
                return(1);
-       if ( ! md_buf_putchar(out, '\n'))
+       }
+
+       xfprintf(stderr, "%s:%d: warning: %s (column %d)\n", 
+                       p->name, line, msg, col);
+
+       if ( ! (p->warn & MD_WARN_ERR))
                return(1);
 
+       xfprintf(stderr, "%s: considering warnings as errors\n", 
+                       __progname);
        return(0);
 }
 
@@ -363,7 +395,8 @@ md_line(struct md_mbuf *out, const struct md_buf *in,
 static void
 usage(void)
 {
-       extern char     *__progname;
 
-       (void)printf("usage: %s [-o outfile] infile\n", __progname);
+       xfprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
+                       __progname);
 }
+