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