]>
git.cameronkatri.com Git - mandoc.git/blob - tbl_term.c
1 /* $Id: tbl_term.c,v 1.6 2011/01/03 16:04:41 kristaps Exp $ */
3 * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
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.
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.
30 /* FIXME: `n' modifier doesn't always do the right thing. */
31 /* FIXME: `n' modifier doesn't use the cell-spacing buffer. */
33 static inline void tbl_char(struct termp
*, char, int);
34 static void tbl_hframe(struct termp
*,
35 const struct tbl_span
*);
36 static void tbl_data_number(struct termp
*,
38 const struct tbl_dat
*,
39 const struct termp_tbl
*);
40 static void tbl_data_literal(struct termp
*,
41 const struct tbl_dat
*,
42 const struct termp_tbl
*);
43 static void tbl_data_spanner(struct termp
*,
44 const struct tbl_dat
*,
45 const struct termp_tbl
*);
46 static void tbl_data(struct termp
*, const struct tbl
*,
47 const struct tbl_dat
*,
48 const struct termp_tbl
*);
49 static void tbl_spanner(struct termp
*,
50 const struct tbl_head
*);
51 static void tbl_hrule(struct termp
*,
52 const struct tbl_span
*);
53 static void tbl_vframe(struct termp
*,
55 static void tbl_calc(struct termp
*,
56 const struct tbl_span
*);
57 static void tbl_calc_data(struct termp
*,
59 const struct tbl_dat
*,
61 static void tbl_calc_data_literal(struct termp
*,
62 const struct tbl_dat
*,
64 static void tbl_calc_data_number(struct termp
*,
66 const struct tbl_dat
*,
70 term_tbl(struct termp
*tp
, const struct tbl_span
*sp
)
72 const struct tbl_head
*hp
;
73 const struct tbl_dat
*dp
;
75 /* Inhibit printing of spaces: we do padding ourselves. */
77 tp
->flags
|= TERMP_NONOSPACE
;
78 tp
->flags
|= TERMP_NOSPACE
;
81 * The first time we're invoked for a given table block, create
82 * the termp_tbl structure. This contains the column
83 * configuration for the entire table, e.g., table-wide column
84 * width, decimal point, etc.
87 if (TBL_SPAN_FIRST
& sp
->flags
) {
88 assert(NULL
== tp
->tbl
);
90 (sp
->tbl
->cols
, sizeof(struct termp_tbl
));
91 if (NULL
== tp
->tbl
) {
97 /* Flush out any preceding data. */
101 /* Horizontal frame at the start of boxed tables. */
103 if (TBL_SPAN_FIRST
& sp
->flags
)
106 /* Vertical frame at the start of each row. */
108 tbl_vframe(tp
, sp
->tbl
);
111 * Now print the actual data itself depending on the span type.
112 * Spanner spans get a horizontal rule; data spanners have their
113 * data printed by matching data to header.
117 case (TBL_SPAN_HORIZ
):
119 case (TBL_SPAN_DHORIZ
):
122 case (TBL_SPAN_DATA
):
123 /* Iterate over template headers. */
125 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
127 case (TBL_HEAD_VERT
):
129 case (TBL_HEAD_DVERT
):
132 case (TBL_HEAD_DATA
):
135 tbl_data(tp
, sp
->tbl
, dp
,
136 &tp
->tbl
[hp
->ident
]);
138 /* Go to the next data cell. */
145 tbl_vframe(tp
, sp
->tbl
);
149 * If we're the last row, clean up after ourselves: clear the
150 * existing table configuration and set it to NULL.
153 if (TBL_SPAN_LAST
& sp
->flags
) {
160 tp
->flags
&= ~TERMP_NONOSPACE
;
165 tbl_hrule(struct termp
*tp
, const struct tbl_span
*sp
)
167 const struct tbl_head
*hp
;
172 * An hrule extends across the entire table and is demarked by a
173 * standalone `_' or whatnot in lieu of a table row. Spanning
174 * headers are marked by a `+', as are table boundaries.
178 if (TBL_SPAN_DHORIZ
== sp
->pos
)
181 /* FIXME: don't use `+' between data and a spanner! */
183 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
184 width
= tp
->tbl
[hp
->ident
].width
;
186 case (TBL_HEAD_DATA
):
187 tbl_char(tp
, c
, width
);
189 case (TBL_HEAD_DVERT
):
190 tbl_char(tp
, '+', width
);
192 case (TBL_HEAD_VERT
):
193 tbl_char(tp
, '+', width
);
203 tbl_hframe(struct termp
*tp
, const struct tbl_span
*sp
)
205 const struct tbl_head
*hp
;
208 if ( ! (TBL_OPT_BOX
& sp
->tbl
->opts
||
209 TBL_OPT_DBOX
& sp
->tbl
->opts
))
212 tp
->flags
|= TERMP_NONOSPACE
;
213 tp
->flags
|= TERMP_NOSPACE
;
216 * Print out the horizontal part of a frame or double frame. A
217 * double frame has an unbroken `-' outer line the width of the
218 * table, bordered by `+'. The frame (or inner frame, in the
219 * case of the double frame) is a `-' bordered by `+' and broken
220 * by `+' whenever a span is encountered.
223 if (TBL_OPT_DBOX
& sp
->tbl
->opts
) {
225 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
226 width
= tp
->tbl
[hp
->ident
].width
;
227 tbl_char(tp
, '-', width
);
234 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
235 width
= tp
->tbl
[hp
->ident
].width
;
237 case (TBL_HEAD_DATA
):
238 tbl_char(tp
, '-', width
);
241 tbl_char(tp
, '+', width
);
250 tbl_data(struct termp
*tp
, const struct tbl
*tbl
,
251 const struct tbl_dat
*dp
,
252 const struct termp_tbl
*tbp
)
257 tbl_char(tp
, ASCII_NBRSP
, tbp
->width
);
262 case (TBL_DATA_HORIZ
):
264 case (TBL_DATA_DHORIZ
):
265 tbl_data_spanner(tp
, dp
, tbp
);
271 pos
= dp
->layout
? dp
->layout
->pos
: TBL_CELL_LEFT
;
274 case (TBL_CELL_HORIZ
):
276 case (TBL_CELL_DHORIZ
):
277 /* FIXME: THIS IS WRONG. */
278 tbl_data_spanner(tp
, dp
, tbp
);
280 case (TBL_CELL_LONG
):
282 case (TBL_CELL_CENTRE
):
284 case (TBL_CELL_LEFT
):
286 case (TBL_CELL_RIGHT
):
287 tbl_data_literal(tp
, dp
, tbp
);
289 case (TBL_CELL_NUMBER
):
290 tbl_data_number(tp
, tbl
, dp
, tbp
);
298 tbl_spanner(struct termp
*tp
, const struct tbl_head
*hp
)
302 case (TBL_HEAD_VERT
):
305 case (TBL_HEAD_DVERT
):
314 tbl_vframe(struct termp
*tp
, const struct tbl
*tbl
)
316 /* Always just a single vertical line. */
318 if (TBL_OPT_BOX
& tbl
->opts
|| TBL_OPT_DBOX
& tbl
->opts
)
324 tbl_char(struct termp
*tp
, char c
, int len
)
332 sz
= term_strlen(tp
, cp
);
334 for (i
= 0; i
< len
; i
+= sz
)
339 tbl_data_spanner(struct termp
*tp
,
340 const struct tbl_dat
*dp
,
341 const struct termp_tbl
*tblp
)
345 case (TBL_DATA_HORIZ
):
346 case (TBL_DATA_NHORIZ
):
347 tbl_char(tp
, '-', tblp
->width
);
349 case (TBL_DATA_DHORIZ
):
350 case (TBL_DATA_NDHORIZ
):
351 tbl_char(tp
, '=', tblp
->width
);
359 tbl_data_literal(struct termp
*tp
,
360 const struct tbl_dat
*dp
,
361 const struct termp_tbl
*tblp
)
368 pos
= dp
->layout
? dp
->layout
->pos
: TBL_CELL_LEFT
;
369 ssz
= term_len(tp
, 1);
372 case (TBL_CELL_LONG
):
374 padr
= tblp
->width
- term_strlen(tp
, dp
->string
) - ssz
;
376 case (TBL_CELL_CENTRE
):
377 padl
= tblp
->width
- term_strlen(tp
, dp
->string
);
383 case (TBL_CELL_RIGHT
):
384 padl
= tblp
->width
- term_strlen(tp
, dp
->string
);
387 padr
= tblp
->width
- term_strlen(tp
, dp
->string
);
391 tbl_char(tp
, ASCII_NBRSP
, padl
);
392 term_word(tp
, dp
->string
);
393 tbl_char(tp
, ASCII_NBRSP
, padr
);
397 tbl_data_number(struct termp
*tp
, const struct tbl
*tbl
,
398 const struct tbl_dat
*dp
,
399 const struct termp_tbl
*tblp
)
402 int d
, padl
, sz
, psz
, ssz
, i
;
405 * See calc_data_number(). Left-pad by taking the offset of our
406 * and the maximum decimal; right-pad by the remaining amount.
409 sz
= term_strlen(tp
, dp
->string
);
410 psz
= term_strlen(tp
, ".");
412 if (NULL
!= (decp
= strchr(dp
->string
, tbl
->decimal
))) {
414 for (ssz
= i
= 0; decp
!= &dp
->string
[i
]; i
++) {
415 buf
[0] = dp
->string
[i
];
416 ssz
+= term_strlen(tp
, buf
);
422 assert(d
<= tblp
->decimal
);
423 assert(sz
- d
<= tblp
->width
- tblp
->decimal
);
425 padl
= tblp
->decimal
- d
+ term_len(tp
, 1);
426 assert(tblp
->width
- sz
- padl
);
428 tbl_char(tp
, ASCII_NBRSP
, padl
);
429 term_word(tp
, dp
->string
);
430 tbl_char(tp
, ASCII_NBRSP
, tblp
->width
- sz
- padl
);
434 tbl_calc(struct termp
*tp
, const struct tbl_span
*sp
)
436 const struct tbl_dat
*dp
;
437 const struct tbl_head
*hp
;
440 /* Calculate width as the max of column cells' widths. */
444 for ( ; sp
; sp
= sp
->next
) {
446 case (TBL_DATA_HORIZ
):
448 case (TBL_DATA_DHORIZ
):
453 for (dp
= sp
->first
; dp
; dp
= dp
->next
) {
454 if (NULL
== dp
->layout
)
456 p
= &tp
->tbl
[dp
->layout
->head
->ident
];
457 tbl_calc_data(tp
, sp
->tbl
, dp
, p
);
461 /* Calculate width as the simple spanner value. */
463 for ( ; hp
; hp
= hp
->next
)
465 case (TBL_HEAD_VERT
):
466 tp
->tbl
[hp
->ident
].width
= term_len(tp
, 1);
468 case (TBL_HEAD_DVERT
):
469 tp
->tbl
[hp
->ident
].width
= term_len(tp
, 2);
477 tbl_calc_data(struct termp
*tp
, const struct tbl
*tbl
,
478 const struct tbl_dat
*dp
, struct termp_tbl
*tblp
)
481 /* Branch down into data sub-types. */
483 switch (dp
->layout
->pos
) {
484 case (TBL_CELL_HORIZ
):
486 case (TBL_CELL_DHORIZ
):
489 case (TBL_CELL_LONG
):
491 case (TBL_CELL_CENTRE
):
493 case (TBL_CELL_LEFT
):
495 case (TBL_CELL_RIGHT
):
496 tbl_calc_data_literal(tp
, dp
, tblp
);
498 case (TBL_CELL_NUMBER
):
499 tbl_calc_data_number(tp
, tbl
, dp
, tblp
);
508 tbl_calc_data_number(struct termp
*tp
, const struct tbl
*tbl
,
509 const struct tbl_dat
*dp
, struct termp_tbl
*tblp
)
511 int sz
, d
, psz
, i
, ssz
;
515 * First calculate number width and decimal place (last + 1 for
516 * no-decimal numbers). If the stored decimal is subsequent
517 * ours, make our size longer by that difference
518 * (right-"shifting"); similarly, if ours is subsequent the
519 * stored, then extend the stored size by the difference.
520 * Finally, re-assign the stored values.
523 /* TODO: use spacing modifier. */
526 sz
= term_strlen(tp
, dp
->string
);
527 psz
= term_strlen(tp
, ".");
529 if (NULL
!= (cp
= strchr(dp
->string
, tbl
->decimal
))) {
531 for (ssz
= i
= 0; cp
!= &dp
->string
[i
]; i
++) {
532 buf
[0] = dp
->string
[i
];
533 ssz
+= term_strlen(tp
, buf
);
539 sz
+= term_len(tp
, 2);
541 if (tblp
->decimal
> d
) {
542 sz
+= tblp
->decimal
- d
;
545 tblp
->width
+= d
- tblp
->decimal
;
547 if (sz
> tblp
->width
)
549 if (d
> tblp
->decimal
)
554 tbl_calc_data_literal(struct termp
*tp
,
555 const struct tbl_dat
*dp
,
556 struct termp_tbl
*tblp
)
561 * Calculate our width and use the spacing, with a minimum
562 * spacing dictated by position (centre, e.g,. gets a space on
563 * either side, while right/left get a single adjacent space).
567 sz
= term_strlen(tp
, dp
->string
);
569 switch (dp
->layout
->pos
) {
570 case (TBL_CELL_LONG
):
572 case (TBL_CELL_CENTRE
):
580 if (dp
->layout
->spacing
)
581 bufsz
= bufsz
> dp
->layout
->spacing
?
582 bufsz
: dp
->layout
->spacing
;
585 if (tblp
->width
< sz
)