summaryrefslogtreecommitdiffstatshomepage
path: root/xml.c
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2008-11-30 21:41:35 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2008-11-30 21:41:35 +0000
commitaf732c7fcc695182a667f1fabbd56d93896ad2f4 (patch)
tree031c3d2525311ea23f66d5da2cfd30d8c0c29137 /xml.c
parent5fe81f4208926eadeabb2221d96e8453443a3bc7 (diff)
downloadmandoc-af732c7fcc695182a667f1fabbd56d93896ad2f4.tar.gz
mandoc-af732c7fcc695182a667f1fabbd56d93896ad2f4.tar.zst
mandoc-af732c7fcc695182a667f1fabbd56d93896ad2f4.zip
Preliminary xml output filter (validate-renamed) done.
Diffstat (limited to 'xml.c')
-rw-r--r--xml.c502
1 files changed, 502 insertions, 0 deletions
diff --git a/xml.c b/xml.c
new file mode 100644
index 00000000..2e87ae44
--- /dev/null
+++ b/xml.c
@@ -0,0 +1,502 @@
+/* $Id: xml.c,v 1.1 2008/11/30 21:41:35 kristaps Exp $ */
+/*
+ * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
+ *
+ * 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 <sys/param.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libmdocml.h"
+#include "private.h"
+
+#define INDENT 4
+#define COLUMNS 60
+
+#ifdef __linux__ /* FIXME */
+#define strlcat strncat
+#endif
+
+enum md_tok {
+ MD_BLKIN,
+ MD_BLKOUT,
+ MD_IN,
+ MD_OUT,
+ MD_TEXT
+};
+
+struct md_xml {
+ const struct md_args *args;
+ const struct md_rbuf *rbuf;
+
+ struct md_mbuf *mbuf;
+ struct rofftree *tree;
+ size_t indent;
+ size_t pos;
+ enum md_tok last;
+ int flags;
+#define MD_LITERAL (1 << 0) /* FIXME */
+};
+
+static void roffmsg(void *arg, enum roffmsg,
+ const char *, const char *, char *);
+static int roffhead(void *);
+static int rofftail(void *);
+static int roffin(void *, int, int *, char **);
+static int roffdata(void *, int, char *);
+static int roffout(void *, int);
+static int roffblkin(void *, int, int *, char **);
+static int roffblkout(void *, int);
+static int roffspecial(void *, int);
+
+static int mbuf_newline(struct md_xml *);
+static int mbuf_indent(struct md_xml *);
+static int mbuf_data(struct md_xml *, int, char *);
+static int mbuf_putstring(struct md_xml *,
+ const char *);
+static int mbuf_nputstring(struct md_xml *,
+ const char *, size_t);
+
+
+static int
+mbuf_putstring(struct md_xml *p, const char *buf)
+{
+
+ return(mbuf_nputstring(p, buf, strlen(buf)));
+}
+
+
+static int
+mbuf_nputstring(struct md_xml *p, const char *buf, size_t sz)
+{
+
+ p->pos += sz;
+ return(md_buf_puts(p->mbuf, buf, sz));
+}
+
+
+static int
+mbuf_indent(struct md_xml *p)
+{
+ size_t i;
+
+ assert(p->pos == 0);
+
+ /* LINTED */
+ for (i = 0; i < MIN(p->indent, INDENT); i++)
+ if ( ! md_buf_putstring(p->mbuf, " "))
+ return(0);
+
+ p->pos += i * INDENT;
+ return(1);
+}
+
+
+static int
+mbuf_newline(struct md_xml *p)
+{
+
+ if ( ! md_buf_putchar(p->mbuf, '\n'))
+ return(0);
+
+ p->pos = 0;
+ return(1);
+}
+
+
+static int
+mbuf_data(struct md_xml *p, int space, char *buf)
+{
+ size_t sz;
+ char *bufp;
+
+ assert(p->mbuf);
+ assert(0 != p->indent);
+
+ if (MD_LITERAL & p->flags)
+ return(mbuf_putstring(p, buf));
+
+ while (*buf) {
+ while (*buf && isspace(*buf))
+ buf++;
+
+ if (0 == *buf)
+ break;
+
+ bufp = buf;
+ while (*buf && ! isspace(*buf))
+ buf++;
+
+ if (0 != *buf)
+ *buf++ = 0;
+
+ sz = strlen(bufp);
+
+ if (0 == p->pos) {
+ if ( ! mbuf_indent(p))
+ return(0);
+ if ( ! mbuf_nputstring(p, bufp, sz))
+ return(0);
+ if (p->indent * INDENT + sz >= COLUMNS) {
+ if ( ! mbuf_newline(p))
+ return(0);
+ continue;
+ }
+ continue;
+ }
+
+ if (space && sz + p->pos >= COLUMNS) {
+ if ( ! mbuf_newline(p))
+ return(0);
+ if ( ! mbuf_indent(p))
+ return(0);
+ } else if (space) {
+ if ( ! mbuf_nputstring(p, " ", 1))
+ return(0);
+ }
+
+ if ( ! mbuf_nputstring(p, bufp, sz))
+ return(0);
+
+ if ( ! space && p->pos >= COLUMNS)
+ if ( ! mbuf_newline(p))
+ return(0);
+ }
+
+ return(1);
+}
+
+
+int
+md_line_xml(void *arg, char *buf)
+{
+ struct md_xml *p;
+
+ p = (struct md_xml *)arg;
+ return(roff_engine(p->tree, buf));
+}
+
+
+int
+md_exit_xml(void *data, int flush)
+{
+ int c;
+ struct md_xml *p;
+
+ p = (struct md_xml *)data;
+ c = roff_free(p->tree, flush);
+ free(p);
+
+ return(c);
+}
+
+
+void *
+md_init_xml(const struct md_args *args,
+ struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
+{
+ struct roffcb cb;
+ struct md_xml *p;
+
+ cb.roffhead = roffhead;
+ cb.rofftail = rofftail;
+ cb.roffin = roffin;
+ cb.roffout = roffout;
+ cb.roffblkin = roffblkin;
+ cb.roffblkout = roffblkout;
+ cb.roffspecial = roffspecial;
+ cb.roffmsg = roffmsg;
+ cb.roffdata = roffdata;
+
+ if (NULL == (p = calloc(1, sizeof(struct md_xml))))
+ err(1, "malloc");
+
+ p->args = args;
+ p->mbuf = mbuf;
+ p->rbuf = rbuf;
+
+ assert(mbuf);
+
+ if (NULL == (p->tree = roff_alloc(&cb, p))) {
+ free(p);
+ return(NULL);
+ }
+
+ return(p);
+}
+
+
+/* ARGSUSED */
+static int
+roffhead(void *arg)
+{
+ struct md_xml *p;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+
+ if ( ! mbuf_putstring(p, "<?xml version=\"1.0\" "
+ "encoding=\"UTF-8\"?>\n"))
+ return(0);
+ if ( ! mbuf_nputstring(p, "<block:mdoc>", 12))
+ return(0);
+
+ p->indent++;
+ p->last = MD_BLKIN;
+ return(mbuf_newline(p));
+}
+
+
+static int
+rofftail(void *arg)
+{
+ struct md_xml *p;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+
+ if (0 != p->pos && ! mbuf_newline(p))
+ return(0);
+
+ if ( ! mbuf_nputstring(p, "</block:mdoc>", 13))
+ return(0);
+
+ p->last = MD_BLKOUT;
+ return(mbuf_newline(p));
+}
+
+
+/* ARGSUSED */
+static int
+roffspecial(void *arg, int tok)
+{
+
+ /* FIXME */
+ return(1);
+}
+
+
+static int
+roffblkin(void *arg, int tok, int *argc, char **argv)
+{
+ struct md_xml *p;
+ int i;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+
+ if (0 != p->pos) {
+ if ( ! mbuf_newline(p))
+ return(0);
+ if ( ! mbuf_indent(p))
+ return(0);
+ } else if ( ! mbuf_indent(p))
+ return(0);
+
+ if ( ! mbuf_nputstring(p, "<", 1))
+ return(0);
+ if ( ! mbuf_nputstring(p, "block:", 6))
+ return(0);
+ if ( ! mbuf_putstring(p, toknames[tok]))
+ return(0);
+
+ for (i = 0; ROFF_ARGMAX != argc[i]; i++) {
+ if ( ! mbuf_nputstring(p, " ", 1))
+ return(0);
+ if ( ! mbuf_putstring(p, tokargnames[argc[i]]))
+ return(0);
+ if ( ! mbuf_nputstring(p, "=\"", 2))
+ return(0);
+ if ( ! mbuf_putstring(p, argv[i] ? argv[i] : "true"))
+ return(0);
+ if ( ! mbuf_nputstring(p, "\"", 1))
+ return(0);
+ }
+
+ if ( ! mbuf_nputstring(p, ">", 1))
+ return(0);
+
+ p->last = MD_BLKIN;
+ p->indent++;
+ return(mbuf_newline(p));
+}
+
+
+static int
+roffblkout(void *arg, int tok)
+{
+ struct md_xml *p;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+
+ p->indent--;
+
+ if (0 != p->pos) {
+ if ( ! mbuf_newline(p))
+ return(0);
+ if ( ! mbuf_indent(p))
+ return(0);
+ } else if ( ! mbuf_indent(p))
+ return(0);
+
+ if ( ! mbuf_nputstring(p, "</", 2))
+ return(0);
+ if ( ! mbuf_nputstring(p, "block:", 6))
+ return(0);
+ if ( ! mbuf_putstring(p, toknames[tok]))
+ return(0);
+ if ( ! mbuf_nputstring(p, ">", 1))
+ return(0);
+
+ p->last = MD_BLKOUT;
+ return(mbuf_newline(p));
+}
+
+
+static int
+roffin(void *arg, int tok, int *argc, char **argv)
+{
+ struct md_xml *p;
+ int i;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+
+ /*
+ * FIXME: put all of this in a buffer, then check the buffer
+ * length versus the column width for nicer output. This is a
+ * bit hacky.
+ */
+
+ if (p->pos + 11 > COLUMNS)
+ if ( ! mbuf_newline(p))
+ return(0);
+
+ if (0 != p->pos) {
+ switch (p->last) {
+ case (MD_TEXT):
+ /* FALLTHROUGH */
+ case (MD_OUT):
+ if ( ! mbuf_nputstring(p, " ", 1))
+ return(0);
+ break;
+ default:
+ break;
+ }
+ } else if ( ! mbuf_indent(p))
+ return(0);
+
+ p->last = MD_IN;
+
+ if ( ! mbuf_nputstring(p, "<", 1))
+ return(0);
+ if ( ! mbuf_nputstring(p, "inline:", 7))
+ return(0);
+ if ( ! mbuf_putstring(p, toknames[tok]))
+ return(0);
+
+ for (i = 0; ROFF_ARGMAX != argc[i]; i++) {
+ if ( ! mbuf_nputstring(p, " ", 1))
+ return(0);
+ if ( ! mbuf_putstring(p, tokargnames[argc[i]]))
+ return(0);
+ if ( ! mbuf_nputstring(p, "=\"", 2))
+ return(0);
+ if ( ! mbuf_putstring(p, argv[i] ? argv[i] : "true"))
+ return(0);
+ if ( ! mbuf_nputstring(p, "\"", 1))
+ return(0);
+ }
+ return(mbuf_nputstring(p, ">", 1));
+}
+
+
+static int
+roffout(void *arg, int tok)
+{
+ struct md_xml *p;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+
+ if (0 == p->pos && ! mbuf_indent(p))
+ return(0);
+
+ p->last = MD_OUT;
+
+ if ( ! mbuf_nputstring(p, "</", 2))
+ return(0);
+ if ( ! mbuf_nputstring(p, "inline:", 7))
+ return(0);
+ if ( ! mbuf_putstring(p, toknames[tok]))
+ return(0);
+ return(mbuf_nputstring(p, ">", 1));
+}
+
+
+static void
+roffmsg(void *arg, enum roffmsg lvl,
+ const char *buf, const char *pos, char *msg)
+{
+ char *level;
+ struct md_xml *p;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+
+ switch (lvl) {
+ case (ROFF_WARN):
+ if ( ! (MD_WARN_ALL & p->args->warnings))
+ return;
+ level = "warning";
+ break;
+ case (ROFF_ERROR):
+ level = "error";
+ break;
+ default:
+ abort();
+ }
+
+ if (pos)
+ (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
+ p->rbuf->name, p->rbuf->line, level,
+ msg, pos - buf);
+ else
+ (void)fprintf(stderr, "%s: %s: %s\n",
+ p->rbuf->name, level, msg);
+
+}
+
+
+static int
+roffdata(void *arg, int space, char *buf)
+{
+ struct md_xml *p;
+
+ assert(arg);
+ p = (struct md_xml *)arg;
+ if ( ! mbuf_data(p, space, buf))
+ return(0);
+
+ p->last = MD_TEXT;
+ return(1);
+}