-/* $Id: xml.c,v 1.4 2008/12/01 15:32:36 kristaps Exp $ */
+/* $Id: xml.c,v 1.20 2008/12/08 12:46:28 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 <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,
- MD_OVERRIDE
-};
-
-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 *,
+#include "ml.h"
+
+
+static int xml_alloc(void **);
+static void xml_free(void *);
+static ssize_t xml_endtag(struct md_mbuf *, void *,
+ const struct md_args *,
+ enum md_ns, int);
+static ssize_t xml_begintag(struct md_mbuf *, void *,
+ const struct md_args *,
+ enum md_ns, int,
+ const int *, const char **);
+static ssize_t xml_beginstring(struct md_mbuf *,
+ const struct md_args *,
const char *, size_t);
-static int mbuf_puts(struct md_xml *, const char *);
-static int mbuf_nputs(struct md_xml *,
+static ssize_t xml_endstring(struct md_mbuf *,
+ const struct md_args *,
const char *, size_t);
+static int xml_begin(struct md_mbuf *,
+ const struct md_args *,
+ const struct tm *,
+ const char *, const char *,
+ enum roffmsec, const char *);
+static int xml_end(struct md_mbuf *,
+ const struct md_args *);
+static ssize_t xml_printtagname(struct md_mbuf *,
+ enum md_ns, int);
+static ssize_t xml_printtagargs(struct md_mbuf *,
+ const int *, const char **);
-static int
-mbuf_putstring(struct md_xml *p, const char *buf)
+static ssize_t
+xml_printtagargs(struct md_mbuf *mbuf, const int *argc,
+ const char **argv)
{
+ int i, c;
+ size_t res;
- return(mbuf_nputstring(p, buf, strlen(buf)));
-}
-
+ if (NULL == argc || NULL == argv)
+ return(0);
+ assert(argc && argv);
-static int
-mbuf_nputstring(struct md_xml *p, const char *buf, size_t sz)
-{
- size_t i;
-
- for (i = 0; i < sz; i++) {
- switch (buf[i]) {
- case ('&'):
- if ( ! md_buf_puts(p->mbuf, "&", 5))
- return(0);
- p->pos += 5;
- break;
- case ('"'):
- if ( ! md_buf_puts(p->mbuf, """, 6))
- return(0);
- p->pos += 6;
- break;
- default:
- if ( ! md_buf_putchar(p->mbuf, buf[i]))
- return(0);
- p->pos++;
- break;
- }
+ /* LINTED */
+ for (res = 0, i = 0; ROFF_ARGMAX != (c = argc[i]); i++) {
+ if ( ! ml_nputs(mbuf, " ", 1, &res))
+ return(-1);
+
+ if ( ! ml_puts(mbuf, tokargnames[c], &res))
+ return(-1);
+ if ( ! ml_nputs(mbuf, "=\"", 2, &res))
+ return(-1);
+ if (argv[i]) {
+ if ( ! ml_putstring(mbuf, argv[i], &res))
+ return(-1);
+ } else if ( ! ml_nputs(mbuf, "true", 4, &res))
+ return(-1);
+ if ( ! ml_nputs(mbuf, "\"", 1, &res))
+ return(-1);
}
- return(1);
-}
-
-
-static int
-mbuf_nputs(struct md_xml *p, const char *buf, size_t sz)
-{
- p->pos += sz;
- return(md_buf_puts(p->mbuf, buf, sz));
+ return((ssize_t)res);
}
-static int
-mbuf_puts(struct md_xml *p, const char *buf)
+static ssize_t
+xml_printtagname(struct md_mbuf *mbuf, enum md_ns ns, int tok)
{
+ size_t res;
- return(mbuf_nputs(p, buf, strlen(buf)));
-}
-
-
-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);
+ res = 0;
+ switch (ns) {
+ case (MD_NS_BLOCK):
+ if ( ! ml_nputs(mbuf, "block:", 6, &res))
+ return(-1);
+ break;
+ case (MD_NS_INLINE):
+ if ( ! ml_nputs(mbuf, "inline:", 7, &res))
+ return(-1);
+ break;
+ case (MD_NS_BODY):
+ if ( ! ml_nputs(mbuf, "body:", 5, &res))
+ return(-1);
+ break;
+ case (MD_NS_HEAD):
+ if ( ! ml_nputs(mbuf, "head:", 5, &res))
+ return(-1);
+ break;
+ default:
+ break;
+ }
- p->pos += i * INDENT;
- return(1);
+ if ( ! ml_puts(mbuf, toknames[tok], &res))
+ return(-1);
+ return((ssize_t)res);
}
-static int
-mbuf_newline(struct md_xml *p)
+/* ARGSUSED */
+static int
+xml_begin(struct md_mbuf *mbuf, const struct md_args *args,
+ const struct tm *tm, const char *os,
+ const char *title, enum roffmsec section,
+ const char *vol)
{
- if ( ! md_buf_putchar(p->mbuf, '\n'))
+ if ( ! ml_puts(mbuf, "<?xml version=\"1.0\" "
+ "encoding=\"UTF-8\"?>\n", NULL))
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_nputs(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);
+ return(ml_puts(mbuf, "<mdoc xmlns:block=\"block\" "
+ "xmlns:body=\"body\" "
+ "xmlns:head=\"head\" "
+ "xmlns:inline=\"inline\">", NULL));
}
-int
-md_line_xml(void *arg, char *buf)
+/* ARGSUSED */
+static int
+xml_end(struct md_mbuf *mbuf, const struct md_args *args)
{
- struct md_xml *p;
- p = (struct md_xml *)arg;
- return(roff_engine(p->tree, buf));
+ return(ml_puts(mbuf, "</mdoc>", NULL));
}
-int
-md_exit_xml(void *data, int flush)
+/* ARGSUSED */
+static ssize_t
+xml_beginstring(struct md_mbuf *mbuf,
+ const struct md_args *args,
+ const char *buf, size_t sz)
{
- int c;
- struct md_xml *p;
-
- p = (struct md_xml *)data;
- c = roff_free(p->tree, flush);
- free(p);
- return(c);
+ return(0);
}
-void *
-md_init_xml(const struct md_args *args,
- struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
+/* ARGSUSED */
+static ssize_t
+xml_endstring(struct md_mbuf *mbuf,
+ const struct md_args *args,
+ const char *buf, size_t sz)
{
- 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);
+ return(0);
}
/* ARGSUSED */
-static int
-roffhead(void *arg)
+static ssize_t
+xml_begintag(struct md_mbuf *mbuf, void *data,
+ const struct md_args *args, enum md_ns ns,
+ int tok, const int *argc, const char **argv)
{
- struct md_xml *p;
-
- assert(arg);
- p = (struct md_xml *)arg;
-
- if ( ! mbuf_puts(p, "<?xml version=\"1.0\" "
- "encoding=\"UTF-8\"?>\n"))
- return(0);
- if ( ! mbuf_puts(p, "<mdoc xmlns:block=\"block\" "
- "xmlns:special=\"special\" "
- "xmlns:inline=\"inline\">"))
- return(0);
+ ssize_t res, sz;
- p->indent++;
- p->last = MD_BLKIN;
- return(mbuf_newline(p));
+ if (-1 == (res = xml_printtagname(mbuf, ns, tok)))
+ return(-1);
+ if (-1 == (sz = xml_printtagargs(mbuf, argc, argv)))
+ return(-1);
+ return(res + sz);
}
-static int
-rofftail(void *arg)
+/* ARGSUSED */
+static ssize_t
+xml_endtag(struct md_mbuf *mbuf, void *data,
+ const struct md_args *args, enum md_ns ns, int tok)
{
- struct md_xml *p;
- assert(arg);
- p = (struct md_xml *)arg;
-
- if (0 != p->pos && ! mbuf_newline(p))
- return(0);
-
- if ( ! mbuf_puts(p, "</mdoc>"))
- return(0);
-
- p->last = MD_BLKOUT;
- return(mbuf_newline(p));
+ return(xml_printtagname(mbuf, ns, tok));
}
/* ARGSUSED */
-static int
-roffspecial(void *arg, int tok)
+int
+xml_alloc(void **p)
{
- struct md_xml *p;
-
- assert(arg);
- p = (struct md_xml *)arg;
-
- switch (tok) {
- case (ROFF_Ns):
- p->last = MD_OVERRIDE;
- break;
- default:
- break;
- }
+ *p = NULL;
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_nputs(p, "<", 1))
- return(0);
- if ( ! mbuf_nputs(p, "block:", 6))
- return(0);
- if ( ! mbuf_puts(p, toknames[tok]))
- return(0);
-
- /* FIXME: xml won't like standards args (e.g., p1003.1-90). */
-
- for (i = 0; ROFF_ARGMAX != argc[i]; i++) {
- if ( ! mbuf_nputs(p, " ", 1))
- return(0);
- if ( ! mbuf_puts(p, tokargnames[argc[i]]))
- return(0);
- if ( ! mbuf_nputs(p, "=\"", 2))
- return(0);
- if ( ! mbuf_putstring(p, argv[i] ? argv[i] : "true"))
- return(0);
- if ( ! mbuf_nputs(p, "\"", 1))
- return(0);
- }
-
- if ( ! mbuf_nputs(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_nputs(p, "</", 2))
- return(0);
- if ( ! mbuf_nputs(p, "block:", 6))
- return(0);
- if ( ! mbuf_puts(p, toknames[tok]))
- return(0);
- if ( ! mbuf_nputs(p, ">", 1))
- return(0);
-
- p->last = MD_BLKOUT;
- return(mbuf_newline(p));
-}
-
-
-static int
-roffin(void *arg, int tok, int *argc, char **argv)
+/* ARGSUSED */
+void
+xml_free(void *p)
{
- 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_nputs(p, " ", 1))
- return(0);
- break;
- default:
- break;
- }
- } else if ( ! mbuf_indent(p))
- return(0);
-
- p->last = MD_IN;
-
- if ( ! mbuf_nputs(p, "<", 1))
- return(0);
- if ( ! mbuf_nputs(p, "inline:", 7))
- return(0);
- if ( ! mbuf_puts(p, toknames[tok]))
- return(0);
- for (i = 0; ROFF_ARGMAX != argc[i]; i++) {
- if ( ! mbuf_nputs(p, " ", 1))
- return(0);
- if ( ! mbuf_puts(p, tokargnames[argc[i]]))
- return(0);
- if ( ! mbuf_nputs(p, "=\"", 2))
- return(0);
- if ( ! mbuf_putstring(p, argv[i] ? argv[i] : "true"))
- return(0);
- if ( ! mbuf_nputs(p, "\"", 1))
- return(0);
- }
- return(mbuf_nputs(p, ">", 1));
+ /* Do nothing. */
}
-static int
-roffout(void *arg, int tok)
+int
+md_line_xml(void *data, char *buf)
{
- struct md_xml *p;
-
- assert(arg);
- p = (struct md_xml *)arg;
- /* Continue with a regular out token. */
-
- if (0 == p->pos && ! mbuf_indent(p))
- return(0);
-
- p->last = MD_OUT;
-
- if ( ! mbuf_nputs(p, "</", 2))
- return(0);
- if ( ! mbuf_nputs(p, "inline:", 7))
- return(0);
- if ( ! mbuf_puts(p, toknames[tok]))
- return(0);
- return(mbuf_nputs(p, ">", 1));
+ return(mlg_line((struct md_mlg *)data, buf));
}
-static void
-roffmsg(void *arg, enum roffmsg lvl,
- const char *buf, const char *pos, char *msg)
+int
+md_exit_xml(void *data, int flush)
{
- 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);
+ return(mlg_exit((struct md_mlg *)data, flush));
}
-static int
-roffdata(void *arg, int space, char *buf)
+void *
+md_init_xml(const struct md_args *args,
+ struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
{
- struct md_xml *p;
+ struct ml_cbs cbs;
- assert(arg);
- p = (struct md_xml *)arg;
- if ( ! mbuf_data(p, space, buf))
- return(0);
+ cbs.ml_alloc = xml_alloc;
+ cbs.ml_free = xml_free;
+ cbs.ml_begintag = xml_begintag;
+ cbs.ml_endtag = xml_endtag;
+ cbs.ml_begin = xml_begin;
+ cbs.ml_end = xml_end;
+ cbs.ml_beginstring = xml_beginstring;
+ cbs.ml_endstring = xml_endstring;
- p->last = MD_TEXT;
- return(1);
+ return(mlg_alloc(args, rbuf, mbuf, &cbs));
}