1 /* $Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */
2 /*
3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011 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 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <sys/types.h>
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include "mandoc.h"
32 #include "out.h"
33
34 static void tblcalc_data(struct rofftbl *, struct roffcol *,
35 const struct tbl *, 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 *, const struct tbl_dat *);
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++;
125 return(0);
126 }
127
128 /* FIXME: do this in the caller. */
129 if ((dst->scale = atof(buf)) < 0)
130 dst->scale = 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 {
144 const struct tbl_dat *dp;
145 const struct tbl_head *hp;
146 struct roffcol *col;
147 int spans;
148
149 /*
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.
153 */
154
155 assert(NULL == tbl->cols);
156 tbl->cols = mandoc_calloc
157 ((size_t)sp->tbl->cols, sizeof(struct roffcol));
158
159 hp = sp->head;
160
161 for ( ; 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 assert(dp->layout);
177 col = &tbl->cols[dp->layout->head->ident];
178 tblcalc_data(tbl, col, sp->tbl, dp);
179 }
180 }
181
182 /*
183 * Calculate width of the spanners. These get one space for a
184 * vertical line, two for a double-vertical line.
185 */
186
187 for ( ; hp; hp = hp->next) {
188 col = &tbl->cols[hp->ident];
189 switch (hp->pos) {
190 case (TBL_HEAD_VERT):
191 col->width = (*tbl->len)(1, tbl->arg);
192 break;
193 case (TBL_HEAD_DVERT):
194 col->width = (*tbl->len)(2, tbl->arg);
195 break;
196 default:
197 break;
198 }
199 }
200 }
201
202 static void
203 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
204 const struct tbl *tp, const struct tbl_dat *dp)
205 {
206 size_t sz;
207
208 /* Branch down into data sub-types. */
209
210 switch (dp->layout->pos) {
211 case (TBL_CELL_HORIZ):
212 /* FALLTHROUGH */
213 case (TBL_CELL_DHORIZ):
214 sz = (*tbl->len)(1, tbl->arg);
215 if (col->width < sz)
216 col->width = sz;
217 break;
218 case (TBL_CELL_LONG):
219 /* FALLTHROUGH */
220 case (TBL_CELL_CENTRE):
221 /* FALLTHROUGH */
222 case (TBL_CELL_LEFT):
223 /* FALLTHROUGH */
224 case (TBL_CELL_RIGHT):
225 tblcalc_literal(tbl, col, dp);
226 break;
227 case (TBL_CELL_NUMBER):
228 tblcalc_number(tbl, col, tp, dp);
229 break;
230 case (TBL_CELL_DOWN):
231 break;
232 default:
233 abort();
234 /* NOTREACHED */
235 }
236 }
237
238 static void
239 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
240 const struct tbl_dat *dp)
241 {
242 size_t sz;
243 const char *str;
244
245 str = dp->string ? dp->string : "";
246 sz = (*tbl->slen)(str, tbl->arg);
247
248 if (col->width < sz)
249 col->width = sz;
250 }
251
252 static void
253 tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
254 const struct tbl *tp, const struct tbl_dat *dp)
255 {
256 int i;
257 size_t sz, psz, ssz, d;
258 const char *str;
259 char *cp;
260 char buf[2];
261
262 /*
263 * First calculate number width and decimal place (last + 1 for
264 * non-decimal numbers). If the stored decimal is subsequent to
265 * ours, make our size longer by that difference
266 * (right-"shifting"); similarly, if ours is subsequent the
267 * stored, then extend the stored size by the difference.
268 * Finally, re-assign the stored values.
269 */
270
271 str = dp->string ? dp->string : "";
272 sz = (*tbl->slen)(str, tbl->arg);
273
274 /* FIXME: TBL_DATA_HORIZ et al.? */
275
276 buf[0] = tp->decimal;
277 buf[1] = '\0';
278
279 psz = (*tbl->slen)(buf, tbl->arg);
280
281 if (NULL != (cp = strrchr(str, tp->decimal))) {
282 buf[1] = '\0';
283 for (ssz = 0, i = 0; cp != &str[i]; i++) {
284 buf[0] = str[i];
285 ssz += (*tbl->slen)(buf, tbl->arg);
286 }
287 d = ssz + psz;
288 } else
289 d = sz + psz;
290
291 /* Adjust the settings for this column. */
292
293 if (col->decimal > d) {
294 sz += col->decimal - d;
295 d = col->decimal;
296 } else
297 col->width += d - col->decimal;
298
299 if (sz > col->width)
300 col->width = sz;
301 if (d > col->decimal)
|
1 /* $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */
2 /*
3 * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011 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 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <sys/types.h>
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include "mandoc.h"
32 #include "out.h"
33
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 *);
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++;
125 return(0);
126 }
127
128 /* FIXME: do this in the caller. */
129 if ((dst->scale = atof(buf)) < 0)
130 dst->scale = 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 {
144 const struct tbl_dat *dp;
145 struct roffcol *col;
146 int spans;
147
148 /*
149 * Allocate the master column specifiers. These will hold the
150 * widths and decimal positions for all cells in the column. It
151 * must be freed and nullified by the caller.
152 */
153
154 assert(NULL == tbl->cols);
155 tbl->cols = mandoc_calloc
156 ((size_t)sp->opts->cols, sizeof(struct roffcol));
157
158 for ( ; sp; sp = sp->next) {
159 if (TBL_SPAN_DATA != sp->pos)
160 continue;
161 spans = 1;
162 /*
163 * Account for the data cells in the layout, matching it
164 * to data cells in the data section.
165 */
166 for (dp = sp->first; dp; dp = dp->next) {
167 /* Do not used spanned cells in the calculation. */
168 if (0 < --spans)
169 continue;
170 spans = dp->spans;
171 if (1 < spans)
172 continue;
173 assert(dp->layout);
174 col = &tbl->cols[dp->layout->head->ident];
175 tblcalc_data(tbl, col, sp->opts, dp);
176 }
177 }
178 }
179
180 static void
181 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
182 const struct tbl_opts *opts, const struct tbl_dat *dp)
183 {
184 size_t sz;
185
186 /* Branch down into data sub-types. */
187
188 switch (dp->layout->pos) {
189 case (TBL_CELL_HORIZ):
190 /* FALLTHROUGH */
191 case (TBL_CELL_DHORIZ):
192 sz = (*tbl->len)(1, tbl->arg);
193 if (col->width < sz)
194 col->width = sz;
195 break;
196 case (TBL_CELL_LONG):
197 /* FALLTHROUGH */
198 case (TBL_CELL_CENTRE):
199 /* FALLTHROUGH */
200 case (TBL_CELL_LEFT):
201 /* FALLTHROUGH */
202 case (TBL_CELL_RIGHT):
203 tblcalc_literal(tbl, col, dp);
204 break;
205 case (TBL_CELL_NUMBER):
206 tblcalc_number(tbl, col, opts, dp);
207 break;
208 case (TBL_CELL_DOWN):
209 break;
210 default:
211 abort();
212 /* NOTREACHED */
213 }
214 }
215
216 static void
217 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
218 const struct tbl_dat *dp)
219 {
220 size_t sz;
221 const char *str;
222
223 str = dp->string ? dp->string : "";
224 sz = (*tbl->slen)(str, tbl->arg);
225
226 if (col->width < sz)
227 col->width = sz;
228 }
229
230 static void
231 tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
232 const struct tbl_opts *opts, const struct tbl_dat *dp)
233 {
234 int i;
235 size_t sz, psz, ssz, d;
236 const char *str;
237 char *cp;
238 char buf[2];
239
240 /*
241 * First calculate number width and decimal place (last + 1 for
242 * non-decimal numbers). If the stored decimal is subsequent to
243 * ours, make our size longer by that difference
244 * (right-"shifting"); similarly, if ours is subsequent the
245 * stored, then extend the stored size by the difference.
246 * Finally, re-assign the stored values.
247 */
248
249 str = dp->string ? dp->string : "";
250 sz = (*tbl->slen)(str, tbl->arg);
251
252 /* FIXME: TBL_DATA_HORIZ et al.? */
253
254 buf[0] = opts->decimal;
255 buf[1] = '\0';
256
257 psz = (*tbl->slen)(buf, tbl->arg);
258
259 if (NULL != (cp = strrchr(str, opts->decimal))) {
260 buf[1] = '\0';
261 for (ssz = 0, i = 0; cp != &str[i]; i++) {
262 buf[0] = str[i];
263 ssz += (*tbl->slen)(buf, tbl->arg);
264 }
265 d = ssz + psz;
266 } else
267 d = sz + psz;
268
269 /* Adjust the settings for this column. */
270
271 if (col->decimal > d) {
272 sz += col->decimal - d;
273 d = col->decimal;
274 } else
275 col->width += d - col->decimal;
276
277 if (sz > col->width)
278 col->width = sz;
279 if (d > col->decimal)
|