Print this page
9718 update mandoc to 1.14.4

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/mandoc/html.c
          +++ new/usr/src/cmd/mandoc/html.c
   1      -/*      $Id: html.c,v 1.219 2017/07/15 17:57:51 schwarze Exp $ */
        1 +/*      $Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */
   2    2  /*
   3    3   * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
   4      - * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
        4 + * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
   5    5   *
   6    6   * Permission to use, copy, modify, and distribute this software for any
   7    7   * purpose with or without fee is hereby granted, provided that the above
   8    8   * copyright notice and this permission notice appear in all copies.
   9    9   *
  10   10   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
  11   11   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12   12   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
  13   13   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14   14   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15   15   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16   16   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17   17   */
  18   18  #include "config.h"
  19   19  
  20   20  #include <sys/types.h>
  21   21  
  22   22  #include <assert.h>
  23   23  #include <ctype.h>
  24   24  #include <stdarg.h>
       25 +#include <stddef.h>
  25   26  #include <stdio.h>
  26   27  #include <stdint.h>
  27   28  #include <stdlib.h>
  28   29  #include <string.h>
  29   30  #include <unistd.h>
  30   31  
  31   32  #include "mandoc_aux.h"
       33 +#include "mandoc_ohash.h"
  32   34  #include "mandoc.h"
  33   35  #include "roff.h"
  34   36  #include "out.h"
  35   37  #include "html.h"
  36   38  #include "manconf.h"
  37   39  #include "main.h"
  38   40  
  39   41  struct  htmldata {
  40   42          const char       *name;
  41   43          int               flags;
↓ open down ↓ 10 lines elided ↑ open up ↑
  52   54  #define HTML_NOINDENT    (1 << 7)
  53   55  };
  54   56  
  55   57  static  const struct htmldata htmltags[TAG_MAX] = {
  56   58          {"html",        HTML_NLALL},
  57   59          {"head",        HTML_NLALL | HTML_INDENT},
  58   60          {"body",        HTML_NLALL},
  59   61          {"meta",        HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
  60   62          {"title",       HTML_NLAROUND},
  61   63          {"div",         HTML_NLAROUND},
       64 +        {"div",         0},
  62   65          {"h1",          HTML_NLAROUND},
  63   66          {"h2",          HTML_NLAROUND},
  64   67          {"span",        0},
  65   68          {"link",        HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
  66   69          {"br",          HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
  67   70          {"a",           0},
  68   71          {"table",       HTML_NLALL | HTML_INDENT},
  69      -        {"colgroup",    HTML_NLALL | HTML_INDENT},
  70      -        {"col",         HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
  71   72          {"tr",          HTML_NLALL | HTML_INDENT},
  72   73          {"td",          HTML_NLAROUND},
  73   74          {"li",          HTML_NLAROUND | HTML_INDENT},
  74   75          {"ul",          HTML_NLALL | HTML_INDENT},
  75   76          {"ol",          HTML_NLALL | HTML_INDENT},
  76   77          {"dl",          HTML_NLALL | HTML_INDENT},
  77   78          {"dt",          HTML_NLAROUND},
  78   79          {"dd",          HTML_NLAROUND | HTML_INDENT},
  79   80          {"pre",         HTML_NLALL | HTML_NOINDENT},
  80   81          {"var",         0},
↓ open down ↓ 15 lines elided ↑ open up ↑
  96   97          {"msqrt",       0},
  97   98          {"mfenced",     0},
  98   99          {"mtable",      0},
  99  100          {"mtr",         0},
 100  101          {"mtd",         0},
 101  102          {"munderover",  0},
 102  103          {"munder",      0},
 103  104          {"mover",       0},
 104  105  };
 105  106  
 106      -static  const char      *const roffscales[SCALE_MAX] = {
 107      -        "cm", /* SCALE_CM */
 108      -        "in", /* SCALE_IN */
 109      -        "pc", /* SCALE_PC */
 110      -        "pt", /* SCALE_PT */
 111      -        "em", /* SCALE_EM */
 112      -        "em", /* SCALE_MM */
 113      -        "ex", /* SCALE_EN */
 114      -        "ex", /* SCALE_BU */
 115      -        "em", /* SCALE_VS */
 116      -        "ex", /* SCALE_FS */
 117      -};
      107 +/* Avoid duplicate HTML id= attributes. */
      108 +static  struct ohash     id_unique;
 118  109  
 119      -static  void     a2width(const char *, struct roffsu *);
 120  110  static  void     print_byte(struct html *, char);
 121  111  static  void     print_endword(struct html *);
 122  112  static  void     print_indent(struct html *);
 123  113  static  void     print_word(struct html *, const char *);
 124  114  
 125  115  static  void     print_ctag(struct html *, struct tag *);
 126  116  static  int      print_escape(struct html *, char);
 127  117  static  int      print_encode(struct html *, const char *, const char *, int);
 128  118  static  void     print_href(struct html *, const char *, const char *, int);
 129  119  static  void     print_metaf(struct html *, enum mandoc_esc);
↓ open down ↓ 6 lines elided ↑ open up ↑
 136  126  
 137  127          h = mandoc_calloc(1, sizeof(struct html));
 138  128  
 139  129          h->tag = NULL;
 140  130          h->style = outopts->style;
 141  131          h->base_man = outopts->man;
 142  132          h->base_includes = outopts->includes;
 143  133          if (outopts->fragment)
 144  134                  h->oflags |= HTML_FRAGMENT;
 145  135  
      136 +        mandoc_ohash_init(&id_unique, 4, 0);
      137 +
 146  138          return h;
 147  139  }
 148  140  
 149  141  void
 150  142  html_free(void *p)
 151  143  {
 152  144          struct tag      *tag;
 153  145          struct html     *h;
      146 +        char            *cp;
      147 +        unsigned int     slot;
 154  148  
 155  149          h = (struct html *)p;
 156      -
 157  150          while ((tag = h->tag) != NULL) {
 158  151                  h->tag = tag->next;
 159  152                  free(tag);
 160  153          }
 161      -
 162  154          free(h);
      155 +
      156 +        cp = ohash_first(&id_unique, &slot);
      157 +        while (cp != NULL) {
      158 +                free(cp);
      159 +                cp = ohash_next(&id_unique, &slot);
      160 +        }
      161 +        ohash_delete(&id_unique);
 163  162  }
 164  163  
 165  164  void
 166  165  print_gen_head(struct html *h)
 167  166  {
 168  167          struct tag      *t;
 169  168  
 170  169          print_otag(h, TAG_META, "?", "charset", "utf-8");
      170 +        if (h->style != NULL) {
      171 +                print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
      172 +                    h->style, "type", "text/css", "media", "all");
      173 +                return;
      174 +        }
 171  175  
 172  176          /*
 173      -         * Print a default style-sheet.
      177 +         * Print a minimal embedded style sheet.
 174  178           */
 175  179  
 176  180          t = print_otag(h, TAG_STYLE, "");
 177  181          print_text(h, "table.head, table.foot { width: 100%; }");
 178  182          print_endline(h);
 179  183          print_text(h, "td.head-rtitle, td.foot-os { text-align: right; }");
 180  184          print_endline(h);
 181  185          print_text(h, "td.head-vol { text-align: center; }");
 182  186          print_endline(h);
 183  187          print_text(h, "div.Pp { margin: 1ex 0ex; }");
      188 +        print_endline(h);
      189 +        print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }");
      190 +        print_endline(h);
      191 +        print_text(h, "span.Pa, span.Ad { font-style: italic; }");
      192 +        print_endline(h);
      193 +        print_text(h, "span.Ms { font-weight: bold; }");
      194 +        print_endline(h);
      195 +        print_text(h, "dl.Bl-diag ");
      196 +        print_byte(h, '>');
      197 +        print_text(h, " dt { font-weight: bold; }");
      198 +        print_endline(h);
      199 +        print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, "
      200 +            "code.In, code.Fd, code.Fn,");
      201 +        print_endline(h);
      202 +        print_text(h, "code.Cd { font-weight: bold; "
      203 +            "font-family: inherit; }");
 184  204          print_tagq(h, t);
 185      -
 186      -        if (h->style)
 187      -                print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
 188      -                    h->style, "type", "text/css", "media", "all");
 189  205  }
 190  206  
 191  207  static void
 192  208  print_metaf(struct html *h, enum mandoc_esc deco)
 193  209  {
 194  210          enum htmlfont    font;
 195  211  
 196  212          switch (deco) {
 197  213          case ESCAPE_FONTPREV:
 198  214                  font = h->metal;
↓ open down ↓ 33 lines elided ↑ open up ↑
 232  248          case HTMLFONT_BI:
 233  249                  h->metaf = print_otag(h, TAG_B, "");
 234  250                  print_otag(h, TAG_I, "");
 235  251                  break;
 236  252          default:
 237  253                  break;
 238  254          }
 239  255  }
 240  256  
 241  257  char *
 242      -html_make_id(const struct roff_node *n)
      258 +html_make_id(const struct roff_node *n, int unique)
 243  259  {
 244  260          const struct roff_node  *nch;
 245      -        char                    *buf, *cp;
      261 +        char                    *buf, *bufs, *cp;
      262 +        unsigned int             slot;
      263 +        int                      suffix;
 246  264  
 247  265          for (nch = n->child; nch != NULL; nch = nch->next)
 248  266                  if (nch->type != ROFFT_TEXT)
 249  267                          return NULL;
 250  268  
 251  269          buf = NULL;
 252  270          deroff(&buf, n);
      271 +        if (buf == NULL)
      272 +                return NULL;
 253  273  
 254      -        /* http://www.w3.org/TR/html5/dom.html#the-id-attribute */
      274 +        /*
      275 +         * In ID attributes, only use ASCII characters that are
      276 +         * permitted in URL-fragment strings according to the
      277 +         * explicit list at:
      278 +         * https://url.spec.whatwg.org/#url-fragment-string
      279 +         */
 255  280  
 256  281          for (cp = buf; *cp != '\0'; cp++)
 257      -                if (*cp == ' ')
      282 +                if (isalnum((unsigned char)*cp) == 0 &&
      283 +                    strchr("!$&'()*+,-./:;=?@_~", *cp) == NULL)
 258  284                          *cp = '_';
 259  285  
 260      -        return buf;
 261      -}
      286 +        if (unique == 0)
      287 +                return buf;
 262  288  
 263      -int
 264      -html_strlen(const char *cp)
 265      -{
 266      -        size_t           rsz;
 267      -        int              skip, sz;
      289 +        /* Avoid duplicate HTML id= attributes. */
 268  290  
 269      -        /*
 270      -         * Account for escaped sequences within string length
 271      -         * calculations.  This follows the logic in term_strlen() as we
 272      -         * must calculate the width of produced strings.
 273      -         * Assume that characters are always width of "1".  This is
 274      -         * hacky, but it gets the job done for approximation of widths.
 275      -         */
 276      -
 277      -        sz = 0;
 278      -        skip = 0;
 279      -        while (1) {
 280      -                rsz = strcspn(cp, "\\");
 281      -                if (rsz) {
 282      -                        cp += rsz;
 283      -                        if (skip) {
 284      -                                skip = 0;
 285      -                                rsz--;
      291 +        bufs = NULL;
      292 +        suffix = 1;
      293 +        slot = ohash_qlookup(&id_unique, buf);
      294 +        cp = ohash_find(&id_unique, slot);
      295 +        if (cp != NULL) {
      296 +                while (cp != NULL) {
      297 +                        free(bufs);
      298 +                        if (++suffix > 127) {
      299 +                                free(buf);
      300 +                                return NULL;
 286  301                          }
 287      -                        sz += rsz;
      302 +                        mandoc_asprintf(&bufs, "%s_%d", buf, suffix);
      303 +                        slot = ohash_qlookup(&id_unique, bufs);
      304 +                        cp = ohash_find(&id_unique, slot);
 288  305                  }
 289      -                if ('\0' == *cp)
 290      -                        break;
 291      -                cp++;
 292      -                switch (mandoc_escape(&cp, NULL, NULL)) {
 293      -                case ESCAPE_ERROR:
 294      -                        return sz;
 295      -                case ESCAPE_UNICODE:
 296      -                case ESCAPE_NUMBERED:
 297      -                case ESCAPE_SPECIAL:
 298      -                case ESCAPE_OVERSTRIKE:
 299      -                        if (skip)
 300      -                                skip = 0;
 301      -                        else
 302      -                                sz++;
 303      -                        break;
 304      -                case ESCAPE_SKIPCHAR:
 305      -                        skip = 1;
 306      -                        break;
 307      -                default:
 308      -                        break;
 309      -                }
      306 +                free(buf);
      307 +                buf = bufs;
 310  308          }
 311      -        return sz;
      309 +        ohash_insert(&id_unique, slot, buf);
      310 +        return buf;
 312  311  }
 313  312  
 314  313  static int
 315  314  print_escape(struct html *h, char c)
 316  315  {
 317  316  
 318  317          switch (c) {
 319  318          case '<':
 320  319                  print_word(h, "&lt;");
 321  320                  break;
↓ open down ↓ 161 lines elided ↑ open up ↑
 483  482                  pp = p + 2;
 484  483          }
 485  484          if (*pp != '\0')
 486  485                  print_encode(h, pp, NULL, 1);
 487  486  }
 488  487  
 489  488  struct tag *
 490  489  print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
 491  490  {
 492  491          va_list          ap;
 493      -        struct roffsu    mysu, *su;
 494      -        char             numbuf[16];
 495  492          struct tag      *t;
 496  493          const char      *attr;
 497  494          char            *arg1, *arg2;
 498      -        double           v;
 499      -        int              i, have_style, tflags;
      495 +        int              tflags;
 500  496  
 501  497          tflags = htmltags[tag].flags;
 502  498  
 503  499          /* Push this tag onto the stack of open scopes. */
 504  500  
 505  501          if ((tflags & HTML_NOSTACK) == 0) {
 506  502                  t = mandoc_malloc(sizeof(struct tag));
 507  503                  t->tag = tag;
 508  504                  t->next = h->tag;
 509  505                  h->tag = t;
↓ open down ↓ 19 lines elided ↑ open up ↑
 529  525          else
 530  526                  h->flags |= HTML_NOSPACE;
 531  527  
 532  528          /* Print out the tag name and attributes. */
 533  529  
 534  530          print_byte(h, '<');
 535  531          print_word(h, htmltags[tag].name);
 536  532  
 537  533          va_start(ap, fmt);
 538  534  
 539      -        have_style = 0;
 540  535          while (*fmt != '\0') {
 541      -                if (*fmt == 's') {
 542      -                        have_style = 1;
 543      -                        fmt++;
 544      -                        break;
 545      -                }
 546  536  
 547      -                /* Parse a non-style attribute and its arguments. */
      537 +                /* Parse attributes and arguments. */
 548  538  
 549  539                  arg1 = va_arg(ap, char *);
      540 +                arg2 = NULL;
 550  541                  switch (*fmt++) {
 551  542                  case 'c':
 552  543                          attr = "class";
 553  544                          break;
 554  545                  case 'h':
 555  546                          attr = "href";
 556  547                          break;
 557  548                  case 'i':
 558  549                          attr = "id";
 559  550                          break;
      551 +                case 's':
      552 +                        attr = "style";
      553 +                        arg2 = va_arg(ap, char *);
      554 +                        break;
 560  555                  case '?':
 561  556                          attr = arg1;
 562  557                          arg1 = va_arg(ap, char *);
 563  558                          break;
 564  559                  default:
 565  560                          abort();
 566  561                  }
 567      -                arg2 = NULL;
 568  562                  if (*fmt == 'M')
 569  563                          arg2 = va_arg(ap, char *);
 570  564                  if (arg1 == NULL)
 571  565                          continue;
 572  566  
 573      -                /* Print the non-style attributes. */
      567 +                /* Print the attributes. */
 574  568  
 575  569                  print_byte(h, ' ');
 576  570                  print_word(h, attr);
 577  571                  print_byte(h, '=');
 578  572                  print_byte(h, '"');
 579  573                  switch (*fmt) {
 580  574                  case 'I':
 581  575                          print_href(h, arg1, NULL, 0);
 582  576                          fmt++;
 583  577                          break;
↓ open down ↓ 6 lines elided ↑ open up ↑
 590  584                          print_encode(h, arg1, NULL, 1);
 591  585                          fmt++;
 592  586                          break;
 593  587                  case 'T':
 594  588                          print_encode(h, arg1, NULL, 1);
 595  589                          print_word(h, "\" title=\"");
 596  590                          print_encode(h, arg1, NULL, 1);
 597  591                          fmt++;
 598  592                          break;
 599  593                  default:
 600      -                        print_encode(h, arg1, NULL, 1);
 601      -                        break;
 602      -                }
 603      -                print_byte(h, '"');
 604      -        }
 605      -
 606      -        /* Print out styles. */
 607      -
 608      -        while (*fmt != '\0') {
 609      -                arg1 = NULL;
 610      -                su = NULL;
 611      -
 612      -                /* First letter: input argument type. */
 613      -
 614      -                switch (*fmt++) {
 615      -                case 'h':
 616      -                        i = va_arg(ap, int);
 617      -                        su = &mysu;
 618      -                        SCALE_HS_INIT(su, i);
 619      -                        break;
 620      -                case 's':
 621      -                        arg1 = va_arg(ap, char *);
 622      -                        break;
 623      -                case 'u':
 624      -                        su = va_arg(ap, struct roffsu *);
 625      -                        break;
 626      -                case 'w':
 627      -                        if ((arg2 = va_arg(ap, char *)) != NULL) {
 628      -                                su = &mysu;
 629      -                                a2width(arg2, su);
      594 +                        if (arg2 == NULL)
      595 +                                print_encode(h, arg1, NULL, 1);
      596 +                        else {
      597 +                                print_word(h, arg1);
      598 +                                print_byte(h, ':');
      599 +                                print_byte(h, ' ');
      600 +                                print_word(h, arg2);
      601 +                                print_byte(h, ';');
 630  602                          }
 631      -                        if (*fmt == '*') {
 632      -                                if (su != NULL && su->unit == SCALE_EN &&
 633      -                                    su->scale > 5.9 && su->scale < 6.1)
 634      -                                        su = NULL;
 635      -                                fmt++;
 636      -                        }
 637      -                        if (*fmt == '+') {
 638      -                                if (su != NULL) {
 639      -                                        /* Make even bold text fit. */
 640      -                                        su->scale *= 1.2;
 641      -                                        /* Add padding. */
 642      -                                        su->scale += 3.0;
 643      -                                }
 644      -                                fmt++;
 645      -                        }
 646      -                        if (*fmt == '-') {
 647      -                                if (su != NULL)
 648      -                                        su->scale *= -1.0;
 649      -                                fmt++;
 650      -                        }
 651  603                          break;
 652      -                default:
 653      -                        abort();
 654  604                  }
 655      -
 656      -                /* Second letter: style name. */
 657      -
 658      -                switch (*fmt++) {
 659      -                case 'h':
 660      -                        attr = "height";
 661      -                        break;
 662      -                case 'i':
 663      -                        attr = "text-indent";
 664      -                        break;
 665      -                case 'l':
 666      -                        attr = "margin-left";
 667      -                        break;
 668      -                case 'w':
 669      -                        attr = "width";
 670      -                        break;
 671      -                case 'W':
 672      -                        attr = "min-width";
 673      -                        break;
 674      -                case '?':
 675      -                        attr = arg1;
 676      -                        arg1 = va_arg(ap, char *);
 677      -                        break;
 678      -                default:
 679      -                        abort();
 680      -                }
 681      -                if (su == NULL && arg1 == NULL)
 682      -                        continue;
 683      -
 684      -                if (have_style == 1)
 685      -                        print_word(h, " style=\"");
 686      -                else
 687      -                        print_byte(h, ' ');
 688      -                print_word(h, attr);
 689      -                print_byte(h, ':');
 690      -                print_byte(h, ' ');
 691      -                if (su != NULL) {
 692      -                        v = su->scale;
 693      -                        if (su->unit == SCALE_MM && (v /= 100.0) == 0.0)
 694      -                                v = 1.0;
 695      -                        else if (su->unit == SCALE_BU)
 696      -                                v /= 24.0;
 697      -                        (void)snprintf(numbuf, sizeof(numbuf), "%.2f", v);
 698      -                        print_word(h, numbuf);
 699      -                        print_word(h, roffscales[su->unit]);
 700      -                } else
 701      -                        print_word(h, arg1);
 702      -                print_byte(h, ';');
 703      -                have_style = 2;
 704      -        }
 705      -        if (have_style == 2)
 706  605                  print_byte(h, '"');
 707      -
      606 +        }
 708  607          va_end(ap);
 709  608  
 710  609          /* Accommodate for "well-formed" singleton escaping. */
 711  610  
 712  611          if (HTML_AUTOCLOSE & htmltags[tag].flags)
 713  612                  print_byte(h, '/');
 714  613  
 715  614          print_byte(h, '>');
 716  615  
 717  616          if (tflags & HTML_NLBEGIN)
↓ open down ↓ 44 lines elided ↑ open up ↑
 762  661  }
 763  662  
 764  663  void
 765  664  print_gen_decls(struct html *h)
 766  665  {
 767  666          print_word(h, "<!DOCTYPE html>");
 768  667          print_endline(h);
 769  668  }
 770  669  
 771  670  void
      671 +print_gen_comment(struct html *h, struct roff_node *n)
      672 +{
      673 +        int      wantblank;
      674 +
      675 +        print_word(h, "<!-- This is an automatically generated file."
      676 +            "  Do not edit.");
      677 +        h->indent = 1;
      678 +        wantblank = 0;
      679 +        while (n != NULL && n->type == ROFFT_COMMENT) {
      680 +                if (strstr(n->string, "-->") == NULL &&
      681 +                    (wantblank || *n->string != '\0')) {
      682 +                        print_endline(h);
      683 +                        print_indent(h);
      684 +                        print_word(h, n->string);
      685 +                        wantblank = *n->string != '\0';
      686 +                }
      687 +                n = n->next;
      688 +        }
      689 +        if (wantblank)
      690 +                print_endline(h);
      691 +        print_word(h, " -->");
      692 +        print_endline(h);
      693 +        h->indent = 0;
      694 +}
      695 +
      696 +void
 772  697  print_text(struct html *h, const char *word)
 773  698  {
 774  699          if (h->col && (h->flags & HTML_NOSPACE) == 0) {
 775  700                  if ( ! (HTML_KEEP & h->flags)) {
 776  701                          if (HTML_PREKEEP & h->flags)
 777  702                                  h->flags |= HTML_KEEP;
 778  703                          print_endword(h);
 779  704                  } else
 780  705                          print_word(h, "&#x00A0;");
 781  706          }
↓ open down ↓ 169 lines elided ↑ open up ↑
 951  876  
 952  877  /*
 953  878   * Print or buffer some characters
 954  879   * depending on the current HTML output buffer state.
 955  880   */
 956  881  static void
 957  882  print_word(struct html *h, const char *cp)
 958  883  {
 959  884          while (*cp != '\0')
 960  885                  print_byte(h, *cp++);
 961      -}
 962      -
 963      -/*
 964      - * Calculate the scaling unit passed in a `-width' argument.  This uses
 965      - * either a native scaling unit (e.g., 1i, 2m) or the string length of
 966      - * the value.
 967      - */
 968      -static void
 969      -a2width(const char *p, struct roffsu *su)
 970      -{
 971      -        const char      *end;
 972      -
 973      -        end = a2roffsu(p, su, SCALE_MAX);
 974      -        if (end == NULL || *end != '\0') {
 975      -                su->unit = SCALE_EN;
 976      -                su->scale = html_strlen(p);
 977      -        } else if (su->scale < 0.0)
 978      -                su->scale = 0.0;
 979  886  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX