Annotation of mandoc/tbl_term.c, Revision 1.13
1.13 ! kristaps 1: /* $Id: tbl_term.c,v 1.12 2011/01/07 13:20:58 kristaps Exp $ */
1.1 kristaps 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: /* FIXME: `n' modifier doesn't always do the right thing. */
31: /* FIXME: `n' modifier doesn't use the cell-spacing buffer. */
32:
1.11 kristaps 33: static size_t term_tbl_len(size_t, void *);
34: static size_t term_tbl_strlen(const char *, void *);
1.12 kristaps 35: static void tbl_char(struct termp *, char, size_t);
1.11 kristaps 36: static void tbl_data(struct termp *, const struct tbl *,
37: const struct tbl_dat *,
38: const struct roffcol *);
39: static void tbl_hframe(struct termp *, const struct tbl_span *);
40: static void tbl_literal(struct termp *, const struct tbl_dat *,
41: const struct roffcol *);
42: static void tbl_number(struct termp *, const struct tbl *,
43: const struct tbl_dat *,
44: const struct roffcol *);
45: static void tbl_hrule(struct termp *, const struct tbl_span *);
46: static void tbl_vframe(struct termp *, const struct tbl *);
47: static void tbl_vrule(struct termp *, const struct tbl_head *);
48:
49:
50: static size_t
51: term_tbl_strlen(const char *p, void *arg)
52: {
53:
54: return(term_strlen((const struct termp *)arg, p));
55: }
56:
57: static size_t
58: term_tbl_len(size_t sz, void *arg)
59: {
60:
61: return(term_len((const struct termp *)arg, sz));
62: }
1.1 kristaps 63:
64: void
65: term_tbl(struct termp *tp, const struct tbl_span *sp)
66: {
1.11 kristaps 67: const struct tbl_head *hp;
68: const struct tbl_dat *dp;
69: struct roffcol *col;
1.12 kristaps 70: size_t rmargin, maxrmargin;
1.11 kristaps 71:
72: rmargin = tp->rmargin;
73: maxrmargin = tp->maxrmargin;
74:
75: tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
1.1 kristaps 76:
1.4 kristaps 77: /* Inhibit printing of spaces: we do padding ourselves. */
78:
79: tp->flags |= TERMP_NONOSPACE;
80: tp->flags |= TERMP_NOSPACE;
81:
82: /*
1.11 kristaps 83: * The first time we're invoked for a given table block,
84: * calculate the table widths and decimal positions.
1.4 kristaps 85: */
86:
1.2 kristaps 87: if (TBL_SPAN_FIRST & sp->flags) {
1.11 kristaps 88: term_flushln(tp);
89:
90: tp->tbl.len = term_tbl_len;
91: tp->tbl.slen = term_tbl_strlen;
92: tp->tbl.arg = tp;
1.4 kristaps 93:
1.11 kristaps 94: tblcalc(&tp->tbl, sp);
1.2 kristaps 95: }
1.1 kristaps 96:
1.4 kristaps 97: /* Horizontal frame at the start of boxed tables. */
98:
1.1 kristaps 99: if (TBL_SPAN_FIRST & sp->flags)
100: tbl_hframe(tp, sp);
101:
1.4 kristaps 102: /* Vertical frame at the start of each row. */
1.1 kristaps 103:
104: tbl_vframe(tp, sp->tbl);
105:
1.4 kristaps 106: /*
107: * Now print the actual data itself depending on the span type.
108: * Spanner spans get a horizontal rule; data spanners have their
109: * data printed by matching data to header.
110: */
111:
1.1 kristaps 112: switch (sp->pos) {
113: case (TBL_SPAN_HORIZ):
114: /* FALLTHROUGH */
115: case (TBL_SPAN_DHORIZ):
116: tbl_hrule(tp, sp);
117: break;
1.4 kristaps 118: case (TBL_SPAN_DATA):
119: /* Iterate over template headers. */
120: dp = sp->first;
121: for (hp = sp->head; hp; hp = hp->next) {
122: switch (hp->pos) {
123: case (TBL_HEAD_VERT):
124: /* FALLTHROUGH */
125: case (TBL_HEAD_DVERT):
1.11 kristaps 126: tbl_vrule(tp, hp);
1.4 kristaps 127: continue;
128: case (TBL_HEAD_DATA):
129: break;
130: }
1.11 kristaps 131:
132: col = &tp->tbl.cols[hp->ident];
133: tbl_data(tp, sp->tbl, dp, col);
1.1 kristaps 134:
1.4 kristaps 135: /* Go to the next data cell. */
1.1 kristaps 136: if (dp)
137: dp = dp->next;
138: }
1.4 kristaps 139: break;
1.1 kristaps 140: }
141:
142: tbl_vframe(tp, sp->tbl);
143: term_flushln(tp);
144:
1.4 kristaps 145: /*
146: * If we're the last row, clean up after ourselves: clear the
147: * existing table configuration and set it to NULL.
148: */
149:
1.2 kristaps 150: if (TBL_SPAN_LAST & sp->flags) {
1.1 kristaps 151: tbl_hframe(tp, sp);
1.11 kristaps 152: assert(tp->tbl.cols);
153: free(tp->tbl.cols);
154: tp->tbl.cols = NULL;
1.2 kristaps 155: }
1.1 kristaps 156:
157: tp->flags &= ~TERMP_NONOSPACE;
1.11 kristaps 158: tp->rmargin = rmargin;
159: tp->maxrmargin = maxrmargin;
1.1 kristaps 160:
161: }
162:
163: static void
164: tbl_hrule(struct termp *tp, const struct tbl_span *sp)
165: {
166: const struct tbl_head *hp;
167: char c;
1.12 kristaps 168: size_t width;
1.1 kristaps 169:
170: /*
171: * An hrule extends across the entire table and is demarked by a
172: * standalone `_' or whatnot in lieu of a table row. Spanning
173: * headers are marked by a `+', as are table boundaries.
174: */
175:
176: c = '-';
177: if (TBL_SPAN_DHORIZ == sp->pos)
178: c = '=';
179:
180: /* FIXME: don't use `+' between data and a spanner! */
181:
182: for (hp = sp->head; hp; hp = hp->next) {
1.11 kristaps 183: width = tp->tbl.cols[hp->ident].width;
1.1 kristaps 184: switch (hp->pos) {
185: case (TBL_HEAD_DATA):
1.2 kristaps 186: tbl_char(tp, c, width);
1.1 kristaps 187: break;
188: case (TBL_HEAD_DVERT):
1.2 kristaps 189: tbl_char(tp, '+', width);
1.1 kristaps 190: /* FALLTHROUGH */
191: case (TBL_HEAD_VERT):
1.2 kristaps 192: tbl_char(tp, '+', width);
1.1 kristaps 193: break;
194: default:
195: abort();
196: /* NOTREACHED */
197: }
198: }
199: }
200:
201: static void
202: tbl_hframe(struct termp *tp, const struct tbl_span *sp)
203: {
204: const struct tbl_head *hp;
1.12 kristaps 205: size_t width;
1.1 kristaps 206:
207: if ( ! (TBL_OPT_BOX & sp->tbl->opts ||
208: TBL_OPT_DBOX & sp->tbl->opts))
209: return;
210:
211: /*
212: * Print out the horizontal part of a frame or double frame. A
213: * double frame has an unbroken `-' outer line the width of the
214: * table, bordered by `+'. The frame (or inner frame, in the
215: * case of the double frame) is a `-' bordered by `+' and broken
216: * by `+' whenever a span is encountered.
217: */
218:
219: if (TBL_OPT_DBOX & sp->tbl->opts) {
220: term_word(tp, "+");
1.2 kristaps 221: for (hp = sp->head; hp; hp = hp->next) {
1.11 kristaps 222: width = tp->tbl.cols[hp->ident].width;
1.2 kristaps 223: tbl_char(tp, '-', width);
224: }
1.1 kristaps 225: term_word(tp, "+");
226: term_flushln(tp);
227: }
228:
229: term_word(tp, "+");
230: for (hp = sp->head; hp; hp = hp->next) {
1.11 kristaps 231: width = tp->tbl.cols[hp->ident].width;
1.1 kristaps 232: switch (hp->pos) {
233: case (TBL_HEAD_DATA):
1.2 kristaps 234: tbl_char(tp, '-', width);
1.1 kristaps 235: break;
236: default:
1.2 kristaps 237: tbl_char(tp, '+', width);
1.1 kristaps 238: break;
239: }
240: }
241: term_word(tp, "+");
242: term_flushln(tp);
243: }
244:
245: static void
246: tbl_data(struct termp *tp, const struct tbl *tbl,
1.2 kristaps 247: const struct tbl_dat *dp,
1.11 kristaps 248: const struct roffcol *col)
1.1 kristaps 249: {
250: enum tbl_cellt pos;
251:
252: if (NULL == dp) {
1.11 kristaps 253: tbl_char(tp, ASCII_NBRSP, col->width);
1.1 kristaps 254: return;
255: }
256:
257: switch (dp->pos) {
1.10 kristaps 258: case (TBL_DATA_NONE):
1.11 kristaps 259: tbl_char(tp, ASCII_NBRSP, col->width);
1.10 kristaps 260: return;
1.1 kristaps 261: case (TBL_DATA_HORIZ):
262: /* FALLTHROUGH */
1.7 kristaps 263: case (TBL_DATA_NHORIZ):
1.11 kristaps 264: tbl_char(tp, '-', col->width);
1.7 kristaps 265: return;
266: case (TBL_DATA_NDHORIZ):
267: /* FALLTHROUGH */
1.1 kristaps 268: case (TBL_DATA_DHORIZ):
1.11 kristaps 269: tbl_char(tp, '=', col->width);
1.1 kristaps 270: return;
271: default:
272: break;
273: }
274:
1.13 ! kristaps 275: pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
1.1 kristaps 276:
277: switch (pos) {
278: case (TBL_CELL_HORIZ):
1.11 kristaps 279: tbl_char(tp, '-', col->width);
1.7 kristaps 280: break;
1.1 kristaps 281: case (TBL_CELL_DHORIZ):
1.11 kristaps 282: tbl_char(tp, '=', col->width);
1.1 kristaps 283: break;
284: case (TBL_CELL_LONG):
285: /* FALLTHROUGH */
286: case (TBL_CELL_CENTRE):
287: /* FALLTHROUGH */
288: case (TBL_CELL_LEFT):
289: /* FALLTHROUGH */
290: case (TBL_CELL_RIGHT):
1.11 kristaps 291: tbl_literal(tp, dp, col);
1.1 kristaps 292: break;
293: case (TBL_CELL_NUMBER):
1.11 kristaps 294: tbl_number(tp, tbl, dp, col);
1.1 kristaps 295: break;
296: default:
297: abort();
298: /* NOTREACHED */
299: }
300: }
1.11 kristaps 301:
1.1 kristaps 302: static void
1.11 kristaps 303: tbl_vrule(struct termp *tp, const struct tbl_head *hp)
1.1 kristaps 304: {
305:
306: switch (hp->pos) {
307: case (TBL_HEAD_VERT):
308: term_word(tp, "|");
309: break;
310: case (TBL_HEAD_DVERT):
311: term_word(tp, "||");
312: break;
313: default:
314: break;
315: }
316: }
317:
318: static void
319: tbl_vframe(struct termp *tp, const struct tbl *tbl)
320: {
321:
322: if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)
323: term_word(tp, "|");
324: }
325:
1.11 kristaps 326: static void
1.12 kristaps 327: tbl_char(struct termp *tp, char c, size_t len)
1.1 kristaps 328: {
1.12 kristaps 329: size_t i, sz;
330: char cp[2];
331:
332: cp[0] = c;
333: cp[1] = '\0';
1.1 kristaps 334:
1.3 kristaps 335: sz = term_strlen(tp, cp);
336:
337: for (i = 0; i < len; i += sz)
1.1 kristaps 338: term_word(tp, cp);
339: }
340:
341: static void
1.11 kristaps 342: tbl_literal(struct termp *tp, const struct tbl_dat *dp,
343: const struct roffcol *col)
1.1 kristaps 344: {
1.12 kristaps 345: size_t padl, padr, ssz;
1.1 kristaps 346: enum tbl_cellt pos;
1.13 ! kristaps 347: const char *str;
1.1 kristaps 348:
349: padl = padr = 0;
350:
1.13 ! kristaps 351: pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
! 352: str = dp && dp->string ? dp->string : "";
! 353:
1.3 kristaps 354: ssz = term_len(tp, 1);
1.1 kristaps 355:
356: switch (pos) {
357: case (TBL_CELL_LONG):
1.3 kristaps 358: padl = ssz;
1.13 ! kristaps 359: padr = col->width - term_strlen(tp, str) - ssz;
1.1 kristaps 360: break;
361: case (TBL_CELL_CENTRE):
1.13 ! kristaps 362: padl = col->width - term_strlen(tp, str);
1.1 kristaps 363: if (padl % 2)
364: padr++;
365: padl /= 2;
366: padr += padl;
367: break;
368: case (TBL_CELL_RIGHT):
1.13 ! kristaps 369: padl = col->width - term_strlen(tp, str);
1.1 kristaps 370: break;
371: default:
1.13 ! kristaps 372: padr = col->width - term_strlen(tp, str);
1.1 kristaps 373: break;
374: }
375:
376: tbl_char(tp, ASCII_NBRSP, padl);
1.13 ! kristaps 377: term_word(tp, str);
1.1 kristaps 378: tbl_char(tp, ASCII_NBRSP, padr);
379: }
380:
381: static void
1.11 kristaps 382: tbl_number(struct termp *tp, const struct tbl *tbl,
1.2 kristaps 383: const struct tbl_dat *dp,
1.11 kristaps 384: const struct roffcol *col)
1.1 kristaps 385: {
1.11 kristaps 386: char *cp;
387: char buf[2];
388: const char *str;
389: size_t sz, psz, ssz, d, padl;
390: int i;
1.1 kristaps 391:
392: /*
393: * See calc_data_number(). Left-pad by taking the offset of our
394: * and the maximum decimal; right-pad by the remaining amount.
395: */
396:
1.13 ! kristaps 397: str = dp && dp->string ? dp->string : "";
1.2 kristaps 398:
1.11 kristaps 399: sz = term_strlen(tp, str);
1.2 kristaps 400:
1.11 kristaps 401: buf[0] = tbl->decimal;
402: buf[1] = '\0';
1.2 kristaps 403:
1.11 kristaps 404: psz = term_strlen(tp, buf);
1.10 kristaps 405:
1.11 kristaps 406: if (NULL != (cp = strchr(str, tbl->decimal))) {
1.5 kristaps 407: buf[1] = '\0';
1.11 kristaps 408: for (ssz = 0, i = 0; cp != &str[i]; i++) {
409: buf[0] = str[i];
1.5 kristaps 410: ssz += term_strlen(tp, buf);
411: }
412: d = ssz + psz;
413: } else
414: d = sz + psz;
1.2 kristaps 415:
1.5 kristaps 416: sz += term_len(tp, 2);
1.11 kristaps 417: d += term_len(tp, 1);
1.2 kristaps 418:
1.11 kristaps 419: padl = col->decimal - d;
1.2 kristaps 420:
1.11 kristaps 421: tbl_char(tp, ASCII_NBRSP, padl);
1.13 ! kristaps 422: term_word(tp, str);
1.11 kristaps 423: tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
1.2 kristaps 424: }
425:
CVSweb