xref: /minix3/external/bsd/mdocml/dist/out.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp  */
2d65f6f70SBen Gras /*
392395e9cSLionel Sambuc  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
492395e9cSLionel Sambuc  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
5d65f6f70SBen Gras  *
6d65f6f70SBen Gras  * Permission to use, copy, modify, and distribute this software for any
7d65f6f70SBen Gras  * purpose with or without fee is hereby granted, provided that the above
8d65f6f70SBen Gras  * copyright notice and this permission notice appear in all copies.
9d65f6f70SBen Gras  *
10d65f6f70SBen Gras  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d65f6f70SBen Gras  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d65f6f70SBen Gras  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d65f6f70SBen Gras  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d65f6f70SBen Gras  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d65f6f70SBen Gras  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d65f6f70SBen Gras  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d65f6f70SBen Gras  */
18d65f6f70SBen Gras #ifdef HAVE_CONFIG_H
19d65f6f70SBen Gras #include "config.h"
20d65f6f70SBen Gras #endif
21d65f6f70SBen Gras 
22d65f6f70SBen Gras #include <sys/types.h>
23d65f6f70SBen Gras 
24d65f6f70SBen Gras #include <assert.h>
25d65f6f70SBen Gras #include <ctype.h>
26d65f6f70SBen Gras #include <stdio.h>
27d65f6f70SBen Gras #include <stdlib.h>
28d65f6f70SBen Gras #include <string.h>
29d65f6f70SBen Gras #include <time.h>
30d65f6f70SBen Gras 
31d65f6f70SBen Gras #include "mandoc.h"
32d65f6f70SBen Gras #include "out.h"
33d65f6f70SBen Gras 
34d65f6f70SBen Gras static	void	tblcalc_data(struct rofftbl *, struct roffcol *,
35*0a6a1f1dSLionel Sambuc 			const struct tbl_opts *, const struct tbl_dat *);
36d65f6f70SBen Gras static	void	tblcalc_literal(struct rofftbl *, struct roffcol *,
37d65f6f70SBen Gras 			const struct tbl_dat *);
38d65f6f70SBen Gras static	void	tblcalc_number(struct rofftbl *, struct roffcol *,
39*0a6a1f1dSLionel Sambuc 			const struct tbl_opts *, const struct tbl_dat *);
40d65f6f70SBen Gras 
41d65f6f70SBen Gras /*
42d65f6f70SBen Gras  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
43d65f6f70SBen Gras  * units are documented in groff.7, mdoc.7, man.7.
44d65f6f70SBen Gras  */
45d65f6f70SBen Gras int
a2roffsu(const char * src,struct roffsu * dst,enum roffscale def)46d65f6f70SBen Gras a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
47d65f6f70SBen Gras {
48d65f6f70SBen Gras 	char		 buf[BUFSIZ], hasd;
49d65f6f70SBen Gras 	int		 i;
50d65f6f70SBen Gras 	enum roffscale	 unit;
51d65f6f70SBen Gras 
52d65f6f70SBen Gras 	if ('\0' == *src)
53d65f6f70SBen Gras 		return(0);
54d65f6f70SBen Gras 
55d65f6f70SBen Gras 	i = hasd = 0;
56d65f6f70SBen Gras 
57d65f6f70SBen Gras 	switch (*src) {
58d65f6f70SBen Gras 	case ('+'):
59d65f6f70SBen Gras 		src++;
60d65f6f70SBen Gras 		break;
61d65f6f70SBen Gras 	case ('-'):
62d65f6f70SBen Gras 		buf[i++] = *src++;
63d65f6f70SBen Gras 		break;
64d65f6f70SBen Gras 	default:
65d65f6f70SBen Gras 		break;
66d65f6f70SBen Gras 	}
67d65f6f70SBen Gras 
68d65f6f70SBen Gras 	if ('\0' == *src)
69d65f6f70SBen Gras 		return(0);
70d65f6f70SBen Gras 
71d65f6f70SBen Gras 	while (i < BUFSIZ) {
7292395e9cSLionel Sambuc 		if ( ! isdigit((unsigned char)*src)) {
73d65f6f70SBen Gras 			if ('.' != *src)
74d65f6f70SBen Gras 				break;
75d65f6f70SBen Gras 			else if (hasd)
76d65f6f70SBen Gras 				break;
77d65f6f70SBen Gras 			else
78d65f6f70SBen Gras 				hasd = 1;
79d65f6f70SBen Gras 		}
80d65f6f70SBen Gras 		buf[i++] = *src++;
81d65f6f70SBen Gras 	}
82d65f6f70SBen Gras 
83d65f6f70SBen Gras 	if (BUFSIZ == i || (*src && *(src + 1)))
84d65f6f70SBen Gras 		return(0);
85d65f6f70SBen Gras 
86d65f6f70SBen Gras 	buf[i] = '\0';
87d65f6f70SBen Gras 
88d65f6f70SBen Gras 	switch (*src) {
89d65f6f70SBen Gras 	case ('c'):
90d65f6f70SBen Gras 		unit = SCALE_CM;
91d65f6f70SBen Gras 		break;
92d65f6f70SBen Gras 	case ('i'):
93d65f6f70SBen Gras 		unit = SCALE_IN;
94d65f6f70SBen Gras 		break;
95d65f6f70SBen Gras 	case ('P'):
96d65f6f70SBen Gras 		unit = SCALE_PC;
97d65f6f70SBen Gras 		break;
98d65f6f70SBen Gras 	case ('p'):
99d65f6f70SBen Gras 		unit = SCALE_PT;
100d65f6f70SBen Gras 		break;
101d65f6f70SBen Gras 	case ('f'):
102d65f6f70SBen Gras 		unit = SCALE_FS;
103d65f6f70SBen Gras 		break;
104d65f6f70SBen Gras 	case ('v'):
105d65f6f70SBen Gras 		unit = SCALE_VS;
106d65f6f70SBen Gras 		break;
107d65f6f70SBen Gras 	case ('m'):
108d65f6f70SBen Gras 		unit = SCALE_EM;
109d65f6f70SBen Gras 		break;
110d65f6f70SBen Gras 	case ('\0'):
111d65f6f70SBen Gras 		if (SCALE_MAX == def)
112d65f6f70SBen Gras 			return(0);
113d65f6f70SBen Gras 		unit = SCALE_BU;
114d65f6f70SBen Gras 		break;
115d65f6f70SBen Gras 	case ('u'):
116d65f6f70SBen Gras 		unit = SCALE_BU;
117d65f6f70SBen Gras 		break;
118d65f6f70SBen Gras 	case ('M'):
119d65f6f70SBen Gras 		unit = SCALE_MM;
120d65f6f70SBen Gras 		break;
121d65f6f70SBen Gras 	case ('n'):
122d65f6f70SBen Gras 		unit = SCALE_EN;
123d65f6f70SBen Gras 		break;
124d65f6f70SBen Gras 	default:
125d65f6f70SBen Gras 		return(0);
126d65f6f70SBen Gras 	}
127d65f6f70SBen Gras 
128d65f6f70SBen Gras 	/* FIXME: do this in the caller. */
129d65f6f70SBen Gras 	if ((dst->scale = atof(buf)) < 0)
130d65f6f70SBen Gras 		dst->scale = 0;
131d65f6f70SBen Gras 	dst->unit = unit;
132d65f6f70SBen Gras 	return(1);
133d65f6f70SBen Gras }
134d65f6f70SBen Gras 
135d65f6f70SBen Gras /*
136d65f6f70SBen Gras  * Calculate the abstract widths and decimal positions of columns in a
137d65f6f70SBen Gras  * table.  This routine allocates the columns structures then runs over
138d65f6f70SBen Gras  * all rows and cells in the table.  The function pointers in "tbl" are
139d65f6f70SBen Gras  * used for the actual width calculations.
140d65f6f70SBen Gras  */
141d65f6f70SBen Gras void
tblcalc(struct rofftbl * tbl,const struct tbl_span * sp)142d65f6f70SBen Gras tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
143d65f6f70SBen Gras {
144d65f6f70SBen Gras 	const struct tbl_dat	*dp;
145d65f6f70SBen Gras 	struct roffcol		*col;
14692395e9cSLionel Sambuc 	int			 spans;
147d65f6f70SBen Gras 
148d65f6f70SBen Gras 	/*
149d65f6f70SBen Gras 	 * Allocate the master column specifiers.  These will hold the
150d65f6f70SBen Gras 	 * widths and decimal positions for all cells in the column.  It
151d65f6f70SBen Gras 	 * must be freed and nullified by the caller.
152d65f6f70SBen Gras 	 */
153d65f6f70SBen Gras 
154d65f6f70SBen Gras 	assert(NULL == tbl->cols);
15592395e9cSLionel Sambuc 	tbl->cols = mandoc_calloc
156*0a6a1f1dSLionel Sambuc 		((size_t)sp->opts->cols, sizeof(struct roffcol));
157d65f6f70SBen Gras 
158d65f6f70SBen Gras 	for ( ; sp; sp = sp->next) {
159d65f6f70SBen Gras 		if (TBL_SPAN_DATA != sp->pos)
160d65f6f70SBen Gras 			continue;
16192395e9cSLionel Sambuc 		spans = 1;
162d65f6f70SBen Gras 		/*
163d65f6f70SBen Gras 		 * Account for the data cells in the layout, matching it
164d65f6f70SBen Gras 		 * to data cells in the data section.
165d65f6f70SBen Gras 		 */
166d65f6f70SBen Gras 		for (dp = sp->first; dp; dp = dp->next) {
16792395e9cSLionel Sambuc 			/* Do not used spanned cells in the calculation. */
16892395e9cSLionel Sambuc 			if (0 < --spans)
169d65f6f70SBen Gras 				continue;
17092395e9cSLionel Sambuc 			spans = dp->spans;
17192395e9cSLionel Sambuc 			if (1 < spans)
17292395e9cSLionel Sambuc 				continue;
17392395e9cSLionel Sambuc 			assert(dp->layout);
174d65f6f70SBen Gras 			col = &tbl->cols[dp->layout->head->ident];
175*0a6a1f1dSLionel Sambuc 			tblcalc_data(tbl, col, sp->opts, dp);
176d65f6f70SBen Gras 		}
177d65f6f70SBen Gras 	}
178d65f6f70SBen Gras }
179d65f6f70SBen Gras 
180d65f6f70SBen Gras static void
tblcalc_data(struct rofftbl * tbl,struct roffcol * col,const struct tbl_opts * opts,const struct tbl_dat * dp)181d65f6f70SBen Gras tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
182*0a6a1f1dSLionel Sambuc 		const struct tbl_opts *opts, const struct tbl_dat *dp)
183d65f6f70SBen Gras {
184d65f6f70SBen Gras 	size_t		 sz;
185d65f6f70SBen Gras 
186d65f6f70SBen Gras 	/* Branch down into data sub-types. */
187d65f6f70SBen Gras 
188d65f6f70SBen Gras 	switch (dp->layout->pos) {
189d65f6f70SBen Gras 	case (TBL_CELL_HORIZ):
190d65f6f70SBen Gras 		/* FALLTHROUGH */
191d65f6f70SBen Gras 	case (TBL_CELL_DHORIZ):
192d65f6f70SBen Gras 		sz = (*tbl->len)(1, tbl->arg);
193d65f6f70SBen Gras 		if (col->width < sz)
194d65f6f70SBen Gras 			col->width = sz;
195d65f6f70SBen Gras 		break;
196d65f6f70SBen Gras 	case (TBL_CELL_LONG):
197d65f6f70SBen Gras 		/* FALLTHROUGH */
198d65f6f70SBen Gras 	case (TBL_CELL_CENTRE):
199d65f6f70SBen Gras 		/* FALLTHROUGH */
200d65f6f70SBen Gras 	case (TBL_CELL_LEFT):
201d65f6f70SBen Gras 		/* FALLTHROUGH */
202d65f6f70SBen Gras 	case (TBL_CELL_RIGHT):
203d65f6f70SBen Gras 		tblcalc_literal(tbl, col, dp);
204d65f6f70SBen Gras 		break;
205d65f6f70SBen Gras 	case (TBL_CELL_NUMBER):
206*0a6a1f1dSLionel Sambuc 		tblcalc_number(tbl, col, opts, dp);
207d65f6f70SBen Gras 		break;
20892395e9cSLionel Sambuc 	case (TBL_CELL_DOWN):
20992395e9cSLionel Sambuc 		break;
210d65f6f70SBen Gras 	default:
211d65f6f70SBen Gras 		abort();
212d65f6f70SBen Gras 		/* NOTREACHED */
213d65f6f70SBen Gras 	}
214d65f6f70SBen Gras }
215d65f6f70SBen Gras 
216d65f6f70SBen Gras static void
tblcalc_literal(struct rofftbl * tbl,struct roffcol * col,const struct tbl_dat * dp)217d65f6f70SBen Gras tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
218d65f6f70SBen Gras 		const struct tbl_dat *dp)
219d65f6f70SBen Gras {
22092395e9cSLionel Sambuc 	size_t		 sz;
22192395e9cSLionel Sambuc 	const char	*str;
222d65f6f70SBen Gras 
22392395e9cSLionel Sambuc 	str = dp->string ? dp->string : "";
22492395e9cSLionel Sambuc 	sz = (*tbl->slen)(str, tbl->arg);
225d65f6f70SBen Gras 
226d65f6f70SBen Gras 	if (col->width < sz)
227d65f6f70SBen Gras 		col->width = sz;
228d65f6f70SBen Gras }
229d65f6f70SBen Gras 
230d65f6f70SBen Gras static void
tblcalc_number(struct rofftbl * tbl,struct roffcol * col,const struct tbl_opts * opts,const struct tbl_dat * dp)231d65f6f70SBen Gras tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
232*0a6a1f1dSLionel Sambuc 		const struct tbl_opts *opts, const struct tbl_dat *dp)
233d65f6f70SBen Gras {
234d65f6f70SBen Gras 	int 		 i;
235d65f6f70SBen Gras 	size_t		 sz, psz, ssz, d;
236d65f6f70SBen Gras 	const char	*str;
23792395e9cSLionel Sambuc 	char		*cp;
238d65f6f70SBen Gras 	char		 buf[2];
239d65f6f70SBen Gras 
240d65f6f70SBen Gras 	/*
241d65f6f70SBen Gras 	 * First calculate number width and decimal place (last + 1 for
24292395e9cSLionel Sambuc 	 * non-decimal numbers).  If the stored decimal is subsequent to
243d65f6f70SBen Gras 	 * ours, make our size longer by that difference
244d65f6f70SBen Gras 	 * (right-"shifting"); similarly, if ours is subsequent the
245d65f6f70SBen Gras 	 * stored, then extend the stored size by the difference.
246d65f6f70SBen Gras 	 * Finally, re-assign the stored values.
247d65f6f70SBen Gras 	 */
248d65f6f70SBen Gras 
24992395e9cSLionel Sambuc 	str = dp->string ? dp->string : "";
250d65f6f70SBen Gras 	sz = (*tbl->slen)(str, tbl->arg);
251d65f6f70SBen Gras 
25292395e9cSLionel Sambuc 	/* FIXME: TBL_DATA_HORIZ et al.? */
25392395e9cSLionel Sambuc 
254*0a6a1f1dSLionel Sambuc 	buf[0] = opts->decimal;
255d65f6f70SBen Gras 	buf[1] = '\0';
256d65f6f70SBen Gras 
257d65f6f70SBen Gras 	psz = (*tbl->slen)(buf, tbl->arg);
258d65f6f70SBen Gras 
259*0a6a1f1dSLionel Sambuc 	if (NULL != (cp = strrchr(str, opts->decimal))) {
260d65f6f70SBen Gras 		buf[1] = '\0';
261d65f6f70SBen Gras 		for (ssz = 0, i = 0; cp != &str[i]; i++) {
262d65f6f70SBen Gras 			buf[0] = str[i];
263d65f6f70SBen Gras 			ssz += (*tbl->slen)(buf, tbl->arg);
264d65f6f70SBen Gras 		}
265d65f6f70SBen Gras 		d = ssz + psz;
266d65f6f70SBen Gras 	} else
267d65f6f70SBen Gras 		d = sz + psz;
268d65f6f70SBen Gras 
269d65f6f70SBen Gras 	/* Adjust the settings for this column. */
270d65f6f70SBen Gras 
271d65f6f70SBen Gras 	if (col->decimal > d) {
272d65f6f70SBen Gras 		sz += col->decimal - d;
273d65f6f70SBen Gras 		d = col->decimal;
274d65f6f70SBen Gras 	} else
275d65f6f70SBen Gras 		col->width += d - col->decimal;
276d65f6f70SBen Gras 
277d65f6f70SBen Gras 	if (sz > col->width)
278d65f6f70SBen Gras 		col->width = sz;
279d65f6f70SBen Gras 	if (d > col->decimal)
280d65f6f70SBen Gras 		col->decimal = d;
281d65f6f70SBen Gras }
282