1 /* $Id: out.c,v 1.45 2013/05/31 21:37:17 schwarze Exp $ */
3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/types.h>
34 static void tblcalc_data(struct rofftbl *, struct roffcol *,
35 const struct tbl_opts *, const struct tbl_dat *);
36 static void tblcalc_literal(struct rofftbl *, struct roffcol *,
37 const struct tbl_dat *);
38 static void tblcalc_number(struct rofftbl *, struct roffcol *,
39 const struct tbl_opts *, const struct tbl_dat *);
42 * Convert a `scaling unit' to a consistent form, or fail. Scaling
43 * units are documented in groff.7, mdoc.7, man.7.
46 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
48 char buf[BUFSIZ], hasd;
72 if ( ! isdigit((unsigned char)*src)) {
83 if (BUFSIZ == i || (*src && *(src + 1)))
111 if (SCALE_MAX == def)
128 /* FIXME: do this in the caller. */
129 if ((dst->scale = atof(buf)) < 0)
136 * Calculate the abstract widths and decimal positions of columns in a
137 * table. This routine allocates the columns structures then runs over
138 * all rows and cells in the table. The function pointers in "tbl" are
139 * used for the actual width calculations.
142 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
144 const struct tbl_dat *dp;
145 const struct tbl_head *hp;
150 * Allocate the master column specifiers. These will hold the
151 * widths and decimal positions for all cells in the column. It
152 * must be freed and nullified by the caller.
155 assert(NULL == tbl->cols);
156 tbl->cols = mandoc_calloc
157 ((size_t)sp->opts->cols, sizeof(struct roffcol));
161 for ( ; sp; sp = sp->next) {
162 if (TBL_SPAN_DATA != sp->pos)
166 * Account for the data cells in the layout, matching it
167 * to data cells in the data section.
169 for (dp = sp->first; dp; dp = dp->next) {
170 /* Do not used spanned cells in the calculation. */
177 col = &tbl->cols[dp->layout->head->ident];
178 tblcalc_data(tbl, col, sp->opts, dp);
184 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
185 const struct tbl_opts *opts, const struct tbl_dat *dp)
189 /* Branch down into data sub-types. */
191 switch (dp->layout->pos) {
192 case (TBL_CELL_HORIZ):
194 case (TBL_CELL_DHORIZ):
195 sz = (*tbl->len)(1, tbl->arg);
199 case (TBL_CELL_LONG):
201 case (TBL_CELL_CENTRE):
203 case (TBL_CELL_LEFT):
205 case (TBL_CELL_RIGHT):
206 tblcalc_literal(tbl, col, dp);
208 case (TBL_CELL_NUMBER):
209 tblcalc_number(tbl, col, opts, dp);
211 case (TBL_CELL_DOWN):
220 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
221 const struct tbl_dat *dp)
226 str = dp->string ? dp->string : "";
227 sz = (*tbl->slen)(str, tbl->arg);
234 tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
235 const struct tbl_opts *opts, const struct tbl_dat *dp)
238 size_t sz, psz, ssz, d;
244 * First calculate number width and decimal place (last + 1 for
245 * non-decimal numbers). If the stored decimal is subsequent to
246 * ours, make our size longer by that difference
247 * (right-"shifting"); similarly, if ours is subsequent the
248 * stored, then extend the stored size by the difference.
249 * Finally, re-assign the stored values.
252 str = dp->string ? dp->string : "";
253 sz = (*tbl->slen)(str, tbl->arg);
255 /* FIXME: TBL_DATA_HORIZ et al.? */
257 buf[0] = opts->decimal;
260 psz = (*tbl->slen)(buf, tbl->arg);
262 if (NULL != (cp = strrchr(str, opts->decimal))) {
264 for (ssz = 0, i = 0; cp != &str[i]; i++) {
266 ssz += (*tbl->slen)(buf, tbl->arg);
272 /* Adjust the settings for this column. */
274 if (col->decimal > d) {
275 sz += col->decimal - d;
278 col->width += d - col->decimal;
282 if (d > col->decimal)