]> git.cameronkatri.com Git - mandoc.git/blob - tbl_term.c
Make dp->string always consist of a value.
[mandoc.git] / tbl_term.c
1 /* $Id: tbl_term.c,v 1.17 2011/01/10 14:56:06 kristaps Exp $ */
2 /*
3 * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "mandoc.h"
27 #include "out.h"
28 #include "term.h"
29
30 static size_t term_tbl_len(size_t, void *);
31 static size_t term_tbl_strlen(const char *, void *);
32 static void tbl_char(struct termp *, char, size_t);
33 static void tbl_data(struct termp *, const struct tbl *,
34 const struct tbl_dat *,
35 const struct roffcol *);
36 static void tbl_hframe(struct termp *, const struct tbl_span *);
37 static void tbl_literal(struct termp *, const struct tbl_dat *,
38 const struct roffcol *);
39 static void tbl_number(struct termp *, const struct tbl *,
40 const struct tbl_dat *,
41 const struct roffcol *);
42 static void tbl_hrule(struct termp *, const struct tbl_span *);
43 static void tbl_vframe(struct termp *, const struct tbl *);
44 static void tbl_vrule(struct termp *, const struct tbl_head *);
45
46
47 static size_t
48 term_tbl_strlen(const char *p, void *arg)
49 {
50
51 return(term_strlen((const struct termp *)arg, p));
52 }
53
54 static size_t
55 term_tbl_len(size_t sz, void *arg)
56 {
57
58 return(term_len((const struct termp *)arg, sz));
59 }
60
61 void
62 term_tbl(struct termp *tp, const struct tbl_span *sp)
63 {
64 const struct tbl_head *hp;
65 const struct tbl_dat *dp;
66 struct roffcol *col;
67 int spans;
68 size_t rmargin, maxrmargin;
69
70 rmargin = tp->rmargin;
71 maxrmargin = tp->maxrmargin;
72
73 tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
74
75 /* Inhibit printing of spaces: we do padding ourselves. */
76
77 tp->flags |= TERMP_NONOSPACE;
78 tp->flags |= TERMP_NOSPACE;
79
80 /*
81 * The first time we're invoked for a given table block,
82 * calculate the table widths and decimal positions.
83 */
84
85 if (TBL_SPAN_FIRST & sp->flags) {
86 term_flushln(tp);
87
88 tp->tbl.len = term_tbl_len;
89 tp->tbl.slen = term_tbl_strlen;
90 tp->tbl.arg = tp;
91
92 tblcalc(&tp->tbl, sp);
93 }
94
95 /* Horizontal frame at the start of boxed tables. */
96
97 if (TBL_SPAN_FIRST & sp->flags)
98 tbl_hframe(tp, sp);
99
100 /* Vertical frame at the start of each row. */
101
102 tbl_vframe(tp, sp->tbl);
103
104 /*
105 * Now print the actual data itself depending on the span type.
106 * Spanner spans get a horizontal rule; data spanners have their
107 * data printed by matching data to header.
108 */
109
110 switch (sp->pos) {
111 case (TBL_SPAN_HORIZ):
112 /* FALLTHROUGH */
113 case (TBL_SPAN_DHORIZ):
114 tbl_hrule(tp, sp);
115 break;
116 case (TBL_SPAN_DATA):
117 /* Iterate over template headers. */
118 dp = sp->first;
119 spans = 0;
120 for (hp = sp->head; hp; hp = hp->next) {
121 /*
122 * If the current data header is invoked during
123 * a spanner ("spans" > 0), don't emit anything
124 * at all.
125 */
126 switch (hp->pos) {
127 case (TBL_HEAD_VERT):
128 /* FALLTHROUGH */
129 case (TBL_HEAD_DVERT):
130 if (spans <= 0)
131 tbl_vrule(tp, hp);
132 continue;
133 case (TBL_HEAD_DATA):
134 break;
135 }
136
137 if (--spans >= 0)
138 continue;
139
140 col = &tp->tbl.cols[hp->ident];
141 tbl_data(tp, sp->tbl, dp, col);
142
143 /*
144 * Go to the next data cell and assign the
145 * number of subsequent spans, if applicable.
146 */
147
148 if (dp) {
149 spans = dp->spans;
150 dp = dp->next;
151 }
152 }
153 break;
154 }
155
156 tbl_vframe(tp, sp->tbl);
157 term_flushln(tp);
158
159 /*
160 * If we're the last row, clean up after ourselves: clear the
161 * existing table configuration and set it to NULL.
162 */
163
164 if (TBL_SPAN_LAST & sp->flags) {
165 tbl_hframe(tp, sp);
166 assert(tp->tbl.cols);
167 free(tp->tbl.cols);
168 tp->tbl.cols = NULL;
169 }
170
171 tp->flags &= ~TERMP_NONOSPACE;
172 tp->rmargin = rmargin;
173 tp->maxrmargin = maxrmargin;
174
175 }
176
177 static void
178 tbl_hrule(struct termp *tp, const struct tbl_span *sp)
179 {
180 const struct tbl_head *hp;
181 char c;
182 size_t width;
183
184 /*
185 * An hrule extends across the entire table and is demarked by a
186 * standalone `_' or whatnot in lieu of a table row. Spanning
187 * headers are marked by a `+', as are table boundaries.
188 */
189
190 c = '-';
191 if (TBL_SPAN_DHORIZ == sp->pos)
192 c = '=';
193
194 /* FIXME: don't use `+' between data and a spanner! */
195
196 for (hp = sp->head; hp; hp = hp->next) {
197 width = tp->tbl.cols[hp->ident].width;
198 switch (hp->pos) {
199 case (TBL_HEAD_DATA):
200 tbl_char(tp, c, width);
201 break;
202 case (TBL_HEAD_DVERT):
203 tbl_char(tp, '+', width);
204 /* FALLTHROUGH */
205 case (TBL_HEAD_VERT):
206 tbl_char(tp, '+', width);
207 break;
208 default:
209 abort();
210 /* NOTREACHED */
211 }
212 }
213 }
214
215 static void
216 tbl_hframe(struct termp *tp, const struct tbl_span *sp)
217 {
218 const struct tbl_head *hp;
219 size_t width;
220
221 if ( ! (TBL_OPT_BOX & sp->tbl->opts ||
222 TBL_OPT_DBOX & sp->tbl->opts))
223 return;
224
225 /*
226 * Print out the horizontal part of a frame or double frame. A
227 * double frame has an unbroken `-' outer line the width of the
228 * table, bordered by `+'. The frame (or inner frame, in the
229 * case of the double frame) is a `-' bordered by `+' and broken
230 * by `+' whenever a span is encountered.
231 */
232
233 if (TBL_OPT_DBOX & sp->tbl->opts) {
234 term_word(tp, "+");
235 for (hp = sp->head; hp; hp = hp->next) {
236 width = tp->tbl.cols[hp->ident].width;
237 tbl_char(tp, '-', width);
238 }
239 term_word(tp, "+");
240 term_flushln(tp);
241 }
242
243 term_word(tp, "+");
244 for (hp = sp->head; hp; hp = hp->next) {
245 width = tp->tbl.cols[hp->ident].width;
246 switch (hp->pos) {
247 case (TBL_HEAD_DATA):
248 tbl_char(tp, '-', width);
249 break;
250 default:
251 tbl_char(tp, '+', width);
252 break;
253 }
254 }
255 term_word(tp, "+");
256 term_flushln(tp);
257 }
258
259 static void
260 tbl_data(struct termp *tp, const struct tbl *tbl,
261 const struct tbl_dat *dp,
262 const struct roffcol *col)
263 {
264
265 if (NULL == dp) {
266 tbl_char(tp, ASCII_NBRSP, col->width);
267 return;
268 }
269 assert(dp->layout);
270
271 switch (dp->pos) {
272 case (TBL_DATA_NONE):
273 tbl_char(tp, ASCII_NBRSP, col->width);
274 return;
275 case (TBL_DATA_HORIZ):
276 /* FALLTHROUGH */
277 case (TBL_DATA_NHORIZ):
278 tbl_char(tp, '-', col->width);
279 return;
280 case (TBL_DATA_NDHORIZ):
281 /* FALLTHROUGH */
282 case (TBL_DATA_DHORIZ):
283 tbl_char(tp, '=', col->width);
284 return;
285 default:
286 break;
287 }
288
289 switch (dp->layout->pos) {
290 case (TBL_CELL_HORIZ):
291 tbl_char(tp, '-', col->width);
292 break;
293 case (TBL_CELL_DHORIZ):
294 tbl_char(tp, '=', col->width);
295 break;
296 case (TBL_CELL_LONG):
297 /* FALLTHROUGH */
298 case (TBL_CELL_CENTRE):
299 /* FALLTHROUGH */
300 case (TBL_CELL_LEFT):
301 /* FALLTHROUGH */
302 case (TBL_CELL_RIGHT):
303 tbl_literal(tp, dp, col);
304 break;
305 case (TBL_CELL_NUMBER):
306 tbl_number(tp, tbl, dp, col);
307 break;
308 default:
309 abort();
310 /* NOTREACHED */
311 }
312 }
313
314 static void
315 tbl_vrule(struct termp *tp, const struct tbl_head *hp)
316 {
317
318 switch (hp->pos) {
319 case (TBL_HEAD_VERT):
320 term_word(tp, "|");
321 break;
322 case (TBL_HEAD_DVERT):
323 term_word(tp, "||");
324 break;
325 default:
326 break;
327 }
328 }
329
330 static void
331 tbl_vframe(struct termp *tp, const struct tbl *tbl)
332 {
333
334 if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)
335 term_word(tp, "|");
336 }
337
338 static void
339 tbl_char(struct termp *tp, char c, size_t len)
340 {
341 size_t i, sz;
342 char cp[2];
343
344 cp[0] = c;
345 cp[1] = '\0';
346
347 sz = term_strlen(tp, cp);
348
349 for (i = 0; i < len; i += sz)
350 term_word(tp, cp);
351 }
352
353 static void
354 tbl_literal(struct termp *tp, const struct tbl_dat *dp,
355 const struct roffcol *col)
356 {
357 size_t padl, padr, ssz;
358
359 padl = padr = 0;
360
361 assert(dp->string);
362
363 ssz = term_len(tp, 1);
364
365 switch (dp->layout->pos) {
366 case (TBL_CELL_LONG):
367 padl = ssz;
368 padr = col->width - term_strlen(tp, dp->string) - ssz;
369 break;
370 case (TBL_CELL_CENTRE):
371 padl = col->width - term_strlen(tp, dp->string);
372 if (padl % 2)
373 padr++;
374 padl /= 2;
375 padr += padl;
376 break;
377 case (TBL_CELL_RIGHT):
378 padl = col->width - term_strlen(tp, dp->string);
379 break;
380 default:
381 padr = col->width - term_strlen(tp, dp->string);
382 break;
383 }
384
385 tbl_char(tp, ASCII_NBRSP, padl);
386 term_word(tp, dp->string);
387 tbl_char(tp, ASCII_NBRSP, padr);
388 }
389
390 static void
391 tbl_number(struct termp *tp, const struct tbl *tbl,
392 const struct tbl_dat *dp,
393 const struct roffcol *col)
394 {
395 char *cp;
396 char buf[2];
397 size_t sz, psz, ssz, d, padl;
398 int i;
399
400 /*
401 * See calc_data_number(). Left-pad by taking the offset of our
402 * and the maximum decimal; right-pad by the remaining amount.
403 */
404
405 assert(dp->string);
406
407 sz = term_strlen(tp, dp->string);
408
409 buf[0] = tbl->decimal;
410 buf[1] = '\0';
411
412 psz = term_strlen(tp, buf);
413
414 if (NULL != (cp = strrchr(dp->string, tbl->decimal))) {
415 buf[1] = '\0';
416 for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
417 buf[0] = dp->string[i];
418 ssz += term_strlen(tp, buf);
419 }
420 d = ssz + psz;
421 } else
422 d = sz + psz;
423
424 sz += term_len(tp, 2);
425 d += term_len(tp, 1);
426
427 padl = col->decimal - d;
428
429 tbl_char(tp, ASCII_NBRSP, padl);
430 term_word(tp, dp->string);
431 tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
432 }
433