1241675Suqs/* $Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */ 2241675Suqs/* 3241675Suqs * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4241675Suqs * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> 5241675Suqs * 6241675Suqs * Permission to use, copy, modify, and distribute this software for any 7241675Suqs * purpose with or without fee is hereby granted, provided that the above 8241675Suqs * copyright notice and this permission notice appear in all copies. 9241675Suqs * 10241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17241675Suqs */ 18241675Suqs#ifdef HAVE_CONFIG_H 19241675Suqs#include "config.h" 20241675Suqs#endif 21241675Suqs 22241675Suqs#include <sys/types.h> 23241675Suqs 24241675Suqs#include <assert.h> 25241675Suqs#include <ctype.h> 26241675Suqs#include <stdio.h> 27241675Suqs#include <stdlib.h> 28241675Suqs#include <string.h> 29241675Suqs#include <time.h> 30241675Suqs 31241675Suqs#include "mandoc.h" 32241675Suqs#include "out.h" 33241675Suqs 34241675Suqsstatic void tblcalc_data(struct rofftbl *, struct roffcol *, 35241675Suqs const struct tbl *, const struct tbl_dat *); 36241675Suqsstatic void tblcalc_literal(struct rofftbl *, struct roffcol *, 37241675Suqs const struct tbl_dat *); 38241675Suqsstatic void tblcalc_number(struct rofftbl *, struct roffcol *, 39241675Suqs const struct tbl *, const struct tbl_dat *); 40241675Suqs 41241675Suqs/* 42241675Suqs * Convert a `scaling unit' to a consistent form, or fail. Scaling 43241675Suqs * units are documented in groff.7, mdoc.7, man.7. 44241675Suqs */ 45241675Suqsint 46241675Suqsa2roffsu(const char *src, struct roffsu *dst, enum roffscale def) 47241675Suqs{ 48241675Suqs char buf[BUFSIZ], hasd; 49241675Suqs int i; 50241675Suqs enum roffscale unit; 51241675Suqs 52241675Suqs if ('\0' == *src) 53241675Suqs return(0); 54241675Suqs 55241675Suqs i = hasd = 0; 56241675Suqs 57241675Suqs switch (*src) { 58241675Suqs case ('+'): 59241675Suqs src++; 60241675Suqs break; 61241675Suqs case ('-'): 62241675Suqs buf[i++] = *src++; 63241675Suqs break; 64241675Suqs default: 65241675Suqs break; 66241675Suqs } 67241675Suqs 68241675Suqs if ('\0' == *src) 69241675Suqs return(0); 70241675Suqs 71241675Suqs while (i < BUFSIZ) { 72241675Suqs if ( ! isdigit((unsigned char)*src)) { 73241675Suqs if ('.' != *src) 74241675Suqs break; 75241675Suqs else if (hasd) 76241675Suqs break; 77241675Suqs else 78241675Suqs hasd = 1; 79241675Suqs } 80241675Suqs buf[i++] = *src++; 81241675Suqs } 82241675Suqs 83241675Suqs if (BUFSIZ == i || (*src && *(src + 1))) 84241675Suqs return(0); 85241675Suqs 86241675Suqs buf[i] = '\0'; 87241675Suqs 88241675Suqs switch (*src) { 89241675Suqs case ('c'): 90241675Suqs unit = SCALE_CM; 91241675Suqs break; 92241675Suqs case ('i'): 93241675Suqs unit = SCALE_IN; 94241675Suqs break; 95241675Suqs case ('P'): 96241675Suqs unit = SCALE_PC; 97241675Suqs break; 98241675Suqs case ('p'): 99241675Suqs unit = SCALE_PT; 100241675Suqs break; 101241675Suqs case ('f'): 102241675Suqs unit = SCALE_FS; 103241675Suqs break; 104241675Suqs case ('v'): 105241675Suqs unit = SCALE_VS; 106241675Suqs break; 107241675Suqs case ('m'): 108241675Suqs unit = SCALE_EM; 109241675Suqs break; 110241675Suqs case ('\0'): 111241675Suqs if (SCALE_MAX == def) 112241675Suqs return(0); 113241675Suqs unit = SCALE_BU; 114241675Suqs break; 115241675Suqs case ('u'): 116241675Suqs unit = SCALE_BU; 117241675Suqs break; 118241675Suqs case ('M'): 119241675Suqs unit = SCALE_MM; 120241675Suqs break; 121241675Suqs case ('n'): 122241675Suqs unit = SCALE_EN; 123241675Suqs break; 124241675Suqs default: 125241675Suqs return(0); 126241675Suqs } 127241675Suqs 128241675Suqs /* FIXME: do this in the caller. */ 129241675Suqs if ((dst->scale = atof(buf)) < 0) 130241675Suqs dst->scale = 0; 131241675Suqs dst->unit = unit; 132241675Suqs return(1); 133241675Suqs} 134241675Suqs 135241675Suqs/* 136241675Suqs * Calculate the abstract widths and decimal positions of columns in a 137241675Suqs * table. This routine allocates the columns structures then runs over 138241675Suqs * all rows and cells in the table. The function pointers in "tbl" are 139241675Suqs * used for the actual width calculations. 140241675Suqs */ 141241675Suqsvoid 142241675Suqstblcalc(struct rofftbl *tbl, const struct tbl_span *sp) 143241675Suqs{ 144241675Suqs const struct tbl_dat *dp; 145241675Suqs const struct tbl_head *hp; 146241675Suqs struct roffcol *col; 147241675Suqs int spans; 148241675Suqs 149241675Suqs /* 150241675Suqs * Allocate the master column specifiers. These will hold the 151241675Suqs * widths and decimal positions for all cells in the column. It 152241675Suqs * must be freed and nullified by the caller. 153241675Suqs */ 154241675Suqs 155241675Suqs assert(NULL == tbl->cols); 156241675Suqs tbl->cols = mandoc_calloc 157241675Suqs ((size_t)sp->tbl->cols, sizeof(struct roffcol)); 158241675Suqs 159241675Suqs hp = sp->head; 160241675Suqs 161241675Suqs for ( ; sp; sp = sp->next) { 162241675Suqs if (TBL_SPAN_DATA != sp->pos) 163241675Suqs continue; 164241675Suqs spans = 1; 165241675Suqs /* 166241675Suqs * Account for the data cells in the layout, matching it 167241675Suqs * to data cells in the data section. 168241675Suqs */ 169241675Suqs for (dp = sp->first; dp; dp = dp->next) { 170241675Suqs /* Do not used spanned cells in the calculation. */ 171241675Suqs if (0 < --spans) 172241675Suqs continue; 173241675Suqs spans = dp->spans; 174241675Suqs if (1 < spans) 175241675Suqs continue; 176241675Suqs assert(dp->layout); 177241675Suqs col = &tbl->cols[dp->layout->head->ident]; 178241675Suqs tblcalc_data(tbl, col, sp->tbl, dp); 179241675Suqs } 180241675Suqs } 181241675Suqs 182241675Suqs /* 183241675Suqs * Calculate width of the spanners. These get one space for a 184241675Suqs * vertical line, two for a double-vertical line. 185241675Suqs */ 186241675Suqs 187241675Suqs for ( ; hp; hp = hp->next) { 188241675Suqs col = &tbl->cols[hp->ident]; 189241675Suqs switch (hp->pos) { 190241675Suqs case (TBL_HEAD_VERT): 191241675Suqs col->width = (*tbl->len)(1, tbl->arg); 192241675Suqs break; 193241675Suqs case (TBL_HEAD_DVERT): 194241675Suqs col->width = (*tbl->len)(2, tbl->arg); 195241675Suqs break; 196241675Suqs default: 197241675Suqs break; 198241675Suqs } 199241675Suqs } 200241675Suqs} 201241675Suqs 202241675Suqsstatic void 203241675Suqstblcalc_data(struct rofftbl *tbl, struct roffcol *col, 204241675Suqs const struct tbl *tp, const struct tbl_dat *dp) 205241675Suqs{ 206241675Suqs size_t sz; 207241675Suqs 208241675Suqs /* Branch down into data sub-types. */ 209241675Suqs 210241675Suqs switch (dp->layout->pos) { 211241675Suqs case (TBL_CELL_HORIZ): 212241675Suqs /* FALLTHROUGH */ 213241675Suqs case (TBL_CELL_DHORIZ): 214241675Suqs sz = (*tbl->len)(1, tbl->arg); 215241675Suqs if (col->width < sz) 216241675Suqs col->width = sz; 217241675Suqs break; 218241675Suqs case (TBL_CELL_LONG): 219241675Suqs /* FALLTHROUGH */ 220241675Suqs case (TBL_CELL_CENTRE): 221241675Suqs /* FALLTHROUGH */ 222241675Suqs case (TBL_CELL_LEFT): 223241675Suqs /* FALLTHROUGH */ 224241675Suqs case (TBL_CELL_RIGHT): 225241675Suqs tblcalc_literal(tbl, col, dp); 226241675Suqs break; 227241675Suqs case (TBL_CELL_NUMBER): 228241675Suqs tblcalc_number(tbl, col, tp, dp); 229241675Suqs break; 230241675Suqs case (TBL_CELL_DOWN): 231241675Suqs break; 232241675Suqs default: 233241675Suqs abort(); 234241675Suqs /* NOTREACHED */ 235241675Suqs } 236241675Suqs} 237241675Suqs 238241675Suqsstatic void 239241675Suqstblcalc_literal(struct rofftbl *tbl, struct roffcol *col, 240241675Suqs const struct tbl_dat *dp) 241241675Suqs{ 242241675Suqs size_t sz; 243241675Suqs const char *str; 244241675Suqs 245241675Suqs str = dp->string ? dp->string : ""; 246241675Suqs sz = (*tbl->slen)(str, tbl->arg); 247241675Suqs 248241675Suqs if (col->width < sz) 249241675Suqs col->width = sz; 250241675Suqs} 251241675Suqs 252241675Suqsstatic void 253241675Suqstblcalc_number(struct rofftbl *tbl, struct roffcol *col, 254241675Suqs const struct tbl *tp, const struct tbl_dat *dp) 255241675Suqs{ 256241675Suqs int i; 257241675Suqs size_t sz, psz, ssz, d; 258241675Suqs const char *str; 259241675Suqs char *cp; 260241675Suqs char buf[2]; 261241675Suqs 262241675Suqs /* 263241675Suqs * First calculate number width and decimal place (last + 1 for 264241675Suqs * non-decimal numbers). If the stored decimal is subsequent to 265241675Suqs * ours, make our size longer by that difference 266241675Suqs * (right-"shifting"); similarly, if ours is subsequent the 267241675Suqs * stored, then extend the stored size by the difference. 268241675Suqs * Finally, re-assign the stored values. 269241675Suqs */ 270241675Suqs 271241675Suqs str = dp->string ? dp->string : ""; 272241675Suqs sz = (*tbl->slen)(str, tbl->arg); 273241675Suqs 274241675Suqs /* FIXME: TBL_DATA_HORIZ et al.? */ 275241675Suqs 276241675Suqs buf[0] = tp->decimal; 277241675Suqs buf[1] = '\0'; 278241675Suqs 279241675Suqs psz = (*tbl->slen)(buf, tbl->arg); 280241675Suqs 281241675Suqs if (NULL != (cp = strrchr(str, tp->decimal))) { 282241675Suqs buf[1] = '\0'; 283241675Suqs for (ssz = 0, i = 0; cp != &str[i]; i++) { 284241675Suqs buf[0] = str[i]; 285241675Suqs ssz += (*tbl->slen)(buf, tbl->arg); 286241675Suqs } 287241675Suqs d = ssz + psz; 288241675Suqs } else 289241675Suqs d = sz + psz; 290241675Suqs 291241675Suqs /* Adjust the settings for this column. */ 292241675Suqs 293241675Suqs if (col->decimal > d) { 294241675Suqs sz += col->decimal - d; 295241675Suqs d = col->decimal; 296241675Suqs } else 297241675Suqs col->width += d - col->decimal; 298241675Suqs 299241675Suqs if (sz > col->width) 300241675Suqs col->width = sz; 301241675Suqs if (d > col->decimal) 302241675Suqs col->decimal = d; 303241675Suqs} 304