diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | html.c | 201 | ||||
-rw-r--r-- | libmdocml.h | 4 | ||||
-rw-r--r-- | mdocml.1 | 59 | ||||
-rw-r--r-- | mdocml.c | 47 | ||||
-rw-r--r-- | mdocml.css | 92 | ||||
-rw-r--r-- | ml.h | 13 | ||||
-rw-r--r-- | mlg.c | 9 | ||||
-rw-r--r-- | private.h | 3 | ||||
-rw-r--r-- | roff.c | 5 | ||||
-rw-r--r-- | xml.c | 12 |
11 files changed, 337 insertions, 110 deletions
@@ -1,4 +1,4 @@ -CFLAGS += -W -Wall -Wno-unused-parameter -g +CFLAGS += -W -Wall -Wno-unused-parameter -g -DDEBUG LINTFLAGS += -c -e -f -u @@ -16,15 +16,24 @@ * 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 <assert.h> +#include <err.h> +#include <fcntl.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> +#include <unistd.h> #include "libmdocml.h" #include "private.h" #include "ml.h" +static int html_loadcss(struct md_mbuf *, const char *); + static ssize_t html_endtag(struct md_mbuf *, const struct md_args *, enum md_ns, int); @@ -32,8 +41,11 @@ static ssize_t html_begintag(struct md_mbuf *, const struct md_args *, enum md_ns, int, const int *, const char **); -static int html_begin(struct md_mbuf *, - const struct md_args *); +static int html_begin(struct md_mbuf *, + const struct md_args *, + const struct tm *, + const char *, const char *, + const char *, const char *); static int html_end(struct md_mbuf *, const struct md_args *); static ssize_t html_blocktagname(struct md_mbuf *, @@ -58,33 +70,113 @@ static ssize_t html_inlinetagargs(struct md_mbuf *, const int *, const char **); +static int +html_loadcss(struct md_mbuf *mbuf, const char *css) +{ + size_t res, bufsz; + char *buf; + struct stat st; + int fd, c; + ssize_t ssz; + + c = 0; + res = 0; + buf = NULL; + + if (-1 == (fd = open(css, O_RDONLY, 0))) { + warn("%s", css); + return(0); + } + + if (-1 == fstat(fd, &st)) { + warn("%s", css); + goto out; + } + + bufsz = MAX(st.st_blksize, BUFSIZ); + if (NULL == (buf = malloc(bufsz))) { + warn("malloc"); + goto out; + } + + for (;;) { + if (-1 == (ssz = read(fd, buf, bufsz))) { + warn("%s", css); + goto out; + } else if (0 == ssz) + break; + if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res)) + goto out; + } + + c = 1; + +out: + if (-1 == close(fd)) { + warn("%s", css); + c = 0; + } + + if (buf) + free(buf); + + return(c); +} + + /* ARGSUSED */ static int -html_begin(struct md_mbuf *mbuf, const struct md_args *args) +html_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) { + const char *preamble, *css, *trail; + char buf[512]; size_t res; + preamble = + "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n" + " \"http://www.w3.org/TR/html4/strict.dtd\">\n" + "<html>\n" + "<head>\n" + " <meta http-equiv=\"Content-Type\"\n" + " content=\"text/html;charset=utf-8\">\n" + " <meta name=\"resource-type\" content=\"document\">\n" + " <title>Manual Page for %s(%s)</title>\n"; + + css = + " <link rel=\"stylesheet\" type=\"text/css\"\n" + " href=\"%s\">\n"; + trail = + "</head>\n" + "<body>\n" + "<div class=\"mdoc\">\n"; + res = 0; - if ( ! ml_puts(mbuf, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD " - "HTML 4.01//EN\" \"http://www.w3.org" - "/TR/html4/strict.dtd\">\n", &res)) - return(0); - if ( ! ml_puts(mbuf, "<html>\n", &res)) - return(0); - if ( ! ml_puts(mbuf, "<head>\n", &res)) - return(0); - if ( ! ml_puts(mbuf, " <title>Manual page</title>\n", &res)) - return(0); - if ( ! ml_puts(mbuf, " <meta http-equiv=\"Content-Type\" " - "content=\"text/html; " - "charset=utf-8\">\n", &res)) - return(0); - if ( ! ml_puts(mbuf, " <meta name=\"resource-type\" " - "content=\"document\">\n", &res)) - return(0); - if ( ! ml_puts(mbuf, "</head>\n", &res)) + + (void)snprintf(buf, sizeof(buf) - 1, + preamble, title, section); + + if ( ! ml_puts(mbuf, buf, &res)) return(0); - if ( ! ml_puts(mbuf, "<body>", &res)) + + assert(args->params.html.css); + if (HTML_CSS_EMBED & args->params.html.flags) { + if ( ! ml_puts(mbuf, " <style><!--\n", &res)) + return(0); + if ( ! html_loadcss(mbuf, args->params.html.css)) + return(0); + if ( ! ml_puts(mbuf, " --!></style>\n", &res)) + return(0); + } else { + (void)snprintf(buf, sizeof(buf) - 1, css, + args->params.html.css); + if ( ! ml_puts(mbuf, buf, &res)) + return(0); + } + + if ( ! ml_puts(mbuf, trail, &res)) return(0); return(1); @@ -98,7 +190,7 @@ html_end(struct md_mbuf *mbuf, const struct md_args *args) size_t res; res = 0; - if ( ! ml_puts(mbuf, "</body>\n</html>", &res)) + if ( ! ml_puts(mbuf, "</div></body>\n</html>", &res)) return(0); return(1); @@ -113,17 +205,8 @@ html_blockbodytagname(struct md_mbuf *mbuf, size_t res; res = 0; - - switch (tok) { - case (ROFF_Sh): - if ( ! ml_puts(mbuf, "blockquote", &res)) - return(-1); - break; - default: - if ( ! ml_puts(mbuf, "div", &res)) - return(-1); - break; - } + if ( ! ml_puts(mbuf, "div", &res)) + return(-1); return((ssize_t)res); } @@ -139,21 +222,8 @@ html_blockheadtagname(struct md_mbuf *mbuf, size_t res; res = 0; - - switch (tok) { - case (ROFF_Sh): - if ( ! ml_puts(mbuf, "h1", &res)) - return(-1); - break; - case (ROFF_Ss): - if ( ! ml_puts(mbuf, "h2", &res)) - return(-1); - break; - default: - if ( ! ml_puts(mbuf, "div", &res)) - return(-1); - break; - } + if ( ! ml_puts(mbuf, "div", &res)) + return(-1); return((ssize_t)res); } @@ -167,25 +237,8 @@ html_blocktagname(struct md_mbuf *mbuf, size_t res; res = 0; - - switch (tok) { - case (ROFF_Bd): - if ( ! ml_puts(mbuf, "pre", &res)) - return(-1); - break; - case (ROFF_Bl): - if ( ! ml_puts(mbuf, "ul", &res)) - return(-1); - break; - case (ROFF_It): - if ( ! ml_puts(mbuf, "li", &res)) - return(-1); - break; - default: - if ( ! ml_puts(mbuf, "div", &res)) - return(-1); - break; - } + if ( ! ml_puts(mbuf, "div", &res)) + return(-1); return((ssize_t)res); } @@ -200,7 +253,7 @@ html_blockheadtagargs(struct md_mbuf *mbuf, const struct md_args *args, res = 0; - if ( ! ml_puts(mbuf, " class=\"head:", &res)) + if ( ! ml_puts(mbuf, " class=\"head-", &res)) return(0); if ( ! ml_puts(mbuf, toknames[tok], &res)) return(0); @@ -225,7 +278,7 @@ html_blockbodytagargs(struct md_mbuf *mbuf, const struct md_args *args, res = 0; - if ( ! ml_puts(mbuf, " class=\"body:", &res)) + if ( ! ml_puts(mbuf, " class=\"body-", &res)) return(0); if ( ! ml_puts(mbuf, toknames[tok], &res)) return(0); @@ -250,7 +303,7 @@ html_blocktagargs(struct md_mbuf *mbuf, const struct md_args *args, res = 0; - if ( ! ml_puts(mbuf, " class=\"block:", &res)) + if ( ! ml_puts(mbuf, " class=\"block-", &res)) return(0); if ( ! ml_puts(mbuf, toknames[tok], &res)) return(0); @@ -275,7 +328,7 @@ html_inlinetagargs(struct md_mbuf *mbuf, const struct md_args *args, res = 0; - if ( ! ml_puts(mbuf, " class=\"inline:", &res)) + if ( ! ml_puts(mbuf, " class=\"inline-", &res)) return(0); if ( ! ml_puts(mbuf, toknames[tok], &res)) return(0); @@ -302,6 +355,10 @@ html_inlinetagname(struct md_mbuf *mbuf, res = 0; switch (tok) { + case (ROFF_Pp): + if ( ! ml_puts(mbuf, "div", &res)) + return(-1); + break; default: if ( ! ml_puts(mbuf, "span", &res)) return(-1); diff --git a/libmdocml.h b/libmdocml.h index 098b7026..97337c2e 100644 --- a/libmdocml.h +++ b/libmdocml.h @@ -26,7 +26,9 @@ struct md_params_xml { }; struct md_params_html { - int dummy; + char *css; + int flags; +#define HTML_CSS_EMBED (1 << 0) }; union md_params { @@ -1,6 +1,6 @@ .\" .Dd $Mdocdate$ -.Dt mdocml 1 +.Dt mdocml 1 alpha .Os .\" .Sh NAME @@ -9,7 +9,7 @@ .\" .Sh SYNOPSIS .Nm mdocml -.Op Fl W +.Op Fl vW .Op Fl f Ar filter .Op Fl o Ar outfile .Op Ar infile @@ -18,9 +18,11 @@ The .Nm utility parses mdoc formatted manual source and passes results into an -output filter. The only current output filter is +output filter. The current output filters are +.Ar html +and .Ar xml , -the default. The arguments are as follows: +the default. Arguments common to all filters follow: .Bl -tag -width "\-o outfile" .It Fl f Ar filter The output filter name. @@ -47,8 +49,10 @@ reads from stdin and writes to stdout using the xml filter. .Ss XML Filter The XML filter, specified by .Fl f Ar xml , -is the default filter. It creates an XML document where element names are -their respective roff macro names. Each element name has an associated +is the default filter. This filter has no additional arguments. +.Pp +The XML filter creates an XML document where element names are their respective +roff macro names. Each element name has an associated namespace, which is one of .Qq block , .Qq head , @@ -58,9 +62,50 @@ or corresponding to the display mode of a node. The document root is always the .Qq mdoc -element, in the default namespace. +element, in the default namespace; the +.Qq head +namespace is for block headers (such as +.Sq .Ss +and +.Sq .Sh ) ; +the +.Qq body +namespace is for block bodies; and the +.Qq inline +namespace is for in-line elements (such as +.Sq .Em ) . +.Ss HTML Filter +The HTML filter, specified by +.Fl f Ar html , +accepts the following filter-specific arguments: +.Bl -tag -width "\-c css" +.It Fl c Ar css +The CSS file location, which defaults to +.Ar mdocml.css . +.It Fl e +Whether to embed the CSS file into the HTML prologue. +.El .\" This next request is for sections 1, 6, 7 & 8 only. .\" .Sh ENVIRONMENT +.Sh EXAMPLES +To produce an HTML4-strict document +.Pa mdocml.html +for +.Pa mdocml.1 +with the default, embedded style-sheet: +.Pp +.D1 % mdocml -fhtml -e mdocml.1 -o mdocml.html +.Pp +To create an XML document on standard output from +.Pa mdocml.1 +with the default namespace identifiers +.Li head , +.Li body , +.Li block +and +.Li inline : +.Pp +.D1 % mdocml mdocml.1 .\" .Sh SEE ALSO .Xr groff 1 , @@ -33,6 +33,12 @@ #define BUFFER_IN_DEF BUFSIZ /* See begin_bufs. */ #define BUFFER_OUT_DEF BUFSIZ /* See begin_bufs. */ +#ifdef DEBUG +#define CSS "mdocml.css" +#else +#define CSS "/usr/local/share/mdocml/mdocml.css" +#endif + static void usage(void); static int begin_io(const struct md_args *, @@ -48,20 +54,37 @@ int main(int argc, char *argv[]) { int c; - char *out, *in, *filter; + char *out, *in; struct md_args args; extern char *optarg; extern int optind; - out = in = filter = NULL; + out = in = NULL; (void)memset(&args, 0, sizeof(struct md_args)); - - while (-1 != (c = getopt(argc, argv, "f:o:vW"))) + + args.type = MD_XML; + + while (-1 != (c = getopt(argc, argv, "c:ef:o: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'): - filter = optarg; + if (0 == strcmp(optarg, "html")) + args.type = MD_HTML; + else if (0 == strcmp(optarg, "xml")) + args.type = MD_XML; + else + errx(1, "invalid filter type"); break; case ('o'): out = optarg; @@ -77,22 +100,16 @@ 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; if (1 == argc) in = *argv++; - if (filter) { - if (0 == strcmp(filter, "html")) - args.type = MD_HTML; - else if (0 == strcmp(filter, "xml")) - args.type = MD_XML; - else - errx(1, "invalid filter type"); - } else - args.type = MD_XML; - return(begin_io(&args, out ? out : "-", in ? in : "-")); } diff --git a/mdocml.css b/mdocml.css new file mode 100644 index 00000000..3acf0d0e --- /dev/null +++ b/mdocml.css @@ -0,0 +1,92 @@ + body + { + margin: 0px; + font-family: Tahoma, sans-serif; + font-size: small; + } + + div.mdoc + { + width: 600px; + } + + div.block-Sh + { + margin-bottom: 20px; + } + + div.head-Sh + { + font-weight: bold; + font-size: larger; + } + + div.head-Ss + { + font-weight: bold; + margin-top: 10px; + text-align: justify; + } + + div.body-Sh + { + margin-left: 20px; + margin-top: 10px; + text-align: justify; + } + + span.inline-Nd:before + { + content: ' - '; + } + + span.inline-Fl:before + { + content: '-'; + } + + span.inline-Fl + { + font-weight: bolder; + } + + span.inline-Ar + { + text-decoration: underline; + } + + span.inline-Pa + { + text-decoration: underline; + } + + span.inline-Op:before + { + content: '['; + } + + span.inline-Op:after + { + content: ']'; + } + + div.block-Bl + { + margin-top: 10px; + margin-left: 20px; + } + + div.inline-Pp + { + margin-bottom: 10px; + } + + span.inline-D1 + { + margin-left: 20px; + } + + span.inline-Qq:before { content: '``'; } + span.inline-Qq:after { content: '\'\''; } + span.inline-Sq:before { content: '`'; } + span.inline-Sq:after { content: '\''; } @@ -29,15 +29,16 @@ enum md_ns { MD_NS_DEFAULT, }; -typedef int (*ml_begin)(struct md_mbuf *, - const struct md_args *); +typedef int (*ml_begin)(struct md_mbuf *, const struct md_args *, + const struct tm *, const char *, const char *, + const char *, const char *); typedef int (*ml_end)(struct md_mbuf *, - const struct md_args *); + const struct md_args *); typedef ssize_t (*ml_endtag)(struct md_mbuf *, - const struct md_args *, enum md_ns, int); + const struct md_args *, enum md_ns, int); typedef ssize_t (*ml_begintag)(struct md_mbuf *, - const struct md_args *, enum md_ns, int, - const int *, const char **); + const struct md_args *, enum md_ns, int, + const int *, const char **); __BEGIN_DECLS @@ -63,7 +63,9 @@ struct md_mlg { static void mlg_roffmsg(void *arg, enum roffmsg, const char *, const char *, char *); -static int mlg_roffhead(void *); +static int mlg_roffhead(void *, const struct tm *, + const char *, const char *, + const char *, const char *); static int mlg_rofftail(void *); static int mlg_roffin(void *, int, int *, char **); static int mlg_roffdata(void *, int, char *); @@ -346,7 +348,8 @@ mlg_alloc(const struct md_args *args, static int -mlg_roffhead(void *arg) +mlg_roffhead(void *arg, const struct tm *tm, const char *os, + const char *title, const char *sec, const char *vol) { struct md_mlg *p; @@ -354,7 +357,7 @@ mlg_roffhead(void *arg) p = (struct md_mlg *)arg; mlg_mode(p, MD_BLK_IN); - if ( ! (*p->begin)(p->mbuf, p->args)) + if ( ! (*p->begin)(p->mbuf, p->args, tm, os, title, sec, vol)) return(0); p->indent++; @@ -213,7 +213,8 @@ enum roffmsg { ROFF_WARN, ROFF_ERROR }; struct roffcb { void (*roffmsg)(void *, enum roffmsg, const char *, const char *, char *); - int (*roffhead)(void *); + int (*roffhead)(void *, const struct tm *, const char *, + const char *, const char *, const char *); int (*rofftail)(void *); int (*roffdata)(void *, int, char *); int (*roffin)(void *, int, int *, char **); @@ -40,6 +40,7 @@ /* TODO: (warn) NAME section has particular order. */ /* TODO: unify empty-content tags a la <br />. */ /* TODO: macros with a set number of arguments? */ +/* TODO: validate Dt macro arguments. */ #define ROFF_MAXARG 32 @@ -1210,7 +1211,9 @@ roff_Os(ROFFCALL_ARGS) assert(NULL == tree->last); - return((*tree->cb.roffhead)(tree->arg)); + return((*tree->cb.roffhead)(tree->arg, &tree->tm, + tree->os, tree->title, tree->section, + tree->volume)); } @@ -31,15 +31,21 @@ 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 *); +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 -xml_begin(struct md_mbuf *mbuf, const struct md_args *args) +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) { size_t res; |