summaryrefslogtreecommitdiffstatshomepage
path: root/mdocml.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdocml.c')
-rw-r--r--mdocml.c463
1 files changed, 310 insertions, 153 deletions
diff --git a/mdocml.c b/mdocml.c
index 3198b4b6..f5440b8f 100644
--- a/mdocml.c
+++ b/mdocml.c
@@ -1,4 +1,4 @@
-/* $Id: mdocml.c,v 1.20 2008/12/10 14:42:46 kristaps Exp $ */
+/* $Id: mdocml.c,v 1.21 2008/12/15 01:54:58 kristaps Exp $ */
/*
* Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
*
@@ -16,39 +16,48 @@
* 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"
+#include "mdoc.h"
-#define BUFFER_IN_DEF BUFSIZ /* See begin_bufs. */
-#define BUFFER_OUT_DEF BUFSIZ /* See begin_bufs. */
+#define MD_LINE_SZ (256)
-#ifdef DEBUG
-#define CSS "mdocml.css"
-#else
-#define CSS "/usr/local/share/mdocml/mdocml.css"
-#endif
+struct md_parse {
+ int warn;
+#define MD_WARN_ALL (1 << 0)
+#define MD_WARN_ERR (1 << 1)
+ int dbg;
+ struct mdoc *mdoc;
+ char *buf;
+ u_long bufsz;
+ char *name;
+ int fd;
+ int lnn;
+ char *line;
+};
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);
+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 int msg_err(void *, int, int, enum mdoc_err);
+static int msg_warn(void *, int, int, enum mdoc_warn);
+static void msg_msg(void *, int, const char *);
#ifdef __linux__
extern int getsubopt(char **, char *const *, char **);
@@ -58,8 +67,8 @@ int
main(int argc, char *argv[])
{
int c;
- char *out, *in, *opts, *v;
- struct md_args args;
+ struct md_parse parser;
+ char *opts, *v;
#define ALL 0
#define ERROR 1
char *toks[] = { "all", "error", NULL };
@@ -67,49 +76,22 @@ main(int argc, char *argv[])
extern char *optarg;
extern int optind;
- out = in = NULL;
+ (void)memset(&parser, 0, sizeof(struct md_parse));
- (void)memset(&args, 0, sizeof(struct md_args));
-
- args.type = MD_NOOP;
-
- while (-1 != (c = getopt(argc, argv, "c:ef:o:vW:")))
+ while (-1 != (c = getopt(argc, argv, "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 if (0 == strcmp(optarg, "noop"))
- args.type = MD_NOOP;
- else
- errx(1, "invalid filter type");
- break;
- case ('o'):
- out = optarg;
- break;
case ('v'):
- args.verbosity++;
+ parser.dbg++;
break;
case ('W'):
opts = optarg;
while (*opts)
switch (getsubopt(&opts, toks, &v)) {
case (ALL):
- args.warnings |= MD_WARN_ALL;
+ parser.warn |= MD_WARN_ALL;
break;
case (ERROR):
- args.warnings |= MD_WARN_ERROR;
+ parser.warn |= MD_WARN_ERR;
break;
default:
usage();
@@ -121,148 +103,324 @@ main(int argc, char *argv[])
return(1);
}
- if (MD_HTML == args.type)
- if (NULL == args.params.html.css)
- args.params.html.css = CSS;
-
argv += optind;
argc -= optind;
+ parser.name = "-";
if (1 == argc)
- in = *argv++;
+ parser.name = *argv++;
+
+ if ( ! io_begin(&parser))
+ return(EXIT_FAILURE);
- return(begin_io(&args, out ? out : "-", in ? in : "-"));
+ return(EXIT_SUCCESS);
}
-/*
- * 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)
+io_leave(struct md_parse *p, int code)
{
- 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 == p->fd || STDIN_FILENO == p->fd)
+ return(code);
+
+ if (-1 == close(p->fd)) {
+ warn("%s", p->name);
+ code = 0;
}
- if (1 == c && STDOUT_FILENO != out->fd)
- if (-1 == unlink(out->name))
- warn("%s", out->name);
+ return(code);
+}
+
+
+static int
+io_begin(struct md_parse *p)
+{
+
+ 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(c);
+ return(io_leave(p, buf_begin(p)));
}
-/*
- * 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)
+buf_leave(struct md_parse *p, int code)
{
- struct md_buf fi;
- struct md_buf fo;
-#define FI_FL O_RDONLY
-#define FO_FL O_WRONLY|O_CREAT|O_TRUNC
+ if (p->buf)
+ free(p->buf);
+ return(code);
+}
- assert(args);
- assert(out);
- assert(in);
- bzero(&fi, sizeof(struct md_buf));
- bzero(&fo, sizeof(struct md_buf));
+static int
+buf_begin(struct md_parse *p)
+{
+ struct stat st;
- fi.fd = STDIN_FILENO;
- fo.fd = STDOUT_FILENO;
+ if (-1 == fstat(p->fd, &st)) {
+ warn("%s", p->name);
+ return(1);
+ }
- fi.name = in;
- fo.name = out;
+ p->bufsz = MAX(st.st_blksize, BUFSIZ);
- 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 (NULL == (p->buf = malloc(p->bufsz))) {
+ warn("malloc");
+ return(buf_leave(p, 0));
+ }
+
+ return(buf_leave(p, parse_begin(p)));
+}
+
+
+static void
+print_node(const struct mdoc_node *n, int indent)
+{
+ const char *p, *t;
+ int i;
+
+ switch (n->type) {
+ case (MDOC_TEXT):
+ assert(NULL == n->child);
+ p = "<text>";
+ t = "text";
+ break;
+ case (MDOC_BODY):
+ p = mdoc_macronames[n->data.body.tok];
+ t = "block-body";
+ break;
+ case (MDOC_HEAD):
+ p = mdoc_macronames[n->data.head.tok];
+ t = "block-head";
+ break;
+ case (MDOC_ELEM):
+ assert(NULL == n->child);
+ p = mdoc_macronames[n->data.elem.tok];
+ t = "element";
+ break;
+ case (MDOC_BLOCK):
+ p = mdoc_macronames[n->data.block.tok];
+ t = "block";
+ break;
+ }
+
+ for (i = 0; i < indent; i++)
+ (void)printf(" ");
+ (void)printf("%s (%s)\n", p, t);
+
+ if (n->child)
+ print_node(n->child, indent + 1);
+ if (n->next)
+ print_node(n->next, indent);
+}
+
+
+static int
+parse_leave(struct md_parse *p, int code)
+{
+ const struct mdoc_node *n;
- 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));
+ if (p->mdoc) {
+ if ((n = mdoc_result(p->mdoc)))
+ print_node(n, 0);
+ mdoc_free(p->mdoc);
+ }
+ return(code);
+}
+
+
+static int
+parse_begin(struct md_parse *p)
+{
+ ssize_t sz, i;
+ size_t pos;
+ char line[256], sv[256];
+ struct mdoc_cb cb;
+
+ 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));
+
+ p->lnn = 1;
+ p->line = sv;
+
+ for (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' != p->buf[i]) {
+ if (pos < sizeof(line)) {
+ /* LINTED */
+ sv[pos] = p->buf[i];
+ line[pos++] = p->buf[i];
+ continue;
+ }
+ warnx("%s: line %d too long",
+ p->name, p->lnn);
+ return(parse_leave(p, 0));
+ }
+
+ line[(int)pos] = sv[(int)pos] = 0;
+ if ( ! mdoc_parseln(p->mdoc, line))
+ return(parse_leave(p, 0));
+
+ p->lnn++;
+ pos = 0;
}
+ }
- return(leave_io(&fo, &fi, begin_bufs(args, &fo, &fi)));
+ return(parse_leave(p, 1));
}
-/*
- * Free buffers allocated in begin_bufs.
- */
static int
-leave_bufs(const struct md_buf *out,
- const struct md_buf *in, int c)
+msg_err(void *arg, int tok, int col, enum mdoc_err type)
+{
+ char *fmt, *lit;
+ struct md_parse *p;
+ int i;
+
+ p = (struct md_parse *)arg;
+
+ fmt = lit = NULL;
+
+ switch (type) {
+ case (ERR_SYNTAX_QUOTE):
+ lit = "syntax: unterminated quotation";
+ break;
+ case (ERR_SYNTAX_WS):
+ lit = "syntax: whitespace in argument";
+ break;
+ case (ERR_SCOPE_BREAK):
+ /* Which scope is broken? */
+ fmt = "macro `%s' breaks prior explicit scope";
+ break;
+ case (ERR_MACRO_NOTSUP):
+ fmt = "macro `%s' not supported";
+ break;
+ case (ERR_MACRO_NOTCALL):
+ fmt = "macro `%s' not callable";
+ break;
+ case (ERR_ARGS_GE1):
+ fmt = "macro `%s' expects one or more arguments";
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+
+ if (fmt) {
+ (void)fprintf(stderr, "%s:%d: error: ",
+ p->name, p->lnn);
+ (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
+ } else
+ (void)fprintf(stderr, "%s:%d: error: %s",
+ p->name, p->lnn, lit);
+
+ if (p->dbg < 1) {
+ (void)fprintf(stderr, " (column %d)\n", col);
+ return(0);
+ }
+
+ (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
+ for (i = 0; i < col; i++)
+ (void)fprintf(stderr, " ");
+ (void)fprintf(stderr, "^\n");
+
+ return(0);
+}
+
+
+static void
+msg_msg(void *arg, int col, const char *msg)
{
- assert(out);
- assert(in);
- if (out->buf)
- free(out->buf);
- if (in->buf)
- free(in->buf);
- return(c);
+ struct md_parse *p;
+ int i;
+
+ p = (struct md_parse *)arg;
+
+ if (p->dbg < 2)
+ return;
+
+ (void)printf("%s:%d: %s", p->name, p->lnn, msg);
+
+ if (p->dbg < 3) {
+ (void)printf(" (column %d)\n", col);
+ return;
+ }
+
+ (void)printf("\nFrom: %s\n ", p->line);
+ for (i = 0; i < col; i++)
+ (void)printf(" ");
+ (void)printf("^\n");
}
-/*
- * 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)
+msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
{
- struct stat stin, stout;
- int c;
+ char *fmt, *lit;
+ struct md_parse *p;
+ int i;
+ extern char *__progname;
- assert(args);
- assert(in);
- assert(out);
+ p = (struct md_parse *)arg;
- 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);
+ if ( ! (p->warn & MD_WARN_ALL))
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);
+ fmt = lit = NULL;
+
+ switch (type) {
+ case (WARN_SYNTAX_WS_EOLN):
+ lit = "syntax: whitespace at end-of-line";
+ break;
+ case (WARN_SYNTAX_MACLIKE):
+ lit = "syntax: macro-like argument";
+ break;
+ case (WARN_ARGS_GE1):
+ fmt = "macro `%s' suggests one or more arguments";
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
- 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));
+ if (fmt) {
+ (void)fprintf(stderr, "%s:%d: warning: ",
+ p->name, p->lnn);
+ (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
+ } else
+ (void)fprintf(stderr, "%s:%d: warning: %s",
+ p->name, p->lnn, lit);
+
+ if (p->dbg >= 1) {
+ (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
+ for (i = 0; i < col; i++)
+ (void)fprintf(stderr, " ");
+ (void)fprintf(stderr, "^\n");
+ } else
+ (void)fprintf(stderr, " (column %d)\n", col);
+
+ if (p->warn & MD_WARN_ERR) {
+ (void)fprintf(stderr, "%s: considering warnings as "
+ "errors\n", __progname);
+ return(0);
}
- c = md_run(args, out, in);
- return(leave_bufs(out, in, -1 == c ? 1 : 0));
+ return(1);
}
@@ -271,8 +429,7 @@ usage(void)
{
extern char *__progname;
- (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] "
- "[-f filter] [-o outfile] [infile]\n",
+ (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
__progname);
}