1*61d06d6bSBaptiste Daroussin /* $Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */ 2*61d06d6bSBaptiste Daroussin /* 3*61d06d6bSBaptiste Daroussin * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*61d06d6bSBaptiste Daroussin * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> 5*61d06d6bSBaptiste Daroussin * 6*61d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 7*61d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 8*61d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 9*61d06d6bSBaptiste Daroussin * 10*61d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*61d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*61d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*61d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*61d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*61d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*61d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*61d06d6bSBaptiste Daroussin */ 18*61d06d6bSBaptiste Daroussin #include "config.h" 19*61d06d6bSBaptiste Daroussin 20*61d06d6bSBaptiste Daroussin #include <sys/types.h> 21*61d06d6bSBaptiste Daroussin 22*61d06d6bSBaptiste Daroussin #include <assert.h> 23*61d06d6bSBaptiste Daroussin #include <stdint.h> 24*61d06d6bSBaptiste Daroussin #include <stdlib.h> 25*61d06d6bSBaptiste Daroussin #include <string.h> 26*61d06d6bSBaptiste Daroussin #include <time.h> 27*61d06d6bSBaptiste Daroussin 28*61d06d6bSBaptiste Daroussin #include "mandoc_aux.h" 29*61d06d6bSBaptiste Daroussin #include "mandoc.h" 30*61d06d6bSBaptiste Daroussin #include "out.h" 31*61d06d6bSBaptiste Daroussin 32*61d06d6bSBaptiste Daroussin static void tblcalc_data(struct rofftbl *, struct roffcol *, 33*61d06d6bSBaptiste Daroussin const struct tbl_opts *, const struct tbl_dat *, 34*61d06d6bSBaptiste Daroussin size_t); 35*61d06d6bSBaptiste Daroussin static void tblcalc_literal(struct rofftbl *, struct roffcol *, 36*61d06d6bSBaptiste Daroussin const struct tbl_dat *, size_t); 37*61d06d6bSBaptiste Daroussin static void tblcalc_number(struct rofftbl *, struct roffcol *, 38*61d06d6bSBaptiste Daroussin const struct tbl_opts *, const struct tbl_dat *); 39*61d06d6bSBaptiste Daroussin 40*61d06d6bSBaptiste Daroussin 41*61d06d6bSBaptiste Daroussin /* 42*61d06d6bSBaptiste Daroussin * Parse the *src string and store a scaling unit into *dst. 43*61d06d6bSBaptiste Daroussin * If the string doesn't specify the unit, use the default. 44*61d06d6bSBaptiste Daroussin * If no default is specified, fail. 45*61d06d6bSBaptiste Daroussin * Return a pointer to the byte after the last byte used, 46*61d06d6bSBaptiste Daroussin * or NULL on total failure. 47*61d06d6bSBaptiste Daroussin */ 48*61d06d6bSBaptiste Daroussin const char * 49*61d06d6bSBaptiste Daroussin a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) 50*61d06d6bSBaptiste Daroussin { 51*61d06d6bSBaptiste Daroussin char *endptr; 52*61d06d6bSBaptiste Daroussin 53*61d06d6bSBaptiste Daroussin dst->unit = def == SCALE_MAX ? SCALE_BU : def; 54*61d06d6bSBaptiste Daroussin dst->scale = strtod(src, &endptr); 55*61d06d6bSBaptiste Daroussin if (endptr == src) 56*61d06d6bSBaptiste Daroussin return NULL; 57*61d06d6bSBaptiste Daroussin 58*61d06d6bSBaptiste Daroussin switch (*endptr++) { 59*61d06d6bSBaptiste Daroussin case 'c': 60*61d06d6bSBaptiste Daroussin dst->unit = SCALE_CM; 61*61d06d6bSBaptiste Daroussin break; 62*61d06d6bSBaptiste Daroussin case 'i': 63*61d06d6bSBaptiste Daroussin dst->unit = SCALE_IN; 64*61d06d6bSBaptiste Daroussin break; 65*61d06d6bSBaptiste Daroussin case 'f': 66*61d06d6bSBaptiste Daroussin dst->unit = SCALE_FS; 67*61d06d6bSBaptiste Daroussin break; 68*61d06d6bSBaptiste Daroussin case 'M': 69*61d06d6bSBaptiste Daroussin dst->unit = SCALE_MM; 70*61d06d6bSBaptiste Daroussin break; 71*61d06d6bSBaptiste Daroussin case 'm': 72*61d06d6bSBaptiste Daroussin dst->unit = SCALE_EM; 73*61d06d6bSBaptiste Daroussin break; 74*61d06d6bSBaptiste Daroussin case 'n': 75*61d06d6bSBaptiste Daroussin dst->unit = SCALE_EN; 76*61d06d6bSBaptiste Daroussin break; 77*61d06d6bSBaptiste Daroussin case 'P': 78*61d06d6bSBaptiste Daroussin dst->unit = SCALE_PC; 79*61d06d6bSBaptiste Daroussin break; 80*61d06d6bSBaptiste Daroussin case 'p': 81*61d06d6bSBaptiste Daroussin dst->unit = SCALE_PT; 82*61d06d6bSBaptiste Daroussin break; 83*61d06d6bSBaptiste Daroussin case 'u': 84*61d06d6bSBaptiste Daroussin dst->unit = SCALE_BU; 85*61d06d6bSBaptiste Daroussin break; 86*61d06d6bSBaptiste Daroussin case 'v': 87*61d06d6bSBaptiste Daroussin dst->unit = SCALE_VS; 88*61d06d6bSBaptiste Daroussin break; 89*61d06d6bSBaptiste Daroussin default: 90*61d06d6bSBaptiste Daroussin endptr--; 91*61d06d6bSBaptiste Daroussin if (SCALE_MAX == def) 92*61d06d6bSBaptiste Daroussin return NULL; 93*61d06d6bSBaptiste Daroussin dst->unit = def; 94*61d06d6bSBaptiste Daroussin break; 95*61d06d6bSBaptiste Daroussin } 96*61d06d6bSBaptiste Daroussin return endptr; 97*61d06d6bSBaptiste Daroussin } 98*61d06d6bSBaptiste Daroussin 99*61d06d6bSBaptiste Daroussin /* 100*61d06d6bSBaptiste Daroussin * Calculate the abstract widths and decimal positions of columns in a 101*61d06d6bSBaptiste Daroussin * table. This routine allocates the columns structures then runs over 102*61d06d6bSBaptiste Daroussin * all rows and cells in the table. The function pointers in "tbl" are 103*61d06d6bSBaptiste Daroussin * used for the actual width calculations. 104*61d06d6bSBaptiste Daroussin */ 105*61d06d6bSBaptiste Daroussin void 106*61d06d6bSBaptiste Daroussin tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, 107*61d06d6bSBaptiste Daroussin size_t offset, size_t rmargin) 108*61d06d6bSBaptiste Daroussin { 109*61d06d6bSBaptiste Daroussin struct roffsu su; 110*61d06d6bSBaptiste Daroussin const struct tbl_opts *opts; 111*61d06d6bSBaptiste Daroussin const struct tbl_dat *dp; 112*61d06d6bSBaptiste Daroussin struct roffcol *col; 113*61d06d6bSBaptiste Daroussin size_t ewidth, xwidth; 114*61d06d6bSBaptiste Daroussin int spans; 115*61d06d6bSBaptiste Daroussin int icol, maxcol, necol, nxcol, quirkcol; 116*61d06d6bSBaptiste Daroussin 117*61d06d6bSBaptiste Daroussin /* 118*61d06d6bSBaptiste Daroussin * Allocate the master column specifiers. These will hold the 119*61d06d6bSBaptiste Daroussin * widths and decimal positions for all cells in the column. It 120*61d06d6bSBaptiste Daroussin * must be freed and nullified by the caller. 121*61d06d6bSBaptiste Daroussin */ 122*61d06d6bSBaptiste Daroussin 123*61d06d6bSBaptiste Daroussin assert(NULL == tbl->cols); 124*61d06d6bSBaptiste Daroussin tbl->cols = mandoc_calloc((size_t)sp->opts->cols, 125*61d06d6bSBaptiste Daroussin sizeof(struct roffcol)); 126*61d06d6bSBaptiste Daroussin opts = sp->opts; 127*61d06d6bSBaptiste Daroussin 128*61d06d6bSBaptiste Daroussin for (maxcol = -1; sp; sp = sp->next) { 129*61d06d6bSBaptiste Daroussin if (TBL_SPAN_DATA != sp->pos) 130*61d06d6bSBaptiste Daroussin continue; 131*61d06d6bSBaptiste Daroussin spans = 1; 132*61d06d6bSBaptiste Daroussin /* 133*61d06d6bSBaptiste Daroussin * Account for the data cells in the layout, matching it 134*61d06d6bSBaptiste Daroussin * to data cells in the data section. 135*61d06d6bSBaptiste Daroussin */ 136*61d06d6bSBaptiste Daroussin for (dp = sp->first; dp; dp = dp->next) { 137*61d06d6bSBaptiste Daroussin /* Do not used spanned cells in the calculation. */ 138*61d06d6bSBaptiste Daroussin if (0 < --spans) 139*61d06d6bSBaptiste Daroussin continue; 140*61d06d6bSBaptiste Daroussin spans = dp->spans; 141*61d06d6bSBaptiste Daroussin if (1 < spans) 142*61d06d6bSBaptiste Daroussin continue; 143*61d06d6bSBaptiste Daroussin icol = dp->layout->col; 144*61d06d6bSBaptiste Daroussin while (maxcol < icol) 145*61d06d6bSBaptiste Daroussin tbl->cols[++maxcol].spacing = SIZE_MAX; 146*61d06d6bSBaptiste Daroussin col = tbl->cols + icol; 147*61d06d6bSBaptiste Daroussin col->flags |= dp->layout->flags; 148*61d06d6bSBaptiste Daroussin if (dp->layout->flags & TBL_CELL_WIGN) 149*61d06d6bSBaptiste Daroussin continue; 150*61d06d6bSBaptiste Daroussin if (dp->layout->wstr != NULL && 151*61d06d6bSBaptiste Daroussin dp->layout->width == 0 && 152*61d06d6bSBaptiste Daroussin a2roffsu(dp->layout->wstr, &su, SCALE_EN) 153*61d06d6bSBaptiste Daroussin != NULL) 154*61d06d6bSBaptiste Daroussin dp->layout->width = 155*61d06d6bSBaptiste Daroussin (*tbl->sulen)(&su, tbl->arg); 156*61d06d6bSBaptiste Daroussin if (col->width < dp->layout->width) 157*61d06d6bSBaptiste Daroussin col->width = dp->layout->width; 158*61d06d6bSBaptiste Daroussin if (dp->layout->spacing != SIZE_MAX && 159*61d06d6bSBaptiste Daroussin (col->spacing == SIZE_MAX || 160*61d06d6bSBaptiste Daroussin col->spacing < dp->layout->spacing)) 161*61d06d6bSBaptiste Daroussin col->spacing = dp->layout->spacing; 162*61d06d6bSBaptiste Daroussin tblcalc_data(tbl, col, opts, dp, 163*61d06d6bSBaptiste Daroussin dp->block == 0 ? 0 : 164*61d06d6bSBaptiste Daroussin dp->layout->width ? dp->layout->width : 165*61d06d6bSBaptiste Daroussin rmargin ? (rmargin + sp->opts->cols / 2) 166*61d06d6bSBaptiste Daroussin / (sp->opts->cols + 1) : 0); 167*61d06d6bSBaptiste Daroussin } 168*61d06d6bSBaptiste Daroussin } 169*61d06d6bSBaptiste Daroussin 170*61d06d6bSBaptiste Daroussin /* 171*61d06d6bSBaptiste Daroussin * Count columns to equalize and columns to maximize. 172*61d06d6bSBaptiste Daroussin * Find maximum width of the columns to equalize. 173*61d06d6bSBaptiste Daroussin * Find total width of the columns *not* to maximize. 174*61d06d6bSBaptiste Daroussin */ 175*61d06d6bSBaptiste Daroussin 176*61d06d6bSBaptiste Daroussin necol = nxcol = 0; 177*61d06d6bSBaptiste Daroussin ewidth = xwidth = 0; 178*61d06d6bSBaptiste Daroussin for (icol = 0; icol <= maxcol; icol++) { 179*61d06d6bSBaptiste Daroussin col = tbl->cols + icol; 180*61d06d6bSBaptiste Daroussin if (col->spacing == SIZE_MAX || icol == maxcol) 181*61d06d6bSBaptiste Daroussin col->spacing = 3; 182*61d06d6bSBaptiste Daroussin if (col->flags & TBL_CELL_EQUAL) { 183*61d06d6bSBaptiste Daroussin necol++; 184*61d06d6bSBaptiste Daroussin if (ewidth < col->width) 185*61d06d6bSBaptiste Daroussin ewidth = col->width; 186*61d06d6bSBaptiste Daroussin } 187*61d06d6bSBaptiste Daroussin if (col->flags & TBL_CELL_WMAX) 188*61d06d6bSBaptiste Daroussin nxcol++; 189*61d06d6bSBaptiste Daroussin else 190*61d06d6bSBaptiste Daroussin xwidth += col->width; 191*61d06d6bSBaptiste Daroussin } 192*61d06d6bSBaptiste Daroussin 193*61d06d6bSBaptiste Daroussin /* 194*61d06d6bSBaptiste Daroussin * Equalize columns, if requested for any of them. 195*61d06d6bSBaptiste Daroussin * Update total width of the columns not to maximize. 196*61d06d6bSBaptiste Daroussin */ 197*61d06d6bSBaptiste Daroussin 198*61d06d6bSBaptiste Daroussin if (necol) { 199*61d06d6bSBaptiste Daroussin for (icol = 0; icol <= maxcol; icol++) { 200*61d06d6bSBaptiste Daroussin col = tbl->cols + icol; 201*61d06d6bSBaptiste Daroussin if ( ! (col->flags & TBL_CELL_EQUAL)) 202*61d06d6bSBaptiste Daroussin continue; 203*61d06d6bSBaptiste Daroussin if (col->width == ewidth) 204*61d06d6bSBaptiste Daroussin continue; 205*61d06d6bSBaptiste Daroussin if (nxcol && rmargin) 206*61d06d6bSBaptiste Daroussin xwidth += ewidth - col->width; 207*61d06d6bSBaptiste Daroussin col->width = ewidth; 208*61d06d6bSBaptiste Daroussin } 209*61d06d6bSBaptiste Daroussin } 210*61d06d6bSBaptiste Daroussin 211*61d06d6bSBaptiste Daroussin /* 212*61d06d6bSBaptiste Daroussin * If there are any columns to maximize, find the total 213*61d06d6bSBaptiste Daroussin * available width, deducting 3n margins between columns. 214*61d06d6bSBaptiste Daroussin * Distribute the available width evenly. 215*61d06d6bSBaptiste Daroussin */ 216*61d06d6bSBaptiste Daroussin 217*61d06d6bSBaptiste Daroussin if (nxcol && rmargin) { 218*61d06d6bSBaptiste Daroussin xwidth += 3*maxcol + 219*61d06d6bSBaptiste Daroussin (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ? 220*61d06d6bSBaptiste Daroussin 2 : !!opts->lvert + !!opts->rvert); 221*61d06d6bSBaptiste Daroussin if (rmargin <= offset + xwidth) 222*61d06d6bSBaptiste Daroussin return; 223*61d06d6bSBaptiste Daroussin xwidth = rmargin - offset - xwidth; 224*61d06d6bSBaptiste Daroussin 225*61d06d6bSBaptiste Daroussin /* 226*61d06d6bSBaptiste Daroussin * Emulate a bug in GNU tbl width calculation that 227*61d06d6bSBaptiste Daroussin * manifests itself for large numbers of x-columns. 228*61d06d6bSBaptiste Daroussin * Emulating it for 5 x-columns gives identical 229*61d06d6bSBaptiste Daroussin * behaviour for up to 6 x-columns. 230*61d06d6bSBaptiste Daroussin */ 231*61d06d6bSBaptiste Daroussin 232*61d06d6bSBaptiste Daroussin if (nxcol == 5) { 233*61d06d6bSBaptiste Daroussin quirkcol = xwidth % nxcol + 2; 234*61d06d6bSBaptiste Daroussin if (quirkcol != 3 && quirkcol != 4) 235*61d06d6bSBaptiste Daroussin quirkcol = -1; 236*61d06d6bSBaptiste Daroussin } else 237*61d06d6bSBaptiste Daroussin quirkcol = -1; 238*61d06d6bSBaptiste Daroussin 239*61d06d6bSBaptiste Daroussin necol = 0; 240*61d06d6bSBaptiste Daroussin ewidth = 0; 241*61d06d6bSBaptiste Daroussin for (icol = 0; icol <= maxcol; icol++) { 242*61d06d6bSBaptiste Daroussin col = tbl->cols + icol; 243*61d06d6bSBaptiste Daroussin if ( ! (col->flags & TBL_CELL_WMAX)) 244*61d06d6bSBaptiste Daroussin continue; 245*61d06d6bSBaptiste Daroussin col->width = (double)xwidth * ++necol / nxcol 246*61d06d6bSBaptiste Daroussin - ewidth + 0.4995; 247*61d06d6bSBaptiste Daroussin if (necol == quirkcol) 248*61d06d6bSBaptiste Daroussin col->width--; 249*61d06d6bSBaptiste Daroussin ewidth += col->width; 250*61d06d6bSBaptiste Daroussin } 251*61d06d6bSBaptiste Daroussin } 252*61d06d6bSBaptiste Daroussin } 253*61d06d6bSBaptiste Daroussin 254*61d06d6bSBaptiste Daroussin static void 255*61d06d6bSBaptiste Daroussin tblcalc_data(struct rofftbl *tbl, struct roffcol *col, 256*61d06d6bSBaptiste Daroussin const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw) 257*61d06d6bSBaptiste Daroussin { 258*61d06d6bSBaptiste Daroussin size_t sz; 259*61d06d6bSBaptiste Daroussin 260*61d06d6bSBaptiste Daroussin /* Branch down into data sub-types. */ 261*61d06d6bSBaptiste Daroussin 262*61d06d6bSBaptiste Daroussin switch (dp->layout->pos) { 263*61d06d6bSBaptiste Daroussin case TBL_CELL_HORIZ: 264*61d06d6bSBaptiste Daroussin case TBL_CELL_DHORIZ: 265*61d06d6bSBaptiste Daroussin sz = (*tbl->len)(1, tbl->arg); 266*61d06d6bSBaptiste Daroussin if (col->width < sz) 267*61d06d6bSBaptiste Daroussin col->width = sz; 268*61d06d6bSBaptiste Daroussin break; 269*61d06d6bSBaptiste Daroussin case TBL_CELL_LONG: 270*61d06d6bSBaptiste Daroussin case TBL_CELL_CENTRE: 271*61d06d6bSBaptiste Daroussin case TBL_CELL_LEFT: 272*61d06d6bSBaptiste Daroussin case TBL_CELL_RIGHT: 273*61d06d6bSBaptiste Daroussin tblcalc_literal(tbl, col, dp, mw); 274*61d06d6bSBaptiste Daroussin break; 275*61d06d6bSBaptiste Daroussin case TBL_CELL_NUMBER: 276*61d06d6bSBaptiste Daroussin tblcalc_number(tbl, col, opts, dp); 277*61d06d6bSBaptiste Daroussin break; 278*61d06d6bSBaptiste Daroussin case TBL_CELL_DOWN: 279*61d06d6bSBaptiste Daroussin break; 280*61d06d6bSBaptiste Daroussin default: 281*61d06d6bSBaptiste Daroussin abort(); 282*61d06d6bSBaptiste Daroussin } 283*61d06d6bSBaptiste Daroussin } 284*61d06d6bSBaptiste Daroussin 285*61d06d6bSBaptiste Daroussin static void 286*61d06d6bSBaptiste Daroussin tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, 287*61d06d6bSBaptiste Daroussin const struct tbl_dat *dp, size_t mw) 288*61d06d6bSBaptiste Daroussin { 289*61d06d6bSBaptiste Daroussin const char *str; /* Beginning of the first line. */ 290*61d06d6bSBaptiste Daroussin const char *beg; /* Beginning of the current line. */ 291*61d06d6bSBaptiste Daroussin char *end; /* End of the current line. */ 292*61d06d6bSBaptiste Daroussin size_t lsz; /* Length of the current line. */ 293*61d06d6bSBaptiste Daroussin size_t wsz; /* Length of the current word. */ 294*61d06d6bSBaptiste Daroussin 295*61d06d6bSBaptiste Daroussin if (dp->string == NULL || *dp->string == '\0') 296*61d06d6bSBaptiste Daroussin return; 297*61d06d6bSBaptiste Daroussin str = mw ? mandoc_strdup(dp->string) : dp->string; 298*61d06d6bSBaptiste Daroussin lsz = 0; 299*61d06d6bSBaptiste Daroussin for (beg = str; beg != NULL && *beg != '\0'; beg = end) { 300*61d06d6bSBaptiste Daroussin end = mw ? strchr(beg, ' ') : NULL; 301*61d06d6bSBaptiste Daroussin if (end != NULL) { 302*61d06d6bSBaptiste Daroussin *end++ = '\0'; 303*61d06d6bSBaptiste Daroussin while (*end == ' ') 304*61d06d6bSBaptiste Daroussin end++; 305*61d06d6bSBaptiste Daroussin } 306*61d06d6bSBaptiste Daroussin wsz = (*tbl->slen)(beg, tbl->arg); 307*61d06d6bSBaptiste Daroussin if (mw && lsz && lsz + 1 + wsz <= mw) 308*61d06d6bSBaptiste Daroussin lsz += 1 + wsz; 309*61d06d6bSBaptiste Daroussin else 310*61d06d6bSBaptiste Daroussin lsz = wsz; 311*61d06d6bSBaptiste Daroussin if (col->width < lsz) 312*61d06d6bSBaptiste Daroussin col->width = lsz; 313*61d06d6bSBaptiste Daroussin } 314*61d06d6bSBaptiste Daroussin if (mw) 315*61d06d6bSBaptiste Daroussin free((void *)str); 316*61d06d6bSBaptiste Daroussin } 317*61d06d6bSBaptiste Daroussin 318*61d06d6bSBaptiste Daroussin static void 319*61d06d6bSBaptiste Daroussin tblcalc_number(struct rofftbl *tbl, struct roffcol *col, 320*61d06d6bSBaptiste Daroussin const struct tbl_opts *opts, const struct tbl_dat *dp) 321*61d06d6bSBaptiste Daroussin { 322*61d06d6bSBaptiste Daroussin int i; 323*61d06d6bSBaptiste Daroussin size_t sz, psz, ssz, d; 324*61d06d6bSBaptiste Daroussin const char *str; 325*61d06d6bSBaptiste Daroussin char *cp; 326*61d06d6bSBaptiste Daroussin char buf[2]; 327*61d06d6bSBaptiste Daroussin 328*61d06d6bSBaptiste Daroussin /* 329*61d06d6bSBaptiste Daroussin * First calculate number width and decimal place (last + 1 for 330*61d06d6bSBaptiste Daroussin * non-decimal numbers). If the stored decimal is subsequent to 331*61d06d6bSBaptiste Daroussin * ours, make our size longer by that difference 332*61d06d6bSBaptiste Daroussin * (right-"shifting"); similarly, if ours is subsequent the 333*61d06d6bSBaptiste Daroussin * stored, then extend the stored size by the difference. 334*61d06d6bSBaptiste Daroussin * Finally, re-assign the stored values. 335*61d06d6bSBaptiste Daroussin */ 336*61d06d6bSBaptiste Daroussin 337*61d06d6bSBaptiste Daroussin str = dp->string ? dp->string : ""; 338*61d06d6bSBaptiste Daroussin sz = (*tbl->slen)(str, tbl->arg); 339*61d06d6bSBaptiste Daroussin 340*61d06d6bSBaptiste Daroussin /* FIXME: TBL_DATA_HORIZ et al.? */ 341*61d06d6bSBaptiste Daroussin 342*61d06d6bSBaptiste Daroussin buf[0] = opts->decimal; 343*61d06d6bSBaptiste Daroussin buf[1] = '\0'; 344*61d06d6bSBaptiste Daroussin 345*61d06d6bSBaptiste Daroussin psz = (*tbl->slen)(buf, tbl->arg); 346*61d06d6bSBaptiste Daroussin 347*61d06d6bSBaptiste Daroussin if (NULL != (cp = strrchr(str, opts->decimal))) { 348*61d06d6bSBaptiste Daroussin buf[1] = '\0'; 349*61d06d6bSBaptiste Daroussin for (ssz = 0, i = 0; cp != &str[i]; i++) { 350*61d06d6bSBaptiste Daroussin buf[0] = str[i]; 351*61d06d6bSBaptiste Daroussin ssz += (*tbl->slen)(buf, tbl->arg); 352*61d06d6bSBaptiste Daroussin } 353*61d06d6bSBaptiste Daroussin d = ssz + psz; 354*61d06d6bSBaptiste Daroussin } else 355*61d06d6bSBaptiste Daroussin d = sz + psz; 356*61d06d6bSBaptiste Daroussin 357*61d06d6bSBaptiste Daroussin /* Adjust the settings for this column. */ 358*61d06d6bSBaptiste Daroussin 359*61d06d6bSBaptiste Daroussin if (col->decimal > d) { 360*61d06d6bSBaptiste Daroussin sz += col->decimal - d; 361*61d06d6bSBaptiste Daroussin d = col->decimal; 362*61d06d6bSBaptiste Daroussin } else 363*61d06d6bSBaptiste Daroussin col->width += d - col->decimal; 364*61d06d6bSBaptiste Daroussin 365*61d06d6bSBaptiste Daroussin if (sz > col->width) 366*61d06d6bSBaptiste Daroussin col->width = sz; 367*61d06d6bSBaptiste Daroussin if (d > col->decimal) 368*61d06d6bSBaptiste Daroussin col->decimal = d; 369*61d06d6bSBaptiste Daroussin } 370