=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.138 retrieving revision 1.195 diff -u -p -r1.138 -r1.195 --- mandoc/html.c 2011/05/14 16:28:23 1.138 +++ mandoc/html.c 2017/01/17 15:32:43 1.195 @@ -1,23 +1,21 @@ -/* $Id: html.c,v 1.138 2011/05/14 16:28:23 kristaps Exp $ */ +/* $Id: html.c,v 1.195 2017/01/17 15:32:43 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2011 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 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include @@ -31,9 +29,10 @@ #include #include "mandoc.h" -#include "libmandoc.h" +#include "mandoc_aux.h" #include "out.h" #include "html.h" +#include "manconf.h" #include "main.h" struct htmldata { @@ -69,96 +68,68 @@ 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 */ + "pc", /* SCALE_PC */ + "pt", /* SCALE_PT */ + "em", /* SCALE_EM */ + "em", /* SCALE_MM */ + "ex", /* SCALE_EN */ + "ex", /* SCALE_BU */ + "em", /* SCALE_VS */ + "ex", /* SCALE_FS */ }; -static void print_num(struct html *, const char *, size_t); -static void print_spec(struct html *, const char *, size_t); -static void print_res(struct html *, const char *, size_t); -static void print_ctag(struct html *, enum htmltag); -static void print_doctype(struct html *); -static void print_xmltype(struct html *); -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 a2width(const char *, struct roffsu *); +static void print_ctag(struct html *, struct tag *); +static int print_escape(char); +static int print_encode(struct html *, const char *, const char *, int); +static void print_href(struct html *, const char *, const char *, int); +static void print_metaf(struct html *, enum mandoc_esc); -static void * -ml_alloc(char *outopts, enum htmltype type) +void * +html_alloc(const struct manoutput *outopts) { struct html *h; - const char *toks[4]; - char *v; - toks[0] = "style"; - toks[1] = "man"; - toks[2] = "includes"; - toks[3] = 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; - 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) { @@ -168,117 +139,61 @@ html_free(void *p) h = (struct html *)p; while ((tag = h->tags.head) != NULL) { - h->tags.head = tag->next; + h->tags.head = tag->next; 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"); } -/* ARGSUSED */ static void -print_num(struct html *h, const char *p, size_t len) -{ - char c; - - if ('\0' != (c = mchars_num2char(p, len))) - putchar((int)c); -} - -static void -print_spec(struct html *h, const char *p, size_t len) -{ - int cp; - const char *rhs; - size_t sz; - - if ((cp = mchars_spec2cp(h->symtab, p, len)) > 0) { - printf("&#%d;", cp); - return; - } else if (-1 == cp && 1 == len) { - fwrite(p, 1, len, stdout); - return; - } else if (-1 == cp) - return; - - if (NULL != (rhs = mchars_spec2str(h->symtab, p, len, &sz))) - fwrite(rhs, 1, sz, stdout); -} - - -static void -print_res(struct html *h, const char *p, size_t len) -{ - int cp; - const char *rhs; - size_t sz; - - if ((cp = mchars_res2cp(h->symtab, p, len)) > 0) { - printf("&#%d;", cp); - return; - } else if (-1 == cp) - return; - - if (NULL != (rhs = mchars_res2str(h->symtab, p, len, &sz))) - fwrite(rhs, 1, sz, stdout); -} - - -static void print_metaf(struct html *h, enum mandoc_esc deco) { enum htmlfont font; switch (deco) { - case (ESCAPE_FONTPREV): + case ESCAPE_FONTPREV: font = h->metal; break; - case (ESCAPE_FONTITALIC): + case ESCAPE_FONTITALIC: font = HTMLFONT_ITALIC; break; - case (ESCAPE_FONTBOLD): + case ESCAPE_FONTBOLD: font = HTMLFONT_BOLD; break; - case (ESCAPE_FONTROMAN): + case ESCAPE_FONTBI: + font = HTMLFONT_BI; + break; + case ESCAPE_FONT: + case ESCAPE_FONTROMAN: font = HTMLFONT_NONE; break; default: abort(); - /* NOTREACHED */ } if (h->metaf) { @@ -289,17 +204,27 @@ print_metaf(struct html *h, enum mandoc_esc deco) h->metal = h->metac; h->metac = font; - if (HTMLFONT_NONE != font) - h->metaf = HTMLFONT_BOLD == font ? - print_otag(h, TAG_B, 0, NULL) : - print_otag(h, TAG_I, 0, NULL); + switch (font) { + case HTMLFONT_ITALIC: + h->metaf = print_otag(h, TAG_I, ""); + break; + case HTMLFONT_BOLD: + h->metaf = print_otag(h, TAG_B, ""); + break; + case HTMLFONT_BI: + h->metaf = print_otag(h, TAG_B, ""); + print_otag(h, TAG_I, ""); + break; + default: + break; + } } int html_strlen(const char *cp) { - int ssz, sz; - const char *seq, *p; + size_t rsz; + int skip, sz; /* * Account for escaped sequences within string length @@ -310,117 +235,207 @@ html_strlen(const char *cp) */ sz = 0; - while (NULL != (p = strchr(cp, '\\'))) { - sz += (int)(p - cp); - ++cp; - switch (mandoc_escape(&cp, &seq, &ssz)) { - case (ESCAPE_ERROR): - return(sz); - case (ESCAPE_PREDEF): - sz++; + skip = 0; + while (1) { + rsz = strcspn(cp, "\\"); + if (rsz) { + cp += rsz; + if (skip) { + skip = 0; + rsz--; + } + sz += rsz; + } + if ('\0' == *cp) break; - case (ESCAPE_SPECIAL): - sz++; + cp++; + switch (mandoc_escape(&cp, NULL, NULL)) { + case ESCAPE_ERROR: + return sz; + case ESCAPE_UNICODE: + case ESCAPE_NUMBERED: + case ESCAPE_SPECIAL: + case ESCAPE_OVERSTRIKE: + if (skip) + skip = 0; + else + sz++; break; + case ESCAPE_SKIPCHAR: + skip = 1; + break; default: break; } } + return sz; +} - assert(sz >= 0); - return(sz + strlen(cp)); +static int +print_escape(char c) +{ + + switch (c) { + case '<': + printf("<"); + break; + case '>': + printf(">"); + break; + case '&': + printf("&"); + break; + case '"': + printf("""); + break; + case ASCII_NBRSP: + printf(" "); + break; + case ASCII_HYPH: + putchar('-'); + break; + case ASCII_BREAK: + break; + default: + return 0; + } + return 1; } static int -print_encode(struct html *h, const char *p, int norecurse) +print_encode(struct html *h, const char *p, const char *pend, int norecurse) { size_t sz; - int len, nospace; + int c, len, nospace; const char *seq; enum mandoc_esc esc; - static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' }; + static const char rejs[9] = { '\\', '<', '>', '&', '"', + ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' }; + if (pend == NULL) + pend = strchr(p, '\0'); + nospace = 0; - while ('\0' != *p) { + while (p < pend) { + if (HTML_SKIPCHAR & h->flags && '\\' != *p) { + h->flags &= ~HTML_SKIPCHAR; + p++; + continue; + } + sz = strcspn(p, rejs); + if (p + sz > pend) + sz = pend - p; fwrite(p, 1, sz, stdout); p += (int)sz; - if ('\0' == *p) + if (p >= pend) break; - switch (*p++) { - case ('<'): - printf("<"); + if (print_escape(*p++)) continue; - case ('>'): - printf(">"); + + esc = mandoc_escape(&p, &seq, &len); + if (ESCAPE_ERROR == esc) + break; + + switch (esc) { + case ESCAPE_FONT: + case ESCAPE_FONTPREV: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBI: + case ESCAPE_FONTROMAN: + if (0 == norecurse) + print_metaf(h, esc); continue; - case ('&'): - printf("&"); + case ESCAPE_SKIPCHAR: + h->flags |= HTML_SKIPCHAR; continue; - case (ASCII_HYPH): - putchar('-'); - continue; default: break; } - esc = mandoc_escape(&p, &seq, &len); - if (ESCAPE_ERROR == esc) - break; + if (h->flags & HTML_SKIPCHAR) { + h->flags &= ~HTML_SKIPCHAR; + continue; + } switch (esc) { - case (ESCAPE_NUMBERED): - print_num(h, seq, len); + case ESCAPE_UNICODE: + /* Skip past "u" header. */ + c = mchars_num2uc(seq + 1, len - 1); break; - case (ESCAPE_PREDEF): - print_res(h, seq, len); + case ESCAPE_NUMBERED: + c = mchars_num2char(seq, len); + if (c < 0) + continue; break; - case (ESCAPE_SPECIAL): - print_spec(h, seq, len); + case ESCAPE_SPECIAL: + c = mchars_spec2cp(seq, len); + if (c <= 0) + continue; break; - case (ESCAPE_FONTPREV): - /* FALLTHROUGH */ - case (ESCAPE_FONTBOLD): - /* FALLTHROUGH */ - case (ESCAPE_FONTITALIC): - /* FALLTHROUGH */ - case (ESCAPE_FONTROMAN): - if (norecurse) - break; - print_metaf(h, esc); - break; - case (ESCAPE_NOSPACE): + 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 -print_attr(struct html *h, const char *key, const char *val) +print_href(struct html *h, const char *name, const char *sec, int man) { - printf(" %s=\"", key); - (void)print_encode(h, val, 1); - putchar('\"'); + const char *p, *pp; + + pp = man ? h->base_man : h->base_includes; + while ((p = strchr(pp, '%')) != NULL) { + print_encode(h, pp, p, 1); + if (man && p[1] == 'S') { + if (sec == NULL) + putchar('1'); + else + print_encode(h, sec, NULL, 1); + } else if ((man && p[1] == 'N') || + (man == 0 && p[1] == 'I')) + print_encode(h, name, NULL, 1); + else + print_encode(h, p, p + 2, 1); + pp = p + 2; + } + if (*pp != '\0') + print_encode(h, pp, NULL, 1); } - 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; + const char *attr; + char *s; + double v; + int i, have_style; /* Push this tags onto the stack of open scopes. */ @@ -451,28 +466,134 @@ 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': + attr = "class"; + break; + case 'h': + attr = "href"; + break; + case 'i': + attr = "id"; + break; + case '?': + attr = s; + s = va_arg(ap, char *); + break; + default: + abort(); + } + printf(" %s=\"", attr); + switch (*fmt) { + case 'M': + print_href(h, s, va_arg(ap, char *), 1); + fmt++; + break; + case 'I': + print_href(h, s, NULL, 0); + fmt++; + break; + case 'R': + putchar('#'); + fmt++; + /* FALLTHROUGH */ + default: + print_encode(h, s, NULL, 1); + break; + } + putchar('"'); } - /* 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. */ + + switch (*fmt++) { + case 'b': + attr = "margin-bottom"; break; + case 'h': + attr = "height"; + break; + case 'i': + attr = "text-indent"; + break; + case 'l': + attr = "margin-left"; + break; + case 't': + attr = "margin-top"; + break; + case 'w': + attr = "width"; + break; + case 'W': + attr = "min-width"; + break; + case '?': + printf("%s: %s;", s, va_arg(ap, char *)); + continue; + default: + abort(); } + v = su->scale; + if (su->unit == SCALE_MM && (v /= 100.0) == 0.0) + v = 1.0; + else if (su->unit == SCALE_BU) + v /= 24.0; + printf("%s: %.2f%s;", attr, v, roffscales[su->unit]); + } + 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; @@ -480,64 +601,39 @@ 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) { - print_xmltype(h); - print_doctype(h); + puts(""); } - -static void -print_xmltype(struct html *h) -{ - - if (HTML_XHTML_1_0_STRICT == h->type) - puts(""); -} - - -static void -print_doctype(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: - 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); -} - void print_text(struct html *h, const char *word) { @@ -553,15 +649,28 @@ print_text(struct html *h, const char *word) } assert(NULL == h->metaf); - if (HTMLFONT_NONE != h->metac) - h->metaf = HTMLFONT_BOLD == h->metac ? - print_otag(h, TAG_B, 0, NULL) : - print_otag(h, TAG_I, 0, NULL); + switch (h->metac) { + case HTMLFONT_ITALIC: + h->metaf = print_otag(h, TAG_I, ""); + break; + case HTMLFONT_BOLD: + h->metaf = print_otag(h, TAG_B, ""); + break; + case HTMLFONT_BI: + h->metaf = print_otag(h, TAG_B, ""); + print_otag(h, TAG_I, ""); + break; + default: + break; + } assert(word); - if ( ! print_encode(h, word, 0)) + if ( ! print_encode(h, word, NULL, 0)) { if ( ! (h->flags & HTML_NONOSPACE)) h->flags &= ~HTML_NOSPACE; + h->flags &= ~HTML_NONEWLINE; + } else + h->flags |= HTML_NOSPACE | HTML_NONEWLINE; if (h->metaf) { print_tagq(h, h->metaf); @@ -571,30 +680,18 @@ print_text(struct html *h, const char *word) h->flags &= ~HTML_IGNDELIM; } - void 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; } } - void print_stagq(struct html *h, const struct tag *suntil) { @@ -603,205 +700,31 @@ 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 -bufinit(struct html *h) +print_paragraph(struct html *h) { + struct tag *t; - h->buf[0] = '\0'; - h->buflen = 0; + t = print_otag(h, TAG_DIV, "c", "spacer"); + print_tagq(h, t); } -void -bufcat_style(struct html *h, const char *key, const char *val) +/* + * 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) { - - bufcat(h, key); - bufncat(h, ":", 1); - bufcat(h, val); - bufncat(h, ";", 1); -} - - -void -bufcat(struct html *h, const char *p) -{ - - bufncat(h, p, strlen(p)); -} - - -void -buffmt(struct html *h, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - (void)vsnprintf(h->buf + (int)h->buflen, - BUFSIZ - h->buflen - 1, fmt, ap); - va_end(ap); - h->buflen = strlen(h->buf); -} - - -void -bufncat(struct html *h, const char *p, size_t sz) -{ - - if (h->buflen + sz > BUFSIZ - 1) - sz = BUFSIZ - 1 - h->buflen; - - (void)strncat(h->buf, p, sz); - h->buflen += sz; -} - - -void -buffmt_includes(struct html *h, const char *name) -{ - const char *p, *pp; - - pp = h->base_includes; - - while (NULL != (p = strchr(pp, '%'))) { - bufncat(h, pp, (size_t)(p - pp)); - switch (*(p + 1)) { - case('I'): - bufcat(h, name); - break; - default: - bufncat(h, p, 2); - break; - } - pp = p + 2; - } - if (pp) - bufcat(h, pp); -} - - -void -buffmt_man(struct html *h, - const char *name, const char *sec) -{ - const char *p, *pp; - - pp = h->base_man; - - /* LINTED */ - while (NULL != (p = strchr(pp, '%'))) { - bufncat(h, pp, (size_t)(p - pp)); - switch (*(p + 1)) { - case('S'): - bufcat(h, sec ? sec : "1"); - break; - case('N'): - buffmt(h, name); - break; - default: - bufncat(h, p, 2); - break; - } - pp = p + 2; - } - if (pp) - bufcat(h, pp); -} - - -void -bufcat_su(struct html *h, const char *p, const struct roffsu *su) -{ - double v; - const char *u; - - v = su->scale; - - switch (su->unit) { - case (SCALE_CM): - u = "cm"; - break; - case (SCALE_IN): - u = "in"; - break; - case (SCALE_PC): - u = "pc"; - break; - case (SCALE_PT): - u = "pt"; - break; - case (SCALE_EM): - u = "em"; - break; - case (SCALE_MM): - if (0 == (v /= 100)) - v = 1; - u = "em"; - break; - case (SCALE_EN): - u = "ex"; - break; - case (SCALE_BU): - u = "ex"; - break; - case (SCALE_VS): - u = "em"; - break; - default: - u = "ex"; - break; - } - - /* - * XXX: the CSS spec isn't clear as to which types accept - * integer or real numbers, so we just make them all decimals. - */ - buffmt(h, "%s: %.2f%s;", p, v, u); -} - - -void -html_idcat(char *dst, const char *src, int sz) -{ - int ssz; - - assert(sz > 2); - - /* Cf. . */ - - /* We can't start with a number (bah). */ - - if ('#' == *dst) { - dst++; - sz--; - } - if ('\0' == *dst) { - *dst++ = 'x'; - *dst = '\0'; - sz--; - } - - for ( ; *dst != '\0' && sz; dst++, sz--) - /* Jump to end. */ ; - - for ( ; *src != '\0' && sz > 1; src++) { - ssz = snprintf(dst, (size_t)sz, "%.2x", *src); - sz -= ssz; - dst += ssz; - } + 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; }