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