Annotation of src/usr.bin/mandoc/tbl_term.c, Revision 1.41
1.41 ! schwarze 1: /* $OpenBSD: tbl_term.c,v 1.40 2017/06/14 17:50:43 schwarze Exp $ */
1.1 schwarze 2: /*
1.9 schwarze 3: * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.32 schwarze 4: * Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 5: *
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.
9: *
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.
17: */
1.17 schwarze 18: #include <sys/types.h>
19:
1.1 schwarze 20: #include <assert.h>
21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <string.h>
24:
1.5 schwarze 25: #include "mandoc.h"
1.2 schwarze 26: #include "out.h"
27: #include "term.h"
1.1 schwarze 28:
1.41 ! schwarze 29: #define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \
! 30: (cp)->pos == TBL_CELL_DHORIZ)
! 31:
1.6 schwarze 32: static size_t term_tbl_len(size_t, void *);
33: static size_t term_tbl_strlen(const char *, void *);
1.34 schwarze 34: static size_t term_tbl_sulen(const struct roffsu *, void *);
1.6 schwarze 35: static void tbl_char(struct termp *, char, size_t);
1.14 schwarze 36: static void tbl_data(struct termp *, const struct tbl_opts *,
1.41 ! schwarze 37: const struct tbl_cell *,
1.16 schwarze 38: const struct tbl_dat *,
1.6 schwarze 39: const struct roffcol *);
1.16 schwarze 40: static void tbl_literal(struct termp *, const struct tbl_dat *,
1.6 schwarze 41: const struct roffcol *);
1.16 schwarze 42: static void tbl_number(struct termp *, const struct tbl_opts *,
43: const struct tbl_dat *,
1.6 schwarze 44: const struct roffcol *);
1.21 schwarze 45: static void tbl_hrule(struct termp *, const struct tbl_span *, int);
1.17 schwarze 46: static void tbl_word(struct termp *, const struct tbl_dat *);
1.1 schwarze 47:
1.6 schwarze 48:
49: static size_t
1.34 schwarze 50: term_tbl_sulen(const struct roffsu *su, void *arg)
51: {
1.40 schwarze 52: return term_hen((const struct termp *)arg, su);
1.34 schwarze 53: }
54:
55: static size_t
1.6 schwarze 56: term_tbl_strlen(const char *p, void *arg)
57: {
1.30 schwarze 58: return term_strlen((const struct termp *)arg, p);
1.6 schwarze 59: }
60:
61: static size_t
62: term_tbl_len(size_t sz, void *arg)
63: {
1.30 schwarze 64: return term_len((const struct termp *)arg, sz);
1.6 schwarze 65: }
1.5 schwarze 66:
67: void
68: term_tbl(struct termp *tp, const struct tbl_span *sp)
69: {
1.41 ! schwarze 70: const struct tbl_cell *cp, *cpn, *cpp;
1.6 schwarze 71: const struct tbl_dat *dp;
1.22 schwarze 72: static size_t offset;
1.35 schwarze 73: size_t coloff, tsz;
74: int ic, horiz, spans, vert, more;
75: char fc;
1.27 schwarze 76:
1.5 schwarze 77: /* Inhibit printing of spaces: we do padding ourselves. */
78:
1.35 schwarze 79: tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE;
1.1 schwarze 80:
81: /*
1.6 schwarze 82: * The first time we're invoked for a given table block,
83: * calculate the table widths and decimal positions.
1.1 schwarze 84: */
85:
1.25 schwarze 86: if (tp->tbl.cols == NULL) {
1.6 schwarze 87: tp->tbl.len = term_tbl_len;
88: tp->tbl.slen = term_tbl_strlen;
1.34 schwarze 89: tp->tbl.sulen = term_tbl_sulen;
1.6 schwarze 90: tp->tbl.arg = tp;
1.5 schwarze 91:
1.36 schwarze 92: tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin);
1.2 schwarze 93:
1.22 schwarze 94: /* Center the table as a whole. */
95:
1.33 schwarze 96: offset = tp->tcol->offset;
1.22 schwarze 97: if (sp->opts->opts & TBL_OPT_CENTRE) {
98: tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
99: ? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
1.24 schwarze 100: for (ic = 0; ic < sp->opts->cols; ic++)
101: tsz += tp->tbl.cols[ic].width + 3;
1.22 schwarze 102: tsz -= 3;
1.33 schwarze 103: if (offset + tsz > tp->tcol->rmargin)
1.22 schwarze 104: tsz -= 1;
1.33 schwarze 105: tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
106: (offset + tp->tcol->rmargin - tsz) / 2 : 0;
1.22 schwarze 107: }
108:
1.21 schwarze 109: /* Horizontal frame at the start of boxed tables. */
1.1 schwarze 110:
1.21 schwarze 111: if (sp->opts->opts & TBL_OPT_DBOX)
1.41 ! schwarze 112: tbl_hrule(tp, sp, 3);
! 113: if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
1.21 schwarze 114: tbl_hrule(tp, sp, 2);
1.10 schwarze 115: }
1.5 schwarze 116:
1.35 schwarze 117: /* Set up the columns. */
1.5 schwarze 118:
1.35 schwarze 119: tp->flags |= TERMP_MULTICOL;
120: horiz = 0;
121: switch (sp->pos) {
122: case TBL_SPAN_HORIZ:
123: case TBL_SPAN_DHORIZ:
124: horiz = 1;
125: term_setcol(tp, 1);
126: break;
127: case TBL_SPAN_DATA:
128: term_setcol(tp, sp->opts->cols + 2);
129: coloff = tp->tcol->offset;
130:
131: /* Set up a column for a left vertical frame. */
132:
133: if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
134: sp->opts->lvert)
135: coloff++;
136: tp->tcol->rmargin = coloff;
1.21 schwarze 137:
1.35 schwarze 138: /* Set up the data columns. */
1.1 schwarze 139:
1.35 schwarze 140: dp = sp->first;
141: spans = 0;
142: for (ic = 0; ic < sp->opts->cols; ic++) {
143: if (spans == 0) {
144: tp->tcol++;
145: tp->tcol->offset = coloff;
146: }
147: coloff += tp->tbl.cols[ic].width;
148: tp->tcol->rmargin = coloff;
149: coloff++;
150: if (ic + 1 < sp->opts->cols)
151: coloff += 2;
152: if (spans) {
153: spans--;
154: continue;
155: }
156: if (dp == NULL)
157: continue;
158: spans = dp->spans;
159: dp = dp->next;
160: }
161:
162: /* Set up a column for a right vertical frame. */
163:
164: tp->tcol++;
165: tp->tcol->offset = coloff;
1.41 ! schwarze 166: tp->tcol->rmargin = tp->maxrmargin;
1.35 schwarze 167:
168: /* Spans may have reduced the number of columns. */
169:
170: tp->lasttcol = tp->tcol - tp->tcols;
171:
172: /* Fill the buffers for all data columns. */
1.1 schwarze 173:
1.35 schwarze 174: tp->tcol = tp->tcols;
1.41 ! schwarze 175: cp = cpn = sp->layout->first;
1.5 schwarze 176: dp = sp->first;
1.7 schwarze 177: spans = 0;
1.24 schwarze 178: for (ic = 0; ic < sp->opts->cols; ic++) {
1.41 ! schwarze 179: if (cpn != NULL) {
! 180: cp = cpn;
! 181: cpn = cpn->next;
! 182: }
1.35 schwarze 183: if (spans) {
184: spans--;
185: continue;
186: }
187: tp->tcol++;
188: tp->col = 0;
1.41 ! schwarze 189: tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
1.35 schwarze 190: if (dp == NULL)
191: continue;
192: spans = dp->spans;
193: dp = dp->next;
194: }
195: break;
196: }
197:
198: do {
199: /* Print the vertical frame at the start of each row. */
200:
201: tp->tcol = tp->tcols;
202: fc = '\0';
203: if (sp->layout->vert ||
1.41 ! schwarze 204: (sp->next != NULL && sp->next->layout->vert &&
! 205: sp->next->pos == TBL_SPAN_DATA) ||
! 206: (sp->prev != NULL && sp->prev->layout->vert &&
! 207: (horiz || (IS_HORIZ(sp->layout->first) &&
! 208: !IS_HORIZ(sp->prev->layout->first)))) ||
1.35 schwarze 209: sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
1.41 ! schwarze 210: fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|';
1.35 schwarze 211: else if (horiz && sp->opts->lvert)
212: fc = '-';
213: if (fc != '\0') {
214: (*tp->advance)(tp, tp->tcols->offset);
215: (*tp->letter)(tp, fc);
216: tp->viscol = tp->tcol->offset + 1;
217: }
1.11 schwarze 218:
1.35 schwarze 219: /* Print the data cells. */
1.10 schwarze 220:
1.35 schwarze 221: more = 0;
222: if (horiz) {
223: tbl_hrule(tp, sp, 0);
224: term_flushln(tp);
225: } else {
226: cp = sp->layout->first;
1.41 ! schwarze 227: cpn = sp->next == NULL ? NULL :
! 228: sp->next->layout->first;
! 229: cpp = sp->prev == NULL ? NULL :
! 230: sp->prev->layout->first;
1.35 schwarze 231: dp = sp->first;
232: spans = 0;
233: for (ic = 0; ic < sp->opts->cols; ic++) {
234:
1.41 ! schwarze 235: /*
! 236: * Figure out whether to print a
! 237: * vertical line after this cell
! 238: * and advance to next layout cell.
! 239: */
1.35 schwarze 240:
241: if (cp != NULL) {
242: vert = cp->vert;
1.41 ! schwarze 243: switch (cp->pos) {
! 244: case TBL_CELL_HORIZ:
! 245: fc = '-';
! 246: break;
! 247: case TBL_CELL_DHORIZ:
! 248: fc = '=';
! 249: break;
! 250: default:
! 251: fc = ' ';
! 252: break;
! 253: }
! 254: } else {
! 255: vert = 0;
! 256: fc = ' ';
! 257: }
! 258: if (cpp != NULL) {
! 259: if (vert == 0 &&
! 260: cp != NULL &&
! 261: ((IS_HORIZ(cp) &&
! 262: !IS_HORIZ(cpp)) ||
! 263: (cp->next != NULL &&
! 264: cpp->next != NULL &&
! 265: IS_HORIZ(cp->next) &&
! 266: !IS_HORIZ(cpp->next))))
! 267: vert = cpp->vert;
! 268: cpp = cpp->next;
! 269: }
! 270: if (vert == 0 &&
! 271: sp->opts->opts & TBL_OPT_ALLBOX)
! 272: vert = 1;
! 273: if (cpn != NULL) {
! 274: if (vert == 0)
! 275: vert = cpn->vert;
! 276: cpn = cpn->next;
! 277: }
! 278: if (cp != NULL)
1.35 schwarze 279: cp = cp->next;
1.39 schwarze 280:
1.41 ! schwarze 281: /*
! 282: * Skip later cells in a span,
! 283: * figure out whether to start a span,
! 284: * and advance to next data cell.
! 285: */
1.39 schwarze 286:
287: if (spans) {
288: spans--;
289: continue;
290: }
291: if (dp != NULL) {
292: spans = dp->spans;
293: dp = dp->next;
294: }
295:
1.41 ! schwarze 296: /*
! 297: * Print one line of text in the cell
! 298: * and remember whether there is more.
! 299: */
1.39 schwarze 300:
301: tp->tcol++;
302: if (tp->tcol->col < tp->tcol->lastcol)
303: term_flushln(tp);
304: if (tp->tcol->col < tp->tcol->lastcol)
305: more = 1;
306:
307: /*
308: * Vertical frames between data cells,
309: * but not after the last column.
310: */
311:
1.41 ! schwarze 312: if (fc == ' ' && ((vert == 0 &&
! 313: (cp == NULL || !IS_HORIZ(cp))) ||
! 314: tp->tcol + 1 == tp->tcols + tp->lasttcol))
! 315: continue;
! 316:
! 317: if (tp->tcol->rmargin > tp->viscol) {
! 318: (*tp->advance)(tp, tp->tcol->rmargin
! 319: - tp->viscol);
! 320: tp->viscol = tp->tcol->rmargin;
! 321: }
! 322:
! 323: if (tp->tcol->rmargin + 1 > tp->viscol) {
! 324: (*tp->letter)(tp, fc);
! 325: tp->viscol++;
! 326: }
! 327:
1.39 schwarze 328: if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
329: continue;
1.35 schwarze 330:
1.41 ! schwarze 331: if (fc == ' ' && cp != NULL) {
! 332: switch (cp->pos) {
! 333: case TBL_CELL_HORIZ:
! 334: fc = '-';
! 335: break;
! 336: case TBL_CELL_DHORIZ:
! 337: fc = '=';
! 338: break;
! 339: default:
! 340: break;
! 341: }
! 342: }
! 343:
! 344: (*tp->letter)(tp,
! 345: fc == ' ' ? '|' : vert ? '+' : fc);
! 346: tp->viscol++;
! 347:
! 348: if (fc != ' ') {
! 349: if (cp != NULL &&
! 350: cp->pos == TBL_CELL_HORIZ)
! 351: fc = '-';
! 352: else if (cp != NULL &&
! 353: cp->pos == TBL_CELL_DHORIZ)
! 354: fc = '=';
! 355: else
! 356: fc = ' ';
1.35 schwarze 357: }
1.41 ! schwarze 358: if (vert > 1 || fc != ' ') {
! 359: (*tp->letter)(tp, fc == ' ' ? '|' :
! 360: vert > 1 ? '+' : fc);
1.35 schwarze 361: tp->viscol++;
1.21 schwarze 362: }
1.35 schwarze 363: }
364: }
1.5 schwarze 365:
1.35 schwarze 366: /* Print the vertical frame at the end of each row. */
1.7 schwarze 367:
1.35 schwarze 368: fc = '\0';
1.41 ! schwarze 369: if ((sp->layout->last->vert &&
! 370: sp->layout->last->col + 1 == sp->opts->cols) ||
! 371: (sp->next != NULL &&
! 372: sp->next->layout->last->vert &&
! 373: sp->next->layout->last->col + 1 == sp->opts->cols) ||
! 374: (sp->prev != NULL &&
! 375: sp->prev->layout->last->vert &&
! 376: sp->prev->layout->last->col + 1 == sp->opts->cols &&
! 377: (horiz || (IS_HORIZ(sp->layout->last) &&
! 378: !IS_HORIZ(sp->prev->layout->last)))) ||
1.35 schwarze 379: (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
1.41 ! schwarze 380: fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|';
1.35 schwarze 381: else if (horiz && sp->opts->rvert)
382: fc = '-';
383: if (fc != '\0') {
1.41 ! schwarze 384: if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
! 385: sp->layout->last->col + 1 < sp->opts->cols)) {
1.35 schwarze 386: tp->tcol++;
387: (*tp->advance)(tp,
388: tp->tcol->offset > tp->viscol ?
389: tp->tcol->offset - tp->viscol : 1);
390: }
391: (*tp->letter)(tp, fc);
392: }
393: (*tp->endline)(tp);
394: tp->viscol = 0;
395: } while (more);
1.1 schwarze 396:
1.5 schwarze 397: /*
1.41 ! schwarze 398: * Clean up after this row. If it is the last line
! 399: * of the table, print the box line and clean up
! 400: * column data; otherwise, print the allbox line.
1.5 schwarze 401: */
1.1 schwarze 402:
1.35 schwarze 403: term_setcol(tp, 1);
404: tp->flags &= ~TERMP_MULTICOL;
405: tp->tcol->rmargin = tp->maxrmargin;
1.25 schwarze 406: if (sp->next == NULL) {
1.21 schwarze 407: if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
1.41 ! schwarze 408: tbl_hrule(tp, sp, 2);
1.13 schwarze 409: tp->skipvsp = 1;
410: }
1.21 schwarze 411: if (sp->opts->opts & TBL_OPT_DBOX) {
1.41 ! schwarze 412: tbl_hrule(tp, sp, 3);
1.13 schwarze 413: tp->skipvsp = 2;
414: }
1.6 schwarze 415: assert(tp->tbl.cols);
416: free(tp->tbl.cols);
417: tp->tbl.cols = NULL;
1.33 schwarze 418: tp->tcol->offset = offset;
1.38 schwarze 419: } else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX &&
420: (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA ||
421: sp->next->next != NULL))
1.37 schwarze 422: tbl_hrule(tp, sp, 1);
423:
1.35 schwarze 424: tp->flags &= ~TERMP_NONOSPACE;
1.1 schwarze 425: }
426:
1.10 schwarze 427: /*
1.21 schwarze 428: * Kinds of horizontal rulers:
429: * 0: inside the table (single or double line with crossings)
1.41 ! schwarze 430: * 1: inside the table (single or double line with crossings and ends)
! 431: * 2: inner frame (single line with crossings and ends)
! 432: * 3: outer frame (single line without crossings with ends)
1.10 schwarze 433: */
1.1 schwarze 434: static void
1.21 schwarze 435: tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
1.1 schwarze 436: {
1.41 ! schwarze 437: const struct tbl_cell *cp, *cpn, *cpp;
1.21 schwarze 438: int vert;
439: char line, cross;
440:
1.41 ! schwarze 441: line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
! 442: cross = (kind < 3) ? '+' : '-';
1.21 schwarze 443:
444: if (kind)
445: term_word(tp, "+");
1.41 ! schwarze 446: cp = sp->layout->first;
! 447: cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first;
! 448: if (cpp == cp)
! 449: cpp = NULL;
! 450: cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first;
! 451: if (cpn == cp)
! 452: cpn = NULL;
1.21 schwarze 453: for (;;) {
1.41 ! schwarze 454: tbl_char(tp, line, tp->tbl.cols[cp->col].width + 1);
! 455: vert = cp->vert;
! 456: if ((cp = cp->next) == NULL)
1.21 schwarze 457: break;
1.41 ! schwarze 458: if (cpp != NULL) {
! 459: if (vert < cpp->vert)
! 460: vert = cpp->vert;
! 461: cpp = cpp->next;
! 462: }
! 463: if (cpn != NULL) {
! 464: if (vert < cpn->vert)
! 465: vert = cpn->vert;
! 466: cpn = cpn->next;
1.21 schwarze 467: }
1.37 schwarze 468: if (sp->opts->opts & TBL_OPT_ALLBOX && !vert)
469: vert = 1;
1.21 schwarze 470: if (vert)
471: tbl_char(tp, cross, vert);
472: if (vert < 2)
473: tbl_char(tp, line, 2 - vert);
1.11 schwarze 474: }
1.21 schwarze 475: if (kind) {
476: term_word(tp, "+");
477: term_flushln(tp);
1.11 schwarze 478: }
1.1 schwarze 479: }
480:
481: static void
1.14 schwarze 482: tbl_data(struct termp *tp, const struct tbl_opts *opts,
1.41 ! schwarze 483: const struct tbl_cell *cp, const struct tbl_dat *dp,
! 484: const struct roffcol *col)
1.1 schwarze 485: {
1.41 ! schwarze 486: switch (cp->pos) {
! 487: case TBL_CELL_HORIZ:
! 488: tbl_char(tp, '-', col->width);
! 489: return;
! 490: case TBL_CELL_DHORIZ:
! 491: tbl_char(tp, '=', col->width);
! 492: return;
! 493: default:
! 494: break;
! 495: }
1.1 schwarze 496:
1.23 schwarze 497: if (dp == NULL) {
1.6 schwarze 498: tbl_char(tp, ASCII_NBRSP, col->width);
1.1 schwarze 499: return;
1.5 schwarze 500: }
1.1 schwarze 501:
1.5 schwarze 502: switch (dp->pos) {
1.16 schwarze 503: case TBL_DATA_NONE:
1.6 schwarze 504: tbl_char(tp, ASCII_NBRSP, col->width);
1.5 schwarze 505: return;
1.16 schwarze 506: case TBL_DATA_HORIZ:
507: case TBL_DATA_NHORIZ:
1.6 schwarze 508: tbl_char(tp, '-', col->width);
1.5 schwarze 509: return;
1.16 schwarze 510: case TBL_DATA_NDHORIZ:
511: case TBL_DATA_DHORIZ:
1.6 schwarze 512: tbl_char(tp, '=', col->width);
1.5 schwarze 513: return;
1.1 schwarze 514: default:
515: break;
516: }
1.16 schwarze 517:
1.41 ! schwarze 518: switch (cp->pos) {
1.16 schwarze 519: case TBL_CELL_LONG:
520: case TBL_CELL_CENTRE:
521: case TBL_CELL_LEFT:
522: case TBL_CELL_RIGHT:
1.6 schwarze 523: tbl_literal(tp, dp, col);
1.1 schwarze 524: break;
1.16 schwarze 525: case TBL_CELL_NUMBER:
1.14 schwarze 526: tbl_number(tp, opts, dp, col);
1.4 schwarze 527: break;
1.16 schwarze 528: case TBL_CELL_DOWN:
1.7 schwarze 529: tbl_char(tp, ASCII_NBRSP, col->width);
530: break;
1.1 schwarze 531: default:
532: abort();
533: }
534: }
535:
536: static void
1.6 schwarze 537: tbl_char(struct termp *tp, char c, size_t len)
1.5 schwarze 538: {
1.6 schwarze 539: size_t i, sz;
1.5 schwarze 540: char cp[2];
1.1 schwarze 541:
1.5 schwarze 542: cp[0] = c;
543: cp[1] = '\0';
1.1 schwarze 544:
1.5 schwarze 545: sz = term_strlen(tp, cp);
1.1 schwarze 546:
1.5 schwarze 547: for (i = 0; i < len; i += sz)
548: term_word(tp, cp);
1.1 schwarze 549: }
550:
551: static void
1.16 schwarze 552: tbl_literal(struct termp *tp, const struct tbl_dat *dp,
1.6 schwarze 553: const struct roffcol *col)
1.1 schwarze 554: {
1.24 schwarze 555: size_t len, padl, padr, width;
556: int ic, spans;
1.1 schwarze 557:
1.7 schwarze 558: assert(dp->string);
1.10 schwarze 559: len = term_strlen(tp, dp->string);
1.12 schwarze 560: width = col->width;
1.24 schwarze 561: ic = dp->layout->col;
562: spans = dp->spans;
563: while (spans--)
564: width += tp->tbl.cols[++ic].width + 3;
1.12 schwarze 565:
566: padr = width > len ? width - len : 0;
1.10 schwarze 567: padl = 0;
1.5 schwarze 568:
1.7 schwarze 569: switch (dp->layout->pos) {
1.16 schwarze 570: case TBL_CELL_LONG:
1.10 schwarze 571: padl = term_len(tp, 1);
572: padr = padr > padl ? padr - padl : 0;
1.1 schwarze 573: break;
1.16 schwarze 574: case TBL_CELL_CENTRE:
1.10 schwarze 575: if (2 > padr)
1.8 schwarze 576: break;
1.10 schwarze 577: padl = padr / 2;
1.8 schwarze 578: padr -= padl;
1.1 schwarze 579: break;
1.16 schwarze 580: case TBL_CELL_RIGHT:
1.10 schwarze 581: padl = padr;
582: padr = 0;
1.1 schwarze 583: break;
584: default:
585: break;
586: }
587:
1.5 schwarze 588: tbl_char(tp, ASCII_NBRSP, padl);
1.17 schwarze 589: tbl_word(tp, dp);
1.10 schwarze 590: tbl_char(tp, ASCII_NBRSP, padr);
1.1 schwarze 591: }
592:
1.5 schwarze 593: static void
1.14 schwarze 594: tbl_number(struct termp *tp, const struct tbl_opts *opts,
1.5 schwarze 595: const struct tbl_dat *dp,
1.6 schwarze 596: const struct roffcol *col)
1.5 schwarze 597: {
1.6 schwarze 598: char *cp;
599: char buf[2];
600: size_t sz, psz, ssz, d, padl;
601: int i;
1.5 schwarze 602:
603: /*
604: * See calc_data_number(). Left-pad by taking the offset of our
605: * and the maximum decimal; right-pad by the remaining amount.
606: */
607:
1.7 schwarze 608: assert(dp->string);
1.5 schwarze 609:
1.7 schwarze 610: sz = term_strlen(tp, dp->string);
1.5 schwarze 611:
1.14 schwarze 612: buf[0] = opts->decimal;
1.6 schwarze 613: buf[1] = '\0';
1.5 schwarze 614:
1.6 schwarze 615: psz = term_strlen(tp, buf);
1.5 schwarze 616:
1.23 schwarze 617: if ((cp = strrchr(dp->string, opts->decimal)) != NULL) {
1.7 schwarze 618: for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
619: buf[0] = dp->string[i];
1.5 schwarze 620: ssz += term_strlen(tp, buf);
621: }
622: d = ssz + psz;
623: } else
624: d = sz + psz;
625:
1.20 schwarze 626: if (col->decimal > d && col->width > sz) {
627: padl = col->decimal - d;
628: if (padl + sz > col->width)
629: padl = col->width - sz;
630: tbl_char(tp, ASCII_NBRSP, padl);
631: } else
632: padl = 0;
1.17 schwarze 633: tbl_word(tp, dp);
1.10 schwarze 634: if (col->width > sz + padl)
635: tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
1.5 schwarze 636: }
1.1 schwarze 637:
1.17 schwarze 638: static void
639: tbl_word(struct termp *tp, const struct tbl_dat *dp)
640: {
1.26 schwarze 641: int prev_font;
1.17 schwarze 642:
1.26 schwarze 643: prev_font = tp->fonti;
1.17 schwarze 644: if (dp->layout->flags & TBL_CELL_BOLD)
645: term_fontpush(tp, TERMFONT_BOLD);
646: else if (dp->layout->flags & TBL_CELL_ITALIC)
647: term_fontpush(tp, TERMFONT_UNDER);
648:
649: term_word(tp, dp->string);
650:
651: term_fontpopq(tp, prev_font);
652: }