=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.160 retrieving revision 1.194 diff -u -p -r1.160 -r1.194 --- mandoc/html.c 2014/08/10 23:54:41 1.160 +++ mandoc/html.c 2017/01/17 01:47:51 1.194 @@ -1,15 +1,15 @@ -/* $Id: html.c,v 1.160 2014/08/10 23:54:41 schwarze Exp $ */ +/* $Id: html.c,v 1.194 2017/01/17 01:47:51 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons + * Copyright (c) 2011-2015, 2017 Ingo Schwarze * * 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 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 @@ -30,9 +30,9 @@ #include "mandoc.h" #include "mandoc_aux.h" -#include "libmandoc.h" #include "out.h" #include "html.h" +#include "manconf.h" #include "main.h" struct htmldata { @@ -68,31 +68,30 @@ static const struct htmldata htmltags[TAG_MAX] = { {"dt", HTML_CLRLINE}, /* TAG_DT */ {"dd", HTML_CLRLINE}, /* TAG_DD */ {"blockquote", HTML_CLRLINE}, /* TAG_BLOCKQUOTE */ - {"p", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_P */ {"pre", HTML_CLRLINE }, /* TAG_PRE */ {"b", 0 }, /* TAG_B */ {"i", 0 }, /* TAG_I */ {"code", 0 }, /* TAG_CODE */ {"small", 0 }, /* TAG_SMALL */ + {"style", HTML_CLRLINE}, /* TAG_STYLE */ + {"math", HTML_CLRLINE}, /* TAG_MATH */ + {"mrow", 0}, /* TAG_MROW */ + {"mi", 0}, /* TAG_MI */ + {"mo", 0}, /* TAG_MO */ + {"msup", 0}, /* TAG_MSUP */ + {"msub", 0}, /* TAG_MSUB */ + {"msubsup", 0}, /* TAG_MSUBSUP */ + {"mfrac", 0}, /* TAG_MFRAC */ + {"msqrt", 0}, /* TAG_MSQRT */ + {"mfenced", 0}, /* TAG_MFENCED */ + {"mtable", 0}, /* TAG_MTABLE */ + {"mtr", 0}, /* TAG_MTR */ + {"mtd", 0}, /* TAG_MTD */ + {"munderover", 0}, /* TAG_MUNDEROVER */ + {"munder", 0}, /* TAG_MUNDER*/ + {"mover", 0}, /* TAG_MOVER*/ }; -static const char *const htmlattrs[ATTR_MAX] = { - "http-equiv", /* ATTR_HTTPEQUIV */ - "content", /* ATTR_CONTENT */ - "name", /* ATTR_NAME */ - "rel", /* ATTR_REL */ - "href", /* ATTR_HREF */ - "type", /* ATTR_TYPE */ - "media", /* ATTR_MEDIA */ - "class", /* ATTR_CLASS */ - "style", /* ATTR_STYLE */ - "width", /* ATTR_WIDTH */ - "id", /* ATTR_ID */ - "summary", /* ATTR_SUMMARY */ - "align", /* ATTR_ALIGN */ - "colspan", /* ATTR_COLSPAN */ -}; - static const char *const roffscales[SCALE_MAX] = { "cm", /* SCALE_CM */ "in", /* SCALE_IN */ @@ -106,69 +105,32 @@ static const char *const roffscales[SCALE_MAX] = { "ex", /* SCALE_FS */ }; +static void a2width(const char *, struct roffsu *); static void bufncat(struct html *, const char *, size_t); -static void print_ctag(struct html *, enum htmltag); +static void print_ctag(struct html *, struct tag *); static int print_escape(char); static int print_encode(struct html *, const char *, int); static void print_metaf(struct html *, enum mandoc_esc); static void print_attr(struct html *, const char *, const char *); -static void *ml_alloc(char *, enum htmltype); -static void * -ml_alloc(char *outopts, enum htmltype type) +void * +html_alloc(const struct manoutput *outopts) { struct html *h; - const char *toks[5]; - char *v; - toks[0] = "style"; - toks[1] = "man"; - toks[2] = "includes"; - toks[3] = "fragment"; - toks[4] = NULL; - h = mandoc_calloc(1, sizeof(struct html)); - h->type = type; h->tags.head = NULL; - h->symtab = mchars_alloc(); + h->style = outopts->style; + h->base_man = outopts->man; + h->base_includes = outopts->includes; + if (outopts->fragment) + h->oflags |= HTML_FRAGMENT; - while (outopts && *outopts) - switch (getsubopt(&outopts, UNCONST(toks), &v)) { - case 0: - h->style = v; - break; - case 1: - h->base_man = v; - break; - case 2: - h->base_includes = v; - break; - case 3: - h->oflags |= HTML_FRAGMENT; - break; - default: - break; - } - - return(h); + return h; } -void * -html_alloc(char *outopts) -{ - - return(ml_alloc(outopts, HTML_HTML_4_01_STRICT)); -} - -void * -xhtml_alloc(char *outopts) -{ - - return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT)); -} - void html_free(void *p) { @@ -182,40 +144,31 @@ html_free(void *p) free(tag); } - if (h->symtab) - mchars_free(h->symtab); - free(h); } void print_gen_head(struct html *h) { - struct htmlpair tag[4]; + struct tag *t; - tag[0].key = ATTR_HTTPEQUIV; - tag[0].val = "Content-Type"; - tag[1].key = ATTR_CONTENT; - tag[1].val = "text/html; charset=utf-8"; - print_otag(h, TAG_META, 2, tag); + print_otag(h, TAG_META, "?", "charset", "utf-8"); - tag[0].key = ATTR_NAME; - tag[0].val = "resource-type"; - tag[1].key = ATTR_CONTENT; - tag[1].val = "document"; - print_otag(h, TAG_META, 2, tag); + /* + * Print a default style-sheet. + */ + t = print_otag(h, TAG_STYLE, ""); + print_text(h, "table.head, table.foot { width: 100%; }\n" + "td.head-rtitle, td.foot-os { text-align: right; }\n" + "td.head-vol { text-align: center; }\n" + "table.foot td { width: 50%; }\n" + "table.head td { width: 33%; }\n" + "div.spacer { margin: 1em 0; }\n"); + print_tagq(h, t); - if (h->style) { - tag[0].key = ATTR_REL; - tag[0].val = "stylesheet"; - tag[1].key = ATTR_HREF; - tag[1].val = h->style; - tag[2].key = ATTR_TYPE; - tag[2].val = "text/css"; - tag[3].key = ATTR_MEDIA; - tag[3].val = "all"; - print_otag(h, TAG_LINK, 4, tag); - } + if (h->style) + print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet", + h->style, "type", "text/css", "media", "all"); } static void @@ -237,13 +190,11 @@ print_metaf(struct html *h, enum mandoc_esc deco) font = HTMLFONT_BI; break; case ESCAPE_FONT: - /* FALLTHROUGH */ case ESCAPE_FONTROMAN: font = HTMLFONT_NONE; break; default: abort(); - /* NOTREACHED */ } if (h->metaf) { @@ -256,14 +207,14 @@ print_metaf(struct html *h, enum mandoc_esc deco) switch (font) { case HTMLFONT_ITALIC: - h->metaf = print_otag(h, TAG_I, 0, NULL); + h->metaf = print_otag(h, TAG_I, ""); break; case HTMLFONT_BOLD: - h->metaf = print_otag(h, TAG_B, 0, NULL); + h->metaf = print_otag(h, TAG_B, ""); break; case HTMLFONT_BI: - h->metaf = print_otag(h, TAG_B, 0, NULL); - print_otag(h, TAG_I, 0, NULL); + h->metaf = print_otag(h, TAG_B, ""); + print_otag(h, TAG_I, ""); break; default: break; @@ -301,12 +252,11 @@ html_strlen(const char *cp) cp++; switch (mandoc_escape(&cp, NULL, NULL)) { case ESCAPE_ERROR: - return(sz); + return sz; case ESCAPE_UNICODE: - /* FALLTHROUGH */ case ESCAPE_NUMBERED: - /* FALLTHROUGH */ case ESCAPE_SPECIAL: + case ESCAPE_OVERSTRIKE: if (skip) skip = 0; else @@ -319,7 +269,7 @@ html_strlen(const char *cp) break; } } - return(sz); + return sz; } static int @@ -340,17 +290,17 @@ print_escape(char c) printf("""); break; case ASCII_NBRSP: - putchar('-'); + printf(" "); break; case ASCII_HYPH: putchar('-'); - /* FALLTHROUGH */ + break; case ASCII_BREAK: break; default: - return(0); + return 0; } - return(1); + return 1; } static int @@ -389,15 +339,10 @@ print_encode(struct html *h, const char *p, int norecu switch (esc) { case ESCAPE_FONT: - /* FALLTHROUGH */ case ESCAPE_FONTPREV: - /* FALLTHROUGH */ case ESCAPE_FONTBOLD: - /* FALLTHROUGH */ case ESCAPE_FONTITALIC: - /* FALLTHROUGH */ case ESCAPE_FONTBI: - /* FALLTHROUGH */ case ESCAPE_FONTROMAN: if (0 == norecurse) print_metaf(h, esc); @@ -418,32 +363,39 @@ print_encode(struct html *h, const char *p, int norecu case ESCAPE_UNICODE: /* Skip past "u" header. */ c = mchars_num2uc(seq + 1, len - 1); - if ('\0' != c) - printf("&#x%x;", c); break; case ESCAPE_NUMBERED: c = mchars_num2char(seq, len); - if ( ! ('\0' == c || print_escape(c))) - putchar(c); + if (c < 0) + continue; break; case ESCAPE_SPECIAL: - c = mchars_spec2cp(h->symtab, seq, len); - if (c > 0) - printf("&#%d;", c); - else if (-1 == c && 1 == len && - !print_escape(*seq)) - putchar((int)*seq); + c = mchars_spec2cp(seq, len); + if (c <= 0) + continue; break; case ESCAPE_NOSPACE: if ('\0' == *p) nospace = 1; + continue; + case ESCAPE_OVERSTRIKE: + if (len == 0) + continue; + c = seq[len - 1]; break; default: - break; + continue; } + if ((c < 0x20 && c != 0x09) || + (c > 0x7E && c < 0xA0)) + c = 0xFFFD; + if (c > 0x7E) + printf("&#%d;", c); + else if ( ! print_escape(c)) + putchar(c); } - return(nospace); + return nospace; } static void @@ -455,11 +407,13 @@ print_attr(struct html *h, const char *key, const char } struct tag * -print_otag(struct html *h, enum htmltag tag, - int sz, const struct htmlpair *p) +print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) { - int i; + va_list ap; + struct roffsu mysu, *su; struct tag *t; + char *s; + int i, have_style; /* Push this tags onto the stack of open scopes. */ @@ -490,28 +444,110 @@ print_otag(struct html *h, enum htmltag tag, /* Print out the tag name and attributes. */ printf("<%s", htmltags[tag].name); - for (i = 0; i < sz; i++) - print_attr(h, htmlattrs[p[i].key], p[i].val); - /* Add non-overridable attributes. */ + va_start(ap, fmt); - if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) { - print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml"); - print_attr(h, "xml:lang", "en"); - print_attr(h, "lang", "en"); + have_style = 0; + while (*fmt != '\0') { + if (*fmt == 's') { + printf(" style=\""); + have_style = 1; + fmt++; + break; + } + s = va_arg(ap, char *); + switch (*fmt++) { + case 'c': + print_attr(h, "class", s); + break; + case 'h': + print_attr(h, "href", s); + break; + case 'i': + print_attr(h, "id", s); + break; + case '?': + print_attr(h, s, va_arg(ap, char *)); + break; + default: + abort(); + } } - /* Accommodate for XML "well-formed" singleton escaping. */ + /* Print out styles. */ - if (HTML_AUTOCLOSE & htmltags[tag].flags) - switch (h->type) { - case HTML_XHTML_1_0_STRICT: - putchar('/'); + s = NULL; + su = &mysu; + while (*fmt != '\0') { + + /* First letter: input argument type. */ + + switch (*fmt++) { + case 'h': + i = va_arg(ap, int); + SCALE_HS_INIT(su, i); break; + case 's': + s = va_arg(ap, char *); + break; + case 'u': + su = va_arg(ap, struct roffsu *); + break; + case 'v': + i = va_arg(ap, int); + SCALE_VS_INIT(su, i); + break; + case 'w': + s = va_arg(ap, char *); + a2width(s, su); + break; default: + abort(); + } + + /* Second letter: style name. */ + + bufinit(h); + switch (*fmt++) { + case 'b': + bufcat_su(h, "margin-bottom", su); break; + case 'h': + bufcat_su(h, "height", su); + break; + case 'i': + bufcat_su(h, "text-indent", su); + break; + case 'l': + bufcat_su(h, "margin-left", su); + break; + case 't': + bufcat_su(h, "margin-top", su); + break; + case 'w': + bufcat_su(h, "width", su); + break; + case 'W': + bufcat_su(h, "min-width", su); + break; + case '?': + bufcat_style(h, s, va_arg(ap, char *)); + break; + default: + abort(); } + printf("%s", h->buf); + } + if (have_style) + putchar('"'); + va_end(ap); + + /* Accommodate for "well-formed" singleton escaping. */ + + if (HTML_AUTOCLOSE & htmltags[tag].flags) + putchar('/'); + putchar('>'); h->flags |= HTML_NOSPACE; @@ -519,43 +555,37 @@ print_otag(struct html *h, enum htmltag tag, if ((HTML_AUTOCLOSE | HTML_CLRLINE) & htmltags[tag].flags) putchar('\n'); - return(t); + return t; } static void -print_ctag(struct html *h, enum htmltag tag) +print_ctag(struct html *h, struct tag *tag) { - printf("", htmltags[tag].name); - if (HTML_CLRLINE & htmltags[tag].flags) { + /* + * Remember to close out and nullify the current + * meta-font and table, if applicable. + */ + if (tag == h->metaf) + h->metaf = NULL; + if (tag == h->tblt) + h->tblt = NULL; + + printf("", htmltags[tag->tag].name); + if (HTML_CLRLINE & htmltags[tag->tag].flags) { h->flags |= HTML_NOSPACE; putchar('\n'); } + + h->tags.head = tag->next; + free(tag); } void print_gen_decls(struct html *h) { - const char *doctype; - const char *dtd; - const char *name; - switch (h->type) { - case HTML_HTML_4_01_STRICT: - name = "HTML"; - doctype = "-//W3C//DTD HTML 4.01//EN"; - dtd = "http://www.w3.org/TR/html4/strict.dtd"; - break; - default: - puts(""); - name = "html"; - doctype = "-//W3C//DTD XHTML 1.0 Strict//EN"; - dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; - break; - } - - printf("\n", - name, doctype, dtd); + puts(""); } void @@ -575,14 +605,14 @@ print_text(struct html *h, const char *word) assert(NULL == h->metaf); switch (h->metac) { case HTMLFONT_ITALIC: - h->metaf = print_otag(h, TAG_I, 0, NULL); + h->metaf = print_otag(h, TAG_I, ""); break; case HTMLFONT_BOLD: - h->metaf = print_otag(h, TAG_B, 0, NULL); + h->metaf = print_otag(h, TAG_B, ""); break; case HTMLFONT_BI: - h->metaf = print_otag(h, TAG_B, 0, NULL); - print_otag(h, TAG_I, 0, NULL); + h->metaf = print_otag(h, TAG_B, ""); + print_otag(h, TAG_I, ""); break; default: break; @@ -592,8 +622,9 @@ print_text(struct html *h, const char *word) if ( ! print_encode(h, word, 0)) { if ( ! (h->flags & HTML_NONOSPACE)) h->flags &= ~HTML_NOSPACE; + h->flags &= ~HTML_NONEWLINE; } else - h->flags |= HTML_NOSPACE; + h->flags |= HTML_NOSPACE | HTML_NONEWLINE; if (h->metaf) { print_tagq(h, h->metaf); @@ -609,17 +640,7 @@ print_tagq(struct html *h, const struct tag *until) struct tag *tag; while ((tag = h->tags.head) != NULL) { - /* - * Remember to close out and nullify the current - * meta-font and table, if applicable. - */ - if (tag == h->metaf) - h->metaf = NULL; - if (tag == h->tblt) - h->tblt = NULL; - print_ctag(h, tag->tag); - h->tags.head = tag->next; - free(tag); + print_ctag(h, tag); if (until && tag == until) return; } @@ -633,21 +654,36 @@ print_stagq(struct html *h, const struct tag *suntil) while ((tag = h->tags.head) != NULL) { if (suntil && tag == suntil) return; - /* - * Remember to close out and nullify the current - * meta-font and table, if applicable. - */ - if (tag == h->metaf) - h->metaf = NULL; - if (tag == h->tblt) - h->tblt = NULL; - print_ctag(h, tag->tag); - h->tags.head = tag->next; - free(tag); + print_ctag(h, tag); } } void +print_paragraph(struct html *h) +{ + struct tag *t; + + t = print_otag(h, TAG_DIV, "c", "spacer"); + print_tagq(h, t); +} + + +/* + * Calculate the scaling unit passed in a `-width' argument. This uses + * either a native scaling unit (e.g., 1i, 2m) or the string length of + * the value. + */ +static void +a2width(const char *p, struct roffsu *su) +{ + if (a2roffsu(p, su, SCALE_MAX) < 2) { + su->unit = SCALE_EN; + su->scale = html_strlen(p); + } else if (su->scale < 0.0) + su->scale = 0.0; +} + +void bufinit(struct html *h) { @@ -711,7 +747,7 @@ buffmt_includes(struct html *h, const char *name) while (NULL != (p = strchr(pp, '%'))) { bufncat(h, pp, (size_t)(p - pp)); switch (*(p + 1)) { - case'I': + case 'I': bufcat(h, name); break; default: @@ -759,6 +795,8 @@ bufcat_su(struct html *h, const char *p, const struct v = su->scale; if (SCALE_MM == su->unit && 0.0 == (v /= 100.0)) v = 1.0; + else if (SCALE_BU == su->unit) + v /= 24.0; bufcat_fmt(h, "%s: %.2f%s;", p, v, roffscales[su->unit]); } @@ -767,8 +805,8 @@ void bufcat_id(struct html *h, const char *src) { - /* Cf. . */ + /* Cf. . */ - while ('\0' != *src) - bufcat_fmt(h, "%.2x", *src++); + for (; '\0' != *src; src++) + bufncat(h, *src == ' ' ? "_" : src, 1); }