Annotation of src/usr.bin/mandoc/out.c, Revision 1.15
1.15 ! schwarze 1: /* $Id: out.c,v 1.14 2011/05/29 21:22:18 schwarze Exp $ */
1.1 schwarze 2: /*
1.9 schwarze 3: * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.12 schwarze 4: * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 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 <sys/types.h>
19:
1.2 schwarze 20: #include <assert.h>
1.1 schwarze 21: #include <ctype.h>
22: #include <stdio.h>
23: #include <stdlib.h>
1.2 schwarze 24: #include <string.h>
25: #include <time.h>
1.1 schwarze 26:
1.9 schwarze 27: #include "mandoc.h"
1.1 schwarze 28: #include "out.h"
29:
1.9 schwarze 30: static void tblcalc_data(struct rofftbl *, struct roffcol *,
31: const struct tbl *, const struct tbl_dat *);
32: static void tblcalc_literal(struct rofftbl *, struct roffcol *,
33: const struct tbl_dat *);
34: static void tblcalc_number(struct rofftbl *, struct roffcol *,
35: const struct tbl *, const struct tbl_dat *);
36:
1.1 schwarze 37: /*
38: * Convert a `scaling unit' to a consistent form, or fail. Scaling
39: * units are documented in groff.7, mdoc.7, man.7.
40: */
41: int
42: a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
43: {
44: char buf[BUFSIZ], hasd;
45: int i;
46: enum roffscale unit;
47:
48: if ('\0' == *src)
49: return(0);
50:
51: i = hasd = 0;
52:
53: switch (*src) {
54: case ('+'):
55: src++;
56: break;
57: case ('-'):
58: buf[i++] = *src++;
59: break;
60: default:
61: break;
62: }
63:
64: if ('\0' == *src)
65: return(0);
66:
67: while (i < BUFSIZ) {
1.15 ! schwarze 68: if ( ! isdigit((unsigned char)*src)) {
1.1 schwarze 69: if ('.' != *src)
70: break;
71: else if (hasd)
72: break;
73: else
74: hasd = 1;
75: }
76: buf[i++] = *src++;
77: }
78:
79: if (BUFSIZ == i || (*src && *(src + 1)))
80: return(0);
81:
82: buf[i] = '\0';
83:
84: switch (*src) {
85: case ('c'):
86: unit = SCALE_CM;
87: break;
88: case ('i'):
89: unit = SCALE_IN;
90: break;
91: case ('P'):
92: unit = SCALE_PC;
93: break;
94: case ('p'):
95: unit = SCALE_PT;
96: break;
97: case ('f'):
98: unit = SCALE_FS;
99: break;
100: case ('v'):
101: unit = SCALE_VS;
102: break;
103: case ('m'):
104: unit = SCALE_EM;
105: break;
106: case ('\0'):
107: if (SCALE_MAX == def)
108: return(0);
109: unit = SCALE_BU;
110: break;
111: case ('u'):
112: unit = SCALE_BU;
113: break;
114: case ('M'):
115: unit = SCALE_MM;
116: break;
117: case ('n'):
118: unit = SCALE_EN;
119: break;
120: default:
121: return(0);
122: }
123:
1.6 schwarze 124: /* FIXME: do this in the caller. */
1.1 schwarze 125: if ((dst->scale = atof(buf)) < 0)
126: dst->scale = 0;
127: dst->unit = unit;
128: return(1);
1.3 schwarze 129: }
1.9 schwarze 130:
131: /*
132: * Calculate the abstract widths and decimal positions of columns in a
133: * table. This routine allocates the columns structures then runs over
134: * all rows and cells in the table. The function pointers in "tbl" are
135: * used for the actual width calculations.
136: */
137: void
138: tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
139: {
140: const struct tbl_dat *dp;
141: const struct tbl_head *hp;
142: struct roffcol *col;
143:
144: /*
145: * Allocate the master column specifiers. These will hold the
146: * widths and decimal positions for all cells in the column. It
147: * must be freed and nullified by the caller.
148: */
149:
150: assert(NULL == tbl->cols);
1.13 schwarze 151: tbl->cols = mandoc_calloc
152: ((size_t)sp->tbl->cols, sizeof(struct roffcol));
1.9 schwarze 153:
154: hp = sp->head;
155:
156: for ( ; sp; sp = sp->next) {
157: if (TBL_SPAN_DATA != sp->pos)
158: continue;
159: /*
160: * Account for the data cells in the layout, matching it
161: * to data cells in the data section.
162: */
163: for (dp = sp->first; dp; dp = dp->next) {
1.10 schwarze 164: assert(dp->layout);
1.9 schwarze 165: col = &tbl->cols[dp->layout->head->ident];
166: tblcalc_data(tbl, col, sp->tbl, dp);
167: }
168: }
169:
170: /*
171: * Calculate width of the spanners. These get one space for a
172: * vertical line, two for a double-vertical line.
173: */
174:
175: for ( ; hp; hp = hp->next) {
176: col = &tbl->cols[hp->ident];
177: switch (hp->pos) {
178: case (TBL_HEAD_VERT):
179: col->width = (*tbl->len)(1, tbl->arg);
180: break;
181: case (TBL_HEAD_DVERT):
182: col->width = (*tbl->len)(2, tbl->arg);
183: break;
184: default:
185: break;
186: }
187: }
188: }
189:
190: static void
191: tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
192: const struct tbl *tp, const struct tbl_dat *dp)
193: {
194: size_t sz;
195:
196: /* Branch down into data sub-types. */
197:
198: switch (dp->layout->pos) {
199: case (TBL_CELL_HORIZ):
200: /* FALLTHROUGH */
201: case (TBL_CELL_DHORIZ):
202: sz = (*tbl->len)(1, tbl->arg);
203: if (col->width < sz)
204: col->width = sz;
205: break;
206: case (TBL_CELL_LONG):
207: /* FALLTHROUGH */
208: case (TBL_CELL_CENTRE):
209: /* FALLTHROUGH */
210: case (TBL_CELL_LEFT):
211: /* FALLTHROUGH */
212: case (TBL_CELL_RIGHT):
213: tblcalc_literal(tbl, col, dp);
214: break;
215: case (TBL_CELL_NUMBER):
216: tblcalc_number(tbl, col, tp, dp);
217: break;
1.10 schwarze 218: case (TBL_CELL_DOWN):
219: break;
1.9 schwarze 220: default:
221: abort();
222: /* NOTREACHED */
223: }
224: }
225:
226: static void
227: tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
228: const struct tbl_dat *dp)
229: {
230: size_t sz, bufsz, spsz;
1.10 schwarze 231: const char *str;
1.9 schwarze 232:
233: /*
234: * Calculate our width and use the spacing, with a minimum
235: * spacing dictated by position (centre, e.g,. gets a space on
236: * either side, while right/left get a single adjacent space).
237: */
238:
1.10 schwarze 239: bufsz = spsz = 0;
240: str = dp->string ? dp->string : "";
241: sz = (*tbl->slen)(str, tbl->arg);
242:
243: /* FIXME: TBL_DATA_HORIZ et al.? */
1.9 schwarze 244:
245: assert(dp->layout);
246: switch (dp->layout->pos) {
247: case (TBL_CELL_LONG):
248: /* FALLTHROUGH */
249: case (TBL_CELL_CENTRE):
1.11 schwarze 250: bufsz = (*tbl->len)(1, tbl->arg);
1.9 schwarze 251: break;
252: default:
253: bufsz = (*tbl->len)(1, tbl->arg);
254: break;
255: }
256:
257: if (dp->layout->spacing) {
258: spsz = (*tbl->len)(dp->layout->spacing, tbl->arg);
259: bufsz = bufsz > spsz ? bufsz : spsz;
260: }
261:
262: sz += bufsz;
263: if (col->width < sz)
264: col->width = sz;
265: }
266:
267: static void
268: tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
269: const struct tbl *tp, const struct tbl_dat *dp)
270: {
271: int i;
1.10 schwarze 272: size_t sz, psz, ssz, d;
273: const char *str;
1.9 schwarze 274: char *cp;
275: char buf[2];
276:
277: /*
278: * First calculate number width and decimal place (last + 1 for
279: * no-decimal numbers). If the stored decimal is subsequent
280: * ours, make our size longer by that difference
281: * (right-"shifting"); similarly, if ours is subsequent the
282: * stored, then extend the stored size by the difference.
283: * Finally, re-assign the stored values.
284: */
285:
1.10 schwarze 286: str = dp->string ? dp->string : "";
287: sz = (*tbl->slen)(str, tbl->arg);
1.9 schwarze 288:
1.10 schwarze 289: /* FIXME: TBL_DATA_HORIZ et al.? */
1.9 schwarze 290:
291: buf[0] = tp->decimal;
292: buf[1] = '\0';
293:
294: psz = (*tbl->slen)(buf, tbl->arg);
295:
296: if (NULL != (cp = strrchr(str, tp->decimal))) {
297: buf[1] = '\0';
298: for (ssz = 0, i = 0; cp != &str[i]; i++) {
299: buf[0] = str[i];
300: ssz += (*tbl->slen)(buf, tbl->arg);
301: }
302: d = ssz + psz;
303: } else
304: d = sz + psz;
305:
306: /* Padding. */
307:
308: sz += (*tbl->len)(2, tbl->arg);
309: d += (*tbl->len)(1, tbl->arg);
310:
311: /* Adjust the settings for this column. */
312:
313: if (col->decimal > d) {
314: sz += col->decimal - d;
315: d = col->decimal;
316: } else
317: col->width += d - col->decimal;
318:
319: if (sz > col->width)
320: col->width = sz;
321: if (d > col->decimal)
322: col->decimal = d;
323:
324: /* Adjust for stipulated width. */
325:
1.10 schwarze 326: if (col->width < dp->layout->spacing)
327: col->width = dp->layout->spacing;
1.9 schwarze 328: }
329:
330: