1*698f87a4SGarrett D'Amore /* $Id: html.c,v 1.152 2013/08/08 20:07:47 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*698f87a4SGarrett D'Amore * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 1995c635efSGarrett D'Amore #include "config.h" 2095c635efSGarrett D'Amore #endif 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <sys/types.h> 2395c635efSGarrett D'Amore 2495c635efSGarrett D'Amore #include <assert.h> 2595c635efSGarrett D'Amore #include <ctype.h> 2695c635efSGarrett D'Amore #include <stdarg.h> 2795c635efSGarrett D'Amore #include <stdio.h> 2895c635efSGarrett D'Amore #include <stdint.h> 2995c635efSGarrett D'Amore #include <stdlib.h> 3095c635efSGarrett D'Amore #include <string.h> 3195c635efSGarrett D'Amore #include <unistd.h> 3295c635efSGarrett D'Amore 3395c635efSGarrett D'Amore #include "mandoc.h" 3495c635efSGarrett D'Amore #include "libmandoc.h" 3595c635efSGarrett D'Amore #include "out.h" 3695c635efSGarrett D'Amore #include "html.h" 3795c635efSGarrett D'Amore #include "main.h" 3895c635efSGarrett D'Amore 3995c635efSGarrett D'Amore struct htmldata { 4095c635efSGarrett D'Amore const char *name; 4195c635efSGarrett D'Amore int flags; 4295c635efSGarrett D'Amore #define HTML_CLRLINE (1 << 0) 4395c635efSGarrett D'Amore #define HTML_NOSTACK (1 << 1) 4495c635efSGarrett D'Amore #define HTML_AUTOCLOSE (1 << 2) /* Tag has auto-closure. */ 4595c635efSGarrett D'Amore }; 4695c635efSGarrett D'Amore 4795c635efSGarrett D'Amore static const struct htmldata htmltags[TAG_MAX] = { 4895c635efSGarrett D'Amore {"html", HTML_CLRLINE}, /* TAG_HTML */ 4995c635efSGarrett D'Amore {"head", HTML_CLRLINE}, /* TAG_HEAD */ 5095c635efSGarrett D'Amore {"body", HTML_CLRLINE}, /* TAG_BODY */ 5195c635efSGarrett D'Amore {"meta", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_META */ 5295c635efSGarrett D'Amore {"title", HTML_CLRLINE}, /* TAG_TITLE */ 5395c635efSGarrett D'Amore {"div", HTML_CLRLINE}, /* TAG_DIV */ 5495c635efSGarrett D'Amore {"h1", 0}, /* TAG_H1 */ 5595c635efSGarrett D'Amore {"h2", 0}, /* TAG_H2 */ 5695c635efSGarrett D'Amore {"span", 0}, /* TAG_SPAN */ 5795c635efSGarrett D'Amore {"link", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_LINK */ 5895c635efSGarrett D'Amore {"br", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_BR */ 5995c635efSGarrett D'Amore {"a", 0}, /* TAG_A */ 6095c635efSGarrett D'Amore {"table", HTML_CLRLINE}, /* TAG_TABLE */ 6195c635efSGarrett D'Amore {"tbody", HTML_CLRLINE}, /* TAG_TBODY */ 6295c635efSGarrett D'Amore {"col", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_COL */ 6395c635efSGarrett D'Amore {"tr", HTML_CLRLINE}, /* TAG_TR */ 6495c635efSGarrett D'Amore {"td", HTML_CLRLINE}, /* TAG_TD */ 6595c635efSGarrett D'Amore {"li", HTML_CLRLINE}, /* TAG_LI */ 6695c635efSGarrett D'Amore {"ul", HTML_CLRLINE}, /* TAG_UL */ 6795c635efSGarrett D'Amore {"ol", HTML_CLRLINE}, /* TAG_OL */ 6895c635efSGarrett D'Amore {"dl", HTML_CLRLINE}, /* TAG_DL */ 6995c635efSGarrett D'Amore {"dt", HTML_CLRLINE}, /* TAG_DT */ 7095c635efSGarrett D'Amore {"dd", HTML_CLRLINE}, /* TAG_DD */ 7195c635efSGarrett D'Amore {"blockquote", HTML_CLRLINE}, /* TAG_BLOCKQUOTE */ 7295c635efSGarrett D'Amore {"p", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_P */ 7395c635efSGarrett D'Amore {"pre", HTML_CLRLINE }, /* TAG_PRE */ 7495c635efSGarrett D'Amore {"b", 0 }, /* TAG_B */ 7595c635efSGarrett D'Amore {"i", 0 }, /* TAG_I */ 7695c635efSGarrett D'Amore {"code", 0 }, /* TAG_CODE */ 7795c635efSGarrett D'Amore {"small", 0 }, /* TAG_SMALL */ 7895c635efSGarrett D'Amore }; 7995c635efSGarrett D'Amore 8095c635efSGarrett D'Amore static const char *const htmlattrs[ATTR_MAX] = { 8195c635efSGarrett D'Amore "http-equiv", /* ATTR_HTTPEQUIV */ 8295c635efSGarrett D'Amore "content", /* ATTR_CONTENT */ 8395c635efSGarrett D'Amore "name", /* ATTR_NAME */ 8495c635efSGarrett D'Amore "rel", /* ATTR_REL */ 8595c635efSGarrett D'Amore "href", /* ATTR_HREF */ 8695c635efSGarrett D'Amore "type", /* ATTR_TYPE */ 8795c635efSGarrett D'Amore "media", /* ATTR_MEDIA */ 8895c635efSGarrett D'Amore "class", /* ATTR_CLASS */ 8995c635efSGarrett D'Amore "style", /* ATTR_STYLE */ 9095c635efSGarrett D'Amore "width", /* ATTR_WIDTH */ 9195c635efSGarrett D'Amore "id", /* ATTR_ID */ 9295c635efSGarrett D'Amore "summary", /* ATTR_SUMMARY */ 9395c635efSGarrett D'Amore "align", /* ATTR_ALIGN */ 9495c635efSGarrett D'Amore "colspan", /* ATTR_COLSPAN */ 9595c635efSGarrett D'Amore }; 9695c635efSGarrett D'Amore 9795c635efSGarrett D'Amore static const char *const roffscales[SCALE_MAX] = { 9895c635efSGarrett D'Amore "cm", /* SCALE_CM */ 9995c635efSGarrett D'Amore "in", /* SCALE_IN */ 10095c635efSGarrett D'Amore "pc", /* SCALE_PC */ 10195c635efSGarrett D'Amore "pt", /* SCALE_PT */ 10295c635efSGarrett D'Amore "em", /* SCALE_EM */ 10395c635efSGarrett D'Amore "em", /* SCALE_MM */ 10495c635efSGarrett D'Amore "ex", /* SCALE_EN */ 10595c635efSGarrett D'Amore "ex", /* SCALE_BU */ 10695c635efSGarrett D'Amore "em", /* SCALE_VS */ 10795c635efSGarrett D'Amore "ex", /* SCALE_FS */ 10895c635efSGarrett D'Amore }; 10995c635efSGarrett D'Amore 11095c635efSGarrett D'Amore static void bufncat(struct html *, const char *, size_t); 11195c635efSGarrett D'Amore static void print_ctag(struct html *, enum htmltag); 11295c635efSGarrett D'Amore static int print_encode(struct html *, const char *, int); 11395c635efSGarrett D'Amore static void print_metaf(struct html *, enum mandoc_esc); 11495c635efSGarrett D'Amore static void print_attr(struct html *, const char *, const char *); 11595c635efSGarrett D'Amore static void *ml_alloc(char *, enum htmltype); 11695c635efSGarrett D'Amore 11795c635efSGarrett D'Amore static void * 11895c635efSGarrett D'Amore ml_alloc(char *outopts, enum htmltype type) 11995c635efSGarrett D'Amore { 12095c635efSGarrett D'Amore struct html *h; 12195c635efSGarrett D'Amore const char *toks[5]; 12295c635efSGarrett D'Amore char *v; 12395c635efSGarrett D'Amore 12495c635efSGarrett D'Amore toks[0] = "style"; 12595c635efSGarrett D'Amore toks[1] = "man"; 12695c635efSGarrett D'Amore toks[2] = "includes"; 12795c635efSGarrett D'Amore toks[3] = "fragment"; 12895c635efSGarrett D'Amore toks[4] = NULL; 12995c635efSGarrett D'Amore 13095c635efSGarrett D'Amore h = mandoc_calloc(1, sizeof(struct html)); 13195c635efSGarrett D'Amore 13295c635efSGarrett D'Amore h->type = type; 13395c635efSGarrett D'Amore h->tags.head = NULL; 13495c635efSGarrett D'Amore h->symtab = mchars_alloc(); 13595c635efSGarrett D'Amore 13695c635efSGarrett D'Amore while (outopts && *outopts) 13795c635efSGarrett D'Amore switch (getsubopt(&outopts, UNCONST(toks), &v)) { 13895c635efSGarrett D'Amore case (0): 13995c635efSGarrett D'Amore h->style = v; 14095c635efSGarrett D'Amore break; 14195c635efSGarrett D'Amore case (1): 14295c635efSGarrett D'Amore h->base_man = v; 14395c635efSGarrett D'Amore break; 14495c635efSGarrett D'Amore case (2): 14595c635efSGarrett D'Amore h->base_includes = v; 14695c635efSGarrett D'Amore break; 14795c635efSGarrett D'Amore case (3): 14895c635efSGarrett D'Amore h->oflags |= HTML_FRAGMENT; 14995c635efSGarrett D'Amore break; 15095c635efSGarrett D'Amore default: 15195c635efSGarrett D'Amore break; 15295c635efSGarrett D'Amore } 15395c635efSGarrett D'Amore 15495c635efSGarrett D'Amore return(h); 15595c635efSGarrett D'Amore } 15695c635efSGarrett D'Amore 15795c635efSGarrett D'Amore void * 15895c635efSGarrett D'Amore html_alloc(char *outopts) 15995c635efSGarrett D'Amore { 16095c635efSGarrett D'Amore 16195c635efSGarrett D'Amore return(ml_alloc(outopts, HTML_HTML_4_01_STRICT)); 16295c635efSGarrett D'Amore } 16395c635efSGarrett D'Amore 16495c635efSGarrett D'Amore 16595c635efSGarrett D'Amore void * 16695c635efSGarrett D'Amore xhtml_alloc(char *outopts) 16795c635efSGarrett D'Amore { 16895c635efSGarrett D'Amore 16995c635efSGarrett D'Amore return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT)); 17095c635efSGarrett D'Amore } 17195c635efSGarrett D'Amore 17295c635efSGarrett D'Amore 17395c635efSGarrett D'Amore void 17495c635efSGarrett D'Amore html_free(void *p) 17595c635efSGarrett D'Amore { 17695c635efSGarrett D'Amore struct tag *tag; 17795c635efSGarrett D'Amore struct html *h; 17895c635efSGarrett D'Amore 17995c635efSGarrett D'Amore h = (struct html *)p; 18095c635efSGarrett D'Amore 18195c635efSGarrett D'Amore while ((tag = h->tags.head) != NULL) { 18295c635efSGarrett D'Amore h->tags.head = tag->next; 18395c635efSGarrett D'Amore free(tag); 18495c635efSGarrett D'Amore } 18595c635efSGarrett D'Amore 18695c635efSGarrett D'Amore if (h->symtab) 18795c635efSGarrett D'Amore mchars_free(h->symtab); 18895c635efSGarrett D'Amore 18995c635efSGarrett D'Amore free(h); 19095c635efSGarrett D'Amore } 19195c635efSGarrett D'Amore 19295c635efSGarrett D'Amore 19395c635efSGarrett D'Amore void 19495c635efSGarrett D'Amore print_gen_head(struct html *h) 19595c635efSGarrett D'Amore { 19695c635efSGarrett D'Amore struct htmlpair tag[4]; 19795c635efSGarrett D'Amore 19895c635efSGarrett D'Amore tag[0].key = ATTR_HTTPEQUIV; 19995c635efSGarrett D'Amore tag[0].val = "Content-Type"; 20095c635efSGarrett D'Amore tag[1].key = ATTR_CONTENT; 20195c635efSGarrett D'Amore tag[1].val = "text/html; charset=utf-8"; 20295c635efSGarrett D'Amore print_otag(h, TAG_META, 2, tag); 20395c635efSGarrett D'Amore 20495c635efSGarrett D'Amore tag[0].key = ATTR_NAME; 20595c635efSGarrett D'Amore tag[0].val = "resource-type"; 20695c635efSGarrett D'Amore tag[1].key = ATTR_CONTENT; 20795c635efSGarrett D'Amore tag[1].val = "document"; 20895c635efSGarrett D'Amore print_otag(h, TAG_META, 2, tag); 20995c635efSGarrett D'Amore 21095c635efSGarrett D'Amore if (h->style) { 21195c635efSGarrett D'Amore tag[0].key = ATTR_REL; 21295c635efSGarrett D'Amore tag[0].val = "stylesheet"; 21395c635efSGarrett D'Amore tag[1].key = ATTR_HREF; 21495c635efSGarrett D'Amore tag[1].val = h->style; 21595c635efSGarrett D'Amore tag[2].key = ATTR_TYPE; 21695c635efSGarrett D'Amore tag[2].val = "text/css"; 21795c635efSGarrett D'Amore tag[3].key = ATTR_MEDIA; 21895c635efSGarrett D'Amore tag[3].val = "all"; 21995c635efSGarrett D'Amore print_otag(h, TAG_LINK, 4, tag); 22095c635efSGarrett D'Amore } 22195c635efSGarrett D'Amore } 22295c635efSGarrett D'Amore 22395c635efSGarrett D'Amore static void 22495c635efSGarrett D'Amore print_metaf(struct html *h, enum mandoc_esc deco) 22595c635efSGarrett D'Amore { 22695c635efSGarrett D'Amore enum htmlfont font; 22795c635efSGarrett D'Amore 22895c635efSGarrett D'Amore switch (deco) { 22995c635efSGarrett D'Amore case (ESCAPE_FONTPREV): 23095c635efSGarrett D'Amore font = h->metal; 23195c635efSGarrett D'Amore break; 23295c635efSGarrett D'Amore case (ESCAPE_FONTITALIC): 23395c635efSGarrett D'Amore font = HTMLFONT_ITALIC; 23495c635efSGarrett D'Amore break; 23595c635efSGarrett D'Amore case (ESCAPE_FONTBOLD): 23695c635efSGarrett D'Amore font = HTMLFONT_BOLD; 23795c635efSGarrett D'Amore break; 238*698f87a4SGarrett D'Amore case (ESCAPE_FONTBI): 239*698f87a4SGarrett D'Amore font = HTMLFONT_BI; 240*698f87a4SGarrett D'Amore break; 24195c635efSGarrett D'Amore case (ESCAPE_FONT): 24295c635efSGarrett D'Amore /* FALLTHROUGH */ 24395c635efSGarrett D'Amore case (ESCAPE_FONTROMAN): 24495c635efSGarrett D'Amore font = HTMLFONT_NONE; 24595c635efSGarrett D'Amore break; 24695c635efSGarrett D'Amore default: 24795c635efSGarrett D'Amore abort(); 24895c635efSGarrett D'Amore /* NOTREACHED */ 24995c635efSGarrett D'Amore } 25095c635efSGarrett D'Amore 25195c635efSGarrett D'Amore if (h->metaf) { 25295c635efSGarrett D'Amore print_tagq(h, h->metaf); 25395c635efSGarrett D'Amore h->metaf = NULL; 25495c635efSGarrett D'Amore } 25595c635efSGarrett D'Amore 25695c635efSGarrett D'Amore h->metal = h->metac; 25795c635efSGarrett D'Amore h->metac = font; 25895c635efSGarrett D'Amore 259*698f87a4SGarrett D'Amore switch (font) { 260*698f87a4SGarrett D'Amore case (HTMLFONT_ITALIC): 261*698f87a4SGarrett D'Amore h->metaf = print_otag(h, TAG_I, 0, NULL); 262*698f87a4SGarrett D'Amore break; 263*698f87a4SGarrett D'Amore case (HTMLFONT_BOLD): 264*698f87a4SGarrett D'Amore h->metaf = print_otag(h, TAG_B, 0, NULL); 265*698f87a4SGarrett D'Amore break; 266*698f87a4SGarrett D'Amore case (HTMLFONT_BI): 267*698f87a4SGarrett D'Amore h->metaf = print_otag(h, TAG_B, 0, NULL); 26895c635efSGarrett D'Amore print_otag(h, TAG_I, 0, NULL); 269*698f87a4SGarrett D'Amore break; 270*698f87a4SGarrett D'Amore default: 271*698f87a4SGarrett D'Amore break; 272*698f87a4SGarrett D'Amore } 27395c635efSGarrett D'Amore } 27495c635efSGarrett D'Amore 27595c635efSGarrett D'Amore int 27695c635efSGarrett D'Amore html_strlen(const char *cp) 27795c635efSGarrett D'Amore { 278*698f87a4SGarrett D'Amore size_t rsz; 279*698f87a4SGarrett D'Amore int skip, sz; 28095c635efSGarrett D'Amore 28195c635efSGarrett D'Amore /* 28295c635efSGarrett D'Amore * Account for escaped sequences within string length 28395c635efSGarrett D'Amore * calculations. This follows the logic in term_strlen() as we 28495c635efSGarrett D'Amore * must calculate the width of produced strings. 28595c635efSGarrett D'Amore * Assume that characters are always width of "1". This is 28695c635efSGarrett D'Amore * hacky, but it gets the job done for approximation of widths. 28795c635efSGarrett D'Amore */ 28895c635efSGarrett D'Amore 28995c635efSGarrett D'Amore sz = 0; 290*698f87a4SGarrett D'Amore skip = 0; 291*698f87a4SGarrett D'Amore while (1) { 292*698f87a4SGarrett D'Amore rsz = strcspn(cp, "\\"); 293*698f87a4SGarrett D'Amore if (rsz) { 294*698f87a4SGarrett D'Amore cp += rsz; 295*698f87a4SGarrett D'Amore if (skip) { 296*698f87a4SGarrett D'Amore skip = 0; 297*698f87a4SGarrett D'Amore rsz--; 298*698f87a4SGarrett D'Amore } 299*698f87a4SGarrett D'Amore sz += rsz; 300*698f87a4SGarrett D'Amore } 301*698f87a4SGarrett D'Amore if ('\0' == *cp) 302*698f87a4SGarrett D'Amore break; 303*698f87a4SGarrett D'Amore cp++; 304*698f87a4SGarrett D'Amore switch (mandoc_escape(&cp, NULL, NULL)) { 30595c635efSGarrett D'Amore case (ESCAPE_ERROR): 30695c635efSGarrett D'Amore return(sz); 30795c635efSGarrett D'Amore case (ESCAPE_UNICODE): 30895c635efSGarrett D'Amore /* FALLTHROUGH */ 30995c635efSGarrett D'Amore case (ESCAPE_NUMBERED): 31095c635efSGarrett D'Amore /* FALLTHROUGH */ 31195c635efSGarrett D'Amore case (ESCAPE_SPECIAL): 312*698f87a4SGarrett D'Amore if (skip) 313*698f87a4SGarrett D'Amore skip = 0; 314*698f87a4SGarrett D'Amore else 31595c635efSGarrett D'Amore sz++; 31695c635efSGarrett D'Amore break; 317*698f87a4SGarrett D'Amore case (ESCAPE_SKIPCHAR): 318*698f87a4SGarrett D'Amore skip = 1; 319*698f87a4SGarrett D'Amore break; 32095c635efSGarrett D'Amore default: 32195c635efSGarrett D'Amore break; 32295c635efSGarrett D'Amore } 32395c635efSGarrett D'Amore } 324*698f87a4SGarrett D'Amore return(sz); 32595c635efSGarrett D'Amore } 32695c635efSGarrett D'Amore 32795c635efSGarrett D'Amore static int 32895c635efSGarrett D'Amore print_encode(struct html *h, const char *p, int norecurse) 32995c635efSGarrett D'Amore { 33095c635efSGarrett D'Amore size_t sz; 33195c635efSGarrett D'Amore int c, len, nospace; 33295c635efSGarrett D'Amore const char *seq; 33395c635efSGarrett D'Amore enum mandoc_esc esc; 33495c635efSGarrett D'Amore static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' }; 33595c635efSGarrett D'Amore 33695c635efSGarrett D'Amore nospace = 0; 33795c635efSGarrett D'Amore 33895c635efSGarrett D'Amore while ('\0' != *p) { 339*698f87a4SGarrett D'Amore if (HTML_SKIPCHAR & h->flags && '\\' != *p) { 340*698f87a4SGarrett D'Amore h->flags &= ~HTML_SKIPCHAR; 341*698f87a4SGarrett D'Amore p++; 342*698f87a4SGarrett D'Amore continue; 343*698f87a4SGarrett D'Amore } 344*698f87a4SGarrett D'Amore 34595c635efSGarrett D'Amore sz = strcspn(p, rejs); 34695c635efSGarrett D'Amore 34795c635efSGarrett D'Amore fwrite(p, 1, sz, stdout); 34895c635efSGarrett D'Amore p += (int)sz; 34995c635efSGarrett D'Amore 35095c635efSGarrett D'Amore if ('\0' == *p) 35195c635efSGarrett D'Amore break; 35295c635efSGarrett D'Amore 35395c635efSGarrett D'Amore switch (*p++) { 35495c635efSGarrett D'Amore case ('<'): 35595c635efSGarrett D'Amore printf("<"); 35695c635efSGarrett D'Amore continue; 35795c635efSGarrett D'Amore case ('>'): 35895c635efSGarrett D'Amore printf(">"); 35995c635efSGarrett D'Amore continue; 36095c635efSGarrett D'Amore case ('&'): 36195c635efSGarrett D'Amore printf("&"); 36295c635efSGarrett D'Amore continue; 36395c635efSGarrett D'Amore case (ASCII_HYPH): 36495c635efSGarrett D'Amore putchar('-'); 36595c635efSGarrett D'Amore continue; 36695c635efSGarrett D'Amore default: 36795c635efSGarrett D'Amore break; 36895c635efSGarrett D'Amore } 36995c635efSGarrett D'Amore 37095c635efSGarrett D'Amore esc = mandoc_escape(&p, &seq, &len); 37195c635efSGarrett D'Amore if (ESCAPE_ERROR == esc) 37295c635efSGarrett D'Amore break; 37395c635efSGarrett D'Amore 37495c635efSGarrett D'Amore switch (esc) { 375*698f87a4SGarrett D'Amore case (ESCAPE_FONT): 376*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 377*698f87a4SGarrett D'Amore case (ESCAPE_FONTPREV): 378*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 379*698f87a4SGarrett D'Amore case (ESCAPE_FONTBOLD): 380*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 381*698f87a4SGarrett D'Amore case (ESCAPE_FONTITALIC): 382*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 383*698f87a4SGarrett D'Amore case (ESCAPE_FONTBI): 384*698f87a4SGarrett D'Amore /* FALLTHROUGH */ 385*698f87a4SGarrett D'Amore case (ESCAPE_FONTROMAN): 386*698f87a4SGarrett D'Amore if (0 == norecurse) 387*698f87a4SGarrett D'Amore print_metaf(h, esc); 388*698f87a4SGarrett D'Amore continue; 389*698f87a4SGarrett D'Amore case (ESCAPE_SKIPCHAR): 390*698f87a4SGarrett D'Amore h->flags |= HTML_SKIPCHAR; 391*698f87a4SGarrett D'Amore continue; 392*698f87a4SGarrett D'Amore default: 393*698f87a4SGarrett D'Amore break; 394*698f87a4SGarrett D'Amore } 395*698f87a4SGarrett D'Amore 396*698f87a4SGarrett D'Amore if (h->flags & HTML_SKIPCHAR) { 397*698f87a4SGarrett D'Amore h->flags &= ~HTML_SKIPCHAR; 398*698f87a4SGarrett D'Amore continue; 399*698f87a4SGarrett D'Amore } 400*698f87a4SGarrett D'Amore 401*698f87a4SGarrett D'Amore switch (esc) { 40295c635efSGarrett D'Amore case (ESCAPE_UNICODE): 40395c635efSGarrett D'Amore /* Skip passed "u" header. */ 40495c635efSGarrett D'Amore c = mchars_num2uc(seq + 1, len - 1); 40595c635efSGarrett D'Amore if ('\0' != c) 40695c635efSGarrett D'Amore printf("&#x%x;", c); 40795c635efSGarrett D'Amore break; 40895c635efSGarrett D'Amore case (ESCAPE_NUMBERED): 40995c635efSGarrett D'Amore c = mchars_num2char(seq, len); 41095c635efSGarrett D'Amore if ('\0' != c) 41195c635efSGarrett D'Amore putchar(c); 41295c635efSGarrett D'Amore break; 41395c635efSGarrett D'Amore case (ESCAPE_SPECIAL): 41495c635efSGarrett D'Amore c = mchars_spec2cp(h->symtab, seq, len); 41595c635efSGarrett D'Amore if (c > 0) 41695c635efSGarrett D'Amore printf("&#%d;", c); 41795c635efSGarrett D'Amore else if (-1 == c && 1 == len) 41895c635efSGarrett D'Amore putchar((int)*seq); 41995c635efSGarrett D'Amore break; 42095c635efSGarrett D'Amore case (ESCAPE_NOSPACE): 42195c635efSGarrett D'Amore if ('\0' == *p) 42295c635efSGarrett D'Amore nospace = 1; 42395c635efSGarrett D'Amore break; 42495c635efSGarrett D'Amore default: 42595c635efSGarrett D'Amore break; 42695c635efSGarrett D'Amore } 42795c635efSGarrett D'Amore } 42895c635efSGarrett D'Amore 42995c635efSGarrett D'Amore return(nospace); 43095c635efSGarrett D'Amore } 43195c635efSGarrett D'Amore 43295c635efSGarrett D'Amore 43395c635efSGarrett D'Amore static void 43495c635efSGarrett D'Amore print_attr(struct html *h, const char *key, const char *val) 43595c635efSGarrett D'Amore { 43695c635efSGarrett D'Amore printf(" %s=\"", key); 43795c635efSGarrett D'Amore (void)print_encode(h, val, 1); 43895c635efSGarrett D'Amore putchar('\"'); 43995c635efSGarrett D'Amore } 44095c635efSGarrett D'Amore 44195c635efSGarrett D'Amore 44295c635efSGarrett D'Amore struct tag * 44395c635efSGarrett D'Amore print_otag(struct html *h, enum htmltag tag, 44495c635efSGarrett D'Amore int sz, const struct htmlpair *p) 44595c635efSGarrett D'Amore { 44695c635efSGarrett D'Amore int i; 44795c635efSGarrett D'Amore struct tag *t; 44895c635efSGarrett D'Amore 44995c635efSGarrett D'Amore /* Push this tags onto the stack of open scopes. */ 45095c635efSGarrett D'Amore 45195c635efSGarrett D'Amore if ( ! (HTML_NOSTACK & htmltags[tag].flags)) { 45295c635efSGarrett D'Amore t = mandoc_malloc(sizeof(struct tag)); 45395c635efSGarrett D'Amore t->tag = tag; 45495c635efSGarrett D'Amore t->next = h->tags.head; 45595c635efSGarrett D'Amore h->tags.head = t; 45695c635efSGarrett D'Amore } else 45795c635efSGarrett D'Amore t = NULL; 45895c635efSGarrett D'Amore 45995c635efSGarrett D'Amore if ( ! (HTML_NOSPACE & h->flags)) 46095c635efSGarrett D'Amore if ( ! (HTML_CLRLINE & htmltags[tag].flags)) { 46195c635efSGarrett D'Amore /* Manage keeps! */ 46295c635efSGarrett D'Amore if ( ! (HTML_KEEP & h->flags)) { 46395c635efSGarrett D'Amore if (HTML_PREKEEP & h->flags) 46495c635efSGarrett D'Amore h->flags |= HTML_KEEP; 46595c635efSGarrett D'Amore putchar(' '); 46695c635efSGarrett D'Amore } else 46795c635efSGarrett D'Amore printf(" "); 46895c635efSGarrett D'Amore } 46995c635efSGarrett D'Amore 47095c635efSGarrett D'Amore if ( ! (h->flags & HTML_NONOSPACE)) 47195c635efSGarrett D'Amore h->flags &= ~HTML_NOSPACE; 47295c635efSGarrett D'Amore else 47395c635efSGarrett D'Amore h->flags |= HTML_NOSPACE; 47495c635efSGarrett D'Amore 47595c635efSGarrett D'Amore /* Print out the tag name and attributes. */ 47695c635efSGarrett D'Amore 47795c635efSGarrett D'Amore printf("<%s", htmltags[tag].name); 47895c635efSGarrett D'Amore for (i = 0; i < sz; i++) 47995c635efSGarrett D'Amore print_attr(h, htmlattrs[p[i].key], p[i].val); 48095c635efSGarrett D'Amore 48195c635efSGarrett D'Amore /* Add non-overridable attributes. */ 48295c635efSGarrett D'Amore 48395c635efSGarrett D'Amore if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) { 48495c635efSGarrett D'Amore print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml"); 48595c635efSGarrett D'Amore print_attr(h, "xml:lang", "en"); 48695c635efSGarrett D'Amore print_attr(h, "lang", "en"); 48795c635efSGarrett D'Amore } 48895c635efSGarrett D'Amore 48995c635efSGarrett D'Amore /* Accommodate for XML "well-formed" singleton escaping. */ 49095c635efSGarrett D'Amore 49195c635efSGarrett D'Amore if (HTML_AUTOCLOSE & htmltags[tag].flags) 49295c635efSGarrett D'Amore switch (h->type) { 49395c635efSGarrett D'Amore case (HTML_XHTML_1_0_STRICT): 49495c635efSGarrett D'Amore putchar('/'); 49595c635efSGarrett D'Amore break; 49695c635efSGarrett D'Amore default: 49795c635efSGarrett D'Amore break; 49895c635efSGarrett D'Amore } 49995c635efSGarrett D'Amore 50095c635efSGarrett D'Amore putchar('>'); 50195c635efSGarrett D'Amore 50295c635efSGarrett D'Amore h->flags |= HTML_NOSPACE; 50395c635efSGarrett D'Amore 50495c635efSGarrett D'Amore if ((HTML_AUTOCLOSE | HTML_CLRLINE) & htmltags[tag].flags) 50595c635efSGarrett D'Amore putchar('\n'); 50695c635efSGarrett D'Amore 50795c635efSGarrett D'Amore return(t); 50895c635efSGarrett D'Amore } 50995c635efSGarrett D'Amore 51095c635efSGarrett D'Amore 51195c635efSGarrett D'Amore static void 51295c635efSGarrett D'Amore print_ctag(struct html *h, enum htmltag tag) 51395c635efSGarrett D'Amore { 51495c635efSGarrett D'Amore 51595c635efSGarrett D'Amore printf("</%s>", htmltags[tag].name); 51695c635efSGarrett D'Amore if (HTML_CLRLINE & htmltags[tag].flags) { 51795c635efSGarrett D'Amore h->flags |= HTML_NOSPACE; 51895c635efSGarrett D'Amore putchar('\n'); 51995c635efSGarrett D'Amore } 52095c635efSGarrett D'Amore } 52195c635efSGarrett D'Amore 52295c635efSGarrett D'Amore void 52395c635efSGarrett D'Amore print_gen_decls(struct html *h) 52495c635efSGarrett D'Amore { 52595c635efSGarrett D'Amore const char *doctype; 52695c635efSGarrett D'Amore const char *dtd; 52795c635efSGarrett D'Amore const char *name; 52895c635efSGarrett D'Amore 52995c635efSGarrett D'Amore switch (h->type) { 53095c635efSGarrett D'Amore case (HTML_HTML_4_01_STRICT): 53195c635efSGarrett D'Amore name = "HTML"; 53295c635efSGarrett D'Amore doctype = "-//W3C//DTD HTML 4.01//EN"; 53395c635efSGarrett D'Amore dtd = "http://www.w3.org/TR/html4/strict.dtd"; 53495c635efSGarrett D'Amore break; 53595c635efSGarrett D'Amore default: 53695c635efSGarrett D'Amore puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 53795c635efSGarrett D'Amore name = "html"; 53895c635efSGarrett D'Amore doctype = "-//W3C//DTD XHTML 1.0 Strict//EN"; 53995c635efSGarrett D'Amore dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; 54095c635efSGarrett D'Amore break; 54195c635efSGarrett D'Amore } 54295c635efSGarrett D'Amore 54395c635efSGarrett D'Amore printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n", 54495c635efSGarrett D'Amore name, doctype, dtd); 54595c635efSGarrett D'Amore } 54695c635efSGarrett D'Amore 54795c635efSGarrett D'Amore void 54895c635efSGarrett D'Amore print_text(struct html *h, const char *word) 54995c635efSGarrett D'Amore { 55095c635efSGarrett D'Amore 55195c635efSGarrett D'Amore if ( ! (HTML_NOSPACE & h->flags)) { 55295c635efSGarrett D'Amore /* Manage keeps! */ 55395c635efSGarrett D'Amore if ( ! (HTML_KEEP & h->flags)) { 55495c635efSGarrett D'Amore if (HTML_PREKEEP & h->flags) 55595c635efSGarrett D'Amore h->flags |= HTML_KEEP; 55695c635efSGarrett D'Amore putchar(' '); 55795c635efSGarrett D'Amore } else 55895c635efSGarrett D'Amore printf(" "); 55995c635efSGarrett D'Amore } 56095c635efSGarrett D'Amore 56195c635efSGarrett D'Amore assert(NULL == h->metaf); 562*698f87a4SGarrett D'Amore switch (h->metac) { 563*698f87a4SGarrett D'Amore case (HTMLFONT_ITALIC): 564*698f87a4SGarrett D'Amore h->metaf = print_otag(h, TAG_I, 0, NULL); 565*698f87a4SGarrett D'Amore break; 566*698f87a4SGarrett D'Amore case (HTMLFONT_BOLD): 567*698f87a4SGarrett D'Amore h->metaf = print_otag(h, TAG_B, 0, NULL); 568*698f87a4SGarrett D'Amore break; 569*698f87a4SGarrett D'Amore case (HTMLFONT_BI): 570*698f87a4SGarrett D'Amore h->metaf = print_otag(h, TAG_B, 0, NULL); 57195c635efSGarrett D'Amore print_otag(h, TAG_I, 0, NULL); 572*698f87a4SGarrett D'Amore break; 573*698f87a4SGarrett D'Amore default: 574*698f87a4SGarrett D'Amore break; 575*698f87a4SGarrett D'Amore } 57695c635efSGarrett D'Amore 57795c635efSGarrett D'Amore assert(word); 57895c635efSGarrett D'Amore if ( ! print_encode(h, word, 0)) { 57995c635efSGarrett D'Amore if ( ! (h->flags & HTML_NONOSPACE)) 58095c635efSGarrett D'Amore h->flags &= ~HTML_NOSPACE; 58195c635efSGarrett D'Amore } else 58295c635efSGarrett D'Amore h->flags |= HTML_NOSPACE; 58395c635efSGarrett D'Amore 58495c635efSGarrett D'Amore if (h->metaf) { 58595c635efSGarrett D'Amore print_tagq(h, h->metaf); 58695c635efSGarrett D'Amore h->metaf = NULL; 58795c635efSGarrett D'Amore } 58895c635efSGarrett D'Amore 58995c635efSGarrett D'Amore h->flags &= ~HTML_IGNDELIM; 59095c635efSGarrett D'Amore } 59195c635efSGarrett D'Amore 59295c635efSGarrett D'Amore 59395c635efSGarrett D'Amore void 59495c635efSGarrett D'Amore print_tagq(struct html *h, const struct tag *until) 59595c635efSGarrett D'Amore { 59695c635efSGarrett D'Amore struct tag *tag; 59795c635efSGarrett D'Amore 59895c635efSGarrett D'Amore while ((tag = h->tags.head) != NULL) { 59995c635efSGarrett D'Amore /* 60095c635efSGarrett D'Amore * Remember to close out and nullify the current 60195c635efSGarrett D'Amore * meta-font and table, if applicable. 60295c635efSGarrett D'Amore */ 60395c635efSGarrett D'Amore if (tag == h->metaf) 60495c635efSGarrett D'Amore h->metaf = NULL; 60595c635efSGarrett D'Amore if (tag == h->tblt) 60695c635efSGarrett D'Amore h->tblt = NULL; 60795c635efSGarrett D'Amore print_ctag(h, tag->tag); 60895c635efSGarrett D'Amore h->tags.head = tag->next; 60995c635efSGarrett D'Amore free(tag); 61095c635efSGarrett D'Amore if (until && tag == until) 61195c635efSGarrett D'Amore return; 61295c635efSGarrett D'Amore } 61395c635efSGarrett D'Amore } 61495c635efSGarrett D'Amore 61595c635efSGarrett D'Amore 61695c635efSGarrett D'Amore void 61795c635efSGarrett D'Amore print_stagq(struct html *h, const struct tag *suntil) 61895c635efSGarrett D'Amore { 61995c635efSGarrett D'Amore struct tag *tag; 62095c635efSGarrett D'Amore 62195c635efSGarrett D'Amore while ((tag = h->tags.head) != NULL) { 62295c635efSGarrett D'Amore if (suntil && tag == suntil) 62395c635efSGarrett D'Amore return; 62495c635efSGarrett D'Amore /* 62595c635efSGarrett D'Amore * Remember to close out and nullify the current 62695c635efSGarrett D'Amore * meta-font and table, if applicable. 62795c635efSGarrett D'Amore */ 62895c635efSGarrett D'Amore if (tag == h->metaf) 62995c635efSGarrett D'Amore h->metaf = NULL; 63095c635efSGarrett D'Amore if (tag == h->tblt) 63195c635efSGarrett D'Amore h->tblt = NULL; 63295c635efSGarrett D'Amore print_ctag(h, tag->tag); 63395c635efSGarrett D'Amore h->tags.head = tag->next; 63495c635efSGarrett D'Amore free(tag); 63595c635efSGarrett D'Amore } 63695c635efSGarrett D'Amore } 63795c635efSGarrett D'Amore 63895c635efSGarrett D'Amore void 63995c635efSGarrett D'Amore bufinit(struct html *h) 64095c635efSGarrett D'Amore { 64195c635efSGarrett D'Amore 64295c635efSGarrett D'Amore h->buf[0] = '\0'; 64395c635efSGarrett D'Amore h->buflen = 0; 64495c635efSGarrett D'Amore } 64595c635efSGarrett D'Amore 64695c635efSGarrett D'Amore void 64795c635efSGarrett D'Amore bufcat_style(struct html *h, const char *key, const char *val) 64895c635efSGarrett D'Amore { 64995c635efSGarrett D'Amore 65095c635efSGarrett D'Amore bufcat(h, key); 65195c635efSGarrett D'Amore bufcat(h, ":"); 65295c635efSGarrett D'Amore bufcat(h, val); 65395c635efSGarrett D'Amore bufcat(h, ";"); 65495c635efSGarrett D'Amore } 65595c635efSGarrett D'Amore 65695c635efSGarrett D'Amore void 65795c635efSGarrett D'Amore bufcat(struct html *h, const char *p) 65895c635efSGarrett D'Amore { 65995c635efSGarrett D'Amore 66095c635efSGarrett D'Amore h->buflen = strlcat(h->buf, p, BUFSIZ); 66195c635efSGarrett D'Amore assert(h->buflen < BUFSIZ); 66295c635efSGarrett D'Amore } 66395c635efSGarrett D'Amore 66495c635efSGarrett D'Amore void 66595c635efSGarrett D'Amore bufcat_fmt(struct html *h, const char *fmt, ...) 66695c635efSGarrett D'Amore { 66795c635efSGarrett D'Amore va_list ap; 66895c635efSGarrett D'Amore 66995c635efSGarrett D'Amore va_start(ap, fmt); 67095c635efSGarrett D'Amore (void)vsnprintf(h->buf + (int)h->buflen, 67195c635efSGarrett D'Amore BUFSIZ - h->buflen - 1, fmt, ap); 67295c635efSGarrett D'Amore va_end(ap); 67395c635efSGarrett D'Amore h->buflen = strlen(h->buf); 67495c635efSGarrett D'Amore } 67595c635efSGarrett D'Amore 67695c635efSGarrett D'Amore static void 67795c635efSGarrett D'Amore bufncat(struct html *h, const char *p, size_t sz) 67895c635efSGarrett D'Amore { 67995c635efSGarrett D'Amore 68095c635efSGarrett D'Amore assert(h->buflen + sz + 1 < BUFSIZ); 68195c635efSGarrett D'Amore strncat(h->buf, p, sz); 68295c635efSGarrett D'Amore h->buflen += sz; 68395c635efSGarrett D'Amore } 68495c635efSGarrett D'Amore 68595c635efSGarrett D'Amore void 68695c635efSGarrett D'Amore buffmt_includes(struct html *h, const char *name) 68795c635efSGarrett D'Amore { 68895c635efSGarrett D'Amore const char *p, *pp; 68995c635efSGarrett D'Amore 69095c635efSGarrett D'Amore pp = h->base_includes; 69195c635efSGarrett D'Amore 69295c635efSGarrett D'Amore bufinit(h); 69395c635efSGarrett D'Amore while (NULL != (p = strchr(pp, '%'))) { 69495c635efSGarrett D'Amore bufncat(h, pp, (size_t)(p - pp)); 69595c635efSGarrett D'Amore switch (*(p + 1)) { 69695c635efSGarrett D'Amore case('I'): 69795c635efSGarrett D'Amore bufcat(h, name); 69895c635efSGarrett D'Amore break; 69995c635efSGarrett D'Amore default: 70095c635efSGarrett D'Amore bufncat(h, p, 2); 70195c635efSGarrett D'Amore break; 70295c635efSGarrett D'Amore } 70395c635efSGarrett D'Amore pp = p + 2; 70495c635efSGarrett D'Amore } 70595c635efSGarrett D'Amore if (pp) 70695c635efSGarrett D'Amore bufcat(h, pp); 70795c635efSGarrett D'Amore } 70895c635efSGarrett D'Amore 70995c635efSGarrett D'Amore void 71095c635efSGarrett D'Amore buffmt_man(struct html *h, 71195c635efSGarrett D'Amore const char *name, const char *sec) 71295c635efSGarrett D'Amore { 71395c635efSGarrett D'Amore const char *p, *pp; 71495c635efSGarrett D'Amore 71595c635efSGarrett D'Amore pp = h->base_man; 71695c635efSGarrett D'Amore 71795c635efSGarrett D'Amore bufinit(h); 71895c635efSGarrett D'Amore while (NULL != (p = strchr(pp, '%'))) { 71995c635efSGarrett D'Amore bufncat(h, pp, (size_t)(p - pp)); 72095c635efSGarrett D'Amore switch (*(p + 1)) { 72195c635efSGarrett D'Amore case('S'): 72295c635efSGarrett D'Amore bufcat(h, sec ? sec : "1"); 72395c635efSGarrett D'Amore break; 72495c635efSGarrett D'Amore case('N'): 72595c635efSGarrett D'Amore bufcat_fmt(h, name); 72695c635efSGarrett D'Amore break; 72795c635efSGarrett D'Amore default: 72895c635efSGarrett D'Amore bufncat(h, p, 2); 72995c635efSGarrett D'Amore break; 73095c635efSGarrett D'Amore } 73195c635efSGarrett D'Amore pp = p + 2; 73295c635efSGarrett D'Amore } 73395c635efSGarrett D'Amore if (pp) 73495c635efSGarrett D'Amore bufcat(h, pp); 73595c635efSGarrett D'Amore } 73695c635efSGarrett D'Amore 73795c635efSGarrett D'Amore void 73895c635efSGarrett D'Amore bufcat_su(struct html *h, const char *p, const struct roffsu *su) 73995c635efSGarrett D'Amore { 74095c635efSGarrett D'Amore double v; 74195c635efSGarrett D'Amore 74295c635efSGarrett D'Amore v = su->scale; 74395c635efSGarrett D'Amore if (SCALE_MM == su->unit && 0.0 == (v /= 100.0)) 74495c635efSGarrett D'Amore v = 1.0; 74595c635efSGarrett D'Amore 74695c635efSGarrett D'Amore bufcat_fmt(h, "%s: %.2f%s;", p, v, roffscales[su->unit]); 74795c635efSGarrett D'Amore } 74895c635efSGarrett D'Amore 74995c635efSGarrett D'Amore void 75095c635efSGarrett D'Amore bufcat_id(struct html *h, const char *src) 75195c635efSGarrett D'Amore { 75295c635efSGarrett D'Amore 75395c635efSGarrett D'Amore /* Cf. <http://www.w3.org/TR/html4/types.html#h-6.2>. */ 75495c635efSGarrett D'Amore 75595c635efSGarrett D'Amore while ('\0' != *src) 75695c635efSGarrett D'Amore bufcat_fmt(h, "%.2x", *src++); 75795c635efSGarrett D'Amore } 758