Print this page
Update to 1.12.3.
   1 /*      $Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
   5  *
   6  * Permission to use, copy, modify, and distribute this software for any
   7  * purpose with or without fee is hereby granted, provided that the above
   8  * copyright notice and this permission notice appear in all copies.
   9  *
  10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17  */
  18 #ifdef HAVE_CONFIG_H
  19 #include "config.h"
  20 #endif
  21 
  22 #include <sys/types.h>
  23 
  24 #include <assert.h>
  25 #include <ctype.h>
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <time.h>
  30 
  31 #include "mandoc.h"
  32 #include "out.h"
  33 
  34 static  void    tblcalc_data(struct rofftbl *, struct roffcol *,
  35                         const struct tbl *, const struct tbl_dat *);
  36 static  void    tblcalc_literal(struct rofftbl *, struct roffcol *,
  37                         const struct tbl_dat *);
  38 static  void    tblcalc_number(struct rofftbl *, struct roffcol *,
  39                         const struct tbl *, const struct tbl_dat *);
  40 
  41 /* 
  42  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
  43  * units are documented in groff.7, mdoc.7, man.7.
  44  */
  45 int
  46 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
  47 {
  48         char             buf[BUFSIZ], hasd;
  49         int              i;
  50         enum roffscale   unit;
  51 
  52         if ('\0' == *src)
  53                 return(0);
  54 
  55         i = hasd = 0;
  56 
  57         switch (*src) {
  58         case ('+'):
  59                 src++;


 125                 return(0);
 126         }
 127 
 128         /* FIXME: do this in the caller. */
 129         if ((dst->scale = atof(buf)) < 0)
 130                 dst->scale = 0;
 131         dst->unit = unit;
 132         return(1);
 133 }
 134 
 135 /*
 136  * Calculate the abstract widths and decimal positions of columns in a
 137  * table.  This routine allocates the columns structures then runs over
 138  * all rows and cells in the table.  The function pointers in "tbl" are
 139  * used for the actual width calculations.
 140  */
 141 void
 142 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
 143 {
 144         const struct tbl_dat    *dp;
 145         const struct tbl_head   *hp;
 146         struct roffcol          *col;
 147         int                      spans;
 148 
 149         /*
 150          * Allocate the master column specifiers.  These will hold the
 151          * widths and decimal positions for all cells in the column.  It
 152          * must be freed and nullified by the caller.
 153          */
 154 
 155         assert(NULL == tbl->cols);
 156         tbl->cols = mandoc_calloc
 157                 ((size_t)sp->tbl->cols, sizeof(struct roffcol));
 158 
 159         hp = sp->head;
 160 
 161         for ( ; sp; sp = sp->next) {
 162                 if (TBL_SPAN_DATA != sp->pos)
 163                         continue;
 164                 spans = 1;
 165                 /*
 166                  * Account for the data cells in the layout, matching it
 167                  * to data cells in the data section.
 168                  */
 169                 for (dp = sp->first; dp; dp = dp->next) {
 170                         /* Do not used spanned cells in the calculation. */
 171                         if (0 < --spans)
 172                                 continue;
 173                         spans = dp->spans;
 174                         if (1 < spans)
 175                                 continue;
 176                         assert(dp->layout);
 177                         col = &tbl->cols[dp->layout->head->ident];
 178                         tblcalc_data(tbl, col, sp->tbl, dp);
 179                 }
 180         }
 181 
 182         /* 
 183          * Calculate width of the spanners.  These get one space for a
 184          * vertical line, two for a double-vertical line. 
 185          */
 186 
 187         for ( ; hp; hp = hp->next) {
 188                 col = &tbl->cols[hp->ident];
 189                 switch (hp->pos) {
 190                 case (TBL_HEAD_VERT):
 191                         col->width = (*tbl->len)(1, tbl->arg);
 192                         break;
 193                 case (TBL_HEAD_DVERT):
 194                         col->width = (*tbl->len)(2, tbl->arg);
 195                         break;
 196                 default:
 197                         break;
 198                 }
 199         }
 200 }
 201 
 202 static void
 203 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
 204                 const struct tbl *tp, const struct tbl_dat *dp)
 205 {
 206         size_t           sz;
 207 
 208         /* Branch down into data sub-types. */
 209 
 210         switch (dp->layout->pos) {
 211         case (TBL_CELL_HORIZ):
 212                 /* FALLTHROUGH */
 213         case (TBL_CELL_DHORIZ):
 214                 sz = (*tbl->len)(1, tbl->arg);
 215                 if (col->width < sz)
 216                         col->width = sz;
 217                 break;
 218         case (TBL_CELL_LONG):
 219                 /* FALLTHROUGH */
 220         case (TBL_CELL_CENTRE):
 221                 /* FALLTHROUGH */
 222         case (TBL_CELL_LEFT):
 223                 /* FALLTHROUGH */
 224         case (TBL_CELL_RIGHT):
 225                 tblcalc_literal(tbl, col, dp);
 226                 break;
 227         case (TBL_CELL_NUMBER):
 228                 tblcalc_number(tbl, col, tp, dp);
 229                 break;
 230         case (TBL_CELL_DOWN):
 231                 break;
 232         default:
 233                 abort();
 234                 /* NOTREACHED */
 235         }
 236 }
 237 
 238 static void
 239 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
 240                 const struct tbl_dat *dp)
 241 {
 242         size_t           sz;
 243         const char      *str;
 244 
 245         str = dp->string ? dp->string : "";
 246         sz = (*tbl->slen)(str, tbl->arg);
 247 
 248         if (col->width < sz)
 249                 col->width = sz;
 250 }
 251 
 252 static void
 253 tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
 254                 const struct tbl *tp, const struct tbl_dat *dp)
 255 {
 256         int              i;
 257         size_t           sz, psz, ssz, d;
 258         const char      *str;
 259         char            *cp;
 260         char             buf[2];
 261 
 262         /*
 263          * First calculate number width and decimal place (last + 1 for
 264          * non-decimal numbers).  If the stored decimal is subsequent to
 265          * ours, make our size longer by that difference
 266          * (right-"shifting"); similarly, if ours is subsequent the
 267          * stored, then extend the stored size by the difference.
 268          * Finally, re-assign the stored values.
 269          */
 270 
 271         str = dp->string ? dp->string : "";
 272         sz = (*tbl->slen)(str, tbl->arg);
 273 
 274         /* FIXME: TBL_DATA_HORIZ et al.? */
 275 
 276         buf[0] = tp->decimal;
 277         buf[1] = '\0';
 278 
 279         psz = (*tbl->slen)(buf, tbl->arg);
 280 
 281         if (NULL != (cp = strrchr(str, tp->decimal))) {
 282                 buf[1] = '\0';
 283                 for (ssz = 0, i = 0; cp != &str[i]; i++) {
 284                         buf[0] = str[i];
 285                         ssz += (*tbl->slen)(buf, tbl->arg);
 286                 }
 287                 d = ssz + psz;
 288         } else
 289                 d = sz + psz;
 290 
 291         /* Adjust the settings for this column. */
 292 
 293         if (col->decimal > d) {
 294                 sz += col->decimal - d;
 295                 d = col->decimal;
 296         } else
 297                 col->width += d - col->decimal;
 298 
 299         if (sz > col->width)
 300                 col->width = sz;
 301         if (d > col->decimal)
   1 /*      $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
   5  *
   6  * Permission to use, copy, modify, and distribute this software for any
   7  * purpose with or without fee is hereby granted, provided that the above
   8  * copyright notice and this permission notice appear in all copies.
   9  *
  10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17  */
  18 #ifdef HAVE_CONFIG_H
  19 #include "config.h"
  20 #endif
  21 
  22 #include <sys/types.h>
  23 
  24 #include <assert.h>
  25 #include <ctype.h>
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <time.h>
  30 
  31 #include "mandoc.h"
  32 #include "out.h"
  33 
  34 static  void    tblcalc_data(struct rofftbl *, struct roffcol *,
  35                         const struct tbl_opts *, const struct tbl_dat *);
  36 static  void    tblcalc_literal(struct rofftbl *, struct roffcol *,
  37                         const struct tbl_dat *);
  38 static  void    tblcalc_number(struct rofftbl *, struct roffcol *,
  39                         const struct tbl_opts *, const struct tbl_dat *);
  40 
  41 /* 
  42  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
  43  * units are documented in groff.7, mdoc.7, man.7.
  44  */
  45 int
  46 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
  47 {
  48         char             buf[BUFSIZ], hasd;
  49         int              i;
  50         enum roffscale   unit;
  51 
  52         if ('\0' == *src)
  53                 return(0);
  54 
  55         i = hasd = 0;
  56 
  57         switch (*src) {
  58         case ('+'):
  59                 src++;


 125                 return(0);
 126         }
 127 
 128         /* FIXME: do this in the caller. */
 129         if ((dst->scale = atof(buf)) < 0)
 130                 dst->scale = 0;
 131         dst->unit = unit;
 132         return(1);
 133 }
 134 
 135 /*
 136  * Calculate the abstract widths and decimal positions of columns in a
 137  * table.  This routine allocates the columns structures then runs over
 138  * all rows and cells in the table.  The function pointers in "tbl" are
 139  * used for the actual width calculations.
 140  */
 141 void
 142 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
 143 {
 144         const struct tbl_dat    *dp;

 145         struct roffcol          *col;
 146         int                      spans;
 147 
 148         /*
 149          * Allocate the master column specifiers.  These will hold the
 150          * widths and decimal positions for all cells in the column.  It
 151          * must be freed and nullified by the caller.
 152          */
 153 
 154         assert(NULL == tbl->cols);
 155         tbl->cols = mandoc_calloc
 156                 ((size_t)sp->opts->cols, sizeof(struct roffcol));
 157 


 158         for ( ; sp; sp = sp->next) {
 159                 if (TBL_SPAN_DATA != sp->pos)
 160                         continue;
 161                 spans = 1;
 162                 /*
 163                  * Account for the data cells in the layout, matching it
 164                  * to data cells in the data section.
 165                  */
 166                 for (dp = sp->first; dp; dp = dp->next) {
 167                         /* Do not used spanned cells in the calculation. */
 168                         if (0 < --spans)
 169                                 continue;
 170                         spans = dp->spans;
 171                         if (1 < spans)
 172                                 continue;
 173                         assert(dp->layout);
 174                         col = &tbl->cols[dp->layout->head->ident];
 175                         tblcalc_data(tbl, col, sp->opts, dp);
 176                 }
 177         }



















 178 }
 179 
 180 static void
 181 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
 182                 const struct tbl_opts *opts, const struct tbl_dat *dp)
 183 {
 184         size_t           sz;
 185 
 186         /* Branch down into data sub-types. */
 187 
 188         switch (dp->layout->pos) {
 189         case (TBL_CELL_HORIZ):
 190                 /* FALLTHROUGH */
 191         case (TBL_CELL_DHORIZ):
 192                 sz = (*tbl->len)(1, tbl->arg);
 193                 if (col->width < sz)
 194                         col->width = sz;
 195                 break;
 196         case (TBL_CELL_LONG):
 197                 /* FALLTHROUGH */
 198         case (TBL_CELL_CENTRE):
 199                 /* FALLTHROUGH */
 200         case (TBL_CELL_LEFT):
 201                 /* FALLTHROUGH */
 202         case (TBL_CELL_RIGHT):
 203                 tblcalc_literal(tbl, col, dp);
 204                 break;
 205         case (TBL_CELL_NUMBER):
 206                 tblcalc_number(tbl, col, opts, dp);
 207                 break;
 208         case (TBL_CELL_DOWN):
 209                 break;
 210         default:
 211                 abort();
 212                 /* NOTREACHED */
 213         }
 214 }
 215 
 216 static void
 217 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
 218                 const struct tbl_dat *dp)
 219 {
 220         size_t           sz;
 221         const char      *str;
 222 
 223         str = dp->string ? dp->string : "";
 224         sz = (*tbl->slen)(str, tbl->arg);
 225 
 226         if (col->width < sz)
 227                 col->width = sz;
 228 }
 229 
 230 static void
 231 tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
 232                 const struct tbl_opts *opts, const struct tbl_dat *dp)
 233 {
 234         int              i;
 235         size_t           sz, psz, ssz, d;
 236         const char      *str;
 237         char            *cp;
 238         char             buf[2];
 239 
 240         /*
 241          * First calculate number width and decimal place (last + 1 for
 242          * non-decimal numbers).  If the stored decimal is subsequent to
 243          * ours, make our size longer by that difference
 244          * (right-"shifting"); similarly, if ours is subsequent the
 245          * stored, then extend the stored size by the difference.
 246          * Finally, re-assign the stored values.
 247          */
 248 
 249         str = dp->string ? dp->string : "";
 250         sz = (*tbl->slen)(str, tbl->arg);
 251 
 252         /* FIXME: TBL_DATA_HORIZ et al.? */
 253 
 254         buf[0] = opts->decimal;
 255         buf[1] = '\0';
 256 
 257         psz = (*tbl->slen)(buf, tbl->arg);
 258 
 259         if (NULL != (cp = strrchr(str, opts->decimal))) {
 260                 buf[1] = '\0';
 261                 for (ssz = 0, i = 0; cp != &str[i]; i++) {
 262                         buf[0] = str[i];
 263                         ssz += (*tbl->slen)(buf, tbl->arg);
 264                 }
 265                 d = ssz + psz;
 266         } else
 267                 d = sz + psz;
 268 
 269         /* Adjust the settings for this column. */
 270 
 271         if (col->decimal > d) {
 272                 sz += col->decimal - d;
 273                 d = col->decimal;
 274         } else
 275                 col->width += d - col->decimal;
 276 
 277         if (sz > col->width)
 278                 col->width = sz;
 279         if (d > col->decimal)