]>
git.cameronkatri.com Git - mandoc.git/blob - tbl_term.c
1 /* $Id: tbl_term.c,v 1.22 2012/05/27 17:54:54 schwarze Exp $ */
3 * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011 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.
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
*,
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
*,
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
*);
49 term_tbl_strlen(const char *p
, void *arg
)
52 return(term_strlen((const struct termp
*)arg
, p
));
56 term_tbl_len(size_t sz
, void *arg
)
59 return(term_len((const struct termp
*)arg
, sz
));
63 term_tbl(struct termp
*tp
, const struct tbl_span
*sp
)
65 const struct tbl_head
*hp
;
66 const struct tbl_dat
*dp
;
69 size_t rmargin
, maxrmargin
;
71 rmargin
= tp
->rmargin
;
72 maxrmargin
= tp
->maxrmargin
;
74 tp
->rmargin
= tp
->maxrmargin
= TERM_MAXMARGIN
;
76 /* Inhibit printing of spaces: we do padding ourselves. */
78 tp
->flags
|= TERMP_NONOSPACE
;
79 tp
->flags
|= TERMP_NOSPACE
;
82 * The first time we're invoked for a given table block,
83 * calculate the table widths and decimal positions.
86 if (TBL_SPAN_FIRST
& sp
->flags
) {
89 tp
->tbl
.len
= term_tbl_len
;
90 tp
->tbl
.slen
= term_tbl_strlen
;
93 tblcalc(&tp
->tbl
, sp
);
96 /* Horizontal frame at the start of boxed tables. */
98 if (TBL_SPAN_FIRST
& sp
->flags
) {
99 if (TBL_OPT_DBOX
& sp
->tbl
->opts
)
100 tbl_hframe(tp
, sp
, 1);
101 if (TBL_OPT_DBOX
& sp
->tbl
->opts
||
102 TBL_OPT_BOX
& sp
->tbl
->opts
)
103 tbl_hframe(tp
, sp
, 0);
106 /* Vertical frame at the start of each row. */
108 if (TBL_OPT_BOX
& sp
->tbl
->opts
|| TBL_OPT_DBOX
& sp
->tbl
->opts
)
109 term_word(tp
, TBL_SPAN_HORIZ
== sp
->pos
||
110 TBL_SPAN_DHORIZ
== sp
->pos
? "+" : "|");
113 * Now print the actual data itself depending on the span type.
114 * Spanner spans get a horizontal rule; data spanners have their
115 * data printed by matching data to header.
119 case (TBL_SPAN_HORIZ
):
121 case (TBL_SPAN_DHORIZ
):
124 case (TBL_SPAN_DATA
):
125 /* Iterate over template headers. */
128 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
131 * If the current data header is invoked during
132 * a spanner ("spans" > 0), don't emit anything
139 /* Separate columns. */
141 if (NULL
!= hp
->prev
)
144 col
= &tp
->tbl
.cols
[hp
->ident
];
145 tbl_data(tp
, sp
->tbl
, dp
, col
);
148 * Go to the next data cell and assign the
149 * number of subsequent spans, if applicable.
160 /* Vertical frame at the end of each row. */
162 if (TBL_OPT_BOX
& sp
->tbl
->opts
|| TBL_OPT_DBOX
& sp
->tbl
->opts
)
163 term_word(tp
, TBL_SPAN_HORIZ
== sp
->pos
||
164 TBL_SPAN_DHORIZ
== sp
->pos
? "+" : " |");
168 * If we're the last row, clean up after ourselves: clear the
169 * existing table configuration and set it to NULL.
172 if (TBL_SPAN_LAST
& sp
->flags
) {
173 if (TBL_OPT_DBOX
& sp
->tbl
->opts
||
174 TBL_OPT_BOX
& sp
->tbl
->opts
)
175 tbl_hframe(tp
, sp
, 0);
176 if (TBL_OPT_DBOX
& sp
->tbl
->opts
)
177 tbl_hframe(tp
, sp
, 1);
178 assert(tp
->tbl
.cols
);
183 tp
->flags
&= ~TERMP_NONOSPACE
;
184 tp
->rmargin
= rmargin
;
185 tp
->maxrmargin
= maxrmargin
;
190 * Horizontal rules extend across the entire table.
191 * Calculate the width by iterating over columns.
194 tbl_rulewidth(struct termp
*tp
, const struct tbl_head
*hp
)
198 width
= tp
->tbl
.cols
[hp
->ident
].width
;
200 /* Account for leading blanks. */
202 width
+= 2 - hp
->vert
;
204 /* Account for trailing blank. */
211 * Rules inside the table can be single or double
212 * and have crossings with vertical rules marked with pluses.
215 tbl_hrule(struct termp
*tp
, const struct tbl_span
*sp
)
217 const struct tbl_head
*hp
;
221 if (TBL_SPAN_DHORIZ
== sp
->pos
)
224 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
225 if (hp
->prev
&& hp
->vert
)
226 tbl_char(tp
, '+', hp
->vert
);
227 tbl_char(tp
, c
, tbl_rulewidth(tp
, hp
));
232 * Rules above and below the table are always single
233 * and have an additional plus at the beginning and end.
234 * For double frames, this function is called twice,
235 * and the outer one does not have crossings.
238 tbl_hframe(struct termp
*tp
, const struct tbl_span
*sp
, int outer
)
240 const struct tbl_head
*hp
;
243 for (hp
= sp
->head
; hp
; hp
= hp
->next
) {
244 if (hp
->prev
&& hp
->vert
)
245 tbl_char(tp
, (outer
? '-' : '+'), hp
->vert
);
246 tbl_char(tp
, '-', tbl_rulewidth(tp
, hp
));
253 tbl_data(struct termp
*tp
, const struct tbl
*tbl
,
254 const struct tbl_dat
*dp
,
255 const struct roffcol
*col
)
259 tbl_char(tp
, ASCII_NBRSP
, col
->width
);
265 case (TBL_DATA_NONE
):
266 tbl_char(tp
, ASCII_NBRSP
, col
->width
);
268 case (TBL_DATA_HORIZ
):
270 case (TBL_DATA_NHORIZ
):
271 tbl_char(tp
, '-', col
->width
);
273 case (TBL_DATA_NDHORIZ
):
275 case (TBL_DATA_DHORIZ
):
276 tbl_char(tp
, '=', col
->width
);
282 switch (dp
->layout
->pos
) {
283 case (TBL_CELL_HORIZ
):
284 tbl_char(tp
, '-', col
->width
);
286 case (TBL_CELL_DHORIZ
):
287 tbl_char(tp
, '=', col
->width
);
289 case (TBL_CELL_LONG
):
291 case (TBL_CELL_CENTRE
):
293 case (TBL_CELL_LEFT
):
295 case (TBL_CELL_RIGHT
):
296 tbl_literal(tp
, dp
, col
);
298 case (TBL_CELL_NUMBER
):
299 tbl_number(tp
, tbl
, dp
, col
);
301 case (TBL_CELL_DOWN
):
302 tbl_char(tp
, ASCII_NBRSP
, col
->width
);
311 tbl_vrule(struct termp
*tp
, const struct tbl_head
*hp
)
314 tbl_char(tp
, ASCII_NBRSP
, 1);
316 tbl_char(tp
, '|', hp
->vert
);
318 tbl_char(tp
, ASCII_NBRSP
, 2 - hp
->vert
);
322 tbl_char(struct termp
*tp
, char c
, size_t len
)
330 sz
= term_strlen(tp
, cp
);
332 for (i
= 0; i
< len
; i
+= sz
)
337 tbl_literal(struct termp
*tp
, const struct tbl_dat
*dp
,
338 const struct roffcol
*col
)
340 size_t len
, padl
, padr
;
343 len
= term_strlen(tp
, dp
->string
);
344 padr
= col
->width
> len
? col
->width
- len
: 0;
347 switch (dp
->layout
->pos
) {
348 case (TBL_CELL_LONG
):
349 padl
= term_len(tp
, 1);
350 padr
= padr
> padl
? padr
- padl
: 0;
352 case (TBL_CELL_CENTRE
):
358 case (TBL_CELL_RIGHT
):
366 tbl_char(tp
, ASCII_NBRSP
, padl
);
367 term_word(tp
, dp
->string
);
368 tbl_char(tp
, ASCII_NBRSP
, padr
);
372 tbl_number(struct termp
*tp
, const struct tbl
*tbl
,
373 const struct tbl_dat
*dp
,
374 const struct roffcol
*col
)
378 size_t sz
, psz
, ssz
, d
, padl
;
382 * See calc_data_number(). Left-pad by taking the offset of our
383 * and the maximum decimal; right-pad by the remaining amount.
388 sz
= term_strlen(tp
, dp
->string
);
390 buf
[0] = tbl
->decimal
;
393 psz
= term_strlen(tp
, buf
);
395 if (NULL
!= (cp
= strrchr(dp
->string
, tbl
->decimal
))) {
397 for (ssz
= 0, i
= 0; cp
!= &dp
->string
[i
]; i
++) {
398 buf
[0] = dp
->string
[i
];
399 ssz
+= term_strlen(tp
, buf
);
405 padl
= col
->decimal
- d
;
407 tbl_char(tp
, ASCII_NBRSP
, padl
);
408 term_word(tp
, dp
->string
);
409 if (col
->width
> sz
+ padl
)
410 tbl_char(tp
, ASCII_NBRSP
, col
->width
- sz
- padl
);