-/* $Id: xml.c,v 1.5 2008/12/01 16:01:28 kristaps Exp $ */
+/* $Id: xml.c,v 1.13 2008/12/04 11:25:29 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"
+#include "ml.h"
-#define MAXINDENT 8
-#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 *,
- const char *, size_t);
-static int mbuf_puts(struct md_xml *, const char *);
-static int mbuf_nputs(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)
-{
- 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;
- }
- }
- 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));
-}
-
-
-static int
-mbuf_puts(struct md_xml *p, const char *buf)
-{
- 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, MAXINDENT); i++)
- if ( ! md_buf_putstring(p->mbuf, " "))
- return(0);
-
- p->pos += i * 4;
- 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 * MAXINDENT + 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);
-}
-
-
-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);
-}
+static ssize_t xml_endtag(struct md_mbuf *,
+ const struct md_args *,
+ enum md_ns, int);
+static ssize_t xml_begintag(struct md_mbuf *,
+ const struct md_args *,
+ enum md_ns, int,
+ const int *, const char **);
+static int xml_begin(struct md_mbuf *,
+ const struct md_args *,
+ const struct tm *,
+ const char *, const char *,
+ const char *, const char *);
+static int xml_end(struct md_mbuf *,
+ const struct md_args *);
/* ARGSUSED */
-static int
-roffhead(void *arg)
+static int
+xml_begin(struct md_mbuf *mbuf, const struct md_args *args,
+ const struct tm *tm, const char *os,
+ const char *title, const char *section,
+ const char *vol)
{
- struct md_xml *p;
+ size_t res;
- assert(arg);
- p = (struct md_xml *)arg;
-
- if ( ! mbuf_puts(p, "<?xml version=\"1.0\" "
- "encoding=\"UTF-8\"?>\n"))
+ if ( ! ml_puts(mbuf, "<?xml version=\"1.0\" "
+ "encoding=\"UTF-8\"?>\n", &res))
return(0);
- if ( ! mbuf_puts(p, "<mdoc xmlns:block=\"block\" "
+ if ( ! ml_puts(mbuf, "<mdoc xmlns:block=\"block\" "
"xmlns:special=\"special\" "
- "xmlns:inline=\"inline\">"))
+ "xmlns:inline=\"inline\">", &res))
return(0);
- p->indent++;
- p->last = MD_BLKIN;
- return(mbuf_newline(p));
+ return(1);
}
-static int
-rofftail(void *arg)
+/* ARGSUSED */
+static int
+xml_end(struct md_mbuf *mbuf, const struct md_args *args)
{
- struct md_xml *p;
-
- assert(arg);
- p = (struct md_xml *)arg;
+ size_t res;
- if (0 != p->pos && ! mbuf_newline(p))
+ res = 0;
+ if ( ! ml_puts(mbuf, "</mdoc>", &res))
return(0);
- if ( ! mbuf_puts(p, "</mdoc>"))
- return(0);
-
- p->last = MD_BLKOUT;
- return(mbuf_newline(p));
+ return(1);
}
/* ARGSUSED */
-static int
-roffspecial(void *arg, int tok)
+static ssize_t
+xml_begintag(struct md_mbuf *mbuf, const struct md_args *args,
+ enum md_ns ns, int tok,
+ const int *argc, const char **argv)
{
- struct md_xml *p;
+ size_t res;
- assert(arg);
- p = (struct md_xml *)arg;
+ res = 0;
- switch (tok) {
- case (ROFF_Ns):
- p->last = MD_OVERRIDE;
+ switch (ns) {
+ case (MD_NS_BLOCK):
+ if ( ! ml_nputs(mbuf, "block:", 6, &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;
+ case (MD_NS_INLINE):
+ if ( ! ml_nputs(mbuf, "inline:", 7, &res))
+ return(-1);
break;
default:
break;
}
- 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 ( ! ml_puts(mbuf, toknames[tok], &res))
+ return(-1);
- if ( ! mbuf_nputs(p, ">", 1))
- return(0);
-
- p->last = MD_BLKIN;
- p->indent++;
- return(mbuf_newline(p));
+ return((ssize_t)res);
}
-static int
-roffblkout(void *arg, int tok)
+/* ARGSUSED */
+static ssize_t
+xml_endtag(struct md_mbuf *mbuf, const struct md_args *args,
+ enum md_ns ns, int tok)
{
- struct md_xml *p;
-
- assert(arg);
- p = (struct md_xml *)arg;
-
- p->indent--;
+ size_t res;
- 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)
-{
- 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);
+ res = 0;
- p->last = MD_IN;
+ 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;
+ }
- if ( ! mbuf_nputs(p, "<", 1))
- return(0);
- if ( ! mbuf_nputs(p, "inline:", 7))
- return(0);
- if ( ! mbuf_puts(p, toknames[tok]))
- return(0);
+ if ( ! ml_puts(mbuf, toknames[tok], &res))
+ return(-1);
- 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));
+ return((ssize_t)res);
}
-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;
-
- assert(arg);
- p = (struct md_xml *)arg;
- if ( ! mbuf_data(p, space, buf))
- return(0);
- p->last = MD_TEXT;
- return(1);
+ return(mlg_alloc(args, rbuf, mbuf, xml_begintag,
+ xml_endtag, xml_begin, xml_end));
}