1*698f87a4SGarrett D'Amore /* $Id: tbl_term.c,v 1.25 2013/05/31 21:37:17 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*698f87a4SGarrett D'Amore * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 1995c635efSGarrett D'Amore #include "config.h" 2095c635efSGarrett D'Amore #endif 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <assert.h> 2395c635efSGarrett D'Amore #include <stdio.h> 2495c635efSGarrett D'Amore #include <stdlib.h> 2595c635efSGarrett D'Amore #include <string.h> 2695c635efSGarrett D'Amore 2795c635efSGarrett D'Amore #include "mandoc.h" 2895c635efSGarrett D'Amore #include "out.h" 2995c635efSGarrett D'Amore #include "term.h" 3095c635efSGarrett D'Amore 3195c635efSGarrett D'Amore static size_t term_tbl_len(size_t, void *); 3295c635efSGarrett D'Amore static size_t term_tbl_strlen(const char *, void *); 3395c635efSGarrett D'Amore static void tbl_char(struct termp *, char, size_t); 34*698f87a4SGarrett D'Amore static void tbl_data(struct termp *, const struct tbl_opts *, 3595c635efSGarrett D'Amore const struct tbl_dat *, 3695c635efSGarrett D'Amore const struct roffcol *); 3795c635efSGarrett D'Amore static size_t tbl_rulewidth(struct termp *, const struct tbl_head *); 3895c635efSGarrett D'Amore static void tbl_hframe(struct termp *, const struct tbl_span *, int); 3995c635efSGarrett D'Amore static void tbl_literal(struct termp *, const struct tbl_dat *, 4095c635efSGarrett D'Amore const struct roffcol *); 41*698f87a4SGarrett D'Amore static void tbl_number(struct termp *, const struct tbl_opts *, 4295c635efSGarrett D'Amore const struct tbl_dat *, 4395c635efSGarrett D'Amore const struct roffcol *); 4495c635efSGarrett D'Amore static void tbl_hrule(struct termp *, const struct tbl_span *); 4595c635efSGarrett D'Amore static void tbl_vrule(struct termp *, const struct tbl_head *); 4695c635efSGarrett D'Amore 4795c635efSGarrett D'Amore 4895c635efSGarrett D'Amore static size_t 4995c635efSGarrett D'Amore term_tbl_strlen(const char *p, void *arg) 5095c635efSGarrett D'Amore { 5195c635efSGarrett D'Amore 5295c635efSGarrett D'Amore return(term_strlen((const struct termp *)arg, p)); 5395c635efSGarrett D'Amore } 5495c635efSGarrett D'Amore 5595c635efSGarrett D'Amore static size_t 5695c635efSGarrett D'Amore term_tbl_len(size_t sz, void *arg) 5795c635efSGarrett D'Amore { 5895c635efSGarrett D'Amore 5995c635efSGarrett D'Amore return(term_len((const struct termp *)arg, sz)); 6095c635efSGarrett D'Amore } 6195c635efSGarrett D'Amore 6295c635efSGarrett D'Amore void 6395c635efSGarrett D'Amore term_tbl(struct termp *tp, const struct tbl_span *sp) 6495c635efSGarrett D'Amore { 6595c635efSGarrett D'Amore const struct tbl_head *hp; 6695c635efSGarrett D'Amore const struct tbl_dat *dp; 6795c635efSGarrett D'Amore struct roffcol *col; 6895c635efSGarrett D'Amore int spans; 6995c635efSGarrett D'Amore size_t rmargin, maxrmargin; 7095c635efSGarrett D'Amore 7195c635efSGarrett D'Amore rmargin = tp->rmargin; 7295c635efSGarrett D'Amore maxrmargin = tp->maxrmargin; 7395c635efSGarrett D'Amore 7495c635efSGarrett D'Amore tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN; 7595c635efSGarrett D'Amore 7695c635efSGarrett D'Amore /* Inhibit printing of spaces: we do padding ourselves. */ 7795c635efSGarrett D'Amore 7895c635efSGarrett D'Amore tp->flags |= TERMP_NONOSPACE; 7995c635efSGarrett D'Amore tp->flags |= TERMP_NOSPACE; 8095c635efSGarrett D'Amore 8195c635efSGarrett D'Amore /* 8295c635efSGarrett D'Amore * The first time we're invoked for a given table block, 8395c635efSGarrett D'Amore * calculate the table widths and decimal positions. 8495c635efSGarrett D'Amore */ 8595c635efSGarrett D'Amore 8695c635efSGarrett D'Amore if (TBL_SPAN_FIRST & sp->flags) { 8795c635efSGarrett D'Amore term_flushln(tp); 8895c635efSGarrett D'Amore 8995c635efSGarrett D'Amore tp->tbl.len = term_tbl_len; 9095c635efSGarrett D'Amore tp->tbl.slen = term_tbl_strlen; 9195c635efSGarrett D'Amore tp->tbl.arg = tp; 9295c635efSGarrett D'Amore 9395c635efSGarrett D'Amore tblcalc(&tp->tbl, sp); 9495c635efSGarrett D'Amore } 9595c635efSGarrett D'Amore 9695c635efSGarrett D'Amore /* Horizontal frame at the start of boxed tables. */ 9795c635efSGarrett D'Amore 9895c635efSGarrett D'Amore if (TBL_SPAN_FIRST & sp->flags) { 99*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts) 10095c635efSGarrett D'Amore tbl_hframe(tp, sp, 1); 101*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts || 102*698f87a4SGarrett D'Amore TBL_OPT_BOX & sp->opts->opts) 10395c635efSGarrett D'Amore tbl_hframe(tp, sp, 0); 10495c635efSGarrett D'Amore } 10595c635efSGarrett D'Amore 10695c635efSGarrett D'Amore /* Vertical frame at the start of each row. */ 10795c635efSGarrett D'Amore 108*698f87a4SGarrett D'Amore if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts) 10995c635efSGarrett D'Amore term_word(tp, TBL_SPAN_HORIZ == sp->pos || 11095c635efSGarrett D'Amore TBL_SPAN_DHORIZ == sp->pos ? "+" : "|"); 11195c635efSGarrett D'Amore 11295c635efSGarrett D'Amore /* 11395c635efSGarrett D'Amore * Now print the actual data itself depending on the span type. 11495c635efSGarrett D'Amore * Spanner spans get a horizontal rule; data spanners have their 11595c635efSGarrett D'Amore * data printed by matching data to header. 11695c635efSGarrett D'Amore */ 11795c635efSGarrett D'Amore 11895c635efSGarrett D'Amore switch (sp->pos) { 11995c635efSGarrett D'Amore case (TBL_SPAN_HORIZ): 12095c635efSGarrett D'Amore /* FALLTHROUGH */ 12195c635efSGarrett D'Amore case (TBL_SPAN_DHORIZ): 12295c635efSGarrett D'Amore tbl_hrule(tp, sp); 12395c635efSGarrett D'Amore break; 12495c635efSGarrett D'Amore case (TBL_SPAN_DATA): 12595c635efSGarrett D'Amore /* Iterate over template headers. */ 12695c635efSGarrett D'Amore dp = sp->first; 12795c635efSGarrett D'Amore spans = 0; 12895c635efSGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) { 129*698f87a4SGarrett D'Amore 13095c635efSGarrett D'Amore /* 13195c635efSGarrett D'Amore * If the current data header is invoked during 13295c635efSGarrett D'Amore * a spanner ("spans" > 0), don't emit anything 13395c635efSGarrett D'Amore * at all. 13495c635efSGarrett D'Amore */ 13595c635efSGarrett D'Amore 13695c635efSGarrett D'Amore if (--spans >= 0) 13795c635efSGarrett D'Amore continue; 13895c635efSGarrett D'Amore 139*698f87a4SGarrett D'Amore /* Separate columns. */ 14095c635efSGarrett D'Amore 141*698f87a4SGarrett D'Amore if (NULL != hp->prev) 142*698f87a4SGarrett D'Amore tbl_vrule(tp, hp); 14395c635efSGarrett D'Amore 14495c635efSGarrett D'Amore col = &tp->tbl.cols[hp->ident]; 145*698f87a4SGarrett D'Amore tbl_data(tp, sp->opts, dp, col); 14695c635efSGarrett D'Amore 14795c635efSGarrett D'Amore /* 14895c635efSGarrett D'Amore * Go to the next data cell and assign the 14995c635efSGarrett D'Amore * number of subsequent spans, if applicable. 15095c635efSGarrett D'Amore */ 15195c635efSGarrett D'Amore 15295c635efSGarrett D'Amore if (dp) { 15395c635efSGarrett D'Amore spans = dp->spans; 15495c635efSGarrett D'Amore dp = dp->next; 15595c635efSGarrett D'Amore } 15695c635efSGarrett D'Amore } 15795c635efSGarrett D'Amore break; 15895c635efSGarrett D'Amore } 15995c635efSGarrett D'Amore 16095c635efSGarrett D'Amore /* Vertical frame at the end of each row. */ 16195c635efSGarrett D'Amore 162*698f87a4SGarrett D'Amore if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts) 16395c635efSGarrett D'Amore term_word(tp, TBL_SPAN_HORIZ == sp->pos || 16495c635efSGarrett D'Amore TBL_SPAN_DHORIZ == sp->pos ? "+" : " |"); 16595c635efSGarrett D'Amore term_flushln(tp); 16695c635efSGarrett D'Amore 16795c635efSGarrett D'Amore /* 16895c635efSGarrett D'Amore * If we're the last row, clean up after ourselves: clear the 16995c635efSGarrett D'Amore * existing table configuration and set it to NULL. 17095c635efSGarrett D'Amore */ 17195c635efSGarrett D'Amore 17295c635efSGarrett D'Amore if (TBL_SPAN_LAST & sp->flags) { 173*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts || 174*698f87a4SGarrett D'Amore TBL_OPT_BOX & sp->opts->opts) { 17595c635efSGarrett D'Amore tbl_hframe(tp, sp, 0); 176*698f87a4SGarrett D'Amore tp->skipvsp = 1; 177*698f87a4SGarrett D'Amore } 178*698f87a4SGarrett D'Amore if (TBL_OPT_DBOX & sp->opts->opts) { 17995c635efSGarrett D'Amore tbl_hframe(tp, sp, 1); 180*698f87a4SGarrett D'Amore tp->skipvsp = 2; 181*698f87a4SGarrett D'Amore } 18295c635efSGarrett D'Amore assert(tp->tbl.cols); 18395c635efSGarrett D'Amore free(tp->tbl.cols); 18495c635efSGarrett D'Amore tp->tbl.cols = NULL; 18595c635efSGarrett D'Amore } 18695c635efSGarrett D'Amore 18795c635efSGarrett D'Amore tp->flags &= ~TERMP_NONOSPACE; 18895c635efSGarrett D'Amore tp->rmargin = rmargin; 18995c635efSGarrett D'Amore tp->maxrmargin = maxrmargin; 19095c635efSGarrett D'Amore 19195c635efSGarrett D'Amore } 19295c635efSGarrett D'Amore 19395c635efSGarrett D'Amore /* 19495c635efSGarrett D'Amore * Horizontal rules extend across the entire table. 19595c635efSGarrett D'Amore * Calculate the width by iterating over columns. 19695c635efSGarrett D'Amore */ 19795c635efSGarrett D'Amore static size_t 19895c635efSGarrett D'Amore tbl_rulewidth(struct termp *tp, const struct tbl_head *hp) 19995c635efSGarrett D'Amore { 20095c635efSGarrett D'Amore size_t width; 20195c635efSGarrett D'Amore 20295c635efSGarrett D'Amore width = tp->tbl.cols[hp->ident].width; 203*698f87a4SGarrett D'Amore 20495c635efSGarrett D'Amore /* Account for leading blanks. */ 205*698f87a4SGarrett D'Amore if (hp->prev) 206*698f87a4SGarrett D'Amore width += 2 - hp->vert; 207*698f87a4SGarrett D'Amore 208*698f87a4SGarrett D'Amore /* Account for trailing blank. */ 20995c635efSGarrett D'Amore width++; 210*698f87a4SGarrett D'Amore 21195c635efSGarrett D'Amore return(width); 21295c635efSGarrett D'Amore } 21395c635efSGarrett D'Amore 21495c635efSGarrett D'Amore /* 21595c635efSGarrett D'Amore * Rules inside the table can be single or double 21695c635efSGarrett D'Amore * and have crossings with vertical rules marked with pluses. 21795c635efSGarrett D'Amore */ 21895c635efSGarrett D'Amore static void 21995c635efSGarrett D'Amore tbl_hrule(struct termp *tp, const struct tbl_span *sp) 22095c635efSGarrett D'Amore { 22195c635efSGarrett D'Amore const struct tbl_head *hp; 22295c635efSGarrett D'Amore char c; 22395c635efSGarrett D'Amore 22495c635efSGarrett D'Amore c = '-'; 22595c635efSGarrett D'Amore if (TBL_SPAN_DHORIZ == sp->pos) 22695c635efSGarrett D'Amore c = '='; 22795c635efSGarrett D'Amore 228*698f87a4SGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) { 229*698f87a4SGarrett D'Amore if (hp->prev && hp->vert) 230*698f87a4SGarrett D'Amore tbl_char(tp, '+', hp->vert); 231*698f87a4SGarrett D'Amore tbl_char(tp, c, tbl_rulewidth(tp, hp)); 232*698f87a4SGarrett D'Amore } 23395c635efSGarrett D'Amore } 23495c635efSGarrett D'Amore 23595c635efSGarrett D'Amore /* 23695c635efSGarrett D'Amore * Rules above and below the table are always single 23795c635efSGarrett D'Amore * and have an additional plus at the beginning and end. 23895c635efSGarrett D'Amore * For double frames, this function is called twice, 23995c635efSGarrett D'Amore * and the outer one does not have crossings. 24095c635efSGarrett D'Amore */ 24195c635efSGarrett D'Amore static void 24295c635efSGarrett D'Amore tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer) 24395c635efSGarrett D'Amore { 24495c635efSGarrett D'Amore const struct tbl_head *hp; 24595c635efSGarrett D'Amore 24695c635efSGarrett D'Amore term_word(tp, "+"); 247*698f87a4SGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) { 248*698f87a4SGarrett D'Amore if (hp->prev && hp->vert) 249*698f87a4SGarrett D'Amore tbl_char(tp, (outer ? '-' : '+'), hp->vert); 250*698f87a4SGarrett D'Amore tbl_char(tp, '-', tbl_rulewidth(tp, hp)); 251*698f87a4SGarrett D'Amore } 25295c635efSGarrett D'Amore term_word(tp, "+"); 25395c635efSGarrett D'Amore term_flushln(tp); 25495c635efSGarrett D'Amore } 25595c635efSGarrett D'Amore 25695c635efSGarrett D'Amore static void 257*698f87a4SGarrett D'Amore tbl_data(struct termp *tp, const struct tbl_opts *opts, 25895c635efSGarrett D'Amore const struct tbl_dat *dp, 25995c635efSGarrett D'Amore const struct roffcol *col) 26095c635efSGarrett D'Amore { 26195c635efSGarrett D'Amore 26295c635efSGarrett D'Amore if (NULL == dp) { 26395c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width); 26495c635efSGarrett D'Amore return; 26595c635efSGarrett D'Amore } 26695c635efSGarrett D'Amore assert(dp->layout); 26795c635efSGarrett D'Amore 26895c635efSGarrett D'Amore switch (dp->pos) { 26995c635efSGarrett D'Amore case (TBL_DATA_NONE): 27095c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width); 27195c635efSGarrett D'Amore return; 27295c635efSGarrett D'Amore case (TBL_DATA_HORIZ): 27395c635efSGarrett D'Amore /* FALLTHROUGH */ 27495c635efSGarrett D'Amore case (TBL_DATA_NHORIZ): 27595c635efSGarrett D'Amore tbl_char(tp, '-', col->width); 27695c635efSGarrett D'Amore return; 27795c635efSGarrett D'Amore case (TBL_DATA_NDHORIZ): 27895c635efSGarrett D'Amore /* FALLTHROUGH */ 27995c635efSGarrett D'Amore case (TBL_DATA_DHORIZ): 28095c635efSGarrett D'Amore tbl_char(tp, '=', col->width); 28195c635efSGarrett D'Amore return; 28295c635efSGarrett D'Amore default: 28395c635efSGarrett D'Amore break; 28495c635efSGarrett D'Amore } 28595c635efSGarrett D'Amore 28695c635efSGarrett D'Amore switch (dp->layout->pos) { 28795c635efSGarrett D'Amore case (TBL_CELL_HORIZ): 28895c635efSGarrett D'Amore tbl_char(tp, '-', col->width); 28995c635efSGarrett D'Amore break; 29095c635efSGarrett D'Amore case (TBL_CELL_DHORIZ): 29195c635efSGarrett D'Amore tbl_char(tp, '=', col->width); 29295c635efSGarrett D'Amore break; 29395c635efSGarrett D'Amore case (TBL_CELL_LONG): 29495c635efSGarrett D'Amore /* FALLTHROUGH */ 29595c635efSGarrett D'Amore case (TBL_CELL_CENTRE): 29695c635efSGarrett D'Amore /* FALLTHROUGH */ 29795c635efSGarrett D'Amore case (TBL_CELL_LEFT): 29895c635efSGarrett D'Amore /* FALLTHROUGH */ 29995c635efSGarrett D'Amore case (TBL_CELL_RIGHT): 30095c635efSGarrett D'Amore tbl_literal(tp, dp, col); 30195c635efSGarrett D'Amore break; 30295c635efSGarrett D'Amore case (TBL_CELL_NUMBER): 303*698f87a4SGarrett D'Amore tbl_number(tp, opts, dp, col); 30495c635efSGarrett D'Amore break; 30595c635efSGarrett D'Amore case (TBL_CELL_DOWN): 30695c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width); 30795c635efSGarrett D'Amore break; 30895c635efSGarrett D'Amore default: 30995c635efSGarrett D'Amore abort(); 31095c635efSGarrett D'Amore /* NOTREACHED */ 31195c635efSGarrett D'Amore } 31295c635efSGarrett D'Amore } 31395c635efSGarrett D'Amore 31495c635efSGarrett D'Amore static void 31595c635efSGarrett D'Amore tbl_vrule(struct termp *tp, const struct tbl_head *hp) 31695c635efSGarrett D'Amore { 31795c635efSGarrett D'Amore 318*698f87a4SGarrett D'Amore tbl_char(tp, ASCII_NBRSP, 1); 319*698f87a4SGarrett D'Amore if (0 < hp->vert) 320*698f87a4SGarrett D'Amore tbl_char(tp, '|', hp->vert); 321*698f87a4SGarrett D'Amore if (2 > hp->vert) 322*698f87a4SGarrett D'Amore tbl_char(tp, ASCII_NBRSP, 2 - hp->vert); 32395c635efSGarrett D'Amore } 32495c635efSGarrett D'Amore 32595c635efSGarrett D'Amore static void 32695c635efSGarrett D'Amore tbl_char(struct termp *tp, char c, size_t len) 32795c635efSGarrett D'Amore { 32895c635efSGarrett D'Amore size_t i, sz; 32995c635efSGarrett D'Amore char cp[2]; 33095c635efSGarrett D'Amore 33195c635efSGarrett D'Amore cp[0] = c; 33295c635efSGarrett D'Amore cp[1] = '\0'; 33395c635efSGarrett D'Amore 33495c635efSGarrett D'Amore sz = term_strlen(tp, cp); 33595c635efSGarrett D'Amore 33695c635efSGarrett D'Amore for (i = 0; i < len; i += sz) 33795c635efSGarrett D'Amore term_word(tp, cp); 33895c635efSGarrett D'Amore } 33995c635efSGarrett D'Amore 34095c635efSGarrett D'Amore static void 34195c635efSGarrett D'Amore tbl_literal(struct termp *tp, const struct tbl_dat *dp, 34295c635efSGarrett D'Amore const struct roffcol *col) 34395c635efSGarrett D'Amore { 344*698f87a4SGarrett D'Amore struct tbl_head *hp; 345*698f87a4SGarrett D'Amore size_t width, len, padl, padr; 346*698f87a4SGarrett D'Amore int spans; 34795c635efSGarrett D'Amore 34895c635efSGarrett D'Amore assert(dp->string); 34995c635efSGarrett D'Amore len = term_strlen(tp, dp->string); 350*698f87a4SGarrett D'Amore 351*698f87a4SGarrett D'Amore hp = dp->layout->head->next; 352*698f87a4SGarrett D'Amore width = col->width; 353*698f87a4SGarrett D'Amore for (spans = dp->spans; spans--; hp = hp->next) 354*698f87a4SGarrett D'Amore width += tp->tbl.cols[hp->ident].width + 3; 355*698f87a4SGarrett D'Amore 356*698f87a4SGarrett D'Amore padr = width > len ? width - len : 0; 35795c635efSGarrett D'Amore padl = 0; 35895c635efSGarrett D'Amore 35995c635efSGarrett D'Amore switch (dp->layout->pos) { 36095c635efSGarrett D'Amore case (TBL_CELL_LONG): 36195c635efSGarrett D'Amore padl = term_len(tp, 1); 36295c635efSGarrett D'Amore padr = padr > padl ? padr - padl : 0; 36395c635efSGarrett D'Amore break; 36495c635efSGarrett D'Amore case (TBL_CELL_CENTRE): 36595c635efSGarrett D'Amore if (2 > padr) 36695c635efSGarrett D'Amore break; 36795c635efSGarrett D'Amore padl = padr / 2; 36895c635efSGarrett D'Amore padr -= padl; 36995c635efSGarrett D'Amore break; 37095c635efSGarrett D'Amore case (TBL_CELL_RIGHT): 37195c635efSGarrett D'Amore padl = padr; 37295c635efSGarrett D'Amore padr = 0; 37395c635efSGarrett D'Amore break; 37495c635efSGarrett D'Amore default: 37595c635efSGarrett D'Amore break; 37695c635efSGarrett D'Amore } 37795c635efSGarrett D'Amore 37895c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl); 37995c635efSGarrett D'Amore term_word(tp, dp->string); 38095c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padr); 38195c635efSGarrett D'Amore } 38295c635efSGarrett D'Amore 38395c635efSGarrett D'Amore static void 384*698f87a4SGarrett D'Amore tbl_number(struct termp *tp, const struct tbl_opts *opts, 38595c635efSGarrett D'Amore const struct tbl_dat *dp, 38695c635efSGarrett D'Amore const struct roffcol *col) 38795c635efSGarrett D'Amore { 38895c635efSGarrett D'Amore char *cp; 38995c635efSGarrett D'Amore char buf[2]; 39095c635efSGarrett D'Amore size_t sz, psz, ssz, d, padl; 39195c635efSGarrett D'Amore int i; 39295c635efSGarrett D'Amore 39395c635efSGarrett D'Amore /* 39495c635efSGarrett D'Amore * See calc_data_number(). Left-pad by taking the offset of our 39595c635efSGarrett D'Amore * and the maximum decimal; right-pad by the remaining amount. 39695c635efSGarrett D'Amore */ 39795c635efSGarrett D'Amore 39895c635efSGarrett D'Amore assert(dp->string); 39995c635efSGarrett D'Amore 40095c635efSGarrett D'Amore sz = term_strlen(tp, dp->string); 40195c635efSGarrett D'Amore 402*698f87a4SGarrett D'Amore buf[0] = opts->decimal; 40395c635efSGarrett D'Amore buf[1] = '\0'; 40495c635efSGarrett D'Amore 40595c635efSGarrett D'Amore psz = term_strlen(tp, buf); 40695c635efSGarrett D'Amore 407*698f87a4SGarrett D'Amore if (NULL != (cp = strrchr(dp->string, opts->decimal))) { 40895c635efSGarrett D'Amore buf[1] = '\0'; 40995c635efSGarrett D'Amore for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { 41095c635efSGarrett D'Amore buf[0] = dp->string[i]; 41195c635efSGarrett D'Amore ssz += term_strlen(tp, buf); 41295c635efSGarrett D'Amore } 41395c635efSGarrett D'Amore d = ssz + psz; 41495c635efSGarrett D'Amore } else 41595c635efSGarrett D'Amore d = sz + psz; 41695c635efSGarrett D'Amore 41795c635efSGarrett D'Amore padl = col->decimal - d; 41895c635efSGarrett D'Amore 41995c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl); 42095c635efSGarrett D'Amore term_word(tp, dp->string); 42195c635efSGarrett D'Amore if (col->width > sz + padl) 42295c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); 42395c635efSGarrett D'Amore } 42495c635efSGarrett D'Amore 425