1*95c635efSGarrett D'Amore /* $Id: tbl_term.c,v 1.21 2011/09/20 23:05:49 schwarze Exp $ */ 2*95c635efSGarrett D'Amore /* 3*95c635efSGarrett D'Amore * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*95c635efSGarrett D'Amore * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> 5*95c635efSGarrett D'Amore * 6*95c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 7*95c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 8*95c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 9*95c635efSGarrett D'Amore * 10*95c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*95c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*95c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*95c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*95c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*95c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*95c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*95c635efSGarrett D'Amore */ 18*95c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H 19*95c635efSGarrett D'Amore #include "config.h" 20*95c635efSGarrett D'Amore #endif 21*95c635efSGarrett D'Amore 22*95c635efSGarrett D'Amore #include <assert.h> 23*95c635efSGarrett D'Amore #include <stdio.h> 24*95c635efSGarrett D'Amore #include <stdlib.h> 25*95c635efSGarrett D'Amore #include <string.h> 26*95c635efSGarrett D'Amore 27*95c635efSGarrett D'Amore #include "mandoc.h" 28*95c635efSGarrett D'Amore #include "out.h" 29*95c635efSGarrett D'Amore #include "term.h" 30*95c635efSGarrett D'Amore 31*95c635efSGarrett D'Amore static size_t term_tbl_len(size_t, void *); 32*95c635efSGarrett D'Amore static size_t term_tbl_strlen(const char *, void *); 33*95c635efSGarrett D'Amore static void tbl_char(struct termp *, char, size_t); 34*95c635efSGarrett D'Amore static void tbl_data(struct termp *, const struct tbl *, 35*95c635efSGarrett D'Amore const struct tbl_dat *, 36*95c635efSGarrett D'Amore const struct roffcol *); 37*95c635efSGarrett D'Amore static size_t tbl_rulewidth(struct termp *, const struct tbl_head *); 38*95c635efSGarrett D'Amore static void tbl_hframe(struct termp *, const struct tbl_span *, int); 39*95c635efSGarrett D'Amore static void tbl_literal(struct termp *, const struct tbl_dat *, 40*95c635efSGarrett D'Amore const struct roffcol *); 41*95c635efSGarrett D'Amore static void tbl_number(struct termp *, const struct tbl *, 42*95c635efSGarrett D'Amore const struct tbl_dat *, 43*95c635efSGarrett D'Amore const struct roffcol *); 44*95c635efSGarrett D'Amore static void tbl_hrule(struct termp *, const struct tbl_span *); 45*95c635efSGarrett D'Amore static void tbl_vrule(struct termp *, const struct tbl_head *); 46*95c635efSGarrett D'Amore 47*95c635efSGarrett D'Amore 48*95c635efSGarrett D'Amore static size_t 49*95c635efSGarrett D'Amore term_tbl_strlen(const char *p, void *arg) 50*95c635efSGarrett D'Amore { 51*95c635efSGarrett D'Amore 52*95c635efSGarrett D'Amore return(term_strlen((const struct termp *)arg, p)); 53*95c635efSGarrett D'Amore } 54*95c635efSGarrett D'Amore 55*95c635efSGarrett D'Amore static size_t 56*95c635efSGarrett D'Amore term_tbl_len(size_t sz, void *arg) 57*95c635efSGarrett D'Amore { 58*95c635efSGarrett D'Amore 59*95c635efSGarrett D'Amore return(term_len((const struct termp *)arg, sz)); 60*95c635efSGarrett D'Amore } 61*95c635efSGarrett D'Amore 62*95c635efSGarrett D'Amore void 63*95c635efSGarrett D'Amore term_tbl(struct termp *tp, const struct tbl_span *sp) 64*95c635efSGarrett D'Amore { 65*95c635efSGarrett D'Amore const struct tbl_head *hp; 66*95c635efSGarrett D'Amore const struct tbl_dat *dp; 67*95c635efSGarrett D'Amore struct roffcol *col; 68*95c635efSGarrett D'Amore int spans; 69*95c635efSGarrett D'Amore size_t rmargin, maxrmargin; 70*95c635efSGarrett D'Amore 71*95c635efSGarrett D'Amore rmargin = tp->rmargin; 72*95c635efSGarrett D'Amore maxrmargin = tp->maxrmargin; 73*95c635efSGarrett D'Amore 74*95c635efSGarrett D'Amore tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN; 75*95c635efSGarrett D'Amore 76*95c635efSGarrett D'Amore /* Inhibit printing of spaces: we do padding ourselves. */ 77*95c635efSGarrett D'Amore 78*95c635efSGarrett D'Amore tp->flags |= TERMP_NONOSPACE; 79*95c635efSGarrett D'Amore tp->flags |= TERMP_NOSPACE; 80*95c635efSGarrett D'Amore 81*95c635efSGarrett D'Amore /* 82*95c635efSGarrett D'Amore * The first time we're invoked for a given table block, 83*95c635efSGarrett D'Amore * calculate the table widths and decimal positions. 84*95c635efSGarrett D'Amore */ 85*95c635efSGarrett D'Amore 86*95c635efSGarrett D'Amore if (TBL_SPAN_FIRST & sp->flags) { 87*95c635efSGarrett D'Amore term_flushln(tp); 88*95c635efSGarrett D'Amore 89*95c635efSGarrett D'Amore tp->tbl.len = term_tbl_len; 90*95c635efSGarrett D'Amore tp->tbl.slen = term_tbl_strlen; 91*95c635efSGarrett D'Amore tp->tbl.arg = tp; 92*95c635efSGarrett D'Amore 93*95c635efSGarrett D'Amore tblcalc(&tp->tbl, sp); 94*95c635efSGarrett D'Amore } 95*95c635efSGarrett D'Amore 96*95c635efSGarrett D'Amore /* Horizontal frame at the start of boxed tables. */ 97*95c635efSGarrett D'Amore 98*95c635efSGarrett D'Amore if (TBL_SPAN_FIRST & sp->flags) { 99*95c635efSGarrett D'Amore if (TBL_OPT_DBOX & sp->tbl->opts) 100*95c635efSGarrett D'Amore tbl_hframe(tp, sp, 1); 101*95c635efSGarrett D'Amore if (TBL_OPT_DBOX & sp->tbl->opts || 102*95c635efSGarrett D'Amore TBL_OPT_BOX & sp->tbl->opts) 103*95c635efSGarrett D'Amore tbl_hframe(tp, sp, 0); 104*95c635efSGarrett D'Amore } 105*95c635efSGarrett D'Amore 106*95c635efSGarrett D'Amore /* Vertical frame at the start of each row. */ 107*95c635efSGarrett D'Amore 108*95c635efSGarrett D'Amore if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) 109*95c635efSGarrett D'Amore term_word(tp, TBL_SPAN_HORIZ == sp->pos || 110*95c635efSGarrett D'Amore TBL_SPAN_DHORIZ == sp->pos ? "+" : "|"); 111*95c635efSGarrett D'Amore 112*95c635efSGarrett D'Amore /* 113*95c635efSGarrett D'Amore * Now print the actual data itself depending on the span type. 114*95c635efSGarrett D'Amore * Spanner spans get a horizontal rule; data spanners have their 115*95c635efSGarrett D'Amore * data printed by matching data to header. 116*95c635efSGarrett D'Amore */ 117*95c635efSGarrett D'Amore 118*95c635efSGarrett D'Amore switch (sp->pos) { 119*95c635efSGarrett D'Amore case (TBL_SPAN_HORIZ): 120*95c635efSGarrett D'Amore /* FALLTHROUGH */ 121*95c635efSGarrett D'Amore case (TBL_SPAN_DHORIZ): 122*95c635efSGarrett D'Amore tbl_hrule(tp, sp); 123*95c635efSGarrett D'Amore break; 124*95c635efSGarrett D'Amore case (TBL_SPAN_DATA): 125*95c635efSGarrett D'Amore /* Iterate over template headers. */ 126*95c635efSGarrett D'Amore dp = sp->first; 127*95c635efSGarrett D'Amore spans = 0; 128*95c635efSGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) { 129*95c635efSGarrett D'Amore /* 130*95c635efSGarrett D'Amore * If the current data header is invoked during 131*95c635efSGarrett D'Amore * a spanner ("spans" > 0), don't emit anything 132*95c635efSGarrett D'Amore * at all. 133*95c635efSGarrett D'Amore */ 134*95c635efSGarrett D'Amore switch (hp->pos) { 135*95c635efSGarrett D'Amore case (TBL_HEAD_VERT): 136*95c635efSGarrett D'Amore /* FALLTHROUGH */ 137*95c635efSGarrett D'Amore case (TBL_HEAD_DVERT): 138*95c635efSGarrett D'Amore if (spans <= 0) 139*95c635efSGarrett D'Amore tbl_vrule(tp, hp); 140*95c635efSGarrett D'Amore continue; 141*95c635efSGarrett D'Amore case (TBL_HEAD_DATA): 142*95c635efSGarrett D'Amore break; 143*95c635efSGarrett D'Amore } 144*95c635efSGarrett D'Amore 145*95c635efSGarrett D'Amore if (--spans >= 0) 146*95c635efSGarrett D'Amore continue; 147*95c635efSGarrett D'Amore 148*95c635efSGarrett D'Amore /* 149*95c635efSGarrett D'Amore * All cells get a leading blank, except the 150*95c635efSGarrett D'Amore * first one and those after double rulers. 151*95c635efSGarrett D'Amore */ 152*95c635efSGarrett D'Amore 153*95c635efSGarrett D'Amore if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) 154*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, 1); 155*95c635efSGarrett D'Amore 156*95c635efSGarrett D'Amore col = &tp->tbl.cols[hp->ident]; 157*95c635efSGarrett D'Amore tbl_data(tp, sp->tbl, dp, col); 158*95c635efSGarrett D'Amore 159*95c635efSGarrett D'Amore /* No trailing blanks. */ 160*95c635efSGarrett D'Amore 161*95c635efSGarrett D'Amore if (NULL == hp->next) 162*95c635efSGarrett D'Amore break; 163*95c635efSGarrett D'Amore 164*95c635efSGarrett D'Amore /* 165*95c635efSGarrett D'Amore * Add another blank between cells, 166*95c635efSGarrett D'Amore * or two when there is no vertical ruler. 167*95c635efSGarrett D'Amore */ 168*95c635efSGarrett D'Amore 169*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, 170*95c635efSGarrett D'Amore TBL_HEAD_VERT == hp->next->pos || 171*95c635efSGarrett D'Amore TBL_HEAD_DVERT == hp->next->pos ? 1 : 2); 172*95c635efSGarrett D'Amore 173*95c635efSGarrett D'Amore /* 174*95c635efSGarrett D'Amore * Go to the next data cell and assign the 175*95c635efSGarrett D'Amore * number of subsequent spans, if applicable. 176*95c635efSGarrett D'Amore */ 177*95c635efSGarrett D'Amore 178*95c635efSGarrett D'Amore if (dp) { 179*95c635efSGarrett D'Amore spans = dp->spans; 180*95c635efSGarrett D'Amore dp = dp->next; 181*95c635efSGarrett D'Amore } 182*95c635efSGarrett D'Amore } 183*95c635efSGarrett D'Amore break; 184*95c635efSGarrett D'Amore } 185*95c635efSGarrett D'Amore 186*95c635efSGarrett D'Amore /* Vertical frame at the end of each row. */ 187*95c635efSGarrett D'Amore 188*95c635efSGarrett D'Amore if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) 189*95c635efSGarrett D'Amore term_word(tp, TBL_SPAN_HORIZ == sp->pos || 190*95c635efSGarrett D'Amore TBL_SPAN_DHORIZ == sp->pos ? "+" : " |"); 191*95c635efSGarrett D'Amore term_flushln(tp); 192*95c635efSGarrett D'Amore 193*95c635efSGarrett D'Amore /* 194*95c635efSGarrett D'Amore * If we're the last row, clean up after ourselves: clear the 195*95c635efSGarrett D'Amore * existing table configuration and set it to NULL. 196*95c635efSGarrett D'Amore */ 197*95c635efSGarrett D'Amore 198*95c635efSGarrett D'Amore if (TBL_SPAN_LAST & sp->flags) { 199*95c635efSGarrett D'Amore if (TBL_OPT_DBOX & sp->tbl->opts || 200*95c635efSGarrett D'Amore TBL_OPT_BOX & sp->tbl->opts) 201*95c635efSGarrett D'Amore tbl_hframe(tp, sp, 0); 202*95c635efSGarrett D'Amore if (TBL_OPT_DBOX & sp->tbl->opts) 203*95c635efSGarrett D'Amore tbl_hframe(tp, sp, 1); 204*95c635efSGarrett D'Amore assert(tp->tbl.cols); 205*95c635efSGarrett D'Amore free(tp->tbl.cols); 206*95c635efSGarrett D'Amore tp->tbl.cols = NULL; 207*95c635efSGarrett D'Amore } 208*95c635efSGarrett D'Amore 209*95c635efSGarrett D'Amore tp->flags &= ~TERMP_NONOSPACE; 210*95c635efSGarrett D'Amore tp->rmargin = rmargin; 211*95c635efSGarrett D'Amore tp->maxrmargin = maxrmargin; 212*95c635efSGarrett D'Amore 213*95c635efSGarrett D'Amore } 214*95c635efSGarrett D'Amore 215*95c635efSGarrett D'Amore /* 216*95c635efSGarrett D'Amore * Horizontal rules extend across the entire table. 217*95c635efSGarrett D'Amore * Calculate the width by iterating over columns. 218*95c635efSGarrett D'Amore */ 219*95c635efSGarrett D'Amore static size_t 220*95c635efSGarrett D'Amore tbl_rulewidth(struct termp *tp, const struct tbl_head *hp) 221*95c635efSGarrett D'Amore { 222*95c635efSGarrett D'Amore size_t width; 223*95c635efSGarrett D'Amore 224*95c635efSGarrett D'Amore width = tp->tbl.cols[hp->ident].width; 225*95c635efSGarrett D'Amore if (TBL_HEAD_DATA == hp->pos) { 226*95c635efSGarrett D'Amore /* Account for leading blanks. */ 227*95c635efSGarrett D'Amore if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) 228*95c635efSGarrett D'Amore width++; 229*95c635efSGarrett D'Amore /* Account for trailing blanks. */ 230*95c635efSGarrett D'Amore width++; 231*95c635efSGarrett D'Amore if (hp->next && 232*95c635efSGarrett D'Amore TBL_HEAD_VERT != hp->next->pos && 233*95c635efSGarrett D'Amore TBL_HEAD_DVERT != hp->next->pos) 234*95c635efSGarrett D'Amore width++; 235*95c635efSGarrett D'Amore } 236*95c635efSGarrett D'Amore return(width); 237*95c635efSGarrett D'Amore } 238*95c635efSGarrett D'Amore 239*95c635efSGarrett D'Amore /* 240*95c635efSGarrett D'Amore * Rules inside the table can be single or double 241*95c635efSGarrett D'Amore * and have crossings with vertical rules marked with pluses. 242*95c635efSGarrett D'Amore */ 243*95c635efSGarrett D'Amore static void 244*95c635efSGarrett D'Amore tbl_hrule(struct termp *tp, const struct tbl_span *sp) 245*95c635efSGarrett D'Amore { 246*95c635efSGarrett D'Amore const struct tbl_head *hp; 247*95c635efSGarrett D'Amore char c; 248*95c635efSGarrett D'Amore 249*95c635efSGarrett D'Amore c = '-'; 250*95c635efSGarrett D'Amore if (TBL_SPAN_DHORIZ == sp->pos) 251*95c635efSGarrett D'Amore c = '='; 252*95c635efSGarrett D'Amore 253*95c635efSGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) 254*95c635efSGarrett D'Amore tbl_char(tp, 255*95c635efSGarrett D'Amore TBL_HEAD_DATA == hp->pos ? c : '+', 256*95c635efSGarrett D'Amore tbl_rulewidth(tp, hp)); 257*95c635efSGarrett D'Amore } 258*95c635efSGarrett D'Amore 259*95c635efSGarrett D'Amore /* 260*95c635efSGarrett D'Amore * Rules above and below the table are always single 261*95c635efSGarrett D'Amore * and have an additional plus at the beginning and end. 262*95c635efSGarrett D'Amore * For double frames, this function is called twice, 263*95c635efSGarrett D'Amore * and the outer one does not have crossings. 264*95c635efSGarrett D'Amore */ 265*95c635efSGarrett D'Amore static void 266*95c635efSGarrett D'Amore tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer) 267*95c635efSGarrett D'Amore { 268*95c635efSGarrett D'Amore const struct tbl_head *hp; 269*95c635efSGarrett D'Amore 270*95c635efSGarrett D'Amore term_word(tp, "+"); 271*95c635efSGarrett D'Amore for (hp = sp->head; hp; hp = hp->next) 272*95c635efSGarrett D'Amore tbl_char(tp, 273*95c635efSGarrett D'Amore outer || TBL_HEAD_DATA == hp->pos ? '-' : '+', 274*95c635efSGarrett D'Amore tbl_rulewidth(tp, hp)); 275*95c635efSGarrett D'Amore term_word(tp, "+"); 276*95c635efSGarrett D'Amore term_flushln(tp); 277*95c635efSGarrett D'Amore } 278*95c635efSGarrett D'Amore 279*95c635efSGarrett D'Amore static void 280*95c635efSGarrett D'Amore tbl_data(struct termp *tp, const struct tbl *tbl, 281*95c635efSGarrett D'Amore const struct tbl_dat *dp, 282*95c635efSGarrett D'Amore const struct roffcol *col) 283*95c635efSGarrett D'Amore { 284*95c635efSGarrett D'Amore 285*95c635efSGarrett D'Amore if (NULL == dp) { 286*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width); 287*95c635efSGarrett D'Amore return; 288*95c635efSGarrett D'Amore } 289*95c635efSGarrett D'Amore assert(dp->layout); 290*95c635efSGarrett D'Amore 291*95c635efSGarrett D'Amore switch (dp->pos) { 292*95c635efSGarrett D'Amore case (TBL_DATA_NONE): 293*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width); 294*95c635efSGarrett D'Amore return; 295*95c635efSGarrett D'Amore case (TBL_DATA_HORIZ): 296*95c635efSGarrett D'Amore /* FALLTHROUGH */ 297*95c635efSGarrett D'Amore case (TBL_DATA_NHORIZ): 298*95c635efSGarrett D'Amore tbl_char(tp, '-', col->width); 299*95c635efSGarrett D'Amore return; 300*95c635efSGarrett D'Amore case (TBL_DATA_NDHORIZ): 301*95c635efSGarrett D'Amore /* FALLTHROUGH */ 302*95c635efSGarrett D'Amore case (TBL_DATA_DHORIZ): 303*95c635efSGarrett D'Amore tbl_char(tp, '=', col->width); 304*95c635efSGarrett D'Amore return; 305*95c635efSGarrett D'Amore default: 306*95c635efSGarrett D'Amore break; 307*95c635efSGarrett D'Amore } 308*95c635efSGarrett D'Amore 309*95c635efSGarrett D'Amore switch (dp->layout->pos) { 310*95c635efSGarrett D'Amore case (TBL_CELL_HORIZ): 311*95c635efSGarrett D'Amore tbl_char(tp, '-', col->width); 312*95c635efSGarrett D'Amore break; 313*95c635efSGarrett D'Amore case (TBL_CELL_DHORIZ): 314*95c635efSGarrett D'Amore tbl_char(tp, '=', col->width); 315*95c635efSGarrett D'Amore break; 316*95c635efSGarrett D'Amore case (TBL_CELL_LONG): 317*95c635efSGarrett D'Amore /* FALLTHROUGH */ 318*95c635efSGarrett D'Amore case (TBL_CELL_CENTRE): 319*95c635efSGarrett D'Amore /* FALLTHROUGH */ 320*95c635efSGarrett D'Amore case (TBL_CELL_LEFT): 321*95c635efSGarrett D'Amore /* FALLTHROUGH */ 322*95c635efSGarrett D'Amore case (TBL_CELL_RIGHT): 323*95c635efSGarrett D'Amore tbl_literal(tp, dp, col); 324*95c635efSGarrett D'Amore break; 325*95c635efSGarrett D'Amore case (TBL_CELL_NUMBER): 326*95c635efSGarrett D'Amore tbl_number(tp, tbl, dp, col); 327*95c635efSGarrett D'Amore break; 328*95c635efSGarrett D'Amore case (TBL_CELL_DOWN): 329*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width); 330*95c635efSGarrett D'Amore break; 331*95c635efSGarrett D'Amore default: 332*95c635efSGarrett D'Amore abort(); 333*95c635efSGarrett D'Amore /* NOTREACHED */ 334*95c635efSGarrett D'Amore } 335*95c635efSGarrett D'Amore } 336*95c635efSGarrett D'Amore 337*95c635efSGarrett D'Amore static void 338*95c635efSGarrett D'Amore tbl_vrule(struct termp *tp, const struct tbl_head *hp) 339*95c635efSGarrett D'Amore { 340*95c635efSGarrett D'Amore 341*95c635efSGarrett D'Amore switch (hp->pos) { 342*95c635efSGarrett D'Amore case (TBL_HEAD_VERT): 343*95c635efSGarrett D'Amore term_word(tp, "|"); 344*95c635efSGarrett D'Amore break; 345*95c635efSGarrett D'Amore case (TBL_HEAD_DVERT): 346*95c635efSGarrett D'Amore term_word(tp, "||"); 347*95c635efSGarrett D'Amore break; 348*95c635efSGarrett D'Amore default: 349*95c635efSGarrett D'Amore break; 350*95c635efSGarrett D'Amore } 351*95c635efSGarrett D'Amore } 352*95c635efSGarrett D'Amore 353*95c635efSGarrett D'Amore static void 354*95c635efSGarrett D'Amore tbl_char(struct termp *tp, char c, size_t len) 355*95c635efSGarrett D'Amore { 356*95c635efSGarrett D'Amore size_t i, sz; 357*95c635efSGarrett D'Amore char cp[2]; 358*95c635efSGarrett D'Amore 359*95c635efSGarrett D'Amore cp[0] = c; 360*95c635efSGarrett D'Amore cp[1] = '\0'; 361*95c635efSGarrett D'Amore 362*95c635efSGarrett D'Amore sz = term_strlen(tp, cp); 363*95c635efSGarrett D'Amore 364*95c635efSGarrett D'Amore for (i = 0; i < len; i += sz) 365*95c635efSGarrett D'Amore term_word(tp, cp); 366*95c635efSGarrett D'Amore } 367*95c635efSGarrett D'Amore 368*95c635efSGarrett D'Amore static void 369*95c635efSGarrett D'Amore tbl_literal(struct termp *tp, const struct tbl_dat *dp, 370*95c635efSGarrett D'Amore const struct roffcol *col) 371*95c635efSGarrett D'Amore { 372*95c635efSGarrett D'Amore size_t len, padl, padr; 373*95c635efSGarrett D'Amore 374*95c635efSGarrett D'Amore assert(dp->string); 375*95c635efSGarrett D'Amore len = term_strlen(tp, dp->string); 376*95c635efSGarrett D'Amore padr = col->width > len ? col->width - len : 0; 377*95c635efSGarrett D'Amore padl = 0; 378*95c635efSGarrett D'Amore 379*95c635efSGarrett D'Amore switch (dp->layout->pos) { 380*95c635efSGarrett D'Amore case (TBL_CELL_LONG): 381*95c635efSGarrett D'Amore padl = term_len(tp, 1); 382*95c635efSGarrett D'Amore padr = padr > padl ? padr - padl : 0; 383*95c635efSGarrett D'Amore break; 384*95c635efSGarrett D'Amore case (TBL_CELL_CENTRE): 385*95c635efSGarrett D'Amore if (2 > padr) 386*95c635efSGarrett D'Amore break; 387*95c635efSGarrett D'Amore padl = padr / 2; 388*95c635efSGarrett D'Amore padr -= padl; 389*95c635efSGarrett D'Amore break; 390*95c635efSGarrett D'Amore case (TBL_CELL_RIGHT): 391*95c635efSGarrett D'Amore padl = padr; 392*95c635efSGarrett D'Amore padr = 0; 393*95c635efSGarrett D'Amore break; 394*95c635efSGarrett D'Amore default: 395*95c635efSGarrett D'Amore break; 396*95c635efSGarrett D'Amore } 397*95c635efSGarrett D'Amore 398*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl); 399*95c635efSGarrett D'Amore term_word(tp, dp->string); 400*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padr); 401*95c635efSGarrett D'Amore } 402*95c635efSGarrett D'Amore 403*95c635efSGarrett D'Amore static void 404*95c635efSGarrett D'Amore tbl_number(struct termp *tp, const struct tbl *tbl, 405*95c635efSGarrett D'Amore const struct tbl_dat *dp, 406*95c635efSGarrett D'Amore const struct roffcol *col) 407*95c635efSGarrett D'Amore { 408*95c635efSGarrett D'Amore char *cp; 409*95c635efSGarrett D'Amore char buf[2]; 410*95c635efSGarrett D'Amore size_t sz, psz, ssz, d, padl; 411*95c635efSGarrett D'Amore int i; 412*95c635efSGarrett D'Amore 413*95c635efSGarrett D'Amore /* 414*95c635efSGarrett D'Amore * See calc_data_number(). Left-pad by taking the offset of our 415*95c635efSGarrett D'Amore * and the maximum decimal; right-pad by the remaining amount. 416*95c635efSGarrett D'Amore */ 417*95c635efSGarrett D'Amore 418*95c635efSGarrett D'Amore assert(dp->string); 419*95c635efSGarrett D'Amore 420*95c635efSGarrett D'Amore sz = term_strlen(tp, dp->string); 421*95c635efSGarrett D'Amore 422*95c635efSGarrett D'Amore buf[0] = tbl->decimal; 423*95c635efSGarrett D'Amore buf[1] = '\0'; 424*95c635efSGarrett D'Amore 425*95c635efSGarrett D'Amore psz = term_strlen(tp, buf); 426*95c635efSGarrett D'Amore 427*95c635efSGarrett D'Amore if (NULL != (cp = strrchr(dp->string, tbl->decimal))) { 428*95c635efSGarrett D'Amore buf[1] = '\0'; 429*95c635efSGarrett D'Amore for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { 430*95c635efSGarrett D'Amore buf[0] = dp->string[i]; 431*95c635efSGarrett D'Amore ssz += term_strlen(tp, buf); 432*95c635efSGarrett D'Amore } 433*95c635efSGarrett D'Amore d = ssz + psz; 434*95c635efSGarrett D'Amore } else 435*95c635efSGarrett D'Amore d = sz + psz; 436*95c635efSGarrett D'Amore 437*95c635efSGarrett D'Amore padl = col->decimal - d; 438*95c635efSGarrett D'Amore 439*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, padl); 440*95c635efSGarrett D'Amore term_word(tp, dp->string); 441*95c635efSGarrett D'Amore if (col->width > sz + padl) 442*95c635efSGarrett D'Amore tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); 443*95c635efSGarrett D'Amore } 444*95c635efSGarrett D'Amore 445