xref: /titanic_41/usr/src/cmd/mandoc/out.c (revision ffb8ebfab4941f959e7caea93ecfb348cfa3515e)
1*ffb8ebfaSGarrett D'Amore /*	$Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */
232a712daSGarrett D'Amore /*
332a712daSGarrett D'Amore  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
432a712daSGarrett D'Amore  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
532a712daSGarrett D'Amore  *
632a712daSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
732a712daSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
832a712daSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
932a712daSGarrett D'Amore  *
1032a712daSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1132a712daSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1232a712daSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1332a712daSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1432a712daSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1532a712daSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1632a712daSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1732a712daSGarrett D'Amore  */
1832a712daSGarrett D'Amore #ifdef HAVE_CONFIG_H
1932a712daSGarrett D'Amore #include "config.h"
2032a712daSGarrett D'Amore #endif
2132a712daSGarrett D'Amore 
2232a712daSGarrett D'Amore #include <sys/types.h>
2332a712daSGarrett D'Amore 
2432a712daSGarrett D'Amore #include <assert.h>
2532a712daSGarrett D'Amore #include <ctype.h>
2632a712daSGarrett D'Amore #include <stdio.h>
2732a712daSGarrett D'Amore #include <stdlib.h>
2832a712daSGarrett D'Amore #include <string.h>
2932a712daSGarrett D'Amore #include <time.h>
3032a712daSGarrett D'Amore 
3132a712daSGarrett D'Amore #include "mandoc.h"
3232a712daSGarrett D'Amore #include "out.h"
3332a712daSGarrett D'Amore 
3432a712daSGarrett D'Amore static	void	tblcalc_data(struct rofftbl *, struct roffcol *,
35*ffb8ebfaSGarrett D'Amore 			const struct tbl_opts *, const struct tbl_dat *);
3632a712daSGarrett D'Amore static	void	tblcalc_literal(struct rofftbl *, struct roffcol *,
3732a712daSGarrett D'Amore 			const struct tbl_dat *);
3832a712daSGarrett D'Amore static	void	tblcalc_number(struct rofftbl *, struct roffcol *,
39*ffb8ebfaSGarrett D'Amore 			const struct tbl_opts *, const struct tbl_dat *);
4032a712daSGarrett D'Amore 
4132a712daSGarrett D'Amore /*
4232a712daSGarrett D'Amore  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
4332a712daSGarrett D'Amore  * units are documented in groff.7, mdoc.7, man.7.
4432a712daSGarrett D'Amore  */
4532a712daSGarrett D'Amore int
a2roffsu(const char * src,struct roffsu * dst,enum roffscale def)4632a712daSGarrett D'Amore a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
4732a712daSGarrett D'Amore {
4832a712daSGarrett D'Amore 	char		 buf[BUFSIZ], hasd;
4932a712daSGarrett D'Amore 	int		 i;
5032a712daSGarrett D'Amore 	enum roffscale	 unit;
5132a712daSGarrett D'Amore 
5232a712daSGarrett D'Amore 	if ('\0' == *src)
5332a712daSGarrett D'Amore 		return(0);
5432a712daSGarrett D'Amore 
5532a712daSGarrett D'Amore 	i = hasd = 0;
5632a712daSGarrett D'Amore 
5732a712daSGarrett D'Amore 	switch (*src) {
5832a712daSGarrett D'Amore 	case ('+'):
5932a712daSGarrett D'Amore 		src++;
6032a712daSGarrett D'Amore 		break;
6132a712daSGarrett D'Amore 	case ('-'):
6232a712daSGarrett D'Amore 		buf[i++] = *src++;
6332a712daSGarrett D'Amore 		break;
6432a712daSGarrett D'Amore 	default:
6532a712daSGarrett D'Amore 		break;
6632a712daSGarrett D'Amore 	}
6732a712daSGarrett D'Amore 
6832a712daSGarrett D'Amore 	if ('\0' == *src)
6932a712daSGarrett D'Amore 		return(0);
7032a712daSGarrett D'Amore 
7132a712daSGarrett D'Amore 	while (i < BUFSIZ) {
7232a712daSGarrett D'Amore 		if ( ! isdigit((unsigned char)*src)) {
7332a712daSGarrett D'Amore 			if ('.' != *src)
7432a712daSGarrett D'Amore 				break;
7532a712daSGarrett D'Amore 			else if (hasd)
7632a712daSGarrett D'Amore 				break;
7732a712daSGarrett D'Amore 			else
7832a712daSGarrett D'Amore 				hasd = 1;
7932a712daSGarrett D'Amore 		}
8032a712daSGarrett D'Amore 		buf[i++] = *src++;
8132a712daSGarrett D'Amore 	}
8232a712daSGarrett D'Amore 
8332a712daSGarrett D'Amore 	if (BUFSIZ == i || (*src && *(src + 1)))
8432a712daSGarrett D'Amore 		return(0);
8532a712daSGarrett D'Amore 
8632a712daSGarrett D'Amore 	buf[i] = '\0';
8732a712daSGarrett D'Amore 
8832a712daSGarrett D'Amore 	switch (*src) {
8932a712daSGarrett D'Amore 	case ('c'):
9032a712daSGarrett D'Amore 		unit = SCALE_CM;
9132a712daSGarrett D'Amore 		break;
9232a712daSGarrett D'Amore 	case ('i'):
9332a712daSGarrett D'Amore 		unit = SCALE_IN;
9432a712daSGarrett D'Amore 		break;
9532a712daSGarrett D'Amore 	case ('P'):
9632a712daSGarrett D'Amore 		unit = SCALE_PC;
9732a712daSGarrett D'Amore 		break;
9832a712daSGarrett D'Amore 	case ('p'):
9932a712daSGarrett D'Amore 		unit = SCALE_PT;
10032a712daSGarrett D'Amore 		break;
10132a712daSGarrett D'Amore 	case ('f'):
10232a712daSGarrett D'Amore 		unit = SCALE_FS;
10332a712daSGarrett D'Amore 		break;
10432a712daSGarrett D'Amore 	case ('v'):
10532a712daSGarrett D'Amore 		unit = SCALE_VS;
10632a712daSGarrett D'Amore 		break;
10732a712daSGarrett D'Amore 	case ('m'):
10832a712daSGarrett D'Amore 		unit = SCALE_EM;
10932a712daSGarrett D'Amore 		break;
11032a712daSGarrett D'Amore 	case ('\0'):
11132a712daSGarrett D'Amore 		if (SCALE_MAX == def)
11232a712daSGarrett D'Amore 			return(0);
11332a712daSGarrett D'Amore 		unit = SCALE_BU;
11432a712daSGarrett D'Amore 		break;
11532a712daSGarrett D'Amore 	case ('u'):
11632a712daSGarrett D'Amore 		unit = SCALE_BU;
11732a712daSGarrett D'Amore 		break;
11832a712daSGarrett D'Amore 	case ('M'):
11932a712daSGarrett D'Amore 		unit = SCALE_MM;
12032a712daSGarrett D'Amore 		break;
12132a712daSGarrett D'Amore 	case ('n'):
12232a712daSGarrett D'Amore 		unit = SCALE_EN;
12332a712daSGarrett D'Amore 		break;
12432a712daSGarrett D'Amore 	default:
12532a712daSGarrett D'Amore 		return(0);
12632a712daSGarrett D'Amore 	}
12732a712daSGarrett D'Amore 
12832a712daSGarrett D'Amore 	/* FIXME: do this in the caller. */
12932a712daSGarrett D'Amore 	if ((dst->scale = atof(buf)) < 0)
13032a712daSGarrett D'Amore 		dst->scale = 0;
13132a712daSGarrett D'Amore 	dst->unit = unit;
13232a712daSGarrett D'Amore 	return(1);
13332a712daSGarrett D'Amore }
13432a712daSGarrett D'Amore 
13532a712daSGarrett D'Amore /*
13632a712daSGarrett D'Amore  * Calculate the abstract widths and decimal positions of columns in a
13732a712daSGarrett D'Amore  * table.  This routine allocates the columns structures then runs over
13832a712daSGarrett D'Amore  * all rows and cells in the table.  The function pointers in "tbl" are
13932a712daSGarrett D'Amore  * used for the actual width calculations.
14032a712daSGarrett D'Amore  */
14132a712daSGarrett D'Amore void
tblcalc(struct rofftbl * tbl,const struct tbl_span * sp)14232a712daSGarrett D'Amore tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
14332a712daSGarrett D'Amore {
14432a712daSGarrett D'Amore 	const struct tbl_dat	*dp;
14532a712daSGarrett D'Amore 	struct roffcol		*col;
14632a712daSGarrett D'Amore 	int			 spans;
14732a712daSGarrett D'Amore 
14832a712daSGarrett D'Amore 	/*
14932a712daSGarrett D'Amore 	 * Allocate the master column specifiers.  These will hold the
15032a712daSGarrett D'Amore 	 * widths and decimal positions for all cells in the column.  It
15132a712daSGarrett D'Amore 	 * must be freed and nullified by the caller.
15232a712daSGarrett D'Amore 	 */
15332a712daSGarrett D'Amore 
15432a712daSGarrett D'Amore 	assert(NULL == tbl->cols);
15532a712daSGarrett D'Amore 	tbl->cols = mandoc_calloc
156*ffb8ebfaSGarrett D'Amore 		((size_t)sp->opts->cols, sizeof(struct roffcol));
15732a712daSGarrett D'Amore 
15832a712daSGarrett D'Amore 	for ( ; sp; sp = sp->next) {
15932a712daSGarrett D'Amore 		if (TBL_SPAN_DATA != sp->pos)
16032a712daSGarrett D'Amore 			continue;
16132a712daSGarrett D'Amore 		spans = 1;
16232a712daSGarrett D'Amore 		/*
16332a712daSGarrett D'Amore 		 * Account for the data cells in the layout, matching it
16432a712daSGarrett D'Amore 		 * to data cells in the data section.
16532a712daSGarrett D'Amore 		 */
16632a712daSGarrett D'Amore 		for (dp = sp->first; dp; dp = dp->next) {
16732a712daSGarrett D'Amore 			/* Do not used spanned cells in the calculation. */
16832a712daSGarrett D'Amore 			if (0 < --spans)
16932a712daSGarrett D'Amore 				continue;
17032a712daSGarrett D'Amore 			spans = dp->spans;
17132a712daSGarrett D'Amore 			if (1 < spans)
17232a712daSGarrett D'Amore 				continue;
17332a712daSGarrett D'Amore 			assert(dp->layout);
17432a712daSGarrett D'Amore 			col = &tbl->cols[dp->layout->head->ident];
175*ffb8ebfaSGarrett D'Amore 			tblcalc_data(tbl, col, sp->opts, dp);
17632a712daSGarrett D'Amore 		}
17732a712daSGarrett D'Amore 	}
17832a712daSGarrett D'Amore }
17932a712daSGarrett D'Amore 
18032a712daSGarrett D'Amore static void
tblcalc_data(struct rofftbl * tbl,struct roffcol * col,const struct tbl_opts * opts,const struct tbl_dat * dp)18132a712daSGarrett D'Amore tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
182*ffb8ebfaSGarrett D'Amore 		const struct tbl_opts *opts, const struct tbl_dat *dp)
18332a712daSGarrett D'Amore {
18432a712daSGarrett D'Amore 	size_t		 sz;
18532a712daSGarrett D'Amore 
18632a712daSGarrett D'Amore 	/* Branch down into data sub-types. */
18732a712daSGarrett D'Amore 
18832a712daSGarrett D'Amore 	switch (dp->layout->pos) {
18932a712daSGarrett D'Amore 	case (TBL_CELL_HORIZ):
19032a712daSGarrett D'Amore 		/* FALLTHROUGH */
19132a712daSGarrett D'Amore 	case (TBL_CELL_DHORIZ):
19232a712daSGarrett D'Amore 		sz = (*tbl->len)(1, tbl->arg);
19332a712daSGarrett D'Amore 		if (col->width < sz)
19432a712daSGarrett D'Amore 			col->width = sz;
19532a712daSGarrett D'Amore 		break;
19632a712daSGarrett D'Amore 	case (TBL_CELL_LONG):
19732a712daSGarrett D'Amore 		/* FALLTHROUGH */
19832a712daSGarrett D'Amore 	case (TBL_CELL_CENTRE):
19932a712daSGarrett D'Amore 		/* FALLTHROUGH */
20032a712daSGarrett D'Amore 	case (TBL_CELL_LEFT):
20132a712daSGarrett D'Amore 		/* FALLTHROUGH */
20232a712daSGarrett D'Amore 	case (TBL_CELL_RIGHT):
20332a712daSGarrett D'Amore 		tblcalc_literal(tbl, col, dp);
20432a712daSGarrett D'Amore 		break;
20532a712daSGarrett D'Amore 	case (TBL_CELL_NUMBER):
206*ffb8ebfaSGarrett D'Amore 		tblcalc_number(tbl, col, opts, dp);
20732a712daSGarrett D'Amore 		break;
20832a712daSGarrett D'Amore 	case (TBL_CELL_DOWN):
20932a712daSGarrett D'Amore 		break;
21032a712daSGarrett D'Amore 	default:
21132a712daSGarrett D'Amore 		abort();
21232a712daSGarrett D'Amore 		/* NOTREACHED */
21332a712daSGarrett D'Amore 	}
21432a712daSGarrett D'Amore }
21532a712daSGarrett D'Amore 
21632a712daSGarrett D'Amore static void
tblcalc_literal(struct rofftbl * tbl,struct roffcol * col,const struct tbl_dat * dp)21732a712daSGarrett D'Amore tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
21832a712daSGarrett D'Amore 		const struct tbl_dat *dp)
21932a712daSGarrett D'Amore {
22032a712daSGarrett D'Amore 	size_t		 sz;
22132a712daSGarrett D'Amore 	const char	*str;
22232a712daSGarrett D'Amore 
22332a712daSGarrett D'Amore 	str = dp->string ? dp->string : "";
22432a712daSGarrett D'Amore 	sz = (*tbl->slen)(str, tbl->arg);
22532a712daSGarrett D'Amore 
22632a712daSGarrett D'Amore 	if (col->width < sz)
22732a712daSGarrett D'Amore 		col->width = sz;
22832a712daSGarrett D'Amore }
22932a712daSGarrett D'Amore 
23032a712daSGarrett D'Amore static void
tblcalc_number(struct rofftbl * tbl,struct roffcol * col,const struct tbl_opts * opts,const struct tbl_dat * dp)23132a712daSGarrett D'Amore tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
232*ffb8ebfaSGarrett D'Amore 		const struct tbl_opts *opts, const struct tbl_dat *dp)
23332a712daSGarrett D'Amore {
23432a712daSGarrett D'Amore 	int 		 i;
23532a712daSGarrett D'Amore 	size_t		 sz, psz, ssz, d;
23632a712daSGarrett D'Amore 	const char	*str;
23732a712daSGarrett D'Amore 	char		*cp;
23832a712daSGarrett D'Amore 	char		 buf[2];
23932a712daSGarrett D'Amore 
24032a712daSGarrett D'Amore 	/*
24132a712daSGarrett D'Amore 	 * First calculate number width and decimal place (last + 1 for
24232a712daSGarrett D'Amore 	 * non-decimal numbers).  If the stored decimal is subsequent to
24332a712daSGarrett D'Amore 	 * ours, make our size longer by that difference
24432a712daSGarrett D'Amore 	 * (right-"shifting"); similarly, if ours is subsequent the
24532a712daSGarrett D'Amore 	 * stored, then extend the stored size by the difference.
24632a712daSGarrett D'Amore 	 * Finally, re-assign the stored values.
24732a712daSGarrett D'Amore 	 */
24832a712daSGarrett D'Amore 
24932a712daSGarrett D'Amore 	str = dp->string ? dp->string : "";
25032a712daSGarrett D'Amore 	sz = (*tbl->slen)(str, tbl->arg);
25132a712daSGarrett D'Amore 
25232a712daSGarrett D'Amore 	/* FIXME: TBL_DATA_HORIZ et al.? */
25332a712daSGarrett D'Amore 
254*ffb8ebfaSGarrett D'Amore 	buf[0] = opts->decimal;
25532a712daSGarrett D'Amore 	buf[1] = '\0';
25632a712daSGarrett D'Amore 
25732a712daSGarrett D'Amore 	psz = (*tbl->slen)(buf, tbl->arg);
25832a712daSGarrett D'Amore 
259*ffb8ebfaSGarrett D'Amore 	if (NULL != (cp = strrchr(str, opts->decimal))) {
26032a712daSGarrett D'Amore 		buf[1] = '\0';
26132a712daSGarrett D'Amore 		for (ssz = 0, i = 0; cp != &str[i]; i++) {
26232a712daSGarrett D'Amore 			buf[0] = str[i];
26332a712daSGarrett D'Amore 			ssz += (*tbl->slen)(buf, tbl->arg);
26432a712daSGarrett D'Amore 		}
26532a712daSGarrett D'Amore 		d = ssz + psz;
26632a712daSGarrett D'Amore 	} else
26732a712daSGarrett D'Amore 		d = sz + psz;
26832a712daSGarrett D'Amore 
26932a712daSGarrett D'Amore 	/* Adjust the settings for this column. */
27032a712daSGarrett D'Amore 
27132a712daSGarrett D'Amore 	if (col->decimal > d) {
27232a712daSGarrett D'Amore 		sz += col->decimal - d;
27332a712daSGarrett D'Amore 		d = col->decimal;
27432a712daSGarrett D'Amore 	} else
27532a712daSGarrett D'Amore 		col->width += d - col->decimal;
27632a712daSGarrett D'Amore 
27732a712daSGarrett D'Amore 	if (sz > col->width)
27832a712daSGarrett D'Amore 		col->width = sz;
27932a712daSGarrett D'Amore 	if (d > col->decimal)
28032a712daSGarrett D'Amore 		col->decimal = d;
28132a712daSGarrett D'Amore }
282