]>
git.cameronkatri.com Git - mandoc.git/blob - out.c
d8696141a7d5bd92f212658a4dcf2a8d6d2d2373
1 /* $Id: out.c,v 1.72 2018/08/18 20:18:14 schwarze Exp $ */
3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011,2014,2015,2017,2018 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.
20 #include <sys/types.h>
28 #include "mandoc_aux.h"
32 static void tblcalc_data(struct rofftbl
*, struct roffcol
*,
33 const struct tbl_opts
*, const struct tbl_dat
*,
35 static void tblcalc_literal(struct rofftbl
*, struct roffcol
*,
36 const struct tbl_dat
*, size_t);
37 static void tblcalc_number(struct rofftbl
*, struct roffcol
*,
38 const struct tbl_opts
*, const struct tbl_dat
*);
42 * Parse the *src string and store a scaling unit into *dst.
43 * If the string doesn't specify the unit, use the default.
44 * If no default is specified, fail.
45 * Return a pointer to the byte after the last byte used,
46 * or NULL on total failure.
49 a2roffsu(const char *src
, struct roffsu
*dst
, enum roffscale def
)
53 dst
->unit
= def
== SCALE_MAX
? SCALE_BU
: def
;
54 dst
->scale
= strtod(src
, &endptr
);
100 * Calculate the abstract widths and decimal positions of columns in a
101 * table. This routine allocates the columns structures then runs over
102 * all rows and cells in the table. The function pointers in "tbl" are
103 * used for the actual width calculations.
106 tblcalc(struct rofftbl
*tbl
, const struct tbl_span
*sp
,
107 size_t offset
, size_t rmargin
)
110 const struct tbl_opts
*opts
;
111 const struct tbl_dat
*dp
;
113 size_t ewidth
, xwidth
;
115 int icol
, maxcol
, necol
, nxcol
, quirkcol
;
118 * Allocate the master column specifiers. These will hold the
119 * widths and decimal positions for all cells in the column. It
120 * must be freed and nullified by the caller.
123 assert(NULL
== tbl
->cols
);
124 tbl
->cols
= mandoc_calloc((size_t)sp
->opts
->cols
,
125 sizeof(struct roffcol
));
128 for (maxcol
= -1; sp
; sp
= sp
->next
) {
129 if (TBL_SPAN_DATA
!= sp
->pos
)
133 * Account for the data cells in the layout, matching it
134 * to data cells in the data section.
136 for (dp
= sp
->first
; dp
; dp
= dp
->next
) {
137 /* Do not used spanned cells in the calculation. */
143 icol
= dp
->layout
->col
;
144 while (maxcol
< icol
)
145 tbl
->cols
[++maxcol
].spacing
= SIZE_MAX
;
146 col
= tbl
->cols
+ icol
;
147 col
->flags
|= dp
->layout
->flags
;
148 if (dp
->layout
->flags
& TBL_CELL_WIGN
)
150 if (dp
->layout
->wstr
!= NULL
&&
151 dp
->layout
->width
== 0 &&
152 a2roffsu(dp
->layout
->wstr
, &su
, SCALE_EN
)
155 (*tbl
->sulen
)(&su
, tbl
->arg
);
156 if (col
->width
< dp
->layout
->width
)
157 col
->width
= dp
->layout
->width
;
158 if (dp
->layout
->spacing
!= SIZE_MAX
&&
159 (col
->spacing
== SIZE_MAX
||
160 col
->spacing
< dp
->layout
->spacing
))
161 col
->spacing
= dp
->layout
->spacing
;
162 tblcalc_data(tbl
, col
, opts
, dp
,
164 dp
->layout
->width
? dp
->layout
->width
:
165 rmargin
? (rmargin
+ sp
->opts
->cols
/ 2)
166 / (sp
->opts
->cols
+ 1) : 0);
171 * Align numbers with text.
172 * Count columns to equalize and columns to maximize.
173 * Find maximum width of the columns to equalize.
174 * Find total width of the columns *not* to maximize.
179 for (icol
= 0; icol
<= maxcol
; icol
++) {
180 col
= tbl
->cols
+ icol
;
181 if (col
->width
> col
->nwidth
)
182 col
->decimal
+= (col
->width
- col
->nwidth
) / 2;
184 col
->width
= col
->nwidth
;
185 if (col
->spacing
== SIZE_MAX
|| icol
== maxcol
)
187 if (col
->flags
& TBL_CELL_EQUAL
) {
189 if (ewidth
< col
->width
)
192 if (col
->flags
& TBL_CELL_WMAX
)
195 xwidth
+= col
->width
;
199 * Equalize columns, if requested for any of them.
200 * Update total width of the columns not to maximize.
204 for (icol
= 0; icol
<= maxcol
; icol
++) {
205 col
= tbl
->cols
+ icol
;
206 if ( ! (col
->flags
& TBL_CELL_EQUAL
))
208 if (col
->width
== ewidth
)
210 if (nxcol
&& rmargin
)
211 xwidth
+= ewidth
- col
->width
;
217 * If there are any columns to maximize, find the total
218 * available width, deducting 3n margins between columns.
219 * Distribute the available width evenly.
222 if (nxcol
&& rmargin
) {
224 (opts
->opts
& (TBL_OPT_BOX
| TBL_OPT_DBOX
) ?
225 2 : !!opts
->lvert
+ !!opts
->rvert
);
226 if (rmargin
<= offset
+ xwidth
)
228 xwidth
= rmargin
- offset
- xwidth
;
231 * Emulate a bug in GNU tbl width calculation that
232 * manifests itself for large numbers of x-columns.
233 * Emulating it for 5 x-columns gives identical
234 * behaviour for up to 6 x-columns.
238 quirkcol
= xwidth
% nxcol
+ 2;
239 if (quirkcol
!= 3 && quirkcol
!= 4)
246 for (icol
= 0; icol
<= maxcol
; icol
++) {
247 col
= tbl
->cols
+ icol
;
248 if ( ! (col
->flags
& TBL_CELL_WMAX
))
250 col
->width
= (double)xwidth
* ++necol
/ nxcol
252 if (necol
== quirkcol
)
254 ewidth
+= col
->width
;
260 tblcalc_data(struct rofftbl
*tbl
, struct roffcol
*col
,
261 const struct tbl_opts
*opts
, const struct tbl_dat
*dp
, size_t mw
)
265 /* Branch down into data sub-types. */
267 switch (dp
->layout
->pos
) {
269 case TBL_CELL_DHORIZ
:
270 sz
= (*tbl
->len
)(1, tbl
->arg
);
275 case TBL_CELL_CENTRE
:
278 tblcalc_literal(tbl
, col
, dp
, mw
);
280 case TBL_CELL_NUMBER
:
281 tblcalc_number(tbl
, col
, opts
, dp
);
291 tblcalc_literal(struct rofftbl
*tbl
, struct roffcol
*col
,
292 const struct tbl_dat
*dp
, size_t mw
)
294 const char *str
; /* Beginning of the first line. */
295 const char *beg
; /* Beginning of the current line. */
296 char *end
; /* End of the current line. */
297 size_t lsz
; /* Length of the current line. */
298 size_t wsz
; /* Length of the current word. */
300 if (dp
->string
== NULL
|| *dp
->string
== '\0')
302 str
= mw
? mandoc_strdup(dp
->string
) : dp
->string
;
304 for (beg
= str
; beg
!= NULL
&& *beg
!= '\0'; beg
= end
) {
305 end
= mw
? strchr(beg
, ' ') : NULL
;
311 wsz
= (*tbl
->slen
)(beg
, tbl
->arg
);
312 if (mw
&& lsz
&& lsz
+ 1 + wsz
<= mw
)
316 if (col
->width
< lsz
)
324 tblcalc_number(struct rofftbl
*tbl
, struct roffcol
*col
,
325 const struct tbl_opts
*opts
, const struct tbl_dat
*dp
)
334 * First calculate number width and decimal place (last + 1 for
335 * non-decimal numbers). If the stored decimal is subsequent to
336 * ours, make our size longer by that difference
337 * (right-"shifting"); similarly, if ours is subsequent the
338 * stored, then extend the stored size by the difference.
339 * Finally, re-assign the stored values.
342 str
= dp
->string
? dp
->string
: "";
343 sz
= (*tbl
->slen
)(str
, tbl
->arg
);
345 /* FIXME: TBL_DATA_HORIZ et al.? */
347 buf
[0] = opts
->decimal
;
350 if (NULL
!= (cp
= strrchr(str
, opts
->decimal
))) {
352 for (ssz
= 0, i
= 0; cp
!= &str
[i
]; i
++) {
354 ssz
+= (*tbl
->slen
)(buf
, tbl
->arg
);
360 /* Adjust the settings for this column. */
362 if (col
->decimal
> d
) {
363 sz
+= col
->decimal
- d
;
366 col
->nwidth
+= d
- col
->decimal
;
368 if (sz
> col
->nwidth
)
370 if (d
> col
->decimal
)