xref: /freebsd/contrib/mandoc/tbl_html.c (revision 45a5aec3f156d8a01fe1ea4ec87c1b1d489f13ac)
1*45a5aec3SBaptiste Daroussin /*	$Id: tbl_html.c,v 1.33 2019/03/17 18:21:45 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
361d06d6bSBaptiste Daroussin  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
47295610fSBaptiste Daroussin  * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
561d06d6bSBaptiste Daroussin  *
661d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
761d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
861d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
961d06d6bSBaptiste Daroussin  *
1061d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1161d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1261d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1361d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1461d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1561d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1661d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1761d06d6bSBaptiste Daroussin  */
1861d06d6bSBaptiste Daroussin #include "config.h"
1961d06d6bSBaptiste Daroussin 
2061d06d6bSBaptiste Daroussin #include <sys/types.h>
2161d06d6bSBaptiste Daroussin 
2261d06d6bSBaptiste Daroussin #include <assert.h>
2361d06d6bSBaptiste Daroussin #include <stdio.h>
2461d06d6bSBaptiste Daroussin #include <stdlib.h>
2561d06d6bSBaptiste Daroussin #include <string.h>
2661d06d6bSBaptiste Daroussin 
2761d06d6bSBaptiste Daroussin #include "mandoc.h"
28*45a5aec3SBaptiste Daroussin #include "roff.h"
297295610fSBaptiste Daroussin #include "tbl.h"
3061d06d6bSBaptiste Daroussin #include "out.h"
3161d06d6bSBaptiste Daroussin #include "html.h"
3261d06d6bSBaptiste Daroussin 
3361d06d6bSBaptiste Daroussin static	void	 html_tblopen(struct html *, const struct tbl_span *);
3461d06d6bSBaptiste Daroussin static	size_t	 html_tbl_len(size_t, void *);
3561d06d6bSBaptiste Daroussin static	size_t	 html_tbl_strlen(const char *, void *);
3661d06d6bSBaptiste Daroussin static	size_t	 html_tbl_sulen(const struct roffsu *, void *);
3761d06d6bSBaptiste Daroussin 
3861d06d6bSBaptiste Daroussin 
3961d06d6bSBaptiste Daroussin static size_t
4061d06d6bSBaptiste Daroussin html_tbl_len(size_t sz, void *arg)
4161d06d6bSBaptiste Daroussin {
4261d06d6bSBaptiste Daroussin 	return sz;
4361d06d6bSBaptiste Daroussin }
4461d06d6bSBaptiste Daroussin 
4561d06d6bSBaptiste Daroussin static size_t
4661d06d6bSBaptiste Daroussin html_tbl_strlen(const char *p, void *arg)
4761d06d6bSBaptiste Daroussin {
4861d06d6bSBaptiste Daroussin 	return strlen(p);
4961d06d6bSBaptiste Daroussin }
5061d06d6bSBaptiste Daroussin 
5161d06d6bSBaptiste Daroussin static size_t
5261d06d6bSBaptiste Daroussin html_tbl_sulen(const struct roffsu *su, void *arg)
5361d06d6bSBaptiste Daroussin {
5461d06d6bSBaptiste Daroussin 	if (su->scale < 0.0)
5561d06d6bSBaptiste Daroussin 		return 0;
5661d06d6bSBaptiste Daroussin 
5761d06d6bSBaptiste Daroussin 	switch (su->unit) {
5861d06d6bSBaptiste Daroussin 	case SCALE_FS:  /* 2^16 basic units */
5961d06d6bSBaptiste Daroussin 		return su->scale * 65536.0 / 24.0;
6061d06d6bSBaptiste Daroussin 	case SCALE_IN:  /* 10 characters per inch */
6161d06d6bSBaptiste Daroussin 		return su->scale * 10.0;
6261d06d6bSBaptiste Daroussin 	case SCALE_CM:  /* 2.54 cm per inch */
6361d06d6bSBaptiste Daroussin 		return su->scale * 10.0 / 2.54;
6461d06d6bSBaptiste Daroussin 	case SCALE_PC:  /* 6 pica per inch */
6561d06d6bSBaptiste Daroussin 	case SCALE_VS:
6661d06d6bSBaptiste Daroussin 		return su->scale * 10.0 / 6.0;
6761d06d6bSBaptiste Daroussin 	case SCALE_EN:
6861d06d6bSBaptiste Daroussin 	case SCALE_EM:
6961d06d6bSBaptiste Daroussin 		return su->scale;
7061d06d6bSBaptiste Daroussin 	case SCALE_PT:  /* 12 points per pica */
7161d06d6bSBaptiste Daroussin 		return su->scale * 10.0 / 6.0 / 12.0;
7261d06d6bSBaptiste Daroussin 	case SCALE_BU:  /* 24 basic units per character */
7361d06d6bSBaptiste Daroussin 		return su->scale / 24.0;
7461d06d6bSBaptiste Daroussin 	case SCALE_MM:  /* 1/1000 inch */
7561d06d6bSBaptiste Daroussin 		return su->scale / 100.0;
7661d06d6bSBaptiste Daroussin 	default:
7761d06d6bSBaptiste Daroussin 		abort();
7861d06d6bSBaptiste Daroussin 	}
7961d06d6bSBaptiste Daroussin }
8061d06d6bSBaptiste Daroussin 
8161d06d6bSBaptiste Daroussin static void
8261d06d6bSBaptiste Daroussin html_tblopen(struct html *h, const struct tbl_span *sp)
8361d06d6bSBaptiste Daroussin {
847295610fSBaptiste Daroussin 	html_close_paragraph(h);
8561d06d6bSBaptiste Daroussin 	if (h->tbl.cols == NULL) {
8661d06d6bSBaptiste Daroussin 		h->tbl.len = html_tbl_len;
8761d06d6bSBaptiste Daroussin 		h->tbl.slen = html_tbl_strlen;
8861d06d6bSBaptiste Daroussin 		h->tbl.sulen = html_tbl_sulen;
8961d06d6bSBaptiste Daroussin 		tblcalc(&h->tbl, sp, 0, 0);
9061d06d6bSBaptiste Daroussin 	}
9161d06d6bSBaptiste Daroussin 	assert(NULL == h->tblt);
927295610fSBaptiste Daroussin 	h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl",
937295610fSBaptiste Daroussin 	    "border",
947295610fSBaptiste Daroussin 		sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL,
957295610fSBaptiste Daroussin 	    "border-style",
967295610fSBaptiste Daroussin 		sp->opts->opts & TBL_OPT_DBOX ? "double" :
977295610fSBaptiste Daroussin 		sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL,
987295610fSBaptiste Daroussin 	    "border-top-style",
997295610fSBaptiste Daroussin 		sp->pos == TBL_SPAN_DHORIZ ? "double" :
1007295610fSBaptiste Daroussin 		sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL);
10161d06d6bSBaptiste Daroussin }
10261d06d6bSBaptiste Daroussin 
10361d06d6bSBaptiste Daroussin void
10461d06d6bSBaptiste Daroussin print_tblclose(struct html *h)
10561d06d6bSBaptiste Daroussin {
10661d06d6bSBaptiste Daroussin 
10761d06d6bSBaptiste Daroussin 	assert(h->tblt);
10861d06d6bSBaptiste Daroussin 	print_tagq(h, h->tblt);
10961d06d6bSBaptiste Daroussin 	h->tblt = NULL;
11061d06d6bSBaptiste Daroussin }
11161d06d6bSBaptiste Daroussin 
11261d06d6bSBaptiste Daroussin void
11361d06d6bSBaptiste Daroussin print_tbl(struct html *h, const struct tbl_span *sp)
11461d06d6bSBaptiste Daroussin {
11561d06d6bSBaptiste Daroussin 	const struct tbl_dat	*dp;
1167295610fSBaptiste Daroussin 	const struct tbl_cell	*cp;
1177295610fSBaptiste Daroussin 	const struct tbl_span	*psp;
11861d06d6bSBaptiste Daroussin 	struct tag		*tt;
1197295610fSBaptiste Daroussin 	const char		*hspans, *vspans, *halign, *valign;
1207295610fSBaptiste Daroussin 	const char		*bborder, *lborder, *rborder;
1217295610fSBaptiste Daroussin 	char			 hbuf[4], vbuf[4];
1227295610fSBaptiste Daroussin 	int			 i;
12361d06d6bSBaptiste Daroussin 
12461d06d6bSBaptiste Daroussin 	if (h->tblt == NULL)
12561d06d6bSBaptiste Daroussin 		html_tblopen(h, sp);
12661d06d6bSBaptiste Daroussin 
1277295610fSBaptiste Daroussin 	/*
1287295610fSBaptiste Daroussin 	 * Horizontal lines spanning the whole table
1297295610fSBaptiste Daroussin 	 * are handled by previous or following table rows.
1307295610fSBaptiste Daroussin 	 */
1317295610fSBaptiste Daroussin 
1327295610fSBaptiste Daroussin 	if (sp->pos != TBL_SPAN_DATA)
1337295610fSBaptiste Daroussin 		return;
1347295610fSBaptiste Daroussin 
1357295610fSBaptiste Daroussin 	/* Inhibit printing of spaces: we do padding ourselves. */
13661d06d6bSBaptiste Daroussin 
13761d06d6bSBaptiste Daroussin 	h->flags |= HTML_NONOSPACE;
13861d06d6bSBaptiste Daroussin 	h->flags |= HTML_NOSPACE;
13961d06d6bSBaptiste Daroussin 
1407295610fSBaptiste Daroussin 	/* Draw a vertical line left of this row? */
14161d06d6bSBaptiste Daroussin 
1427295610fSBaptiste Daroussin 	switch (sp->layout->vert) {
1437295610fSBaptiste Daroussin 	case 2:
1447295610fSBaptiste Daroussin 		lborder = "double";
1457295610fSBaptiste Daroussin 		break;
1467295610fSBaptiste Daroussin 	case 1:
1477295610fSBaptiste Daroussin 		lborder = "solid";
14861d06d6bSBaptiste Daroussin 		break;
14961d06d6bSBaptiste Daroussin 	default:
1507295610fSBaptiste Daroussin 		lborder = NULL;
1517295610fSBaptiste Daroussin 		break;
1527295610fSBaptiste Daroussin 	}
15361d06d6bSBaptiste Daroussin 
1547295610fSBaptiste Daroussin 	/* Draw a horizontal line below this row? */
1557295610fSBaptiste Daroussin 
1567295610fSBaptiste Daroussin 	bborder = NULL;
1577295610fSBaptiste Daroussin 	if ((psp = sp->next) != NULL) {
1587295610fSBaptiste Daroussin 		switch (psp->pos) {
1597295610fSBaptiste Daroussin 		case TBL_SPAN_DHORIZ:
1607295610fSBaptiste Daroussin 			bborder = "double";
1617295610fSBaptiste Daroussin 			break;
1627295610fSBaptiste Daroussin 		case TBL_SPAN_HORIZ:
1637295610fSBaptiste Daroussin 			bborder = "solid";
1647295610fSBaptiste Daroussin 			break;
1657295610fSBaptiste Daroussin 		default:
1667295610fSBaptiste Daroussin 			break;
1677295610fSBaptiste Daroussin 		}
1687295610fSBaptiste Daroussin 	}
1697295610fSBaptiste Daroussin 
1707295610fSBaptiste Daroussin 	tt = print_otag(h, TAG_TR, "ss",
1717295610fSBaptiste Daroussin 	    "border-left-style", lborder,
1727295610fSBaptiste Daroussin 	    "border-bottom-style", bborder);
1737295610fSBaptiste Daroussin 
1747295610fSBaptiste Daroussin 	for (dp = sp->first; dp != NULL; dp = dp->next) {
1757295610fSBaptiste Daroussin 		print_stagq(h, tt);
1767295610fSBaptiste Daroussin 
1777295610fSBaptiste Daroussin 		/*
1787295610fSBaptiste Daroussin 		 * Do not generate <td> elements for continuations
1797295610fSBaptiste Daroussin 		 * of spanned cells.  Larger <td> elements covering
1807295610fSBaptiste Daroussin 		 * this space were already generated earlier.
1817295610fSBaptiste Daroussin 		 */
1827295610fSBaptiste Daroussin 
1837295610fSBaptiste Daroussin 		cp = dp->layout;
1847295610fSBaptiste Daroussin 		if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN ||
1857295610fSBaptiste Daroussin 		    (dp->string != NULL && strcmp(dp->string, "\\^") == 0))
18661d06d6bSBaptiste Daroussin 			continue;
1877295610fSBaptiste Daroussin 
1887295610fSBaptiste Daroussin 		/* Determine the attribute values. */
1897295610fSBaptiste Daroussin 
1907295610fSBaptiste Daroussin 		if (dp->hspans > 0) {
1917295610fSBaptiste Daroussin 			(void)snprintf(hbuf, sizeof(hbuf),
1927295610fSBaptiste Daroussin 			    "%d", dp->hspans + 1);
1937295610fSBaptiste Daroussin 			hspans = hbuf;
1947295610fSBaptiste Daroussin 		} else
1957295610fSBaptiste Daroussin 			hspans = NULL;
1967295610fSBaptiste Daroussin 		if (dp->vspans > 0) {
1977295610fSBaptiste Daroussin 			(void)snprintf(vbuf, sizeof(vbuf),
1987295610fSBaptiste Daroussin 			    "%d", dp->vspans + 1);
1997295610fSBaptiste Daroussin 			vspans = vbuf;
2007295610fSBaptiste Daroussin 		} else
2017295610fSBaptiste Daroussin 			vspans = NULL;
2027295610fSBaptiste Daroussin 
2037295610fSBaptiste Daroussin 		switch (cp->pos) {
2047295610fSBaptiste Daroussin 		case TBL_CELL_CENTRE:
2057295610fSBaptiste Daroussin 			halign = "center";
2067295610fSBaptiste Daroussin 			break;
2077295610fSBaptiste Daroussin 		case TBL_CELL_RIGHT:
2087295610fSBaptiste Daroussin 		case TBL_CELL_NUMBER:
2097295610fSBaptiste Daroussin 			halign = "right";
2107295610fSBaptiste Daroussin 			break;
2117295610fSBaptiste Daroussin 		default:
2127295610fSBaptiste Daroussin 			halign = NULL;
2137295610fSBaptiste Daroussin 			break;
2147295610fSBaptiste Daroussin 		}
2157295610fSBaptiste Daroussin 		if (cp->flags & TBL_CELL_TALIGN)
2167295610fSBaptiste Daroussin 			valign = "top";
2177295610fSBaptiste Daroussin 		else if (cp->flags & TBL_CELL_BALIGN)
2187295610fSBaptiste Daroussin 			valign = "bottom";
2197295610fSBaptiste Daroussin 		else
2207295610fSBaptiste Daroussin 			valign = NULL;
2217295610fSBaptiste Daroussin 
2227295610fSBaptiste Daroussin 		for (i = dp->hspans; i > 0; i--)
2237295610fSBaptiste Daroussin 			cp = cp->next;
2247295610fSBaptiste Daroussin 		switch (cp->vert) {
2257295610fSBaptiste Daroussin 		case 2:
2267295610fSBaptiste Daroussin 			rborder = "double";
2277295610fSBaptiste Daroussin 			break;
2287295610fSBaptiste Daroussin 		case 1:
2297295610fSBaptiste Daroussin 			rborder = "solid";
2307295610fSBaptiste Daroussin 			break;
2317295610fSBaptiste Daroussin 		default:
2327295610fSBaptiste Daroussin 			rborder = NULL;
2337295610fSBaptiste Daroussin 			break;
2347295610fSBaptiste Daroussin 		}
2357295610fSBaptiste Daroussin 
2367295610fSBaptiste Daroussin 		/* Print the element and the attributes. */
2377295610fSBaptiste Daroussin 
2387295610fSBaptiste Daroussin 		print_otag(h, TAG_TD, "??sss",
2397295610fSBaptiste Daroussin 		    "colspan", hspans, "rowspan", vspans,
2407295610fSBaptiste Daroussin 		    "vertical-align", valign,
2417295610fSBaptiste Daroussin 		    "text-align", halign,
2427295610fSBaptiste Daroussin 		    "border-right-style", rborder);
24361d06d6bSBaptiste Daroussin 		if (dp->string != NULL)
24461d06d6bSBaptiste Daroussin 			print_text(h, dp->string);
24561d06d6bSBaptiste Daroussin 	}
24661d06d6bSBaptiste Daroussin 
24761d06d6bSBaptiste Daroussin 	print_tagq(h, tt);
24861d06d6bSBaptiste Daroussin 
24961d06d6bSBaptiste Daroussin 	h->flags &= ~HTML_NONOSPACE;
25061d06d6bSBaptiste Daroussin 
25161d06d6bSBaptiste Daroussin 	if (sp->next == NULL) {
25261d06d6bSBaptiste Daroussin 		assert(h->tbl.cols);
25361d06d6bSBaptiste Daroussin 		free(h->tbl.cols);
25461d06d6bSBaptiste Daroussin 		h->tbl.cols = NULL;
25561d06d6bSBaptiste Daroussin 		print_tblclose(h);
25661d06d6bSBaptiste Daroussin 	}
25761d06d6bSBaptiste Daroussin }
258