]>
git.cameronkatri.com Git - mandoc.git/blob - tbl_term.c
1 /* $Id: tbl_term.c,v 1.31 2014/10/14 18:18:05 schwarze Exp $ */
3 * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
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.
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.
20 #include <sys/types.h>
31 static size_t term_tbl_len(size_t, void *);
32 static size_t term_tbl_strlen(const char *, void *);
33 static void tbl_char(struct termp
*, char, size_t);
34 static void tbl_data(struct termp
*, const struct tbl_opts
*,
35 const struct tbl_dat
*,
36 const struct roffcol
*);
37 static size_t tbl_rulewidth(struct termp
*, const struct tbl_head
*);
38 static void tbl_hframe(struct termp
*, const struct tbl_span
*, int);
39 static void tbl_literal(struct termp
*, const struct tbl_dat
*,
40 const struct roffcol
*);
41 static void tbl_number(struct termp
*, const struct tbl_opts
*,
42 const struct tbl_dat
*,
43 const struct roffcol
*);
44 static void tbl_hrule(struct termp
*, const struct tbl_span
*);
45 static void tbl_vrule(struct termp
*, const struct tbl_head
*);
46 static void tbl_word(struct termp
*, const struct tbl_dat
*);
50 term_tbl_strlen(const char *p
, void *arg
)
53 return(term_strlen((const struct termp
*)arg
, p
));
57 term_tbl_len(size_t sz
, void *arg
)
60 return(term_len((const struct termp
*)arg
, sz
));
64 term_tbl(struct termp
*tp
, const struct tbl_span
*sp
)
66 const struct tbl_head
*hp
;
67 const struct tbl_dat
*dp
;
70 size_t rmargin
, maxrmargin
;
72 rmargin
= tp
->rmargin
;
73 maxrmargin
= tp
->maxrmargin
;
75 tp
->rmargin
= tp
->maxrmargin
= TERM_MAXMARGIN
;
77 /* Inhibit printing of spaces: we do padding ourselves. */
79 tp
->flags
|= TERMP_NONOSPACE
;
80 tp
->flags
|= TERMP_NOSPACE
;
83 * The first time we're invoked for a given table block,
84 * calculate the table widths and decimal positions.
87 if (TBL_SPAN_FIRST
& sp
->flags
) {
90 tp
->tbl
.len
= term_tbl_len
;
91 tp
->tbl
.slen
= term_tbl_strlen
;
94 tblcalc(&tp
->tbl
, sp
, rmargin
- tp
->offset
);
97 /* Horizontal frame at the start of boxed tables. */
99 if (TBL_SPAN_FIRST
& sp
->flags
) {
100 if (TBL_OPT_DBOX
& sp
->opts
->opts
)
101 tbl_hframe(tp
, sp
, 1);
102 if (TBL_OPT_DBOX
& sp
->opts
->opts
||
103 TBL_OPT_BOX
& sp
->opts
->opts
)
104 tbl_hframe(tp
, sp
, 0);
107 /* Vertical frame at the start of each row. */
109 if ((TBL_OPT_BOX
| TBL_OPT_DBOX
) & sp
->opts
->opts
||
110 (sp
->head
!= NULL
&& sp
->head
->vert
))
111 term_word(tp
, TBL_SPAN_HORIZ
== sp
->pos
||
112 TBL_SPAN_DHORIZ
== sp
->pos
? "+" : "|");
115 * Now print the actual data itself depending on the span type.
116 * Spanner spans get a horizontal rule; data spanners have their
117 * data printed by matching data to header.
123 case TBL_SPAN_DHORIZ
:
127 /* Iterate over template headers. */
130 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
133 * If the current data header is invoked during
134 * a spanner ("spans" > 0), don't emit anything
141 /* Separate columns. */
143 if (NULL
!= hp
->prev
)
146 col
= &tp
->tbl
.cols
[hp
->ident
];
147 tbl_data(tp
, sp
->opts
, dp
, col
);
150 * Go to the next data cell and assign the
151 * number of subsequent spans, if applicable.
162 /* Vertical frame at the end of each row. */
164 if ((TBL_OPT_BOX
| TBL_OPT_DBOX
) & sp
->opts
->opts
||
166 term_word(tp
, TBL_SPAN_HORIZ
== sp
->pos
||
167 TBL_SPAN_DHORIZ
== sp
->pos
? "+" : " |");
171 * If we're the last row, clean up after ourselves: clear the
172 * existing table configuration and set it to NULL.
175 if (TBL_SPAN_LAST
& sp
->flags
) {
176 if (TBL_OPT_DBOX
& sp
->opts
->opts
||
177 TBL_OPT_BOX
& sp
->opts
->opts
) {
178 tbl_hframe(tp
, sp
, 0);
181 if (TBL_OPT_DBOX
& sp
->opts
->opts
) {
182 tbl_hframe(tp
, sp
, 1);
185 assert(tp
->tbl
.cols
);
190 tp
->flags
&= ~TERMP_NONOSPACE
;
191 tp
->rmargin
= rmargin
;
192 tp
->maxrmargin
= maxrmargin
;
197 * Horizontal rules extend across the entire table.
198 * Calculate the width by iterating over columns.
201 tbl_rulewidth(struct termp
*tp
, const struct tbl_head
*hp
)
205 width
= tp
->tbl
.cols
[hp
->ident
].width
;
207 /* Account for leading blanks. */
209 width
+= 2 - hp
->vert
;
211 /* Account for trailing blank. */
218 * Rules inside the table can be single or double
219 * and have crossings with vertical rules marked with pluses.
222 tbl_hrule(struct termp
*tp
, const struct tbl_span
*sp
)
224 const struct tbl_head
*hp
;
228 if (TBL_SPAN_DHORIZ
== sp
->pos
)
231 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
232 if (hp
->prev
&& hp
->vert
)
233 tbl_char(tp
, '+', hp
->vert
);
234 tbl_char(tp
, c
, tbl_rulewidth(tp
, hp
));
239 * Rules above and below the table are always single
240 * and have an additional plus at the beginning and end.
241 * For double frames, this function is called twice,
242 * and the outer one does not have crossings.
245 tbl_hframe(struct termp
*tp
, const struct tbl_span
*sp
, int outer
)
247 const struct tbl_head
*hp
;
250 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
251 if (hp
->prev
&& hp
->vert
)
252 tbl_char(tp
, (outer
? '-' : '+'), hp
->vert
);
253 tbl_char(tp
, '-', tbl_rulewidth(tp
, hp
));
260 tbl_data(struct termp
*tp
, const struct tbl_opts
*opts
,
261 const struct tbl_dat
*dp
,
262 const struct roffcol
*col
)
266 tbl_char(tp
, ASCII_NBRSP
, col
->width
);
273 tbl_char(tp
, ASCII_NBRSP
, col
->width
);
277 case TBL_DATA_NHORIZ
:
278 tbl_char(tp
, '-', col
->width
);
280 case TBL_DATA_NDHORIZ
:
282 case TBL_DATA_DHORIZ
:
283 tbl_char(tp
, '=', col
->width
);
289 switch (dp
->layout
->pos
) {
291 tbl_char(tp
, '-', col
->width
);
293 case TBL_CELL_DHORIZ
:
294 tbl_char(tp
, '=', col
->width
);
298 case TBL_CELL_CENTRE
:
303 tbl_literal(tp
, dp
, col
);
305 case TBL_CELL_NUMBER
:
306 tbl_number(tp
, opts
, dp
, col
);
309 tbl_char(tp
, ASCII_NBRSP
, col
->width
);
318 tbl_vrule(struct termp
*tp
, const struct tbl_head
*hp
)
321 tbl_char(tp
, ASCII_NBRSP
, 1);
323 tbl_char(tp
, '|', hp
->vert
);
325 tbl_char(tp
, ASCII_NBRSP
, 2 - hp
->vert
);
329 tbl_char(struct termp
*tp
, char c
, size_t len
)
337 sz
= term_strlen(tp
, cp
);
339 for (i
= 0; i
< len
; i
+= sz
)
344 tbl_literal(struct termp
*tp
, const struct tbl_dat
*dp
,
345 const struct roffcol
*col
)
348 size_t width
, len
, padl
, padr
;
352 len
= term_strlen(tp
, dp
->string
);
354 hp
= dp
->layout
->head
->next
;
356 for (spans
= dp
->spans
; spans
--; hp
= hp
->next
)
357 width
+= tp
->tbl
.cols
[hp
->ident
].width
+ 3;
359 padr
= width
> len
? width
- len
: 0;
362 switch (dp
->layout
->pos
) {
364 padl
= term_len(tp
, 1);
365 padr
= padr
> padl
? padr
- padl
: 0;
367 case TBL_CELL_CENTRE
:
381 tbl_char(tp
, ASCII_NBRSP
, padl
);
383 tbl_char(tp
, ASCII_NBRSP
, padr
);
387 tbl_number(struct termp
*tp
, const struct tbl_opts
*opts
,
388 const struct tbl_dat
*dp
,
389 const struct roffcol
*col
)
393 size_t sz
, psz
, ssz
, d
, padl
;
397 * See calc_data_number(). Left-pad by taking the offset of our
398 * and the maximum decimal; right-pad by the remaining amount.
403 sz
= term_strlen(tp
, dp
->string
);
405 buf
[0] = opts
->decimal
;
408 psz
= term_strlen(tp
, buf
);
410 if (NULL
!= (cp
= strrchr(dp
->string
, opts
->decimal
))) {
412 for (ssz
= 0, i
= 0; cp
!= &dp
->string
[i
]; i
++) {
413 buf
[0] = dp
->string
[i
];
414 ssz
+= term_strlen(tp
, buf
);
420 padl
= col
->decimal
- d
;
422 tbl_char(tp
, ASCII_NBRSP
, padl
);
424 if (col
->width
> sz
+ padl
)
425 tbl_char(tp
, ASCII_NBRSP
, col
->width
- sz
- padl
);
429 tbl_word(struct termp
*tp
, const struct tbl_dat
*dp
)
431 const void *prev_font
;
433 prev_font
= term_fontq(tp
);
434 if (dp
->layout
->flags
& TBL_CELL_BOLD
)
435 term_fontpush(tp
, TERMFONT_BOLD
);
436 else if (dp
->layout
->flags
& TBL_CELL_ITALIC
)
437 term_fontpush(tp
, TERMFONT_UNDER
);
439 term_word(tp
, dp
->string
);
441 term_fontpopq(tp
, prev_font
);