xref: /titanic_44/usr/src/cmd/mandoc/out.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
1*698f87a4SGarrett D'Amore /*	$Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
495c635efSGarrett D'Amore  * Copyright (c) 2011 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 <stdio.h>
2795c635efSGarrett D'Amore #include <stdlib.h>
2895c635efSGarrett D'Amore #include <string.h>
2995c635efSGarrett D'Amore #include <time.h>
3095c635efSGarrett D'Amore 
3195c635efSGarrett D'Amore #include "mandoc.h"
3295c635efSGarrett D'Amore #include "out.h"
3395c635efSGarrett D'Amore 
3495c635efSGarrett D'Amore static	void	tblcalc_data(struct rofftbl *, struct roffcol *,
35*698f87a4SGarrett D'Amore 			const struct tbl_opts *, const struct tbl_dat *);
3695c635efSGarrett D'Amore static	void	tblcalc_literal(struct rofftbl *, struct roffcol *,
3795c635efSGarrett D'Amore 			const struct tbl_dat *);
3895c635efSGarrett D'Amore static	void	tblcalc_number(struct rofftbl *, struct roffcol *,
39*698f87a4SGarrett D'Amore 			const struct tbl_opts *, const struct tbl_dat *);
4095c635efSGarrett D'Amore 
4195c635efSGarrett D'Amore /*
4295c635efSGarrett D'Amore  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
4395c635efSGarrett D'Amore  * units are documented in groff.7, mdoc.7, man.7.
4495c635efSGarrett D'Amore  */
4595c635efSGarrett D'Amore int
a2roffsu(const char * src,struct roffsu * dst,enum roffscale def)4695c635efSGarrett D'Amore a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
4795c635efSGarrett D'Amore {
4895c635efSGarrett D'Amore 	char		 buf[BUFSIZ], hasd;
4995c635efSGarrett D'Amore 	int		 i;
5095c635efSGarrett D'Amore 	enum roffscale	 unit;
5195c635efSGarrett D'Amore 
5295c635efSGarrett D'Amore 	if ('\0' == *src)
5395c635efSGarrett D'Amore 		return(0);
5495c635efSGarrett D'Amore 
5595c635efSGarrett D'Amore 	i = hasd = 0;
5695c635efSGarrett D'Amore 
5795c635efSGarrett D'Amore 	switch (*src) {
5895c635efSGarrett D'Amore 	case ('+'):
5995c635efSGarrett D'Amore 		src++;
6095c635efSGarrett D'Amore 		break;
6195c635efSGarrett D'Amore 	case ('-'):
6295c635efSGarrett D'Amore 		buf[i++] = *src++;
6395c635efSGarrett D'Amore 		break;
6495c635efSGarrett D'Amore 	default:
6595c635efSGarrett D'Amore 		break;
6695c635efSGarrett D'Amore 	}
6795c635efSGarrett D'Amore 
6895c635efSGarrett D'Amore 	if ('\0' == *src)
6995c635efSGarrett D'Amore 		return(0);
7095c635efSGarrett D'Amore 
7195c635efSGarrett D'Amore 	while (i < BUFSIZ) {
7295c635efSGarrett D'Amore 		if ( ! isdigit((unsigned char)*src)) {
7395c635efSGarrett D'Amore 			if ('.' != *src)
7495c635efSGarrett D'Amore 				break;
7595c635efSGarrett D'Amore 			else if (hasd)
7695c635efSGarrett D'Amore 				break;
7795c635efSGarrett D'Amore 			else
7895c635efSGarrett D'Amore 				hasd = 1;
7995c635efSGarrett D'Amore 		}
8095c635efSGarrett D'Amore 		buf[i++] = *src++;
8195c635efSGarrett D'Amore 	}
8295c635efSGarrett D'Amore 
8395c635efSGarrett D'Amore 	if (BUFSIZ == i || (*src && *(src + 1)))
8495c635efSGarrett D'Amore 		return(0);
8595c635efSGarrett D'Amore 
8695c635efSGarrett D'Amore 	buf[i] = '\0';
8795c635efSGarrett D'Amore 
8895c635efSGarrett D'Amore 	switch (*src) {
8995c635efSGarrett D'Amore 	case ('c'):
9095c635efSGarrett D'Amore 		unit = SCALE_CM;
9195c635efSGarrett D'Amore 		break;
9295c635efSGarrett D'Amore 	case ('i'):
9395c635efSGarrett D'Amore 		unit = SCALE_IN;
9495c635efSGarrett D'Amore 		break;
9595c635efSGarrett D'Amore 	case ('P'):
9695c635efSGarrett D'Amore 		unit = SCALE_PC;
9795c635efSGarrett D'Amore 		break;
9895c635efSGarrett D'Amore 	case ('p'):
9995c635efSGarrett D'Amore 		unit = SCALE_PT;
10095c635efSGarrett D'Amore 		break;
10195c635efSGarrett D'Amore 	case ('f'):
10295c635efSGarrett D'Amore 		unit = SCALE_FS;
10395c635efSGarrett D'Amore 		break;
10495c635efSGarrett D'Amore 	case ('v'):
10595c635efSGarrett D'Amore 		unit = SCALE_VS;
10695c635efSGarrett D'Amore 		break;
10795c635efSGarrett D'Amore 	case ('m'):
10895c635efSGarrett D'Amore 		unit = SCALE_EM;
10995c635efSGarrett D'Amore 		break;
11095c635efSGarrett D'Amore 	case ('\0'):
11195c635efSGarrett D'Amore 		if (SCALE_MAX == def)
11295c635efSGarrett D'Amore 			return(0);
11395c635efSGarrett D'Amore 		unit = SCALE_BU;
11495c635efSGarrett D'Amore 		break;
11595c635efSGarrett D'Amore 	case ('u'):
11695c635efSGarrett D'Amore 		unit = SCALE_BU;
11795c635efSGarrett D'Amore 		break;
11895c635efSGarrett D'Amore 	case ('M'):
11995c635efSGarrett D'Amore 		unit = SCALE_MM;
12095c635efSGarrett D'Amore 		break;
12195c635efSGarrett D'Amore 	case ('n'):
12295c635efSGarrett D'Amore 		unit = SCALE_EN;
12395c635efSGarrett D'Amore 		break;
12495c635efSGarrett D'Amore 	default:
12595c635efSGarrett D'Amore 		return(0);
12695c635efSGarrett D'Amore 	}
12795c635efSGarrett D'Amore 
12895c635efSGarrett D'Amore 	/* FIXME: do this in the caller. */
12995c635efSGarrett D'Amore 	if ((dst->scale = atof(buf)) < 0)
13095c635efSGarrett D'Amore 		dst->scale = 0;
13195c635efSGarrett D'Amore 	dst->unit = unit;
13295c635efSGarrett D'Amore 	return(1);
13395c635efSGarrett D'Amore }
13495c635efSGarrett D'Amore 
13595c635efSGarrett D'Amore /*
13695c635efSGarrett D'Amore  * Calculate the abstract widths and decimal positions of columns in a
13795c635efSGarrett D'Amore  * table.  This routine allocates the columns structures then runs over
13895c635efSGarrett D'Amore  * all rows and cells in the table.  The function pointers in "tbl" are
13995c635efSGarrett D'Amore  * used for the actual width calculations.
14095c635efSGarrett D'Amore  */
14195c635efSGarrett D'Amore void
tblcalc(struct rofftbl * tbl,const struct tbl_span * sp)14295c635efSGarrett D'Amore tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
14395c635efSGarrett D'Amore {
14495c635efSGarrett D'Amore 	const struct tbl_dat	*dp;
14595c635efSGarrett D'Amore 	struct roffcol		*col;
14695c635efSGarrett D'Amore 	int			 spans;
14795c635efSGarrett D'Amore 
14895c635efSGarrett D'Amore 	/*
14995c635efSGarrett D'Amore 	 * Allocate the master column specifiers.  These will hold the
15095c635efSGarrett D'Amore 	 * widths and decimal positions for all cells in the column.  It
15195c635efSGarrett D'Amore 	 * must be freed and nullified by the caller.
15295c635efSGarrett D'Amore 	 */
15395c635efSGarrett D'Amore 
15495c635efSGarrett D'Amore 	assert(NULL == tbl->cols);
15595c635efSGarrett D'Amore 	tbl->cols = mandoc_calloc
156*698f87a4SGarrett D'Amore 		((size_t)sp->opts->cols, sizeof(struct roffcol));
15795c635efSGarrett D'Amore 
15895c635efSGarrett D'Amore 	for ( ; sp; sp = sp->next) {
15995c635efSGarrett D'Amore 		if (TBL_SPAN_DATA != sp->pos)
16095c635efSGarrett D'Amore 			continue;
16195c635efSGarrett D'Amore 		spans = 1;
16295c635efSGarrett D'Amore 		/*
16395c635efSGarrett D'Amore 		 * Account for the data cells in the layout, matching it
16495c635efSGarrett D'Amore 		 * to data cells in the data section.
16595c635efSGarrett D'Amore 		 */
16695c635efSGarrett D'Amore 		for (dp = sp->first; dp; dp = dp->next) {
16795c635efSGarrett D'Amore 			/* Do not used spanned cells in the calculation. */
16895c635efSGarrett D'Amore 			if (0 < --spans)
16995c635efSGarrett D'Amore 				continue;
17095c635efSGarrett D'Amore 			spans = dp->spans;
17195c635efSGarrett D'Amore 			if (1 < spans)
17295c635efSGarrett D'Amore 				continue;
17395c635efSGarrett D'Amore 			assert(dp->layout);
17495c635efSGarrett D'Amore 			col = &tbl->cols[dp->layout->head->ident];
175*698f87a4SGarrett D'Amore 			tblcalc_data(tbl, col, sp->opts, dp);
17695c635efSGarrett D'Amore 		}
17795c635efSGarrett D'Amore 	}
17895c635efSGarrett D'Amore }
17995c635efSGarrett D'Amore 
18095c635efSGarrett D'Amore static void
tblcalc_data(struct rofftbl * tbl,struct roffcol * col,const struct tbl_opts * opts,const struct tbl_dat * dp)18195c635efSGarrett D'Amore tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
182*698f87a4SGarrett D'Amore 		const struct tbl_opts *opts, const struct tbl_dat *dp)
18395c635efSGarrett D'Amore {
18495c635efSGarrett D'Amore 	size_t		 sz;
18595c635efSGarrett D'Amore 
18695c635efSGarrett D'Amore 	/* Branch down into data sub-types. */
18795c635efSGarrett D'Amore 
18895c635efSGarrett D'Amore 	switch (dp->layout->pos) {
18995c635efSGarrett D'Amore 	case (TBL_CELL_HORIZ):
19095c635efSGarrett D'Amore 		/* FALLTHROUGH */
19195c635efSGarrett D'Amore 	case (TBL_CELL_DHORIZ):
19295c635efSGarrett D'Amore 		sz = (*tbl->len)(1, tbl->arg);
19395c635efSGarrett D'Amore 		if (col->width < sz)
19495c635efSGarrett D'Amore 			col->width = sz;
19595c635efSGarrett D'Amore 		break;
19695c635efSGarrett D'Amore 	case (TBL_CELL_LONG):
19795c635efSGarrett D'Amore 		/* FALLTHROUGH */
19895c635efSGarrett D'Amore 	case (TBL_CELL_CENTRE):
19995c635efSGarrett D'Amore 		/* FALLTHROUGH */
20095c635efSGarrett D'Amore 	case (TBL_CELL_LEFT):
20195c635efSGarrett D'Amore 		/* FALLTHROUGH */
20295c635efSGarrett D'Amore 	case (TBL_CELL_RIGHT):
20395c635efSGarrett D'Amore 		tblcalc_literal(tbl, col, dp);
20495c635efSGarrett D'Amore 		break;
20595c635efSGarrett D'Amore 	case (TBL_CELL_NUMBER):
206*698f87a4SGarrett D'Amore 		tblcalc_number(tbl, col, opts, dp);
20795c635efSGarrett D'Amore 		break;
20895c635efSGarrett D'Amore 	case (TBL_CELL_DOWN):
20995c635efSGarrett D'Amore 		break;
21095c635efSGarrett D'Amore 	default:
21195c635efSGarrett D'Amore 		abort();
21295c635efSGarrett D'Amore 		/* NOTREACHED */
21395c635efSGarrett D'Amore 	}
21495c635efSGarrett D'Amore }
21595c635efSGarrett D'Amore 
21695c635efSGarrett D'Amore static void
tblcalc_literal(struct rofftbl * tbl,struct roffcol * col,const struct tbl_dat * dp)21795c635efSGarrett D'Amore tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
21895c635efSGarrett D'Amore 		const struct tbl_dat *dp)
21995c635efSGarrett D'Amore {
22095c635efSGarrett D'Amore 	size_t		 sz;
22195c635efSGarrett D'Amore 	const char	*str;
22295c635efSGarrett D'Amore 
22395c635efSGarrett D'Amore 	str = dp->string ? dp->string : "";
22495c635efSGarrett D'Amore 	sz = (*tbl->slen)(str, tbl->arg);
22595c635efSGarrett D'Amore 
22695c635efSGarrett D'Amore 	if (col->width < sz)
22795c635efSGarrett D'Amore 		col->width = sz;
22895c635efSGarrett D'Amore }
22995c635efSGarrett D'Amore 
23095c635efSGarrett D'Amore static void
tblcalc_number(struct rofftbl * tbl,struct roffcol * col,const struct tbl_opts * opts,const struct tbl_dat * dp)23195c635efSGarrett D'Amore tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
232*698f87a4SGarrett D'Amore 		const struct tbl_opts *opts, const struct tbl_dat *dp)
23395c635efSGarrett D'Amore {
23495c635efSGarrett D'Amore 	int 		 i;
23595c635efSGarrett D'Amore 	size_t		 sz, psz, ssz, d;
23695c635efSGarrett D'Amore 	const char	*str;
23795c635efSGarrett D'Amore 	char		*cp;
23895c635efSGarrett D'Amore 	char		 buf[2];
23995c635efSGarrett D'Amore 
24095c635efSGarrett D'Amore 	/*
24195c635efSGarrett D'Amore 	 * First calculate number width and decimal place (last + 1 for
24295c635efSGarrett D'Amore 	 * non-decimal numbers).  If the stored decimal is subsequent to
24395c635efSGarrett D'Amore 	 * ours, make our size longer by that difference
24495c635efSGarrett D'Amore 	 * (right-"shifting"); similarly, if ours is subsequent the
24595c635efSGarrett D'Amore 	 * stored, then extend the stored size by the difference.
24695c635efSGarrett D'Amore 	 * Finally, re-assign the stored values.
24795c635efSGarrett D'Amore 	 */
24895c635efSGarrett D'Amore 
24995c635efSGarrett D'Amore 	str = dp->string ? dp->string : "";
25095c635efSGarrett D'Amore 	sz = (*tbl->slen)(str, tbl->arg);
25195c635efSGarrett D'Amore 
25295c635efSGarrett D'Amore 	/* FIXME: TBL_DATA_HORIZ et al.? */
25395c635efSGarrett D'Amore 
254*698f87a4SGarrett D'Amore 	buf[0] = opts->decimal;
25595c635efSGarrett D'Amore 	buf[1] = '\0';
25695c635efSGarrett D'Amore 
25795c635efSGarrett D'Amore 	psz = (*tbl->slen)(buf, tbl->arg);
25895c635efSGarrett D'Amore 
259*698f87a4SGarrett D'Amore 	if (NULL != (cp = strrchr(str, opts->decimal))) {
26095c635efSGarrett D'Amore 		buf[1] = '\0';
26195c635efSGarrett D'Amore 		for (ssz = 0, i = 0; cp != &str[i]; i++) {
26295c635efSGarrett D'Amore 			buf[0] = str[i];
26395c635efSGarrett D'Amore 			ssz += (*tbl->slen)(buf, tbl->arg);
26495c635efSGarrett D'Amore 		}
26595c635efSGarrett D'Amore 		d = ssz + psz;
26695c635efSGarrett D'Amore 	} else
26795c635efSGarrett D'Amore 		d = sz + psz;
26895c635efSGarrett D'Amore 
26995c635efSGarrett D'Amore 	/* Adjust the settings for this column. */
27095c635efSGarrett D'Amore 
27195c635efSGarrett D'Amore 	if (col->decimal > d) {
27295c635efSGarrett D'Amore 		sz += col->decimal - d;
27395c635efSGarrett D'Amore 		d = col->decimal;
27495c635efSGarrett D'Amore 	} else
27595c635efSGarrett D'Amore 		col->width += d - col->decimal;
27695c635efSGarrett D'Amore 
27795c635efSGarrett D'Amore 	if (sz > col->width)
27895c635efSGarrett D'Amore 		col->width = sz;
27995c635efSGarrett D'Amore 	if (d > col->decimal)
28095c635efSGarrett D'Amore 		col->decimal = d;
28195c635efSGarrett D'Amore }
282