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