Annotation of mandoc/tbl_term.c, Revision 1.11
1.11 ! kristaps 1: /* $Id: tbl_term.c,v 1.10 2011/01/04 15:02:00 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 *);
! 35: static void tbl_char(struct termp *, char, int);
! 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;
! 70: int rmargin, maxrmargin;
! 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.2 kristaps 168: int 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.2 kristaps 205: int 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:
275: pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
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.1 kristaps 327: tbl_char(struct termp *tp, char c, int len)
328: {
1.3 kristaps 329: int i, sz;
1.11 ! kristaps 330: const char cp[2] = {c, '\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.3 kristaps 342: int padl, padr, ssz;
1.1 kristaps 343: enum tbl_cellt pos;
344:
345: padl = padr = 0;
346:
347: pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
1.3 kristaps 348: ssz = term_len(tp, 1);
1.1 kristaps 349:
350: switch (pos) {
351: case (TBL_CELL_LONG):
1.3 kristaps 352: padl = ssz;
1.11 ! kristaps 353: padr = col->width - term_strlen(tp, dp->string) - ssz;
1.1 kristaps 354: break;
355: case (TBL_CELL_CENTRE):
1.11 ! kristaps 356: padl = col->width - term_strlen(tp, dp->string);
1.1 kristaps 357: if (padl % 2)
358: padr++;
359: padl /= 2;
360: padr += padl;
361: break;
362: case (TBL_CELL_RIGHT):
1.11 ! kristaps 363: padl = col->width - term_strlen(tp, dp->string);
1.1 kristaps 364: break;
365: default:
1.11 ! kristaps 366: padr = col->width - term_strlen(tp, dp->string);
1.1 kristaps 367: break;
368: }
369:
370: tbl_char(tp, ASCII_NBRSP, padl);
371: term_word(tp, dp->string);
372: tbl_char(tp, ASCII_NBRSP, padr);
373: }
374:
375: static void
1.11 ! kristaps 376: tbl_number(struct termp *tp, const struct tbl *tbl,
1.2 kristaps 377: const struct tbl_dat *dp,
1.11 ! kristaps 378: const struct roffcol *col)
1.1 kristaps 379: {
1.11 ! kristaps 380: char *cp;
! 381: char buf[2];
! 382: const char *str;
! 383: size_t sz, psz, ssz, d, padl;
! 384: int i;
1.1 kristaps 385:
386: /*
387: * See calc_data_number(). Left-pad by taking the offset of our
388: * and the maximum decimal; right-pad by the remaining amount.
389: */
390:
1.11 ! kristaps 391: str = "";
! 392: if (dp->string)
! 393: str = dp->string;
1.2 kristaps 394:
1.11 ! kristaps 395: sz = term_strlen(tp, str);
1.2 kristaps 396:
1.11 ! kristaps 397: buf[0] = tbl->decimal;
! 398: buf[1] = '\0';
1.2 kristaps 399:
1.11 ! kristaps 400: psz = term_strlen(tp, buf);
1.10 kristaps 401:
1.11 ! kristaps 402: if (NULL != (cp = strchr(str, tbl->decimal))) {
1.5 kristaps 403: buf[1] = '\0';
1.11 ! kristaps 404: for (ssz = 0, i = 0; cp != &str[i]; i++) {
! 405: buf[0] = str[i];
1.5 kristaps 406: ssz += term_strlen(tp, buf);
407: }
408: d = ssz + psz;
409: } else
410: d = sz + psz;
1.2 kristaps 411:
1.5 kristaps 412: sz += term_len(tp, 2);
1.11 ! kristaps 413: d += term_len(tp, 1);
1.2 kristaps 414:
1.11 ! kristaps 415: padl = col->decimal - d;
1.2 kristaps 416:
1.11 ! kristaps 417: tbl_char(tp, ASCII_NBRSP, padl);
! 418: term_word(tp, dp->string);
! 419: tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
1.2 kristaps 420: }
421:
CVSweb