1*95c635efSGarrett D'Amore /* $Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */ 2*95c635efSGarrett D'Amore /* 3*95c635efSGarrett D'Amore * Copyright (c) 2009, 2010, 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 <sys/types.h> 23*95c635efSGarrett D'Amore 24*95c635efSGarrett D'Amore #include <assert.h> 25*95c635efSGarrett D'Amore #include <ctype.h> 26*95c635efSGarrett D'Amore #include <stdio.h> 27*95c635efSGarrett D'Amore #include <stdlib.h> 28*95c635efSGarrett D'Amore #include <string.h> 29*95c635efSGarrett D'Amore #include <time.h> 30*95c635efSGarrett D'Amore 31*95c635efSGarrett D'Amore #include "mandoc.h" 32*95c635efSGarrett D'Amore #include "out.h" 33*95c635efSGarrett D'Amore 34*95c635efSGarrett D'Amore static void tblcalc_data(struct rofftbl *, struct roffcol *, 35*95c635efSGarrett D'Amore const struct tbl *, const struct tbl_dat *); 36*95c635efSGarrett D'Amore static void tblcalc_literal(struct rofftbl *, struct roffcol *, 37*95c635efSGarrett D'Amore const struct tbl_dat *); 38*95c635efSGarrett D'Amore static void tblcalc_number(struct rofftbl *, struct roffcol *, 39*95c635efSGarrett D'Amore const struct tbl *, const struct tbl_dat *); 40*95c635efSGarrett D'Amore 41*95c635efSGarrett D'Amore /* 42*95c635efSGarrett D'Amore * Convert a `scaling unit' to a consistent form, or fail. Scaling 43*95c635efSGarrett D'Amore * units are documented in groff.7, mdoc.7, man.7. 44*95c635efSGarrett D'Amore */ 45*95c635efSGarrett D'Amore int 46*95c635efSGarrett D'Amore a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) 47*95c635efSGarrett D'Amore { 48*95c635efSGarrett D'Amore char buf[BUFSIZ], hasd; 49*95c635efSGarrett D'Amore int i; 50*95c635efSGarrett D'Amore enum roffscale unit; 51*95c635efSGarrett D'Amore 52*95c635efSGarrett D'Amore if ('\0' == *src) 53*95c635efSGarrett D'Amore return(0); 54*95c635efSGarrett D'Amore 55*95c635efSGarrett D'Amore i = hasd = 0; 56*95c635efSGarrett D'Amore 57*95c635efSGarrett D'Amore switch (*src) { 58*95c635efSGarrett D'Amore case ('+'): 59*95c635efSGarrett D'Amore src++; 60*95c635efSGarrett D'Amore break; 61*95c635efSGarrett D'Amore case ('-'): 62*95c635efSGarrett D'Amore buf[i++] = *src++; 63*95c635efSGarrett D'Amore break; 64*95c635efSGarrett D'Amore default: 65*95c635efSGarrett D'Amore break; 66*95c635efSGarrett D'Amore } 67*95c635efSGarrett D'Amore 68*95c635efSGarrett D'Amore if ('\0' == *src) 69*95c635efSGarrett D'Amore return(0); 70*95c635efSGarrett D'Amore 71*95c635efSGarrett D'Amore while (i < BUFSIZ) { 72*95c635efSGarrett D'Amore if ( ! isdigit((unsigned char)*src)) { 73*95c635efSGarrett D'Amore if ('.' != *src) 74*95c635efSGarrett D'Amore break; 75*95c635efSGarrett D'Amore else if (hasd) 76*95c635efSGarrett D'Amore break; 77*95c635efSGarrett D'Amore else 78*95c635efSGarrett D'Amore hasd = 1; 79*95c635efSGarrett D'Amore } 80*95c635efSGarrett D'Amore buf[i++] = *src++; 81*95c635efSGarrett D'Amore } 82*95c635efSGarrett D'Amore 83*95c635efSGarrett D'Amore if (BUFSIZ == i || (*src && *(src + 1))) 84*95c635efSGarrett D'Amore return(0); 85*95c635efSGarrett D'Amore 86*95c635efSGarrett D'Amore buf[i] = '\0'; 87*95c635efSGarrett D'Amore 88*95c635efSGarrett D'Amore switch (*src) { 89*95c635efSGarrett D'Amore case ('c'): 90*95c635efSGarrett D'Amore unit = SCALE_CM; 91*95c635efSGarrett D'Amore break; 92*95c635efSGarrett D'Amore case ('i'): 93*95c635efSGarrett D'Amore unit = SCALE_IN; 94*95c635efSGarrett D'Amore break; 95*95c635efSGarrett D'Amore case ('P'): 96*95c635efSGarrett D'Amore unit = SCALE_PC; 97*95c635efSGarrett D'Amore break; 98*95c635efSGarrett D'Amore case ('p'): 99*95c635efSGarrett D'Amore unit = SCALE_PT; 100*95c635efSGarrett D'Amore break; 101*95c635efSGarrett D'Amore case ('f'): 102*95c635efSGarrett D'Amore unit = SCALE_FS; 103*95c635efSGarrett D'Amore break; 104*95c635efSGarrett D'Amore case ('v'): 105*95c635efSGarrett D'Amore unit = SCALE_VS; 106*95c635efSGarrett D'Amore break; 107*95c635efSGarrett D'Amore case ('m'): 108*95c635efSGarrett D'Amore unit = SCALE_EM; 109*95c635efSGarrett D'Amore break; 110*95c635efSGarrett D'Amore case ('\0'): 111*95c635efSGarrett D'Amore if (SCALE_MAX == def) 112*95c635efSGarrett D'Amore return(0); 113*95c635efSGarrett D'Amore unit = SCALE_BU; 114*95c635efSGarrett D'Amore break; 115*95c635efSGarrett D'Amore case ('u'): 116*95c635efSGarrett D'Amore unit = SCALE_BU; 117*95c635efSGarrett D'Amore break; 118*95c635efSGarrett D'Amore case ('M'): 119*95c635efSGarrett D'Amore unit = SCALE_MM; 120*95c635efSGarrett D'Amore break; 121*95c635efSGarrett D'Amore case ('n'): 122*95c635efSGarrett D'Amore unit = SCALE_EN; 123*95c635efSGarrett D'Amore break; 124*95c635efSGarrett D'Amore default: 125*95c635efSGarrett D'Amore return(0); 126*95c635efSGarrett D'Amore } 127*95c635efSGarrett D'Amore 128*95c635efSGarrett D'Amore /* FIXME: do this in the caller. */ 129*95c635efSGarrett D'Amore if ((dst->scale = atof(buf)) < 0) 130*95c635efSGarrett D'Amore dst->scale = 0; 131*95c635efSGarrett D'Amore dst->unit = unit; 132*95c635efSGarrett D'Amore return(1); 133*95c635efSGarrett D'Amore } 134*95c635efSGarrett D'Amore 135*95c635efSGarrett D'Amore /* 136*95c635efSGarrett D'Amore * Calculate the abstract widths and decimal positions of columns in a 137*95c635efSGarrett D'Amore * table. This routine allocates the columns structures then runs over 138*95c635efSGarrett D'Amore * all rows and cells in the table. The function pointers in "tbl" are 139*95c635efSGarrett D'Amore * used for the actual width calculations. 140*95c635efSGarrett D'Amore */ 141*95c635efSGarrett D'Amore void 142*95c635efSGarrett D'Amore tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) 143*95c635efSGarrett D'Amore { 144*95c635efSGarrett D'Amore const struct tbl_dat *dp; 145*95c635efSGarrett D'Amore const struct tbl_head *hp; 146*95c635efSGarrett D'Amore struct roffcol *col; 147*95c635efSGarrett D'Amore int spans; 148*95c635efSGarrett D'Amore 149*95c635efSGarrett D'Amore /* 150*95c635efSGarrett D'Amore * Allocate the master column specifiers. These will hold the 151*95c635efSGarrett D'Amore * widths and decimal positions for all cells in the column. It 152*95c635efSGarrett D'Amore * must be freed and nullified by the caller. 153*95c635efSGarrett D'Amore */ 154*95c635efSGarrett D'Amore 155*95c635efSGarrett D'Amore assert(NULL == tbl->cols); 156*95c635efSGarrett D'Amore tbl->cols = mandoc_calloc 157*95c635efSGarrett D'Amore ((size_t)sp->tbl->cols, sizeof(struct roffcol)); 158*95c635efSGarrett D'Amore 159*95c635efSGarrett D'Amore hp = sp->head; 160*95c635efSGarrett D'Amore 161*95c635efSGarrett D'Amore for ( ; sp; sp = sp->next) { 162*95c635efSGarrett D'Amore if (TBL_SPAN_DATA != sp->pos) 163*95c635efSGarrett D'Amore continue; 164*95c635efSGarrett D'Amore spans = 1; 165*95c635efSGarrett D'Amore /* 166*95c635efSGarrett D'Amore * Account for the data cells in the layout, matching it 167*95c635efSGarrett D'Amore * to data cells in the data section. 168*95c635efSGarrett D'Amore */ 169*95c635efSGarrett D'Amore for (dp = sp->first; dp; dp = dp->next) { 170*95c635efSGarrett D'Amore /* Do not used spanned cells in the calculation. */ 171*95c635efSGarrett D'Amore if (0 < --spans) 172*95c635efSGarrett D'Amore continue; 173*95c635efSGarrett D'Amore spans = dp->spans; 174*95c635efSGarrett D'Amore if (1 < spans) 175*95c635efSGarrett D'Amore continue; 176*95c635efSGarrett D'Amore assert(dp->layout); 177*95c635efSGarrett D'Amore col = &tbl->cols[dp->layout->head->ident]; 178*95c635efSGarrett D'Amore tblcalc_data(tbl, col, sp->tbl, dp); 179*95c635efSGarrett D'Amore } 180*95c635efSGarrett D'Amore } 181*95c635efSGarrett D'Amore 182*95c635efSGarrett D'Amore /* 183*95c635efSGarrett D'Amore * Calculate width of the spanners. These get one space for a 184*95c635efSGarrett D'Amore * vertical line, two for a double-vertical line. 185*95c635efSGarrett D'Amore */ 186*95c635efSGarrett D'Amore 187*95c635efSGarrett D'Amore for ( ; hp; hp = hp->next) { 188*95c635efSGarrett D'Amore col = &tbl->cols[hp->ident]; 189*95c635efSGarrett D'Amore switch (hp->pos) { 190*95c635efSGarrett D'Amore case (TBL_HEAD_VERT): 191*95c635efSGarrett D'Amore col->width = (*tbl->len)(1, tbl->arg); 192*95c635efSGarrett D'Amore break; 193*95c635efSGarrett D'Amore case (TBL_HEAD_DVERT): 194*95c635efSGarrett D'Amore col->width = (*tbl->len)(2, tbl->arg); 195*95c635efSGarrett D'Amore break; 196*95c635efSGarrett D'Amore default: 197*95c635efSGarrett D'Amore break; 198*95c635efSGarrett D'Amore } 199*95c635efSGarrett D'Amore } 200*95c635efSGarrett D'Amore } 201*95c635efSGarrett D'Amore 202*95c635efSGarrett D'Amore static void 203*95c635efSGarrett D'Amore tblcalc_data(struct rofftbl *tbl, struct roffcol *col, 204*95c635efSGarrett D'Amore const struct tbl *tp, const struct tbl_dat *dp) 205*95c635efSGarrett D'Amore { 206*95c635efSGarrett D'Amore size_t sz; 207*95c635efSGarrett D'Amore 208*95c635efSGarrett D'Amore /* Branch down into data sub-types. */ 209*95c635efSGarrett D'Amore 210*95c635efSGarrett D'Amore switch (dp->layout->pos) { 211*95c635efSGarrett D'Amore case (TBL_CELL_HORIZ): 212*95c635efSGarrett D'Amore /* FALLTHROUGH */ 213*95c635efSGarrett D'Amore case (TBL_CELL_DHORIZ): 214*95c635efSGarrett D'Amore sz = (*tbl->len)(1, tbl->arg); 215*95c635efSGarrett D'Amore if (col->width < sz) 216*95c635efSGarrett D'Amore col->width = sz; 217*95c635efSGarrett D'Amore break; 218*95c635efSGarrett D'Amore case (TBL_CELL_LONG): 219*95c635efSGarrett D'Amore /* FALLTHROUGH */ 220*95c635efSGarrett D'Amore case (TBL_CELL_CENTRE): 221*95c635efSGarrett D'Amore /* FALLTHROUGH */ 222*95c635efSGarrett D'Amore case (TBL_CELL_LEFT): 223*95c635efSGarrett D'Amore /* FALLTHROUGH */ 224*95c635efSGarrett D'Amore case (TBL_CELL_RIGHT): 225*95c635efSGarrett D'Amore tblcalc_literal(tbl, col, dp); 226*95c635efSGarrett D'Amore break; 227*95c635efSGarrett D'Amore case (TBL_CELL_NUMBER): 228*95c635efSGarrett D'Amore tblcalc_number(tbl, col, tp, dp); 229*95c635efSGarrett D'Amore break; 230*95c635efSGarrett D'Amore case (TBL_CELL_DOWN): 231*95c635efSGarrett D'Amore break; 232*95c635efSGarrett D'Amore default: 233*95c635efSGarrett D'Amore abort(); 234*95c635efSGarrett D'Amore /* NOTREACHED */ 235*95c635efSGarrett D'Amore } 236*95c635efSGarrett D'Amore } 237*95c635efSGarrett D'Amore 238*95c635efSGarrett D'Amore static void 239*95c635efSGarrett D'Amore tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, 240*95c635efSGarrett D'Amore const struct tbl_dat *dp) 241*95c635efSGarrett D'Amore { 242*95c635efSGarrett D'Amore size_t sz; 243*95c635efSGarrett D'Amore const char *str; 244*95c635efSGarrett D'Amore 245*95c635efSGarrett D'Amore str = dp->string ? dp->string : ""; 246*95c635efSGarrett D'Amore sz = (*tbl->slen)(str, tbl->arg); 247*95c635efSGarrett D'Amore 248*95c635efSGarrett D'Amore if (col->width < sz) 249*95c635efSGarrett D'Amore col->width = sz; 250*95c635efSGarrett D'Amore } 251*95c635efSGarrett D'Amore 252*95c635efSGarrett D'Amore static void 253*95c635efSGarrett D'Amore tblcalc_number(struct rofftbl *tbl, struct roffcol *col, 254*95c635efSGarrett D'Amore const struct tbl *tp, const struct tbl_dat *dp) 255*95c635efSGarrett D'Amore { 256*95c635efSGarrett D'Amore int i; 257*95c635efSGarrett D'Amore size_t sz, psz, ssz, d; 258*95c635efSGarrett D'Amore const char *str; 259*95c635efSGarrett D'Amore char *cp; 260*95c635efSGarrett D'Amore char buf[2]; 261*95c635efSGarrett D'Amore 262*95c635efSGarrett D'Amore /* 263*95c635efSGarrett D'Amore * First calculate number width and decimal place (last + 1 for 264*95c635efSGarrett D'Amore * non-decimal numbers). If the stored decimal is subsequent to 265*95c635efSGarrett D'Amore * ours, make our size longer by that difference 266*95c635efSGarrett D'Amore * (right-"shifting"); similarly, if ours is subsequent the 267*95c635efSGarrett D'Amore * stored, then extend the stored size by the difference. 268*95c635efSGarrett D'Amore * Finally, re-assign the stored values. 269*95c635efSGarrett D'Amore */ 270*95c635efSGarrett D'Amore 271*95c635efSGarrett D'Amore str = dp->string ? dp->string : ""; 272*95c635efSGarrett D'Amore sz = (*tbl->slen)(str, tbl->arg); 273*95c635efSGarrett D'Amore 274*95c635efSGarrett D'Amore /* FIXME: TBL_DATA_HORIZ et al.? */ 275*95c635efSGarrett D'Amore 276*95c635efSGarrett D'Amore buf[0] = tp->decimal; 277*95c635efSGarrett D'Amore buf[1] = '\0'; 278*95c635efSGarrett D'Amore 279*95c635efSGarrett D'Amore psz = (*tbl->slen)(buf, tbl->arg); 280*95c635efSGarrett D'Amore 281*95c635efSGarrett D'Amore if (NULL != (cp = strrchr(str, tp->decimal))) { 282*95c635efSGarrett D'Amore buf[1] = '\0'; 283*95c635efSGarrett D'Amore for (ssz = 0, i = 0; cp != &str[i]; i++) { 284*95c635efSGarrett D'Amore buf[0] = str[i]; 285*95c635efSGarrett D'Amore ssz += (*tbl->slen)(buf, tbl->arg); 286*95c635efSGarrett D'Amore } 287*95c635efSGarrett D'Amore d = ssz + psz; 288*95c635efSGarrett D'Amore } else 289*95c635efSGarrett D'Amore d = sz + psz; 290*95c635efSGarrett D'Amore 291*95c635efSGarrett D'Amore /* Adjust the settings for this column. */ 292*95c635efSGarrett D'Amore 293*95c635efSGarrett D'Amore if (col->decimal > d) { 294*95c635efSGarrett D'Amore sz += col->decimal - d; 295*95c635efSGarrett D'Amore d = col->decimal; 296*95c635efSGarrett D'Amore } else 297*95c635efSGarrett D'Amore col->width += d - col->decimal; 298*95c635efSGarrett D'Amore 299*95c635efSGarrett D'Amore if (sz > col->width) 300*95c635efSGarrett D'Amore col->width = sz; 301*95c635efSGarrett D'Amore if (d > col->decimal) 302*95c635efSGarrett D'Amore col->decimal = d; 303*95c635efSGarrett D'Amore } 304