xref: /freebsd/contrib/mandoc/tbl_html.c (revision 7295610f5da64ab1818458ce007d9eb924496330)
1*7295610fSBaptiste Daroussin /*	$Id: tbl_html.c,v 1.32 2019/01/06 04:55:09 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
361d06d6bSBaptiste Daroussin  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*7295610fSBaptiste 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*7295610fSBaptiste Daroussin #include "tbl.h"
2961d06d6bSBaptiste Daroussin #include "out.h"
3061d06d6bSBaptiste Daroussin #include "html.h"
3161d06d6bSBaptiste Daroussin 
3261d06d6bSBaptiste Daroussin static	void	 html_tblopen(struct html *, const struct tbl_span *);
3361d06d6bSBaptiste Daroussin static	size_t	 html_tbl_len(size_t, void *);
3461d06d6bSBaptiste Daroussin static	size_t	 html_tbl_strlen(const char *, void *);
3561d06d6bSBaptiste Daroussin static	size_t	 html_tbl_sulen(const struct roffsu *, void *);
3661d06d6bSBaptiste Daroussin 
3761d06d6bSBaptiste Daroussin 
3861d06d6bSBaptiste Daroussin static size_t
3961d06d6bSBaptiste Daroussin html_tbl_len(size_t sz, void *arg)
4061d06d6bSBaptiste Daroussin {
4161d06d6bSBaptiste Daroussin 	return sz;
4261d06d6bSBaptiste Daroussin }
4361d06d6bSBaptiste Daroussin 
4461d06d6bSBaptiste Daroussin static size_t
4561d06d6bSBaptiste Daroussin html_tbl_strlen(const char *p, void *arg)
4661d06d6bSBaptiste Daroussin {
4761d06d6bSBaptiste Daroussin 	return strlen(p);
4861d06d6bSBaptiste Daroussin }
4961d06d6bSBaptiste Daroussin 
5061d06d6bSBaptiste Daroussin static size_t
5161d06d6bSBaptiste Daroussin html_tbl_sulen(const struct roffsu *su, void *arg)
5261d06d6bSBaptiste Daroussin {
5361d06d6bSBaptiste Daroussin 	if (su->scale < 0.0)
5461d06d6bSBaptiste Daroussin 		return 0;
5561d06d6bSBaptiste Daroussin 
5661d06d6bSBaptiste Daroussin 	switch (su->unit) {
5761d06d6bSBaptiste Daroussin 	case SCALE_FS:  /* 2^16 basic units */
5861d06d6bSBaptiste Daroussin 		return su->scale * 65536.0 / 24.0;
5961d06d6bSBaptiste Daroussin 	case SCALE_IN:  /* 10 characters per inch */
6061d06d6bSBaptiste Daroussin 		return su->scale * 10.0;
6161d06d6bSBaptiste Daroussin 	case SCALE_CM:  /* 2.54 cm per inch */
6261d06d6bSBaptiste Daroussin 		return su->scale * 10.0 / 2.54;
6361d06d6bSBaptiste Daroussin 	case SCALE_PC:  /* 6 pica per inch */
6461d06d6bSBaptiste Daroussin 	case SCALE_VS:
6561d06d6bSBaptiste Daroussin 		return su->scale * 10.0 / 6.0;
6661d06d6bSBaptiste Daroussin 	case SCALE_EN:
6761d06d6bSBaptiste Daroussin 	case SCALE_EM:
6861d06d6bSBaptiste Daroussin 		return su->scale;
6961d06d6bSBaptiste Daroussin 	case SCALE_PT:  /* 12 points per pica */
7061d06d6bSBaptiste Daroussin 		return su->scale * 10.0 / 6.0 / 12.0;
7161d06d6bSBaptiste Daroussin 	case SCALE_BU:  /* 24 basic units per character */
7261d06d6bSBaptiste Daroussin 		return su->scale / 24.0;
7361d06d6bSBaptiste Daroussin 	case SCALE_MM:  /* 1/1000 inch */
7461d06d6bSBaptiste Daroussin 		return su->scale / 100.0;
7561d06d6bSBaptiste Daroussin 	default:
7661d06d6bSBaptiste Daroussin 		abort();
7761d06d6bSBaptiste Daroussin 	}
7861d06d6bSBaptiste Daroussin }
7961d06d6bSBaptiste Daroussin 
8061d06d6bSBaptiste Daroussin static void
8161d06d6bSBaptiste Daroussin html_tblopen(struct html *h, const struct tbl_span *sp)
8261d06d6bSBaptiste Daroussin {
83*7295610fSBaptiste Daroussin 	html_close_paragraph(h);
8461d06d6bSBaptiste Daroussin 	if (h->tbl.cols == NULL) {
8561d06d6bSBaptiste Daroussin 		h->tbl.len = html_tbl_len;
8661d06d6bSBaptiste Daroussin 		h->tbl.slen = html_tbl_strlen;
8761d06d6bSBaptiste Daroussin 		h->tbl.sulen = html_tbl_sulen;
8861d06d6bSBaptiste Daroussin 		tblcalc(&h->tbl, sp, 0, 0);
8961d06d6bSBaptiste Daroussin 	}
9061d06d6bSBaptiste Daroussin 	assert(NULL == h->tblt);
91*7295610fSBaptiste Daroussin 	h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl",
92*7295610fSBaptiste Daroussin 	    "border",
93*7295610fSBaptiste Daroussin 		sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL,
94*7295610fSBaptiste Daroussin 	    "border-style",
95*7295610fSBaptiste Daroussin 		sp->opts->opts & TBL_OPT_DBOX ? "double" :
96*7295610fSBaptiste Daroussin 		sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL,
97*7295610fSBaptiste Daroussin 	    "border-top-style",
98*7295610fSBaptiste Daroussin 		sp->pos == TBL_SPAN_DHORIZ ? "double" :
99*7295610fSBaptiste Daroussin 		sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL);
10061d06d6bSBaptiste Daroussin }
10161d06d6bSBaptiste Daroussin 
10261d06d6bSBaptiste Daroussin void
10361d06d6bSBaptiste Daroussin print_tblclose(struct html *h)
10461d06d6bSBaptiste Daroussin {
10561d06d6bSBaptiste Daroussin 
10661d06d6bSBaptiste Daroussin 	assert(h->tblt);
10761d06d6bSBaptiste Daroussin 	print_tagq(h, h->tblt);
10861d06d6bSBaptiste Daroussin 	h->tblt = NULL;
10961d06d6bSBaptiste Daroussin }
11061d06d6bSBaptiste Daroussin 
11161d06d6bSBaptiste Daroussin void
11261d06d6bSBaptiste Daroussin print_tbl(struct html *h, const struct tbl_span *sp)
11361d06d6bSBaptiste Daroussin {
11461d06d6bSBaptiste Daroussin 	const struct tbl_dat	*dp;
115*7295610fSBaptiste Daroussin 	const struct tbl_cell	*cp;
116*7295610fSBaptiste Daroussin 	const struct tbl_span	*psp;
11761d06d6bSBaptiste Daroussin 	struct tag		*tt;
118*7295610fSBaptiste Daroussin 	const char		*hspans, *vspans, *halign, *valign;
119*7295610fSBaptiste Daroussin 	const char		*bborder, *lborder, *rborder;
120*7295610fSBaptiste Daroussin 	char			 hbuf[4], vbuf[4];
121*7295610fSBaptiste Daroussin 	int			 i;
12261d06d6bSBaptiste Daroussin 
12361d06d6bSBaptiste Daroussin 	if (h->tblt == NULL)
12461d06d6bSBaptiste Daroussin 		html_tblopen(h, sp);
12561d06d6bSBaptiste Daroussin 
126*7295610fSBaptiste Daroussin 	/*
127*7295610fSBaptiste Daroussin 	 * Horizontal lines spanning the whole table
128*7295610fSBaptiste Daroussin 	 * are handled by previous or following table rows.
129*7295610fSBaptiste Daroussin 	 */
130*7295610fSBaptiste Daroussin 
131*7295610fSBaptiste Daroussin 	if (sp->pos != TBL_SPAN_DATA)
132*7295610fSBaptiste Daroussin 		return;
133*7295610fSBaptiste Daroussin 
134*7295610fSBaptiste Daroussin 	/* Inhibit printing of spaces: we do padding ourselves. */
13561d06d6bSBaptiste Daroussin 
13661d06d6bSBaptiste Daroussin 	h->flags |= HTML_NONOSPACE;
13761d06d6bSBaptiste Daroussin 	h->flags |= HTML_NOSPACE;
13861d06d6bSBaptiste Daroussin 
139*7295610fSBaptiste Daroussin 	/* Draw a vertical line left of this row? */
14061d06d6bSBaptiste Daroussin 
141*7295610fSBaptiste Daroussin 	switch (sp->layout->vert) {
142*7295610fSBaptiste Daroussin 	case 2:
143*7295610fSBaptiste Daroussin 		lborder = "double";
144*7295610fSBaptiste Daroussin 		break;
145*7295610fSBaptiste Daroussin 	case 1:
146*7295610fSBaptiste Daroussin 		lborder = "solid";
14761d06d6bSBaptiste Daroussin 		break;
14861d06d6bSBaptiste Daroussin 	default:
149*7295610fSBaptiste Daroussin 		lborder = NULL;
150*7295610fSBaptiste Daroussin 		break;
151*7295610fSBaptiste Daroussin 	}
15261d06d6bSBaptiste Daroussin 
153*7295610fSBaptiste Daroussin 	/* Draw a horizontal line below this row? */
154*7295610fSBaptiste Daroussin 
155*7295610fSBaptiste Daroussin 	bborder = NULL;
156*7295610fSBaptiste Daroussin 	if ((psp = sp->next) != NULL) {
157*7295610fSBaptiste Daroussin 		switch (psp->pos) {
158*7295610fSBaptiste Daroussin 		case TBL_SPAN_DHORIZ:
159*7295610fSBaptiste Daroussin 			bborder = "double";
160*7295610fSBaptiste Daroussin 			break;
161*7295610fSBaptiste Daroussin 		case TBL_SPAN_HORIZ:
162*7295610fSBaptiste Daroussin 			bborder = "solid";
163*7295610fSBaptiste Daroussin 			break;
164*7295610fSBaptiste Daroussin 		default:
165*7295610fSBaptiste Daroussin 			break;
166*7295610fSBaptiste Daroussin 		}
167*7295610fSBaptiste Daroussin 	}
168*7295610fSBaptiste Daroussin 
169*7295610fSBaptiste Daroussin 	tt = print_otag(h, TAG_TR, "ss",
170*7295610fSBaptiste Daroussin 	    "border-left-style", lborder,
171*7295610fSBaptiste Daroussin 	    "border-bottom-style", bborder);
172*7295610fSBaptiste Daroussin 
173*7295610fSBaptiste Daroussin 	for (dp = sp->first; dp != NULL; dp = dp->next) {
174*7295610fSBaptiste Daroussin 		print_stagq(h, tt);
175*7295610fSBaptiste Daroussin 
176*7295610fSBaptiste Daroussin 		/*
177*7295610fSBaptiste Daroussin 		 * Do not generate <td> elements for continuations
178*7295610fSBaptiste Daroussin 		 * of spanned cells.  Larger <td> elements covering
179*7295610fSBaptiste Daroussin 		 * this space were already generated earlier.
180*7295610fSBaptiste Daroussin 		 */
181*7295610fSBaptiste Daroussin 
182*7295610fSBaptiste Daroussin 		cp = dp->layout;
183*7295610fSBaptiste Daroussin 		if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN ||
184*7295610fSBaptiste Daroussin 		    (dp->string != NULL && strcmp(dp->string, "\\^") == 0))
18561d06d6bSBaptiste Daroussin 			continue;
186*7295610fSBaptiste Daroussin 
187*7295610fSBaptiste Daroussin 		/* Determine the attribute values. */
188*7295610fSBaptiste Daroussin 
189*7295610fSBaptiste Daroussin 		if (dp->hspans > 0) {
190*7295610fSBaptiste Daroussin 			(void)snprintf(hbuf, sizeof(hbuf),
191*7295610fSBaptiste Daroussin 			    "%d", dp->hspans + 1);
192*7295610fSBaptiste Daroussin 			hspans = hbuf;
193*7295610fSBaptiste Daroussin 		} else
194*7295610fSBaptiste Daroussin 			hspans = NULL;
195*7295610fSBaptiste Daroussin 		if (dp->vspans > 0) {
196*7295610fSBaptiste Daroussin 			(void)snprintf(vbuf, sizeof(vbuf),
197*7295610fSBaptiste Daroussin 			    "%d", dp->vspans + 1);
198*7295610fSBaptiste Daroussin 			vspans = vbuf;
199*7295610fSBaptiste Daroussin 		} else
200*7295610fSBaptiste Daroussin 			vspans = NULL;
201*7295610fSBaptiste Daroussin 
202*7295610fSBaptiste Daroussin 		switch (cp->pos) {
203*7295610fSBaptiste Daroussin 		case TBL_CELL_CENTRE:
204*7295610fSBaptiste Daroussin 			halign = "center";
205*7295610fSBaptiste Daroussin 			break;
206*7295610fSBaptiste Daroussin 		case TBL_CELL_RIGHT:
207*7295610fSBaptiste Daroussin 		case TBL_CELL_NUMBER:
208*7295610fSBaptiste Daroussin 			halign = "right";
209*7295610fSBaptiste Daroussin 			break;
210*7295610fSBaptiste Daroussin 		default:
211*7295610fSBaptiste Daroussin 			halign = NULL;
212*7295610fSBaptiste Daroussin 			break;
213*7295610fSBaptiste Daroussin 		}
214*7295610fSBaptiste Daroussin 		if (cp->flags & TBL_CELL_TALIGN)
215*7295610fSBaptiste Daroussin 			valign = "top";
216*7295610fSBaptiste Daroussin 		else if (cp->flags & TBL_CELL_BALIGN)
217*7295610fSBaptiste Daroussin 			valign = "bottom";
218*7295610fSBaptiste Daroussin 		else
219*7295610fSBaptiste Daroussin 			valign = NULL;
220*7295610fSBaptiste Daroussin 
221*7295610fSBaptiste Daroussin 		for (i = dp->hspans; i > 0; i--)
222*7295610fSBaptiste Daroussin 			cp = cp->next;
223*7295610fSBaptiste Daroussin 		switch (cp->vert) {
224*7295610fSBaptiste Daroussin 		case 2:
225*7295610fSBaptiste Daroussin 			rborder = "double";
226*7295610fSBaptiste Daroussin 			break;
227*7295610fSBaptiste Daroussin 		case 1:
228*7295610fSBaptiste Daroussin 			rborder = "solid";
229*7295610fSBaptiste Daroussin 			break;
230*7295610fSBaptiste Daroussin 		default:
231*7295610fSBaptiste Daroussin 			rborder = NULL;
232*7295610fSBaptiste Daroussin 			break;
233*7295610fSBaptiste Daroussin 		}
234*7295610fSBaptiste Daroussin 
235*7295610fSBaptiste Daroussin 		/* Print the element and the attributes. */
236*7295610fSBaptiste Daroussin 
237*7295610fSBaptiste Daroussin 		print_otag(h, TAG_TD, "??sss",
238*7295610fSBaptiste Daroussin 		    "colspan", hspans, "rowspan", vspans,
239*7295610fSBaptiste Daroussin 		    "vertical-align", valign,
240*7295610fSBaptiste Daroussin 		    "text-align", halign,
241*7295610fSBaptiste Daroussin 		    "border-right-style", rborder);
24261d06d6bSBaptiste Daroussin 		if (dp->string != NULL)
24361d06d6bSBaptiste Daroussin 			print_text(h, dp->string);
24461d06d6bSBaptiste Daroussin 	}
24561d06d6bSBaptiste Daroussin 
24661d06d6bSBaptiste Daroussin 	print_tagq(h, tt);
24761d06d6bSBaptiste Daroussin 
24861d06d6bSBaptiste Daroussin 	h->flags &= ~HTML_NONOSPACE;
24961d06d6bSBaptiste Daroussin 
25061d06d6bSBaptiste Daroussin 	if (sp->next == NULL) {
25161d06d6bSBaptiste Daroussin 		assert(h->tbl.cols);
25261d06d6bSBaptiste Daroussin 		free(h->tbl.cols);
25361d06d6bSBaptiste Daroussin 		h->tbl.cols = NULL;
25461d06d6bSBaptiste Daroussin 		print_tblclose(h);
25561d06d6bSBaptiste Daroussin 	}
25661d06d6bSBaptiste Daroussin }
257