1*698f87a4SGarrett D'Amore /* $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 495c635efSGarrett D'Amore * Copyright (c) 2011 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 <sys/types.h> 2395c635efSGarrett D'Amore 2495c635efSGarrett D'Amore #include <assert.h> 2595c635efSGarrett D'Amore #include <ctype.h> 2695c635efSGarrett D'Amore #include <stdio.h> 2795c635efSGarrett D'Amore #include <stdlib.h> 2895c635efSGarrett D'Amore #include <string.h> 2995c635efSGarrett D'Amore #include <time.h> 3095c635efSGarrett D'Amore 3195c635efSGarrett D'Amore #include "mandoc.h" 3295c635efSGarrett D'Amore #include "out.h" 3395c635efSGarrett D'Amore 3495c635efSGarrett D'Amore static void tblcalc_data(struct rofftbl *, struct roffcol *, 35*698f87a4SGarrett D'Amore const struct tbl_opts *, const struct tbl_dat *); 3695c635efSGarrett D'Amore static void tblcalc_literal(struct rofftbl *, struct roffcol *, 3795c635efSGarrett D'Amore const struct tbl_dat *); 3895c635efSGarrett D'Amore static void tblcalc_number(struct rofftbl *, struct roffcol *, 39*698f87a4SGarrett D'Amore const struct tbl_opts *, const struct tbl_dat *); 4095c635efSGarrett D'Amore 4195c635efSGarrett D'Amore /* 4295c635efSGarrett D'Amore * Convert a `scaling unit' to a consistent form, or fail. Scaling 4395c635efSGarrett D'Amore * units are documented in groff.7, mdoc.7, man.7. 4495c635efSGarrett D'Amore */ 4595c635efSGarrett D'Amore int 4695c635efSGarrett D'Amore a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) 4795c635efSGarrett D'Amore { 4895c635efSGarrett D'Amore char buf[BUFSIZ], hasd; 4995c635efSGarrett D'Amore int i; 5095c635efSGarrett D'Amore enum roffscale unit; 5195c635efSGarrett D'Amore 5295c635efSGarrett D'Amore if ('\0' == *src) 5395c635efSGarrett D'Amore return(0); 5495c635efSGarrett D'Amore 5595c635efSGarrett D'Amore i = hasd = 0; 5695c635efSGarrett D'Amore 5795c635efSGarrett D'Amore switch (*src) { 5895c635efSGarrett D'Amore case ('+'): 5995c635efSGarrett D'Amore src++; 6095c635efSGarrett D'Amore break; 6195c635efSGarrett D'Amore case ('-'): 6295c635efSGarrett D'Amore buf[i++] = *src++; 6395c635efSGarrett D'Amore break; 6495c635efSGarrett D'Amore default: 6595c635efSGarrett D'Amore break; 6695c635efSGarrett D'Amore } 6795c635efSGarrett D'Amore 6895c635efSGarrett D'Amore if ('\0' == *src) 6995c635efSGarrett D'Amore return(0); 7095c635efSGarrett D'Amore 7195c635efSGarrett D'Amore while (i < BUFSIZ) { 7295c635efSGarrett D'Amore if ( ! isdigit((unsigned char)*src)) { 7395c635efSGarrett D'Amore if ('.' != *src) 7495c635efSGarrett D'Amore break; 7595c635efSGarrett D'Amore else if (hasd) 7695c635efSGarrett D'Amore break; 7795c635efSGarrett D'Amore else 7895c635efSGarrett D'Amore hasd = 1; 7995c635efSGarrett D'Amore } 8095c635efSGarrett D'Amore buf[i++] = *src++; 8195c635efSGarrett D'Amore } 8295c635efSGarrett D'Amore 8395c635efSGarrett D'Amore if (BUFSIZ == i || (*src && *(src + 1))) 8495c635efSGarrett D'Amore return(0); 8595c635efSGarrett D'Amore 8695c635efSGarrett D'Amore buf[i] = '\0'; 8795c635efSGarrett D'Amore 8895c635efSGarrett D'Amore switch (*src) { 8995c635efSGarrett D'Amore case ('c'): 9095c635efSGarrett D'Amore unit = SCALE_CM; 9195c635efSGarrett D'Amore break; 9295c635efSGarrett D'Amore case ('i'): 9395c635efSGarrett D'Amore unit = SCALE_IN; 9495c635efSGarrett D'Amore break; 9595c635efSGarrett D'Amore case ('P'): 9695c635efSGarrett D'Amore unit = SCALE_PC; 9795c635efSGarrett D'Amore break; 9895c635efSGarrett D'Amore case ('p'): 9995c635efSGarrett D'Amore unit = SCALE_PT; 10095c635efSGarrett D'Amore break; 10195c635efSGarrett D'Amore case ('f'): 10295c635efSGarrett D'Amore unit = SCALE_FS; 10395c635efSGarrett D'Amore break; 10495c635efSGarrett D'Amore case ('v'): 10595c635efSGarrett D'Amore unit = SCALE_VS; 10695c635efSGarrett D'Amore break; 10795c635efSGarrett D'Amore case ('m'): 10895c635efSGarrett D'Amore unit = SCALE_EM; 10995c635efSGarrett D'Amore break; 11095c635efSGarrett D'Amore case ('\0'): 11195c635efSGarrett D'Amore if (SCALE_MAX == def) 11295c635efSGarrett D'Amore return(0); 11395c635efSGarrett D'Amore unit = SCALE_BU; 11495c635efSGarrett D'Amore break; 11595c635efSGarrett D'Amore case ('u'): 11695c635efSGarrett D'Amore unit = SCALE_BU; 11795c635efSGarrett D'Amore break; 11895c635efSGarrett D'Amore case ('M'): 11995c635efSGarrett D'Amore unit = SCALE_MM; 12095c635efSGarrett D'Amore break; 12195c635efSGarrett D'Amore case ('n'): 12295c635efSGarrett D'Amore unit = SCALE_EN; 12395c635efSGarrett D'Amore break; 12495c635efSGarrett D'Amore default: 12595c635efSGarrett D'Amore return(0); 12695c635efSGarrett D'Amore } 12795c635efSGarrett D'Amore 12895c635efSGarrett D'Amore /* FIXME: do this in the caller. */ 12995c635efSGarrett D'Amore if ((dst->scale = atof(buf)) < 0) 13095c635efSGarrett D'Amore dst->scale = 0; 13195c635efSGarrett D'Amore dst->unit = unit; 13295c635efSGarrett D'Amore return(1); 13395c635efSGarrett D'Amore } 13495c635efSGarrett D'Amore 13595c635efSGarrett D'Amore /* 13695c635efSGarrett D'Amore * Calculate the abstract widths and decimal positions of columns in a 13795c635efSGarrett D'Amore * table. This routine allocates the columns structures then runs over 13895c635efSGarrett D'Amore * all rows and cells in the table. The function pointers in "tbl" are 13995c635efSGarrett D'Amore * used for the actual width calculations. 14095c635efSGarrett D'Amore */ 14195c635efSGarrett D'Amore void 14295c635efSGarrett D'Amore tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) 14395c635efSGarrett D'Amore { 14495c635efSGarrett D'Amore const struct tbl_dat *dp; 14595c635efSGarrett D'Amore struct roffcol *col; 14695c635efSGarrett D'Amore int spans; 14795c635efSGarrett D'Amore 14895c635efSGarrett D'Amore /* 14995c635efSGarrett D'Amore * Allocate the master column specifiers. These will hold the 15095c635efSGarrett D'Amore * widths and decimal positions for all cells in the column. It 15195c635efSGarrett D'Amore * must be freed and nullified by the caller. 15295c635efSGarrett D'Amore */ 15395c635efSGarrett D'Amore 15495c635efSGarrett D'Amore assert(NULL == tbl->cols); 15595c635efSGarrett D'Amore tbl->cols = mandoc_calloc 156*698f87a4SGarrett D'Amore ((size_t)sp->opts->cols, sizeof(struct roffcol)); 15795c635efSGarrett D'Amore 15895c635efSGarrett D'Amore for ( ; sp; sp = sp->next) { 15995c635efSGarrett D'Amore if (TBL_SPAN_DATA != sp->pos) 16095c635efSGarrett D'Amore continue; 16195c635efSGarrett D'Amore spans = 1; 16295c635efSGarrett D'Amore /* 16395c635efSGarrett D'Amore * Account for the data cells in the layout, matching it 16495c635efSGarrett D'Amore * to data cells in the data section. 16595c635efSGarrett D'Amore */ 16695c635efSGarrett D'Amore for (dp = sp->first; dp; dp = dp->next) { 16795c635efSGarrett D'Amore /* Do not used spanned cells in the calculation. */ 16895c635efSGarrett D'Amore if (0 < --spans) 16995c635efSGarrett D'Amore continue; 17095c635efSGarrett D'Amore spans = dp->spans; 17195c635efSGarrett D'Amore if (1 < spans) 17295c635efSGarrett D'Amore continue; 17395c635efSGarrett D'Amore assert(dp->layout); 17495c635efSGarrett D'Amore col = &tbl->cols[dp->layout->head->ident]; 175*698f87a4SGarrett D'Amore tblcalc_data(tbl, col, sp->opts, dp); 17695c635efSGarrett D'Amore } 17795c635efSGarrett D'Amore } 17895c635efSGarrett D'Amore } 17995c635efSGarrett D'Amore 18095c635efSGarrett D'Amore static void 18195c635efSGarrett D'Amore tblcalc_data(struct rofftbl *tbl, struct roffcol *col, 182*698f87a4SGarrett D'Amore const struct tbl_opts *opts, const struct tbl_dat *dp) 18395c635efSGarrett D'Amore { 18495c635efSGarrett D'Amore size_t sz; 18595c635efSGarrett D'Amore 18695c635efSGarrett D'Amore /* Branch down into data sub-types. */ 18795c635efSGarrett D'Amore 18895c635efSGarrett D'Amore switch (dp->layout->pos) { 18995c635efSGarrett D'Amore case (TBL_CELL_HORIZ): 19095c635efSGarrett D'Amore /* FALLTHROUGH */ 19195c635efSGarrett D'Amore case (TBL_CELL_DHORIZ): 19295c635efSGarrett D'Amore sz = (*tbl->len)(1, tbl->arg); 19395c635efSGarrett D'Amore if (col->width < sz) 19495c635efSGarrett D'Amore col->width = sz; 19595c635efSGarrett D'Amore break; 19695c635efSGarrett D'Amore case (TBL_CELL_LONG): 19795c635efSGarrett D'Amore /* FALLTHROUGH */ 19895c635efSGarrett D'Amore case (TBL_CELL_CENTRE): 19995c635efSGarrett D'Amore /* FALLTHROUGH */ 20095c635efSGarrett D'Amore case (TBL_CELL_LEFT): 20195c635efSGarrett D'Amore /* FALLTHROUGH */ 20295c635efSGarrett D'Amore case (TBL_CELL_RIGHT): 20395c635efSGarrett D'Amore tblcalc_literal(tbl, col, dp); 20495c635efSGarrett D'Amore break; 20595c635efSGarrett D'Amore case (TBL_CELL_NUMBER): 206*698f87a4SGarrett D'Amore tblcalc_number(tbl, col, opts, dp); 20795c635efSGarrett D'Amore break; 20895c635efSGarrett D'Amore case (TBL_CELL_DOWN): 20995c635efSGarrett D'Amore break; 21095c635efSGarrett D'Amore default: 21195c635efSGarrett D'Amore abort(); 21295c635efSGarrett D'Amore /* NOTREACHED */ 21395c635efSGarrett D'Amore } 21495c635efSGarrett D'Amore } 21595c635efSGarrett D'Amore 21695c635efSGarrett D'Amore static void 21795c635efSGarrett D'Amore tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, 21895c635efSGarrett D'Amore const struct tbl_dat *dp) 21995c635efSGarrett D'Amore { 22095c635efSGarrett D'Amore size_t sz; 22195c635efSGarrett D'Amore const char *str; 22295c635efSGarrett D'Amore 22395c635efSGarrett D'Amore str = dp->string ? dp->string : ""; 22495c635efSGarrett D'Amore sz = (*tbl->slen)(str, tbl->arg); 22595c635efSGarrett D'Amore 22695c635efSGarrett D'Amore if (col->width < sz) 22795c635efSGarrett D'Amore col->width = sz; 22895c635efSGarrett D'Amore } 22995c635efSGarrett D'Amore 23095c635efSGarrett D'Amore static void 23195c635efSGarrett D'Amore tblcalc_number(struct rofftbl *tbl, struct roffcol *col, 232*698f87a4SGarrett D'Amore const struct tbl_opts *opts, const struct tbl_dat *dp) 23395c635efSGarrett D'Amore { 23495c635efSGarrett D'Amore int i; 23595c635efSGarrett D'Amore size_t sz, psz, ssz, d; 23695c635efSGarrett D'Amore const char *str; 23795c635efSGarrett D'Amore char *cp; 23895c635efSGarrett D'Amore char buf[2]; 23995c635efSGarrett D'Amore 24095c635efSGarrett D'Amore /* 24195c635efSGarrett D'Amore * First calculate number width and decimal place (last + 1 for 24295c635efSGarrett D'Amore * non-decimal numbers). If the stored decimal is subsequent to 24395c635efSGarrett D'Amore * ours, make our size longer by that difference 24495c635efSGarrett D'Amore * (right-"shifting"); similarly, if ours is subsequent the 24595c635efSGarrett D'Amore * stored, then extend the stored size by the difference. 24695c635efSGarrett D'Amore * Finally, re-assign the stored values. 24795c635efSGarrett D'Amore */ 24895c635efSGarrett D'Amore 24995c635efSGarrett D'Amore str = dp->string ? dp->string : ""; 25095c635efSGarrett D'Amore sz = (*tbl->slen)(str, tbl->arg); 25195c635efSGarrett D'Amore 25295c635efSGarrett D'Amore /* FIXME: TBL_DATA_HORIZ et al.? */ 25395c635efSGarrett D'Amore 254*698f87a4SGarrett D'Amore buf[0] = opts->decimal; 25595c635efSGarrett D'Amore buf[1] = '\0'; 25695c635efSGarrett D'Amore 25795c635efSGarrett D'Amore psz = (*tbl->slen)(buf, tbl->arg); 25895c635efSGarrett D'Amore 259*698f87a4SGarrett D'Amore if (NULL != (cp = strrchr(str, opts->decimal))) { 26095c635efSGarrett D'Amore buf[1] = '\0'; 26195c635efSGarrett D'Amore for (ssz = 0, i = 0; cp != &str[i]; i++) { 26295c635efSGarrett D'Amore buf[0] = str[i]; 26395c635efSGarrett D'Amore ssz += (*tbl->slen)(buf, tbl->arg); 26495c635efSGarrett D'Amore } 26595c635efSGarrett D'Amore d = ssz + psz; 26695c635efSGarrett D'Amore } else 26795c635efSGarrett D'Amore d = sz + psz; 26895c635efSGarrett D'Amore 26995c635efSGarrett D'Amore /* Adjust the settings for this column. */ 27095c635efSGarrett D'Amore 27195c635efSGarrett D'Amore if (col->decimal > d) { 27295c635efSGarrett D'Amore sz += col->decimal - d; 27395c635efSGarrett D'Amore d = col->decimal; 27495c635efSGarrett D'Amore } else 27595c635efSGarrett D'Amore col->width += d - col->decimal; 27695c635efSGarrett D'Amore 27795c635efSGarrett D'Amore if (sz > col->width) 27895c635efSGarrett D'Amore col->width = sz; 27995c635efSGarrett D'Amore if (d > col->decimal) 28095c635efSGarrett D'Amore col->decimal = d; 28195c635efSGarrett D'Amore } 282