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 *
ml_alloc(char * outopts,enum htmltype type)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 *
html_alloc(char * outopts)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 *
xhtml_alloc(char * outopts)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
html_free(void * p)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
print_gen_head(struct html * h)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
print_metaf(struct html * h,enum mandoc_esc deco)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
html_strlen(const char * cp)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
print_encode(struct html * h,const char * p,int norecurse)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
print_attr(struct html * h,const char * key,const char * val)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 *
print_otag(struct html * h,enum htmltag tag,int sz,const struct htmlpair * p)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
print_ctag(struct html * h,enum htmltag tag)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
print_gen_decls(struct html * h)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
print_text(struct html * h,const char * word)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
print_tagq(struct html * h,const struct tag * until)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
print_stagq(struct html * h,const struct tag * suntil)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
bufinit(struct html * h)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
bufcat_style(struct html * h,const char * key,const char * val)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
bufcat(struct html * h,const char * p)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
bufcat_fmt(struct html * h,const char * fmt,...)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
bufncat(struct html * h,const char * p,size_t sz)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
buffmt_includes(struct html * h,const char * name)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
buffmt_man(struct html * h,const char * name,const char * sec)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
bufcat_su(struct html * h,const char * p,const struct roffsu * su)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
bufcat_id(struct html * h,const char * src)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