Print this page
5051 import mdocml-1.12.3
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Approved by: TBD

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/mandoc/term.c
          +++ new/usr/src/cmd/mandoc/term.c
   1      -/*      $Id: term.c,v 1.201 2011/09/21 09:57:13 schwarze Exp $ */
        1 +/*      $Id: term.c,v 1.214 2013/12/25 00:39:31 schwarze Exp $ */
   2    2  /*
   3    3   * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
   4      - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
        4 + * Copyright (c) 2010, 2011, 2012, 2013 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 AUTHOR DISCLAIMS ALL WARRANTIES
  11   11   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12   12   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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
↓ open down ↓ 11 lines elided ↑ open up ↑
  26   26  #include <stdint.h>
  27   27  #include <stdio.h>
  28   28  #include <stdlib.h>
  29   29  #include <string.h>
  30   30  
  31   31  #include "mandoc.h"
  32   32  #include "out.h"
  33   33  #include "term.h"
  34   34  #include "main.h"
  35   35  
  36      -static  void             adjbuf(struct termp *p, int);
       36 +static  size_t           cond_width(const struct termp *, int, int *);
       37 +static  void             adjbuf(struct termp *p, size_t);
  37   38  static  void             bufferc(struct termp *, char);
  38   39  static  void             encode(struct termp *, const char *, size_t);
  39   40  static  void             encode1(struct termp *, int);
  40   41  
  41   42  void
  42   43  term_free(struct termp *p)
  43   44  {
  44   45  
  45   46          if (p->buf)
  46   47                  free(p->buf);
↓ open down ↓ 28 lines elided ↑ open up ↑
  75   76   * that should be followed by a newline, regardless of whether it's
  76   77   * broken apart by newlines getting there.  A line can also be a
  77   78   * fragment of a columnar list (`Bl -tag' or `Bl -column'), which does
  78   79   * not have a trailing newline.
  79   80   *
  80   81   * The following flags may be specified:
  81   82   *
  82   83   *  - TERMP_NOBREAK: this is the most important and is used when making
  83   84   *    columns.  In short: don't print a newline and instead expect the
  84   85   *    next call to do the padding up to the start of the next column.
       86 + *    p->trailspace may be set to 0, 1, or 2, depending on how many
       87 + *    space characters are required at the end of the column.
  85   88   *
  86      - *  - TERMP_TWOSPACE: make sure there is room for at least two space
  87      - *    characters of padding.  Otherwise, rather break the line.
  88      - *
  89   89   *  - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
  90   90   *    the line is overrun, and don't pad-right if it's underrun.
  91   91   *
  92   92   *  - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
  93   93   *    overrunning, instead save the position and continue at that point
  94   94   *    when the next invocation.
  95   95   *
  96   96   *  In-line line breaking:
  97   97   *
  98   98   *  If TERMP_NOBREAK is specified and the line overruns the right
  99   99   *  margin, it will break and pad-right to the right margin after
 100  100   *  writing.  If maxrmargin is violated, it will break and continue
 101  101   *  writing from the right-margin, which will lead to the above scenario
 102  102   *  upon exit.  Otherwise, the line will break at the right margin.
 103  103   */
 104  104  void
 105  105  term_flushln(struct termp *p)
 106  106  {
 107      -        int              i;     /* current input position in p->buf */
      107 +        size_t           i;     /* current input position in p->buf */
      108 +        int              ntab;  /* number of tabs to prepend */
 108  109          size_t           vis;   /* current visual position on output */
 109  110          size_t           vbl;   /* number of blanks to prepend to output */
 110  111          size_t           vend;  /* end of word visual position on output */
 111  112          size_t           bp;    /* visual right border position */
 112  113          size_t           dv;    /* temporary for visual pos calculations */
 113      -        int              j;     /* temporary loop index for p->buf */
 114      -        int              jhy;   /* last hyph before overflow w/r/t j */
      114 +        size_t           j;     /* temporary loop index for p->buf */
      115 +        size_t           jhy;   /* last hyph before overflow w/r/t j */
 115  116          size_t           maxvis; /* output position of visible boundary */
 116  117          size_t           mmax; /* used in calculating bp */
 117  118  
 118  119          /*
 119  120           * First, establish the maximum columns of "visible" content.
 120  121           * This is usually the difference between the right-margin and
 121  122           * an indentation, but can be, for tagged lists or columns, a
 122      -         * small set of values. 
      123 +         * small set of values.
      124 +         *
      125 +         * The following unsigned-signed subtractions look strange,
      126 +         * but they are actually correct.  If the int p->overstep
      127 +         * is negative, it gets sign extended.  Subtracting that
      128 +         * very large size_t effectively adds a small number to dv.
 123  129           */
 124  130          assert  (p->rmargin >= p->offset);
 125  131          dv     = p->rmargin - p->offset;
 126  132          maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
 127  133          dv     = p->maxrmargin - p->offset;
 128  134          mmax   = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
 129  135  
 130  136          bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
 131  137  
 132  138          /*
↓ open down ↓ 3 lines elided ↑ open up ↑
 136  142                p->offset + p->overstep - p->viscol : 0;
 137  143  
 138  144          vis = vend = 0;
 139  145          i = 0;
 140  146  
 141  147          while (i < p->col) {
 142  148                  /*
 143  149                   * Handle literal tab characters: collapse all
 144  150                   * subsequent tabs into a single huge set of spaces.
 145  151                   */
      152 +                ntab = 0;
 146  153                  while (i < p->col && '\t' == p->buf[i]) {
 147  154                          vend = (vis / p->tabwidth + 1) * p->tabwidth;
 148  155                          vbl += vend - vis;
 149  156                          vis = vend;
      157 +                        ntab++;
 150  158                          i++;
 151  159                  }
 152  160  
 153  161                  /*
 154  162                   * Count up visible word characters.  Control sequences
 155  163                   * (starting with the CSI) aren't counted.  A space
 156  164                   * generates a non-printing word, which is valid (the
 157  165                   * space is printed according to regular spacing rules).
 158  166                   */
 159  167  
 160  168                  for (j = i, jhy = 0; j < p->col; j++) {
 161      -                        if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j])
      169 +                        if (' ' == p->buf[j] || '\t' == p->buf[j])
 162  170                                  break;
 163  171  
 164  172                          /* Back over the the last printed character. */
 165  173                          if (8 == p->buf[j]) {
 166  174                                  assert(j);
 167  175                                  vend -= (*p->width)(p, p->buf[j - 1]);
 168  176                                  continue;
 169  177                          }
 170  178  
 171  179                          /* Regular word. */
↓ open down ↓ 12 lines elided ↑ open up ↑
 184  192                  if (vend > bp && 0 == jhy && vis > 0) {
 185  193                          vend -= vis;
 186  194                          (*p->endline)(p);
 187  195                          p->viscol = 0;
 188  196                          if (TERMP_NOBREAK & p->flags) {
 189  197                                  vbl = p->rmargin;
 190  198                                  vend += p->rmargin - p->offset;
 191  199                          } else
 192  200                                  vbl = p->offset;
 193  201  
 194      -                        /* Remove the p->overstep width. */
      202 +                        /* use pending tabs on the new line */
 195  203  
      204 +                        if (0 < ntab)
      205 +                                vbl += ntab * p->tabwidth;
      206 +
      207 +                        /*
      208 +                         * Remove the p->overstep width.
      209 +                         * Again, if p->overstep is negative,
      210 +                         * sign extension does the right thing.
      211 +                         */
      212 +
 196  213                          bp += (size_t)p->overstep;
 197  214                          p->overstep = 0;
 198  215                  }
 199  216  
 200  217                  /* Write out the [remaining] word. */
 201  218                  for ( ; i < p->col; i++) {
 202  219                          if (vend > bp && jhy > 0 && i > jhy)
 203  220                                  break;
 204  221                          if ('\t' == p->buf[i])
 205  222                                  break;
 206  223                          if (' ' == p->buf[i]) {
 207  224                                  j = i;
 208  225                                  while (' ' == p->buf[i])
 209  226                                          i++;
 210      -                                dv = (size_t)(i - j) * (*p->width)(p, ' ');
      227 +                                dv = (i - j) * (*p->width)(p, ' ');
 211  228                                  vbl += dv;
 212  229                                  vend += dv;
 213  230                                  break;
 214  231                          }
 215  232                          if (ASCII_NBRSP == p->buf[i]) {
 216  233                                  vbl += (*p->width)(p, ' ');
 217  234                                  continue;
 218  235                          }
 219  236  
 220  237                          /*
↓ open down ↓ 32 lines elided ↑ open up ↑
 253  270          p->col = 0;
 254  271          p->overstep = 0;
 255  272  
 256  273          if ( ! (TERMP_NOBREAK & p->flags)) {
 257  274                  p->viscol = 0;
 258  275                  (*p->endline)(p);
 259  276                  return;
 260  277          }
 261  278  
 262  279          if (TERMP_HANG & p->flags) {
 263      -                /* We need one blank after the tag. */
 264      -                p->overstep = (int)(vis - maxvis + (*p->width)(p, ' '));
      280 +                p->overstep = (int)(vis - maxvis +
      281 +                                p->trailspace * (*p->width)(p, ' '));
 265  282  
 266  283                  /*
 267      -                 * Behave exactly the same way as groff:
 268  284                   * If we have overstepped the margin, temporarily move
 269  285                   * it to the right and flag the rest of the line to be
 270  286                   * shorter.
 271      -                 * If we landed right at the margin, be happy.
 272      -                 * If we are one step before the margin, temporarily
 273      -                 * move it one step LEFT and flag the rest of the line
 274      -                 * to be longer.
      287 +                 * If there is a request to keep the columns together,
      288 +                 * allow negative overstep when the column is not full.
 275  289                   */
 276      -                if (p->overstep < -1)
      290 +                if (p->trailspace && p->overstep < 0)
 277  291                          p->overstep = 0;
 278  292                  return;
 279  293  
 280  294          } else if (TERMP_DANGLE & p->flags)
 281  295                  return;
 282  296  
 283  297          /* If the column was overrun, break the line. */
 284      -        if (maxvis <= vis +
 285      -            ((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) {
      298 +        if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) {
 286  299                  (*p->endline)(p);
 287  300                  p->viscol = 0;
 288  301          }
 289  302  }
 290  303  
 291  304  
 292  305  /* 
 293  306   * A newline only breaks an existing line; it won't assert vertical
 294  307   * space.  All data in the output buffer is flushed prior to the newline
 295  308   * assertion.
↓ open down ↓ 13 lines elided ↑ open up ↑
 309  322   * Note that if used twice, this will cause two blank spaces and so on.
 310  323   * All data in the output buffer is flushed prior to the newline
 311  324   * assertion.
 312  325   */
 313  326  void
 314  327  term_vspace(struct termp *p)
 315  328  {
 316  329  
 317  330          term_newln(p);
 318  331          p->viscol = 0;
 319      -        (*p->endline)(p);
      332 +        if (0 < p->skipvsp)
      333 +                p->skipvsp--;
      334 +        else
      335 +                (*p->endline)(p);
 320  336  }
 321  337  
 322  338  void
 323  339  term_fontlast(struct termp *p)
 324  340  {
 325  341          enum termfont    f;
 326  342  
 327  343          f = p->fontl;
 328  344          p->fontl = p->fontq[p->fonti];
 329  345          p->fontq[p->fonti] = f;
↓ open down ↓ 32 lines elided ↑ open up ↑
 362  378  {
 363  379  
 364  380          return(p->fontq[p->fonti]);
 365  381  }
 366  382  
 367  383  
 368  384  void
 369  385  term_fontpopq(struct termp *p, const void *key)
 370  386  {
 371  387  
 372      -        while (p->fonti >= 0 && key != &p->fontq[p->fonti])
      388 +        while (p->fonti >= 0 && key < (void *)(p->fontq + p->fonti))
 373  389                  p->fonti--;
 374  390          assert(p->fonti >= 0);
 375  391  }
 376  392  
 377  393  
 378  394  void
 379  395  term_fontpop(struct termp *p)
 380  396  {
 381  397  
 382  398          assert(p->fonti);
↓ open down ↓ 1 lines elided ↑ open up ↑
 384  400  }
 385  401  
 386  402  /*
 387  403   * Handle pwords, partial words, which may be either a single word or a
 388  404   * phrase that cannot be broken down (such as a literal string).  This
 389  405   * handles word styling.
 390  406   */
 391  407  void
 392  408  term_word(struct termp *p, const char *word)
 393  409  {
      410 +        const char       nbrsp[2] = { ASCII_NBRSP, 0 };
 394  411          const char      *seq, *cp;
 395  412          char             c;
 396  413          int              sz, uc;
 397  414          size_t           ssz;
 398  415          enum mandoc_esc  esc;
 399  416  
 400  417          if ( ! (TERMP_NOSPACE & p->flags)) {
 401  418                  if ( ! (TERMP_KEEP & p->flags)) {
 402      -                        if (TERMP_PREKEEP & p->flags)
 403      -                                p->flags |= TERMP_KEEP;
 404  419                          bufferc(p, ' ');
 405  420                          if (TERMP_SENTENCE & p->flags)
 406  421                                  bufferc(p, ' ');
 407  422                  } else
 408  423                          bufferc(p, ASCII_NBRSP);
 409  424          }
      425 +        if (TERMP_PREKEEP & p->flags)
      426 +                p->flags |= TERMP_KEEP;
 410  427  
 411  428          if ( ! (p->flags & TERMP_NONOSPACE))
 412  429                  p->flags &= ~TERMP_NOSPACE;
 413  430          else
 414  431                  p->flags |= TERMP_NOSPACE;
 415  432  
 416      -        p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM);
      433 +        p->flags &= ~TERMP_SENTENCE;
 417  434  
 418  435          while ('\0' != *word) {
 419      -                if ((ssz = strcspn(word, "\\")) > 0)
      436 +                if ('\\' != *word) {
      437 +                        if (TERMP_SKIPCHAR & p->flags) {
      438 +                                p->flags &= ~TERMP_SKIPCHAR;
      439 +                                word++;
      440 +                                continue;
      441 +                        }
      442 +                        if (TERMP_NBRWORD & p->flags) {
      443 +                                if (' ' == *word) {
      444 +                                        encode(p, nbrsp, 1);
      445 +                                        word++;
      446 +                                        continue;
      447 +                                }
      448 +                                ssz = strcspn(word, "\\ ");
      449 +                        } else
      450 +                                ssz = strcspn(word, "\\");
 420  451                          encode(p, word, ssz);
 421      -
 422      -                word += (int)ssz;
 423      -                if ('\\' != *word)
      452 +                        word += (int)ssz;
 424  453                          continue;
      454 +                }
 425  455  
 426  456                  word++;
 427  457                  esc = mandoc_escape(&word, &seq, &sz);
 428  458                  if (ESCAPE_ERROR == esc)
 429  459                          break;
 430  460  
 431  461                  if (TERMENC_ASCII != p->enc)
 432  462                          switch (esc) {
 433  463                          case (ESCAPE_UNICODE):
 434  464                                  uc = mchars_num2uc(seq + 1, sz - 1);
↓ open down ↓ 26 lines elided ↑ open up ↑
 461  491                                  encode(p, cp, ssz);
 462  492                          else if (1 == ssz)
 463  493                                  encode(p, seq, sz);
 464  494                          break;
 465  495                  case (ESCAPE_FONTBOLD):
 466  496                          term_fontrepl(p, TERMFONT_BOLD);
 467  497                          break;
 468  498                  case (ESCAPE_FONTITALIC):
 469  499                          term_fontrepl(p, TERMFONT_UNDER);
 470  500                          break;
      501 +                case (ESCAPE_FONTBI):
      502 +                        term_fontrepl(p, TERMFONT_BI);
      503 +                        break;
 471  504                  case (ESCAPE_FONT):
 472  505                          /* FALLTHROUGH */
 473  506                  case (ESCAPE_FONTROMAN):
 474  507                          term_fontrepl(p, TERMFONT_NONE);
 475  508                          break;
 476  509                  case (ESCAPE_FONTPREV):
 477  510                          term_fontlast(p);
 478  511                          break;
 479  512                  case (ESCAPE_NOSPACE):
 480      -                        if ('\0' == *word)
      513 +                        if (TERMP_SKIPCHAR & p->flags)
      514 +                                p->flags &= ~TERMP_SKIPCHAR;
      515 +                        else if ('\0' == *word)
 481  516                                  p->flags |= TERMP_NOSPACE;
 482  517                          break;
      518 +                case (ESCAPE_SKIPCHAR):
      519 +                        p->flags |= TERMP_SKIPCHAR;
      520 +                        break;
 483  521                  default:
 484  522                          break;
 485  523                  }
 486  524          }
      525 +        p->flags &= ~TERMP_NBRWORD;
 487  526  }
 488  527  
 489  528  static void
 490      -adjbuf(struct termp *p, int sz)
      529 +adjbuf(struct termp *p, size_t sz)
 491  530  {
 492  531  
 493  532          if (0 == p->maxcols)
 494  533                  p->maxcols = 1024;
 495  534          while (sz >= p->maxcols)
 496  535                  p->maxcols <<= 2;
 497  536  
 498      -        p->buf = mandoc_realloc
 499      -                (p->buf, sizeof(int) * (size_t)p->maxcols);
      537 +        p->buf = mandoc_realloc(p->buf, sizeof(int) * p->maxcols);
 500  538  }
 501  539  
 502  540  static void
 503  541  bufferc(struct termp *p, char c)
 504  542  {
 505  543  
 506  544          if (p->col + 1 >= p->maxcols)
 507  545                  adjbuf(p, p->col + 1);
 508  546  
 509  547          p->buf[p->col++] = c;
↓ open down ↓ 2 lines elided ↑ open up ↑
 512  550  /*
 513  551   * See encode().
 514  552   * Do this for a single (probably unicode) value.
 515  553   * Does not check for non-decorated glyphs.
 516  554   */
 517  555  static void
 518  556  encode1(struct termp *p, int c)
 519  557  {
 520  558          enum termfont     f;
 521  559  
 522      -        if (p->col + 4 >= p->maxcols)
 523      -                adjbuf(p, p->col + 4);
      560 +        if (TERMP_SKIPCHAR & p->flags) {
      561 +                p->flags &= ~TERMP_SKIPCHAR;
      562 +                return;
      563 +        }
 524  564  
      565 +        if (p->col + 6 >= p->maxcols)
      566 +                adjbuf(p, p->col + 6);
      567 +
 525  568          f = term_fonttop(p);
 526  569  
 527      -        if (TERMFONT_NONE == f) {
 528      -                p->buf[p->col++] = c;
 529      -                return;
 530      -        } else if (TERMFONT_UNDER == f) {
      570 +        if (TERMFONT_UNDER == f || TERMFONT_BI == f) {
 531  571                  p->buf[p->col++] = '_';
 532      -        } else
 533      -                p->buf[p->col++] = c;
 534      -
 535      -        p->buf[p->col++] = 8;
      572 +                p->buf[p->col++] = 8;
      573 +        }
      574 +        if (TERMFONT_BOLD == f || TERMFONT_BI == f) {
      575 +                if (ASCII_HYPH == c)
      576 +                        p->buf[p->col++] = '-';
      577 +                else
      578 +                        p->buf[p->col++] = c;
      579 +                p->buf[p->col++] = 8;
      580 +        }
 536  581          p->buf[p->col++] = c;
 537  582  }
 538  583  
 539  584  static void
 540  585  encode(struct termp *p, const char *word, size_t sz)
 541  586  {
 542      -        enum termfont     f;
 543      -        int               i, len;
      587 +        size_t            i;
 544  588  
 545      -        /* LINTED */
 546      -        len = sz;
      589 +        if (TERMP_SKIPCHAR & p->flags) {
      590 +                p->flags &= ~TERMP_SKIPCHAR;
      591 +                return;
      592 +        }
 547  593  
 548  594          /*
 549  595           * Encode and buffer a string of characters.  If the current
 550  596           * font mode is unset, buffer directly, else encode then buffer
 551  597           * character by character.
 552  598           */
 553  599  
 554      -        if (TERMFONT_NONE == (f = term_fonttop(p))) {
 555      -                if (p->col + len >= p->maxcols) 
 556      -                        adjbuf(p, p->col + len);
 557      -                for (i = 0; i < len; i++)
      600 +        if (TERMFONT_NONE == term_fonttop(p)) {
      601 +                if (p->col + sz >= p->maxcols) 
      602 +                        adjbuf(p, p->col + sz);
      603 +                for (i = 0; i < sz; i++)
 558  604                          p->buf[p->col++] = word[i];
 559  605                  return;
 560  606          }
 561  607  
 562  608          /* Pre-buffer, assuming worst-case. */
 563  609  
 564      -        if (p->col + 1 + (len * 3) >= p->maxcols)
 565      -                adjbuf(p, p->col + 1 + (len * 3));
      610 +        if (p->col + 1 + (sz * 5) >= p->maxcols)
      611 +                adjbuf(p, p->col + 1 + (sz * 5));
 566  612  
 567      -        for (i = 0; i < len; i++) {
 568      -                if (ASCII_HYPH != word[i] &&
 569      -                    ! isgraph((unsigned char)word[i])) {
 570      -                        p->buf[p->col++] = word[i];
 571      -                        continue;
 572      -                }
 573      -
 574      -                if (TERMFONT_UNDER == f)
 575      -                        p->buf[p->col++] = '_';
 576      -                else if (ASCII_HYPH == word[i])
 577      -                        p->buf[p->col++] = '-';
      613 +        for (i = 0; i < sz; i++) {
      614 +                if (ASCII_HYPH == word[i] ||
      615 +                    isgraph((unsigned char)word[i]))
      616 +                        encode1(p, word[i]);
 578  617                  else
 579  618                          p->buf[p->col++] = word[i];
 580      -
 581      -                p->buf[p->col++] = 8;
 582      -                p->buf[p->col++] = word[i];
 583  619          }
 584  620  }
 585  621  
 586  622  size_t
 587  623  term_len(const struct termp *p, size_t sz)
 588  624  {
 589  625  
 590  626          return((*p->width)(p, ' ') * sz);
 591  627  }
 592  628  
      629 +static size_t
      630 +cond_width(const struct termp *p, int c, int *skip)
      631 +{
 593  632  
      633 +        if (*skip) {
      634 +                (*skip) = 0;
      635 +                return(0);
      636 +        } else
      637 +                return((*p->width)(p, c));
      638 +}
      639 +
 594  640  size_t
 595  641  term_strlen(const struct termp *p, const char *cp)
 596  642  {
 597  643          size_t           sz, rsz, i;
 598      -        int              ssz, c;
      644 +        int              ssz, skip, c;
 599  645          const char      *seq, *rhs;
 600  646          enum mandoc_esc  esc;
 601  647          static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
 602  648  
 603  649          /*
 604  650           * Account for escaped sequences within string length
 605  651           * calculations.  This follows the logic in term_word() as we
 606  652           * must calculate the width of produced strings.
 607  653           */
 608  654  
 609  655          sz = 0;
      656 +        skip = 0;
 610  657          while ('\0' != *cp) {
 611  658                  rsz = strcspn(cp, rej);
 612  659                  for (i = 0; i < rsz; i++)
 613      -                        sz += (*p->width)(p, *cp++);
      660 +                        sz += cond_width(p, *cp++, &skip);
 614  661  
 615  662                  c = 0;
 616  663                  switch (*cp) {
 617  664                  case ('\\'):
 618  665                          cp++;
 619  666                          esc = mandoc_escape(&cp, &seq, &ssz);
 620  667                          if (ESCAPE_ERROR == esc)
 621  668                                  return(sz);
 622  669  
 623  670                          if (TERMENC_ASCII != p->enc)
 624  671                                  switch (esc) {
 625  672                                  case (ESCAPE_UNICODE):
 626  673                                          c = mchars_num2uc
 627  674                                                  (seq + 1, ssz - 1);
 628  675                                          if ('\0' == c)
 629  676                                                  break;
 630      -                                        sz += (*p->width)(p, c);
      677 +                                        sz += cond_width(p, c, &skip);
 631  678                                          continue;
 632  679                                  case (ESCAPE_SPECIAL):
 633  680                                          c = mchars_spec2cp
 634  681                                                  (p->symtab, seq, ssz);
 635  682                                          if (c <= 0)
 636  683                                                  break;
 637      -                                        sz += (*p->width)(p, c);
      684 +                                        sz += cond_width(p, c, &skip);
 638  685                                          continue;
 639  686                                  default:
 640  687                                          break;
 641  688                                  }
 642  689  
 643  690                          rhs = NULL;
 644  691  
 645  692                          switch (esc) {
 646  693                          case (ESCAPE_UNICODE):
 647      -                                sz += (*p->width)(p, '?');
      694 +                                sz += cond_width(p, '?', &skip);
 648  695                                  break;
 649  696                          case (ESCAPE_NUMBERED):
 650  697                                  c = mchars_num2char(seq, ssz);
 651  698                                  if ('\0' != c)
 652      -                                        sz += (*p->width)(p, c);
      699 +                                        sz += cond_width(p, c, &skip);
 653  700                                  break;
 654  701                          case (ESCAPE_SPECIAL):
 655  702                                  rhs = mchars_spec2str
 656  703                                          (p->symtab, seq, ssz, &rsz);
 657  704  
 658  705                                  if (ssz != 1 || rhs)
 659  706                                          break;
 660  707  
 661  708                                  rhs = seq;
 662  709                                  rsz = ssz;
 663  710                                  break;
      711 +                        case (ESCAPE_SKIPCHAR):
      712 +                                skip = 1;
      713 +                                break;
 664  714                          default:
 665  715                                  break;
 666  716                          }
 667  717  
 668  718                          if (NULL == rhs)
 669  719                                  break;
 670  720  
      721 +                        if (skip) {
      722 +                                skip = 0;
      723 +                                break;
      724 +                        }
      725 +
 671  726                          for (i = 0; i < rsz; i++)
 672  727                                  sz += (*p->width)(p, *rhs++);
 673  728                          break;
 674  729                  case (ASCII_NBRSP):
 675      -                        sz += (*p->width)(p, ' ');
      730 +                        sz += cond_width(p, ' ', &skip);
 676  731                          cp++;
 677  732                          break;
 678  733                  case (ASCII_HYPH):
 679      -                        sz += (*p->width)(p, '-');
      734 +                        sz += cond_width(p, '-', &skip);
 680  735                          cp++;
 681  736                          break;
 682  737                  default:
 683  738                          break;
 684  739                  }
 685  740          }
 686  741  
 687  742          return(sz);
 688  743  }
 689  744  
↓ open down ↓ 47 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX