From ac4bc07079be4963163734d67749697140f23b4b Mon Sep 17 00:00:00 2001 From: Kristaps Dzonsons Date: Wed, 3 Dec 2008 14:39:59 +0000 Subject: Abstract ml/mlg/html/xml. --- mlg.c | 496 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 496 insertions(+) create mode 100644 mlg.c (limited to 'mlg.c') diff --git a/mlg.c b/mlg.c new file mode 100644 index 00000000..454751d0 --- /dev/null +++ b/mlg.c @@ -0,0 +1,496 @@ +/* $Id$ */ +/* + * Copyright (c) 2008 Kristaps Dzonsons + * + * 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 +#include +#include +#include +#include +#include + +#include "libmdocml.h" +#include "private.h" +#include "ml.h" + +/* TODO: literal tokens. */ + +#define COLUMNS 72 +#define INDENT 4 +#define MAXINDENT 8 + +enum md_tok { + MD_TEXT, + MD_INLINE_IN, + MD_INLINE_OUT, + MD_BLK_IN, + MD_BLK_OUT, +}; + +struct md_mlg { + 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; + void *arg; + ml_begintag begintag; + ml_endtag endtag; + int flags; +#define ML_OVERRIDE_ONE (1 << 0) +#define ML_OVERRIDE_ALL (1 << 1) +}; + + +static void mlg_roffmsg(void *arg, enum roffmsg, + const char *, const char *, char *); +static int mlg_roffhead(void *); +static int mlg_rofftail(void *); +static int mlg_roffin(void *, int, int *, char **); +static int mlg_roffdata(void *, int, char *); +static int mlg_roffout(void *, int); +static int mlg_roffblkin(void *, int, int *, char **); +static int mlg_roffblkout(void *, int); +static int mlg_roffspecial(void *, int, int *, char **, char **); +static int mlg_begintag(struct md_mlg *, enum md_ns, + int, int *, char **); +static int mlg_endtag(struct md_mlg *, enum md_ns, int); +static int mlg_indent(struct md_mlg *); +static int mlg_newline(struct md_mlg *); +static void mlg_mode(struct md_mlg *, enum md_tok); +static int mlg_data(struct md_mlg *, int, char *); + +#ifdef __linux__ +extern size_t strlcat(char *, const char *, size_t); +extern size_t strlcpy(char *, const char *, size_t); +#endif + + +static int +mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok, + int *argc, char **argv) +{ + ssize_t res; + + /* TODO: extra rules for block/inline. */ + + if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos)) + return(0); + + res = (*p->begintag)(p->mbuf, p->args, ns, tok, + argc, (const char **)argv); + if (-1 == res) + return(0); + + assert(res >= 0); + p->pos += (size_t)res; + + /* TODO: extra rules for block/inline. */ + + return(ml_nputs(p->mbuf, ">", 1, &p->pos)); +} + + +static int +mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok) +{ + ssize_t res; + + /* TODO: extra rules for block/inline. */ + + if ( ! ml_nputs(p->mbuf, "pos)) + return(0); + + res = (*p->endtag)(p->mbuf, p->args, ns, tok); + if (-1 == res) + return(0); + + assert(res >= 0); + p->pos += (size_t)res; + + /* TODO: extra rules for block/inline. */ + + return(ml_nputs(p->mbuf, ">", 1, &p->pos)); +} + + +static int +mlg_indent(struct md_mlg *p) +{ + size_t count; + + count = p->indent > MAXINDENT ? MAXINDENT : p->indent; + count *= INDENT; + + assert(0 == p->pos); + return(ml_putchars(p->mbuf, ' ', count, &p->pos)); +} + + +static int +mlg_newline(struct md_mlg *p) +{ + size_t dummy; + + if ( ! ml_nputs(p->mbuf, "\n", 1, &dummy)) + return(0); + p->pos = 0; + return(1); +} + + +static void +mlg_mode(struct md_mlg *p, enum md_tok ns) +{ + p->flags &= ~ML_OVERRIDE_ONE; + p->last = ns; +} + + +static int +mlg_data(struct md_mlg *p, int space, char *buf) +{ + size_t sz; + char *bufp; + + assert(p->mbuf); + assert(0 != p->indent); + + if (ML_OVERRIDE_ONE & p->flags || + ML_OVERRIDE_ALL & p->flags) + space = 0; + + 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 ( ! mlg_indent(p)) + return(0); + if ( ! ml_nputstring(p->mbuf, bufp, + sz, &p->pos)) + return(0); + if (p->indent * MAXINDENT + sz >= COLUMNS) + if ( ! mlg_newline(p)) + return(0); + if ( ! (ML_OVERRIDE_ALL & p->flags)) + space = 1; + continue; + } + + if (space && sz + p->pos >= COLUMNS) { + if ( ! mlg_newline(p)) + return(0); + if ( ! mlg_indent(p)) + return(0); + } else if (space) { + if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos)) + return(0); + } + + if ( ! ml_nputstring(p->mbuf, bufp, sz, &p->pos)) + return(0); + + if ( ! (ML_OVERRIDE_ALL & p->flags)) + space = 1; + } + + return(1); +} + + +int +mlg_line(struct md_mlg *p, char *buf) +{ + + return(roff_engine(p->tree, buf)); +} + + +int +mlg_exit(struct md_mlg *p, int flush) +{ + int c; + + c = roff_free(p->tree, flush); + free(p); + return(c); +} + + +struct md_mlg * +mlg_alloc(const struct md_args *args, + const struct md_rbuf *rbuf, + struct md_mbuf *mbuf, + ml_begintag begintag, ml_endtag endtag) +{ + struct roffcb cb; + struct md_mlg *p; + + cb.roffhead = mlg_roffhead; + cb.rofftail = mlg_rofftail; + cb.roffin = mlg_roffin; + cb.roffout = mlg_roffout; + cb.roffblkin = mlg_roffblkin; + cb.roffblkout = mlg_roffblkout; + cb.roffspecial = mlg_roffspecial; + cb.roffmsg = mlg_roffmsg; + cb.roffdata = mlg_roffdata; + + if (NULL == (p = calloc(1, sizeof(struct md_mlg)))) + err(1, "calloc"); + + p->args = args; + p->mbuf = mbuf; + p->rbuf = rbuf; + p->begintag = begintag; + p->endtag = endtag; + + if (NULL == (p->tree = roff_alloc(&cb, p))) { + free(p); + return(NULL); + } + + return(p); +} + + +static int +mlg_roffhead(void *arg) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + mlg_mode(p, MD_BLK_IN); + if ( ! mlg_begintag(p, MD_NS_DEFAULT, -1, NULL, NULL)) + return(0); + + p->indent++; + return(mlg_newline(p)); +} + + +static int +mlg_rofftail(void *arg) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + if (0 != p->pos && ! mlg_newline(p)) + return(0); + + mlg_mode(p, MD_BLK_OUT); + if ( ! mlg_endtag(p, -1, MD_NS_DEFAULT)) + return(0); + + return(mlg_newline(p)); +} + + +/* ARGSUSED */ +static int +mlg_roffspecial(void *arg, int tok, int *argc, char **argv, char **more) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + switch (tok) { + case (ROFF_Ns): + p->flags |= ML_OVERRIDE_ONE; + break; + case (ROFF_Sm): + assert(*more); + if (0 == strcmp(*more, "on")) + p->flags |= ML_OVERRIDE_ALL; + else + p->flags &= ~ML_OVERRIDE_ALL; + break; + default: + break; + } + + return(1); +} + + +static int +mlg_roffblkin(void *arg, int tok, int *argc, char **argv) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + if (0 != p->pos) { + if ( ! mlg_newline(p)) + return(0); + if ( ! mlg_indent(p)) + return(0); + } else if ( ! mlg_indent(p)) + return(0); + + p->indent++; + mlg_mode(p, MD_BLK_IN); + + if ( ! mlg_begintag(p, MD_NS_BLOCK, tok, argc, argv)) + return(0); + return(mlg_newline(p)); +} + + +static int +mlg_roffblkout(void *arg, int tok) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + p->indent--; + + if (0 != p->pos) { + if ( ! mlg_newline(p)) + return(0); + if ( ! mlg_indent(p)) + return(0); + } else if ( ! mlg_indent(p)) + return(0); + + mlg_mode(p, MD_BLK_OUT); + if ( ! mlg_endtag(p, MD_NS_BLOCK, tok)) + return(0); + return(mlg_newline(p)); +} + + +static int +mlg_roffin(void *arg, int tok, int *argc, char **argv) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + /* FIXME: this part. */ + + if ( ! (ML_OVERRIDE_ONE & p->flags) && + ! (ML_OVERRIDE_ALL & p->flags) && + p->pos + 11 > COLUMNS) + if ( ! mlg_newline(p)) + return(0); + + if (0 != p->pos && (MD_TEXT == p->last || + MD_INLINE_OUT == p->last) + && ! (ML_OVERRIDE_ONE & p->flags) + && ! (ML_OVERRIDE_ALL & p->flags)) + if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos)) + return(0); + + if (0 == p->pos && ! mlg_indent(p)) + return(0); + + mlg_mode(p, MD_INLINE_IN); + return(mlg_begintag(p, MD_NS_INLINE, tok, argc, argv)); +} + + +static int +mlg_roffout(void *arg, int tok) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + if (0 == p->pos && ! mlg_indent(p)) + return(0); + + mlg_mode(p, MD_INLINE_OUT); + return(mlg_endtag(p, MD_NS_INLINE, tok)); +} + + +static void +mlg_roffmsg(void *arg, enum roffmsg lvl, + const char *buf, const char *pos, char *msg) +{ + char *level; + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)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 +mlg_roffdata(void *arg, int space, char *buf) +{ + struct md_mlg *p; + + assert(arg); + p = (struct md_mlg *)arg; + + if ( ! mlg_data(p, space, buf)) + return(0); + + mlg_mode(p, MD_TEXT); + return(1); +} + -- cgit