Print this page
9718 update mandoc to 1.14.4

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/mandoc/roff.c
          +++ new/usr/src/cmd/mandoc/roff.c
   1      -/*      $Id: roff.c,v 1.324 2017/07/14 17:16:16 schwarze Exp $ */
        1 +/*      $Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */
   2    2  /*
   3    3   * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
   4      - * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
        4 + * Copyright (c) 2010-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
↓ open down ↓ 24 lines elided ↑ open up ↑
  39   39  /* Maximum number of string expansions per line, to break infinite loops. */
  40   40  #define EXPAND_LIMIT    1000
  41   41  
  42   42  /* Types of definitions of macros and strings. */
  43   43  #define ROFFDEF_USER    (1 << 1)  /* User-defined. */
  44   44  #define ROFFDEF_PRE     (1 << 2)  /* Predefined. */
  45   45  #define ROFFDEF_REN     (1 << 3)  /* Renamed standard macro. */
  46   46  #define ROFFDEF_STD     (1 << 4)  /* mdoc(7) or man(7) macro. */
  47   47  #define ROFFDEF_ANY     (ROFFDEF_USER | ROFFDEF_PRE | \
  48   48                           ROFFDEF_REN | ROFFDEF_STD)
       49 +#define ROFFDEF_UNDEF   (1 << 5)  /* Completely undefined. */
  49   50  
  50   51  /* --- data types --------------------------------------------------------- */
  51   52  
  52   53  /*
  53   54   * An incredibly-simple string buffer.
  54   55   */
  55   56  struct  roffstr {
  56   57          char            *p; /* nil-terminated buffer */
  57   58          size_t           sz; /* saved strlen(p) */
  58   59  };
↓ open down ↓ 6 lines elided ↑ open up ↑
  65   66          struct roffstr   val;
  66   67          struct roffkv   *next; /* next in list */
  67   68  };
  68   69  
  69   70  /*
  70   71   * A single number register as part of a singly-linked list.
  71   72   */
  72   73  struct  roffreg {
  73   74          struct roffstr   key;
  74   75          int              val;
       76 +        int              step;
  75   77          struct roffreg  *next;
  76   78  };
  77   79  
  78   80  /*
  79   81   * Association of request and macro names with token IDs.
  80   82   */
  81   83  struct  roffreq {
  82   84          enum roff_tok    tok;
  83   85          char             name[];
  84   86  };
↓ open down ↓ 89 lines elided ↑ open up ↑
 174  176                                  const char *, int *, int *, int);
 175  177  static  int              roff_evalpar(struct roff *, int,
 176  178                                  const char *, int *, int *, int);
 177  179  static  int              roff_evalstrcond(const char *, int *);
 178  180  static  void             roff_free1(struct roff *);
 179  181  static  void             roff_freereg(struct roffreg *);
 180  182  static  void             roff_freestr(struct roffkv *);
 181  183  static  size_t           roff_getname(struct roff *, char **, int, int);
 182  184  static  int              roff_getnum(const char *, int *, int *, int);
 183  185  static  int              roff_getop(const char *, int *, char *);
 184      -static  int              roff_getregn(const struct roff *,
 185      -                                const char *, size_t);
      186 +static  int              roff_getregn(struct roff *,
      187 +                                const char *, size_t, char);
 186  188  static  int              roff_getregro(const struct roff *,
 187  189                                  const char *name);
 188      -static  const char      *roff_getstrn(const struct roff *,
      190 +static  const char      *roff_getstrn(struct roff *,
 189  191                                  const char *, size_t, int *);
 190  192  static  int              roff_hasregn(const struct roff *,
 191  193                                  const char *, size_t);
 192  194  static  enum rofferr     roff_insec(ROFF_ARGS);
 193  195  static  enum rofferr     roff_it(ROFF_ARGS);
 194  196  static  enum rofferr     roff_line_ignore(ROFF_ARGS);
 195  197  static  void             roff_man_alloc1(struct roff_man *);
 196  198  static  void             roff_man_free1(struct roff_man *);
 197  199  static  enum rofferr     roff_manyarg(ROFF_ARGS);
 198  200  static  enum rofferr     roff_nr(ROFF_ARGS);
 199  201  static  enum rofferr     roff_onearg(ROFF_ARGS);
 200  202  static  enum roff_tok    roff_parse(struct roff *, char *, int *,
 201  203                                  int, int);
 202  204  static  enum rofferr     roff_parsetext(struct roff *, struct buf *,
 203  205                                  int, int *);
 204  206  static  enum rofferr     roff_renamed(ROFF_ARGS);
 205  207  static  enum rofferr     roff_res(struct roff *, struct buf *, int, int);
 206  208  static  enum rofferr     roff_rm(ROFF_ARGS);
 207  209  static  enum rofferr     roff_rn(ROFF_ARGS);
 208  210  static  enum rofferr     roff_rr(ROFF_ARGS);
      211 +static  void             roff_setregn(struct roff *, const char *,
      212 +                                size_t, int, char, int);
 209  213  static  void             roff_setstr(struct roff *,
 210  214                                  const char *, const char *, int);
 211  215  static  void             roff_setstrn(struct roffkv **, const char *,
 212  216                                  size_t, const char *, size_t, int);
 213  217  static  enum rofferr     roff_so(ROFF_ARGS);
 214  218  static  enum rofferr     roff_tr(ROFF_ARGS);
 215  219  static  enum rofferr     roff_Dd(ROFF_ARGS);
 216  220  static  enum rofferr     roff_TE(ROFF_ARGS);
 217  221  static  enum rofferr     roff_TS(ROFF_ARGS);
 218  222  static  enum rofferr     roff_EQ(ROFF_ARGS);
↓ open down ↓ 532 lines elided ↑ open up ↑
 751  755          free(r);
 752  756  }
 753  757  
 754  758  struct roff *
 755  759  roff_alloc(struct mparse *parse, int options)
 756  760  {
 757  761          struct roff     *r;
 758  762  
 759  763          r = mandoc_calloc(1, sizeof(struct roff));
 760  764          r->parse = parse;
 761      -        r->reqtab = roffhash_alloc(0, ROFF_USERDEF);
      765 +        r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
 762  766          r->options = options;
 763  767          r->format = options & (MPARSE_MDOC | MPARSE_MAN);
 764  768          r->rstackpos = -1;
 765  769          r->escape = '\\';
 766  770          return r;
 767  771  }
 768  772  
 769  773  /* --- syntax tree state data management ---------------------------------- */
 770  774  
 771  775  static void
↓ open down ↓ 339 lines elided ↑ open up ↑
1111 1115  
1112 1116  /*
1113 1117   * In the current line, expand escape sequences that tend to get
1114 1118   * used in numerical expressions and conditional requests.
1115 1119   * Also check the syntax of the remaining escape sequences.
1116 1120   */
1117 1121  static enum rofferr
1118 1122  roff_res(struct roff *r, struct buf *buf, int ln, int pos)
1119 1123  {
1120 1124          char             ubuf[24]; /* buffer to print the number */
     1125 +        struct roff_node *n;    /* used for header comments */
1121 1126          const char      *start; /* start of the string to process */
1122 1127          char            *stesc; /* start of an escape sequence ('\\') */
     1128 +        char            *ep;    /* end of comment string */
1123 1129          const char      *stnam; /* start of the name, after "[(*" */
1124 1130          const char      *cp;    /* end of the name, e.g. before ']' */
1125 1131          const char      *res;   /* the string to be substituted */
1126 1132          char            *nbuf;  /* new buffer to copy buf->buf to */
1127 1133          size_t           maxl;  /* expected length of the escape name */
1128 1134          size_t           naml;  /* actual length of the escape name */
1129 1135          enum mandoc_esc  esc;   /* type of the escape sequence */
1130 1136          int              inaml; /* length returned from mandoc_escape() */
1131 1137          int              expand_count;  /* to avoid infinite loops */
1132 1138          int              npos;  /* position in numeric expression */
1133 1139          int              arg_complete; /* argument not interrupted by eol */
1134 1140          int              done;  /* no more input available */
1135 1141          int              deftype; /* type of definition to paste */
1136 1142          int              rcsid; /* kind of RCS id seen */
     1143 +        char             sign;  /* increment number register */
1137 1144          char             term;  /* character terminating the escape */
1138 1145  
1139 1146          /* Search forward for comments. */
1140 1147  
1141 1148          done = 0;
1142 1149          start = buf->buf + pos;
1143 1150          for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) {
1144 1151                  if (stesc[0] != r->escape || stesc[1] == '\0')
1145 1152                          continue;
1146 1153                  stesc++;
↓ open down ↓ 14 lines elided ↑ open up ↑
1161 1168                      isalnum((unsigned char)*cp) == 0 &&
1162 1169                      strchr(cp, '$') != NULL) {
1163 1170                          if (r->man->meta.rcsids & rcsid)
1164 1171                                  mandoc_msg(MANDOCERR_RCS_REP, r->parse,
1165 1172                                      ln, stesc + 1 - buf->buf, stesc + 1);
1166 1173                          r->man->meta.rcsids |= rcsid;
1167 1174                  }
1168 1175  
1169 1176                  /* Handle trailing whitespace. */
1170 1177  
1171      -                cp = strchr(stesc--, '\0') - 1;
1172      -                if (*cp == '\n') {
     1178 +                ep = strchr(stesc--, '\0') - 1;
     1179 +                if (*ep == '\n') {
1173 1180                          done = 1;
1174      -                        cp--;
     1181 +                        ep--;
1175 1182                  }
1176      -                if (*cp == ' ' || *cp == '\t')
     1183 +                if (*ep == ' ' || *ep == '\t')
1177 1184                          mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
1178      -                            ln, cp - buf->buf, NULL);
     1185 +                            ln, ep - buf->buf, NULL);
     1186 +
     1187 +                /*
     1188 +                 * Save comments preceding the title macro
     1189 +                 * in the syntax tree.
     1190 +                 */
     1191 +
     1192 +                if (r->format == 0) {
     1193 +                        while (*ep == ' ' || *ep == '\t')
     1194 +                                ep--;
     1195 +                        ep[1] = '\0';
     1196 +                        n = roff_node_alloc(r->man,
     1197 +                            ln, stesc + 1 - buf->buf,
     1198 +                            ROFFT_COMMENT, TOKEN_NONE);
     1199 +                        n->string = mandoc_strdup(stesc + 2);
     1200 +                        roff_node_append(r->man, n);
     1201 +                        n->flags |= NODE_VALID | NODE_ENDED;
     1202 +                        r->man->next = ROFF_NEXT_SIBLING;
     1203 +                }
     1204 +
     1205 +                /* Discard comments. */
     1206 +
1179 1207                  while (stesc > start && stesc[-1] == ' ')
1180 1208                          stesc--;
1181 1209                  *stesc = '\0';
1182 1210                  break;
1183 1211          }
1184 1212          if (stesc == start)
1185 1213                  return ROFF_CONT;
1186 1214          stesc--;
1187 1215  
1188 1216          /* Notice the end of the input. */
↓ open down ↓ 48 lines elided ↑ open up ↑
1237 1265                  cp = stesc + 1;
1238 1266                  switch (*cp) {
1239 1267                  case '*':
1240 1268                          res = NULL;
1241 1269                          break;
1242 1270                  case 'B':
1243 1271                  case 'w':
1244 1272                          term = cp[1];
1245 1273                          /* FALLTHROUGH */
1246 1274                  case 'n':
     1275 +                        sign = cp[1];
     1276 +                        if (sign == '+' || sign == '-')
     1277 +                                cp++;
1247 1278                          res = ubuf;
1248 1279                          break;
1249 1280                  default:
1250 1281                          esc = mandoc_escape(&cp, &stnam, &inaml);
1251 1282                          if (esc == ESCAPE_ERROR ||
1252 1283                              (esc == ESCAPE_SPECIAL &&
1253 1284                               mchars_spec2cp(stnam, inaml) < 0))
1254 1285                                  mandoc_vmsg(MANDOCERR_ESC_BAD,
1255 1286                                      r->parse, ln, (int)(stesc - buf->buf),
1256 1287                                      "%.*s", (int)(cp - stesc), stesc);
↓ open down ↓ 84 lines elided ↑ open up ↑
1341 1372                          npos = 0;
1342 1373                          ubuf[0] = arg_complete &&
1343 1374                              roff_evalnum(r, ln, stnam, &npos,
1344 1375                                NULL, ROFFNUM_SCALE) &&
1345 1376                              stnam + npos + 1 == cp ? '1' : '0';
1346 1377                          ubuf[1] = '\0';
1347 1378                          break;
1348 1379                  case 'n':
1349 1380                          if (arg_complete)
1350 1381                                  (void)snprintf(ubuf, sizeof(ubuf), "%d",
1351      -                                    roff_getregn(r, stnam, naml));
     1382 +                                    roff_getregn(r, stnam, naml, sign));
1352 1383                          else
1353 1384                                  ubuf[0] = '\0';
1354 1385                          break;
1355 1386                  case 'w':
1356 1387                          /* use even incomplete args */
1357 1388                          (void)snprintf(ubuf, sizeof(ubuf), "%d",
1358 1389                              24 * (int)naml);
1359 1390                          break;
1360 1391                  }
1361 1392  
↓ open down ↓ 270 lines elided ↑ open up ↑
1632 1663                  break;
1633 1664          case ROFFDEF_REN:
1634 1665                  t = ROFF_RENAMED;
1635 1666                  break;
1636 1667          default:
1637 1668                  t = roffhash_find(r->reqtab, mac, maclen);
1638 1669                  break;
1639 1670          }
1640 1671          if (t != TOKEN_NONE)
1641 1672                  *pos = cp - buf;
     1673 +        else if (deftype == ROFFDEF_UNDEF) {
     1674 +                /* Using an undefined macro defines it to be empty. */
     1675 +                roff_setstrn(&r->strtab, mac, maclen, "", 0, 0);
     1676 +                roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0);
     1677 +        }
1642 1678          return t;
1643 1679  }
1644 1680  
1645 1681  /* --- handling of request blocks ----------------------------------------- */
1646 1682  
1647 1683  static enum rofferr
1648 1684  roff_cblock(ROFF_ARGS)
1649 1685  {
1650 1686  
1651 1687          /*
↓ open down ↓ 856 lines elided ↑ open up ↑
2508 2544                  }
2509 2545          }
2510 2546          return 1;
2511 2547  }
2512 2548  
2513 2549  /* --- register management ------------------------------------------------ */
2514 2550  
2515 2551  void
2516 2552  roff_setreg(struct roff *r, const char *name, int val, char sign)
2517 2553  {
     2554 +        roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
     2555 +}
     2556 +
     2557 +static void
     2558 +roff_setregn(struct roff *r, const char *name, size_t len,
     2559 +    int val, char sign, int step)
     2560 +{
2518 2561          struct roffreg  *reg;
2519 2562  
2520 2563          /* Search for an existing register with the same name. */
2521 2564          reg = r->regtab;
2522 2565  
2523      -        while (reg && strcmp(name, reg->key.p))
     2566 +        while (reg != NULL && (reg->key.sz != len ||
     2567 +            strncmp(reg->key.p, name, len) != 0))
2524 2568                  reg = reg->next;
2525 2569  
2526 2570          if (NULL == reg) {
2527 2571                  /* Create a new register. */
2528 2572                  reg = mandoc_malloc(sizeof(struct roffreg));
2529      -                reg->key.p = mandoc_strdup(name);
2530      -                reg->key.sz = strlen(name);
     2573 +                reg->key.p = mandoc_strndup(name, len);
     2574 +                reg->key.sz = len;
2531 2575                  reg->val = 0;
     2576 +                reg->step = 0;
2532 2577                  reg->next = r->regtab;
2533 2578                  r->regtab = reg;
2534 2579          }
2535 2580  
2536 2581          if ('+' == sign)
2537 2582                  reg->val += val;
2538 2583          else if ('-' == sign)
2539 2584                  reg->val -= val;
2540 2585          else
2541 2586                  reg->val = val;
     2587 +        if (step != INT_MIN)
     2588 +                reg->step = step;
2542 2589  }
2543 2590  
2544 2591  /*
2545 2592   * Handle some predefined read-only number registers.
2546 2593   * For now, return -1 if the requested register is not predefined;
2547 2594   * in case a predefined read-only register having the value -1
2548 2595   * were to turn up, another special value would have to be chosen.
2549 2596   */
2550 2597  static int
2551 2598  roff_getregro(const struct roff *r, const char *name)
↓ open down ↓ 13 lines elided ↑ open up ↑
2565 2612          case 'T':  /* Some output device is always defined. */
2566 2613                  return 1;
2567 2614          case 'V':  /* Fixed vertical resolution. */
2568 2615                  return 40;
2569 2616          default:
2570 2617                  return -1;
2571 2618          }
2572 2619  }
2573 2620  
2574 2621  int
2575      -roff_getreg(const struct roff *r, const char *name)
     2622 +roff_getreg(struct roff *r, const char *name)
2576 2623  {
2577      -        struct roffreg  *reg;
2578      -        int              val;
2579      -
2580      -        if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
2581      -                val = roff_getregro(r, name + 1);
2582      -                if (-1 != val)
2583      -                        return val;
2584      -        }
2585      -
2586      -        for (reg = r->regtab; reg; reg = reg->next)
2587      -                if (0 == strcmp(name, reg->key.p))
2588      -                        return reg->val;
2589      -
2590      -        return 0;
     2624 +        return roff_getregn(r, name, strlen(name), '\0');
2591 2625  }
2592 2626  
2593 2627  static int
2594      -roff_getregn(const struct roff *r, const char *name, size_t len)
     2628 +roff_getregn(struct roff *r, const char *name, size_t len, char sign)
2595 2629  {
2596 2630          struct roffreg  *reg;
2597 2631          int              val;
2598 2632  
2599 2633          if ('.' == name[0] && 2 == len) {
2600 2634                  val = roff_getregro(r, name + 1);
2601 2635                  if (-1 != val)
2602 2636                          return val;
2603 2637          }
2604 2638  
2605      -        for (reg = r->regtab; reg; reg = reg->next)
     2639 +        for (reg = r->regtab; reg; reg = reg->next) {
2606 2640                  if (len == reg->key.sz &&
2607      -                    0 == strncmp(name, reg->key.p, len))
     2641 +                    0 == strncmp(name, reg->key.p, len)) {
     2642 +                        switch (sign) {
     2643 +                        case '+':
     2644 +                                reg->val += reg->step;
     2645 +                                break;
     2646 +                        case '-':
     2647 +                                reg->val -= reg->step;
     2648 +                                break;
     2649 +                        default:
     2650 +                                break;
     2651 +                        }
2608 2652                          return reg->val;
     2653 +                }
     2654 +        }
2609 2655  
     2656 +        roff_setregn(r, name, len, 0, '\0', INT_MIN);
2610 2657          return 0;
2611 2658  }
2612 2659  
2613 2660  static int
2614 2661  roff_hasregn(const struct roff *r, const char *name, size_t len)
2615 2662  {
2616 2663          struct roffreg  *reg;
2617 2664          int              val;
2618 2665  
2619 2666          if ('.' == name[0] && 2 == len) {
↓ open down ↓ 19 lines elided ↑ open up ↑
2639 2686                  free(reg->key.p);
2640 2687                  old_reg = reg;
2641 2688                  reg = reg->next;
2642 2689                  free(old_reg);
2643 2690          }
2644 2691  }
2645 2692  
2646 2693  static enum rofferr
2647 2694  roff_nr(ROFF_ARGS)
2648 2695  {
2649      -        char            *key, *val;
     2696 +        char            *key, *val, *step;
2650 2697          size_t           keysz;
2651      -        int              iv;
     2698 +        int              iv, is, len;
2652 2699          char             sign;
2653 2700  
2654 2701          key = val = buf->buf + pos;
2655 2702          if (*key == '\0')
2656 2703                  return ROFF_IGN;
2657 2704  
2658 2705          keysz = roff_getname(r, &val, ln, pos);
2659 2706          if (key[keysz] == '\\')
2660 2707                  return ROFF_IGN;
2661      -        key[keysz] = '\0';
2662 2708  
2663 2709          sign = *val;
2664 2710          if (sign == '+' || sign == '-')
2665 2711                  val++;
2666 2712  
2667      -        if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
2668      -                roff_setreg(r, key, iv, sign);
     2713 +        len = 0;
     2714 +        if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
     2715 +                return ROFF_IGN;
2669 2716  
     2717 +        step = val + len;
     2718 +        while (isspace((unsigned char)*step))
     2719 +                step++;
     2720 +        if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
     2721 +                is = INT_MIN;
     2722 +
     2723 +        roff_setregn(r, key, keysz, iv, sign, is);
2670 2724          return ROFF_IGN;
2671 2725  }
2672 2726  
2673 2727  static enum rofferr
2674 2728  roff_rr(ROFF_ARGS)
2675 2729  {
2676 2730          struct roffreg  *reg, **prev;
2677 2731          char            *name, *cp;
2678 2732          size_t           namesz;
2679 2733  
↓ open down ↓ 104 lines elided ↑ open up ↑
2784 2838          if (r->tbl == NULL) {
2785 2839                  mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
2786 2840                      ln, ppos, "TE");
2787 2841                  return ROFF_IGN;
2788 2842          }
2789 2843          if (tbl_end(r->tbl) == 0) {
2790 2844                  r->tbl = NULL;
2791 2845                  free(buf->buf);
2792 2846                  buf->buf = mandoc_strdup(".sp");
2793 2847                  buf->sz = 4;
     2848 +                *offs = 0;
2794 2849                  return ROFF_REPARSE;
2795 2850          }
2796 2851          r->tbl = NULL;
2797 2852          return ROFF_IGN;
2798 2853  }
2799 2854  
2800 2855  static enum rofferr
2801 2856  roff_T_(ROFF_ARGS)
2802 2857  {
2803 2858  
↓ open down ↓ 499 lines elided ↑ open up ↑
3303 3358                   * Prevent infinite recursion.
3304 3359                   */
3305 3360  
3306 3361                  if (cp >= n2)
3307 3362                          expand_count = 1;
3308 3363                  else if (++expand_count > EXPAND_LIMIT) {
3309 3364                          mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
3310 3365                              ln, (int)(cp - n1), NULL);
3311 3366                          free(buf->buf);
3312 3367                          buf->buf = n1;
     3368 +                        *offs = 0;
3313 3369                          return ROFF_IGN;
3314 3370                  }
3315 3371  
3316 3372                  /*
3317 3373                   * Determine the size of the expanded argument,
3318 3374                   * taking escaping of quotes into account.
3319 3375                   */
3320 3376  
3321 3377                  asz = ie > ib ? ie - ib : 0;  /* for blanks */
3322 3378                  for (i = ib; i <= ie; i++) {
↓ open down ↓ 74 lines elided ↑ open up ↑
3397 3453   */
3398 3454  static enum rofferr
3399 3455  roff_renamed(ROFF_ARGS)
3400 3456  {
3401 3457          char    *nbuf;
3402 3458  
3403 3459          buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string,
3404 3460              buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
3405 3461          free(buf->buf);
3406 3462          buf->buf = nbuf;
     3463 +        *offs = 0;
3407 3464          return ROFF_CONT;
3408 3465  }
3409 3466  
3410 3467  static size_t
3411 3468  roff_getname(struct roff *r, char **cpp, int ln, int pos)
3412 3469  {
3413 3470          char     *name, *cp;
3414 3471          size_t    namesz;
3415 3472  
3416 3473          name = *cpp;
↓ open down ↓ 113 lines elided ↑ open up ↑
3530 3587  
3531 3588          /* Append terminating bytes. */
3532 3589          if (1 < append)
3533 3590                  *c++ = '\n';
3534 3591  
3535 3592          *c = '\0';
3536 3593          n->val.sz = (int)(c - n->val.p);
3537 3594  }
3538 3595  
3539 3596  static const char *
3540      -roff_getstrn(const struct roff *r, const char *name, size_t len,
     3597 +roff_getstrn(struct roff *r, const char *name, size_t len,
3541 3598      int *deftype)
3542 3599  {
3543 3600          const struct roffkv     *n;
3544      -        int                      i;
     3601 +        int                      found, i;
3545 3602          enum roff_tok            tok;
3546 3603  
3547      -        if (*deftype & ROFFDEF_USER) {
3548      -                for (n = r->strtab; n != NULL; n = n->next) {
3549      -                        if (strncmp(name, n->key.p, len) == 0 &&
3550      -                            n->key.p[len] == '\0' &&
3551      -                            n->val.p != NULL) {
3552      -                                *deftype = ROFFDEF_USER;
3553      -                                return n->val.p;
3554      -                        }
     3604 +        found = 0;
     3605 +        for (n = r->strtab; n != NULL; n = n->next) {
     3606 +                if (strncmp(name, n->key.p, len) != 0 ||
     3607 +                    n->key.p[len] != '\0' || n->val.p == NULL)
     3608 +                        continue;
     3609 +                if (*deftype & ROFFDEF_USER) {
     3610 +                        *deftype = ROFFDEF_USER;
     3611 +                        return n->val.p;
     3612 +                } else {
     3613 +                        found = 1;
     3614 +                        break;
3555 3615                  }
3556 3616          }
3557      -        if (*deftype & ROFFDEF_PRE) {
3558      -                for (i = 0; i < PREDEFS_MAX; i++) {
3559      -                        if (strncmp(name, predefs[i].name, len) == 0 &&
3560      -                            predefs[i].name[len] == '\0') {
3561      -                                *deftype = ROFFDEF_PRE;
3562      -                                return predefs[i].str;
3563      -                        }
     3617 +        for (n = r->rentab; n != NULL; n = n->next) {
     3618 +                if (strncmp(name, n->key.p, len) != 0 ||
     3619 +                    n->key.p[len] != '\0' || n->val.p == NULL)
     3620 +                        continue;
     3621 +                if (*deftype & ROFFDEF_REN) {
     3622 +                        *deftype = ROFFDEF_REN;
     3623 +                        return n->val.p;
     3624 +                } else {
     3625 +                        found = 1;
     3626 +                        break;
3564 3627                  }
3565 3628          }
3566      -        if (*deftype & ROFFDEF_REN) {
3567      -                for (n = r->rentab; n != NULL; n = n->next) {
3568      -                        if (strncmp(name, n->key.p, len) == 0 &&
3569      -                            n->key.p[len] == '\0' &&
3570      -                            n->val.p != NULL) {
3571      -                                *deftype = ROFFDEF_REN;
3572      -                                return n->val.p;
3573      -                        }
     3629 +        for (i = 0; i < PREDEFS_MAX; i++) {
     3630 +                if (strncmp(name, predefs[i].name, len) != 0 ||
     3631 +                    predefs[i].name[len] != '\0')
     3632 +                        continue;
     3633 +                if (*deftype & ROFFDEF_PRE) {
     3634 +                        *deftype = ROFFDEF_PRE;
     3635 +                        return predefs[i].str;
     3636 +                } else {
     3637 +                        found = 1;
     3638 +                        break;
3574 3639                  }
3575 3640          }
3576      -        if (*deftype & ROFFDEF_STD) {
3577      -                if (r->man->macroset != MACROSET_MAN) {
3578      -                        for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
3579      -                                if (strncmp(name, roff_name[tok], len) == 0 &&
3580      -                                    roff_name[tok][len] == '\0') {
3581      -                                        *deftype = ROFFDEF_STD;
3582      -                                        return NULL;
3583      -                                }
     3641 +        if (r->man->macroset != MACROSET_MAN) {
     3642 +                for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
     3643 +                        if (strncmp(name, roff_name[tok], len) != 0 ||
     3644 +                            roff_name[tok][len] != '\0')
     3645 +                                continue;
     3646 +                        if (*deftype & ROFFDEF_STD) {
     3647 +                                *deftype = ROFFDEF_STD;
     3648 +                                return NULL;
     3649 +                        } else {
     3650 +                                found = 1;
     3651 +                                break;
3584 3652                          }
3585 3653                  }
3586      -                if (r->man->macroset != MACROSET_MDOC) {
3587      -                        for (tok = MAN_TH; tok < MAN_MAX; tok++) {
3588      -                                if (strncmp(name, roff_name[tok], len) == 0 &&
3589      -                                    roff_name[tok][len] == '\0') {
3590      -                                        *deftype = ROFFDEF_STD;
3591      -                                        return NULL;
3592      -                                }
     3654 +        }
     3655 +        if (r->man->macroset != MACROSET_MDOC) {
     3656 +                for (tok = MAN_TH; tok < MAN_MAX; tok++) {
     3657 +                        if (strncmp(name, roff_name[tok], len) != 0 ||
     3658 +                            roff_name[tok][len] != '\0')
     3659 +                                continue;
     3660 +                        if (*deftype & ROFFDEF_STD) {
     3661 +                                *deftype = ROFFDEF_STD;
     3662 +                                return NULL;
     3663 +                        } else {
     3664 +                                found = 1;
     3665 +                                break;
3593 3666                          }
3594 3667                  }
3595 3668          }
     3669 +
     3670 +        if (found == 0 && *deftype != ROFFDEF_ANY) {
     3671 +                if (*deftype & ROFFDEF_REN) {
     3672 +                        /*
     3673 +                         * This might still be a request,
     3674 +                         * so do not treat it as undefined yet.
     3675 +                         */
     3676 +                        *deftype = ROFFDEF_UNDEF;
     3677 +                        return NULL;
     3678 +                }
     3679 +
     3680 +                /* Using an undefined string defines it to be empty. */
     3681 +
     3682 +                roff_setstrn(&r->strtab, name, len, "", 0, 0);
     3683 +                roff_setstrn(&r->rentab, name, len, NULL, 0, 0);
     3684 +        }
     3685 +
3596 3686          *deftype = 0;
3597 3687          return NULL;
3598 3688  }
3599 3689  
3600 3690  static void
3601 3691  roff_freestr(struct roffkv *r)
3602 3692  {
3603 3693          struct roffkv    *n, *nn;
3604 3694  
3605 3695          for (n = r; n; n = nn) {
↓ open down ↓ 143 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX