]> git.cameronkatri.com Git - mandoc.git/blob - out.c
implement -h (synopsis only) for preformatted (cat) pages;
[mandoc.git] / out.c
1 /* $Id: out.c,v 1.53 2014/10/14 18:18:05 schwarze Exp $ */
2 /*
3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
5 *
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.
9 *
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.
17 */
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28
29 #include "mandoc_aux.h"
30 #include "mandoc.h"
31 #include "out.h"
32
33 static void tblcalc_data(struct rofftbl *, struct roffcol *,
34 const struct tbl_opts *, const struct tbl_dat *);
35 static void tblcalc_literal(struct rofftbl *, struct roffcol *,
36 const struct tbl_dat *);
37 static void tblcalc_number(struct rofftbl *, struct roffcol *,
38 const struct tbl_opts *, const struct tbl_dat *);
39
40
41 /*
42 * Convert a `scaling unit' to a consistent form, or fail. Scaling
43 * units are documented in groff.7, mdoc.7, man.7.
44 */
45 int
46 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
47 {
48 char buf[BUFSIZ], hasd;
49 int i;
50 enum roffscale unit;
51
52 if ('\0' == *src)
53 return(0);
54
55 i = hasd = 0;
56
57 switch (*src) {
58 case '+':
59 src++;
60 break;
61 case '-':
62 buf[i++] = *src++;
63 break;
64 default:
65 break;
66 }
67
68 if ('\0' == *src)
69 return(0);
70
71 while (i < BUFSIZ) {
72 if ( ! isdigit((unsigned char)*src)) {
73 if ('.' != *src)
74 break;
75 else if (hasd)
76 break;
77 else
78 hasd = 1;
79 }
80 buf[i++] = *src++;
81 }
82
83 if (BUFSIZ == i || (*src && *(src + 1)))
84 return(0);
85
86 buf[i] = '\0';
87
88 switch (*src) {
89 case 'c':
90 unit = SCALE_CM;
91 break;
92 case 'i':
93 unit = SCALE_IN;
94 break;
95 case 'P':
96 unit = SCALE_PC;
97 break;
98 case 'p':
99 unit = SCALE_PT;
100 break;
101 case 'f':
102 unit = SCALE_FS;
103 break;
104 case 'v':
105 unit = SCALE_VS;
106 break;
107 case 'm':
108 unit = SCALE_EM;
109 break;
110 case '\0':
111 if (SCALE_MAX == def)
112 return(0);
113 unit = SCALE_EN;
114 break;
115 case 'u':
116 unit = SCALE_BU;
117 break;
118 case 'M':
119 unit = SCALE_MM;
120 break;
121 case 'n':
122 unit = SCALE_EN;
123 break;
124 default:
125 return(0);
126 }
127
128 /* FIXME: do this in the caller. */
129 if ((dst->scale = atof(buf)) < 0.0)
130 dst->scale = 0.0;
131 dst->unit = unit;
132 return(1);
133 }
134
135 /*
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.
140 */
141 void
142 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
143 size_t totalwidth)
144 {
145 const struct tbl_dat *dp;
146 struct roffcol *col;
147 size_t ewidth, xwidth;
148 int spans;
149 int icol, maxcol, necol, nxcol;
150
151 /*
152 * Allocate the master column specifiers. These will hold the
153 * widths and decimal positions for all cells in the column. It
154 * must be freed and nullified by the caller.
155 */
156
157 assert(NULL == tbl->cols);
158 tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
159 sizeof(struct roffcol));
160
161 for (maxcol = -1; sp; sp = sp->next) {
162 if (TBL_SPAN_DATA != sp->pos)
163 continue;
164 spans = 1;
165 /*
166 * Account for the data cells in the layout, matching it
167 * to data cells in the data section.
168 */
169 for (dp = sp->first; dp; dp = dp->next) {
170 /* Do not used spanned cells in the calculation. */
171 if (0 < --spans)
172 continue;
173 spans = dp->spans;
174 if (1 < spans)
175 continue;
176 icol = dp->layout->head->ident;
177 if (maxcol < icol)
178 maxcol = icol;
179 col = tbl->cols + icol;
180 col->flags |= dp->layout->flags;
181 if (dp->layout->flags & TBL_CELL_WIGN)
182 continue;
183 tblcalc_data(tbl, col, sp->opts, dp);
184 }
185 }
186
187 /*
188 * Count columns to equalize and columns to maximize.
189 * Find maximum width of the columns to equalize.
190 * Find total width of the columns *not* to maximize.
191 */
192
193 necol = nxcol = 0;
194 ewidth = xwidth = 0;
195 for (icol = 0; icol <= maxcol; icol++) {
196 col = tbl->cols + icol;
197 if (col->flags & TBL_CELL_EQUAL) {
198 necol++;
199 if (ewidth < col->width)
200 ewidth = col->width;
201 }
202 if (col->flags & TBL_CELL_WMAX)
203 nxcol++;
204 else
205 xwidth += col->width;
206 }
207
208 /*
209 * Equalize columns, if requested for any of them.
210 * Update total width of the columns not to maximize.
211 */
212
213 if (necol) {
214 for (icol = 0; icol <= maxcol; icol++) {
215 col = tbl->cols + icol;
216 if ( ! (col->flags & TBL_CELL_EQUAL))
217 continue;
218 if (col->width == ewidth)
219 continue;
220 if (nxcol && totalwidth)
221 xwidth += ewidth - col->width;
222 col->width = ewidth;
223 }
224 }
225
226 /*
227 * If there are any columns to maximize, find the total
228 * available width, deducting 3n margins between columns.
229 * Distribute the available width evenly.
230 */
231
232 if (nxcol && totalwidth) {
233 xwidth = totalwidth - 3*maxcol - xwidth;
234 for (icol = 0; icol <= maxcol; icol++) {
235 col = tbl->cols + icol;
236 if ( ! (col->flags & TBL_CELL_WMAX))
237 continue;
238 col->width = xwidth / nxcol--;
239 xwidth -= col->width;
240 }
241 }
242 }
243
244 static void
245 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
246 const struct tbl_opts *opts, const struct tbl_dat *dp)
247 {
248 size_t sz;
249
250 /* Branch down into data sub-types. */
251
252 switch (dp->layout->pos) {
253 case TBL_CELL_HORIZ:
254 /* FALLTHROUGH */
255 case TBL_CELL_DHORIZ:
256 sz = (*tbl->len)(1, tbl->arg);
257 if (col->width < sz)
258 col->width = sz;
259 break;
260 case TBL_CELL_LONG:
261 /* FALLTHROUGH */
262 case TBL_CELL_CENTRE:
263 /* FALLTHROUGH */
264 case TBL_CELL_LEFT:
265 /* FALLTHROUGH */
266 case TBL_CELL_RIGHT:
267 tblcalc_literal(tbl, col, dp);
268 break;
269 case TBL_CELL_NUMBER:
270 tblcalc_number(tbl, col, opts, dp);
271 break;
272 case TBL_CELL_DOWN:
273 break;
274 default:
275 abort();
276 /* NOTREACHED */
277 }
278 }
279
280 static void
281 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
282 const struct tbl_dat *dp)
283 {
284 size_t sz;
285 const char *str;
286
287 str = dp->string ? dp->string : "";
288 sz = (*tbl->slen)(str, tbl->arg);
289
290 if (col->width < sz)
291 col->width = sz;
292 }
293
294 static void
295 tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
296 const struct tbl_opts *opts, const struct tbl_dat *dp)
297 {
298 int i;
299 size_t sz, psz, ssz, d;
300 const char *str;
301 char *cp;
302 char buf[2];
303
304 /*
305 * First calculate number width and decimal place (last + 1 for
306 * non-decimal numbers). If the stored decimal is subsequent to
307 * ours, make our size longer by that difference
308 * (right-"shifting"); similarly, if ours is subsequent the
309 * stored, then extend the stored size by the difference.
310 * Finally, re-assign the stored values.
311 */
312
313 str = dp->string ? dp->string : "";
314 sz = (*tbl->slen)(str, tbl->arg);
315
316 /* FIXME: TBL_DATA_HORIZ et al.? */
317
318 buf[0] = opts->decimal;
319 buf[1] = '\0';
320
321 psz = (*tbl->slen)(buf, tbl->arg);
322
323 if (NULL != (cp = strrchr(str, opts->decimal))) {
324 buf[1] = '\0';
325 for (ssz = 0, i = 0; cp != &str[i]; i++) {
326 buf[0] = str[i];
327 ssz += (*tbl->slen)(buf, tbl->arg);
328 }
329 d = ssz + psz;
330 } else
331 d = sz + psz;
332
333 /* Adjust the settings for this column. */
334
335 if (col->decimal > d) {
336 sz += col->decimal - d;
337 d = col->decimal;
338 } else
339 col->width += d - col->decimal;
340
341 if (sz > col->width)
342 col->width = sz;
343 if (d > col->decimal)
344 col->decimal = d;
345 }