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