Print this page
9718 update mandoc to 1.14.4
   1 /*      $Id: roff.c,v 1.324 2017/07/14 17:16:16 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
   5  *
   6  * Permission to use, copy, modify, and distribute this software for any
   7  * purpose with or without fee is hereby granted, provided that the above
   8  * copyright notice and this permission notice appear in all copies.
   9  *
  10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
  11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
  13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17  */
  18 #include "config.h"
  19 
  20 #include <sys/types.h>
  21 
  22 #include <assert.h>
  23 #include <ctype.h>
  24 #include <limits.h>


  29 #include <string.h>
  30 
  31 #include "mandoc.h"
  32 #include "mandoc_aux.h"
  33 #include "mandoc_ohash.h"
  34 #include "roff.h"
  35 #include "libmandoc.h"
  36 #include "roff_int.h"
  37 #include "libroff.h"
  38 
  39 /* Maximum number of string expansions per line, to break infinite loops. */
  40 #define EXPAND_LIMIT    1000
  41 
  42 /* Types of definitions of macros and strings. */
  43 #define ROFFDEF_USER    (1 << 1)  /* User-defined. */
  44 #define ROFFDEF_PRE     (1 << 2)  /* Predefined. */
  45 #define ROFFDEF_REN     (1 << 3)  /* Renamed standard macro. */
  46 #define ROFFDEF_STD     (1 << 4)  /* mdoc(7) or man(7) macro. */
  47 #define ROFFDEF_ANY     (ROFFDEF_USER | ROFFDEF_PRE | \
  48                          ROFFDEF_REN | ROFFDEF_STD)

  49 
  50 /* --- data types --------------------------------------------------------- */
  51 
  52 /*
  53  * An incredibly-simple string buffer.
  54  */
  55 struct  roffstr {
  56         char            *p; /* nil-terminated buffer */
  57         size_t           sz; /* saved strlen(p) */
  58 };
  59 
  60 /*
  61  * A key-value roffstr pair as part of a singly-linked list.
  62  */
  63 struct  roffkv {
  64         struct roffstr   key;
  65         struct roffstr   val;
  66         struct roffkv   *next; /* next in list */
  67 };
  68 
  69 /*
  70  * A single number register as part of a singly-linked list.
  71  */
  72 struct  roffreg {
  73         struct roffstr   key;
  74         int              val;

  75         struct roffreg  *next;
  76 };
  77 
  78 /*
  79  * Association of request and macro names with token IDs.
  80  */
  81 struct  roffreq {
  82         enum roff_tok    tok;
  83         char             name[];
  84 };
  85 
  86 struct  roff {
  87         struct mparse   *parse; /* parse point */
  88         struct roff_man *man; /* mdoc or man parser */
  89         struct roffnode *last; /* leaf of stack */
  90         int             *rstack; /* stack of inverted `ie' values */
  91         struct ohash    *reqtab; /* request lookup table */
  92         struct roffreg  *regtab; /* number registers */
  93         struct roffkv   *strtab; /* user-defined strings & macros */
  94         struct roffkv   *rentab; /* renamed strings & macros */


 164 static  void             roff_ccond(struct roff *, int, int);
 165 static  enum rofferr     roff_cond(ROFF_ARGS);
 166 static  enum rofferr     roff_cond_text(ROFF_ARGS);
 167 static  enum rofferr     roff_cond_sub(ROFF_ARGS);
 168 static  enum rofferr     roff_ds(ROFF_ARGS);
 169 static  enum rofferr     roff_ec(ROFF_ARGS);
 170 static  enum rofferr     roff_eo(ROFF_ARGS);
 171 static  enum rofferr     roff_eqndelim(struct roff *, struct buf *, int);
 172 static  int              roff_evalcond(struct roff *r, int, char *, int *);
 173 static  int              roff_evalnum(struct roff *, int,
 174                                 const char *, int *, int *, int);
 175 static  int              roff_evalpar(struct roff *, int,
 176                                 const char *, int *, int *, int);
 177 static  int              roff_evalstrcond(const char *, int *);
 178 static  void             roff_free1(struct roff *);
 179 static  void             roff_freereg(struct roffreg *);
 180 static  void             roff_freestr(struct roffkv *);
 181 static  size_t           roff_getname(struct roff *, char **, int, int);
 182 static  int              roff_getnum(const char *, int *, int *, int);
 183 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_getregro(const struct roff *,
 187                                 const char *name);
 188 static  const char      *roff_getstrn(const struct roff *,
 189                                 const char *, size_t, int *);
 190 static  int              roff_hasregn(const struct roff *,
 191                                 const char *, size_t);
 192 static  enum rofferr     roff_insec(ROFF_ARGS);
 193 static  enum rofferr     roff_it(ROFF_ARGS);
 194 static  enum rofferr     roff_line_ignore(ROFF_ARGS);
 195 static  void             roff_man_alloc1(struct roff_man *);
 196 static  void             roff_man_free1(struct roff_man *);
 197 static  enum rofferr     roff_manyarg(ROFF_ARGS);
 198 static  enum rofferr     roff_nr(ROFF_ARGS);
 199 static  enum rofferr     roff_onearg(ROFF_ARGS);
 200 static  enum roff_tok    roff_parse(struct roff *, char *, int *,
 201                                 int, int);
 202 static  enum rofferr     roff_parsetext(struct roff *, struct buf *,
 203                                 int, int *);
 204 static  enum rofferr     roff_renamed(ROFF_ARGS);
 205 static  enum rofferr     roff_res(struct roff *, struct buf *, int, int);
 206 static  enum rofferr     roff_rm(ROFF_ARGS);
 207 static  enum rofferr     roff_rn(ROFF_ARGS);
 208 static  enum rofferr     roff_rr(ROFF_ARGS);


 209 static  void             roff_setstr(struct roff *,
 210                                 const char *, const char *, int);
 211 static  void             roff_setstrn(struct roffkv **, const char *,
 212                                 size_t, const char *, size_t, int);
 213 static  enum rofferr     roff_so(ROFF_ARGS);
 214 static  enum rofferr     roff_tr(ROFF_ARGS);
 215 static  enum rofferr     roff_Dd(ROFF_ARGS);
 216 static  enum rofferr     roff_TE(ROFF_ARGS);
 217 static  enum rofferr     roff_TS(ROFF_ARGS);
 218 static  enum rofferr     roff_EQ(ROFF_ARGS);
 219 static  enum rofferr     roff_EN(ROFF_ARGS);
 220 static  enum rofferr     roff_T_(ROFF_ARGS);
 221 static  enum rofferr     roff_unsupp(ROFF_ARGS);
 222 static  enum rofferr     roff_userdef(ROFF_ARGS);
 223 
 224 /* --- constant data ------------------------------------------------------ */
 225 
 226 #define ROFFNUM_SCALE   (1 << 0)  /* Honour scaling in roff_getnum(). */
 227 #define ROFFNUM_WHITE   (1 << 1)  /* Skip whitespace in roff_evalnum(). */
 228 


 741         roffce_node = NULL;
 742         roffit_lines = 0;
 743         roffit_macro = NULL;
 744 }
 745 
 746 void
 747 roff_free(struct roff *r)
 748 {
 749         roff_free1(r);
 750         roffhash_free(r->reqtab);
 751         free(r);
 752 }
 753 
 754 struct roff *
 755 roff_alloc(struct mparse *parse, int options)
 756 {
 757         struct roff     *r;
 758 
 759         r = mandoc_calloc(1, sizeof(struct roff));
 760         r->parse = parse;
 761         r->reqtab = roffhash_alloc(0, ROFF_USERDEF);
 762         r->options = options;
 763         r->format = options & (MPARSE_MDOC | MPARSE_MAN);
 764         r->rstackpos = -1;
 765         r->escape = '\\';
 766         return r;
 767 }
 768 
 769 /* --- syntax tree state data management ---------------------------------- */
 770 
 771 static void
 772 roff_man_free1(struct roff_man *man)
 773 {
 774 
 775         if (man->first != NULL)
 776                 roff_node_delete(man, man->first);
 777         free(man->meta.msec);
 778         free(man->meta.vol);
 779         free(man->meta.os);
 780         free(man->meta.arch);
 781         free(man->meta.title);


1101                 *dest = mandoc_strndup(cp, sz);
1102                 return;
1103         }
1104 
1105         mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
1106         free(*dest);
1107         *dest = cp;
1108 }
1109 
1110 /* --- main functions of the roff parser ---------------------------------- */
1111 
1112 /*
1113  * In the current line, expand escape sequences that tend to get
1114  * used in numerical expressions and conditional requests.
1115  * Also check the syntax of the remaining escape sequences.
1116  */
1117 static enum rofferr
1118 roff_res(struct roff *r, struct buf *buf, int ln, int pos)
1119 {
1120         char             ubuf[24]; /* buffer to print the number */

1121         const char      *start; /* start of the string to process */
1122         char            *stesc; /* start of an escape sequence ('\\') */

1123         const char      *stnam; /* start of the name, after "[(*" */
1124         const char      *cp;    /* end of the name, e.g. before ']' */
1125         const char      *res;   /* the string to be substituted */
1126         char            *nbuf;  /* new buffer to copy buf->buf to */
1127         size_t           maxl;  /* expected length of the escape name */
1128         size_t           naml;  /* actual length of the escape name */
1129         enum mandoc_esc  esc;   /* type of the escape sequence */
1130         int              inaml; /* length returned from mandoc_escape() */
1131         int              expand_count;  /* to avoid infinite loops */
1132         int              npos;  /* position in numeric expression */
1133         int              arg_complete; /* argument not interrupted by eol */
1134         int              done;  /* no more input available */
1135         int              deftype; /* type of definition to paste */
1136         int              rcsid; /* kind of RCS id seen */

1137         char             term;  /* character terminating the escape */
1138 
1139         /* Search forward for comments. */
1140 
1141         done = 0;
1142         start = buf->buf + pos;
1143         for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) {
1144                 if (stesc[0] != r->escape || stesc[1] == '\0')
1145                         continue;
1146                 stesc++;
1147                 if (*stesc != '"' && *stesc != '#')
1148                         continue;
1149 
1150                 /* Comment found, look for RCS id. */
1151 
1152                 rcsid = 0;
1153                 if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) {
1154                         rcsid = 1 << MANDOC_OS_OPENBSD;
1155                         cp += 8;
1156                 } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) {
1157                         rcsid = 1 << MANDOC_OS_NETBSD;
1158                         cp += 7;
1159                 }
1160                 if (cp != NULL &&
1161                     isalnum((unsigned char)*cp) == 0 &&
1162                     strchr(cp, '$') != NULL) {
1163                         if (r->man->meta.rcsids & rcsid)
1164                                 mandoc_msg(MANDOCERR_RCS_REP, r->parse,
1165                                     ln, stesc + 1 - buf->buf, stesc + 1);
1166                         r->man->meta.rcsids |= rcsid;
1167                 }
1168 
1169                 /* Handle trailing whitespace. */
1170 
1171                 cp = strchr(stesc--, '\0') - 1;
1172                 if (*cp == '\n') {
1173                         done = 1;
1174                         cp--;
1175                 }
1176                 if (*cp == ' ' || *cp == '\t')
1177                         mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
1178                             ln, cp - buf->buf, NULL);





















1179                 while (stesc > start && stesc[-1] == ' ')
1180                         stesc--;
1181                 *stesc = '\0';
1182                 break;
1183         }
1184         if (stesc == start)
1185                 return ROFF_CONT;
1186         stesc--;
1187 
1188         /* Notice the end of the input. */
1189 
1190         if (*stesc == '\n') {
1191                 *stesc-- = '\0';
1192                 done = 1;
1193         }
1194 
1195         expand_count = 0;
1196         while (stesc >= start) {
1197 
1198                 /* Search backwards for the next backslash. */


1227                         *stesc-- = '\0';
1228                         if (done)
1229                                 continue;
1230                         else
1231                                 return ROFF_APPEND;
1232                 }
1233 
1234                 /* Decide whether to expand or to check only. */
1235 
1236                 term = '\0';
1237                 cp = stesc + 1;
1238                 switch (*cp) {
1239                 case '*':
1240                         res = NULL;
1241                         break;
1242                 case 'B':
1243                 case 'w':
1244                         term = cp[1];
1245                         /* FALLTHROUGH */
1246                 case 'n':



1247                         res = ubuf;
1248                         break;
1249                 default:
1250                         esc = mandoc_escape(&cp, &stnam, &inaml);
1251                         if (esc == ESCAPE_ERROR ||
1252                             (esc == ESCAPE_SPECIAL &&
1253                              mchars_spec2cp(stnam, inaml) < 0))
1254                                 mandoc_vmsg(MANDOCERR_ESC_BAD,
1255                                     r->parse, ln, (int)(stesc - buf->buf),
1256                                     "%.*s", (int)(cp - stesc), stesc);
1257                         stesc--;
1258                         continue;
1259                 }
1260 
1261                 if (EXPAND_LIMIT < ++expand_count) {
1262                         mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
1263                             ln, (int)(stesc - buf->buf), NULL);
1264                         return ROFF_IGN;
1265                 }
1266 


1331                  */
1332 
1333                 switch (stesc[1]) {
1334                 case '*':
1335                         if (arg_complete) {
1336                                 deftype = ROFFDEF_USER | ROFFDEF_PRE;
1337                                 res = roff_getstrn(r, stnam, naml, &deftype);
1338                         }
1339                         break;
1340                 case 'B':
1341                         npos = 0;
1342                         ubuf[0] = arg_complete &&
1343                             roff_evalnum(r, ln, stnam, &npos,
1344                               NULL, ROFFNUM_SCALE) &&
1345                             stnam + npos + 1 == cp ? '1' : '0';
1346                         ubuf[1] = '\0';
1347                         break;
1348                 case 'n':
1349                         if (arg_complete)
1350                                 (void)snprintf(ubuf, sizeof(ubuf), "%d",
1351                                     roff_getregn(r, stnam, naml));
1352                         else
1353                                 ubuf[0] = '\0';
1354                         break;
1355                 case 'w':
1356                         /* use even incomplete args */
1357                         (void)snprintf(ubuf, sizeof(ubuf), "%d",
1358                             24 * (int)naml);
1359                         break;
1360                 }
1361 
1362                 if (res == NULL) {
1363                         mandoc_vmsg(MANDOCERR_STR_UNDEF,
1364                             r->parse, ln, (int)(stesc - buf->buf),
1365                             "%.*s", (int)naml, stnam);
1366                         res = "";
1367                 } else if (buf->sz + strlen(res) > SHRT_MAX) {
1368                         mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
1369                             ln, (int)(stesc - buf->buf), NULL);
1370                         return ROFF_IGN;
1371                 }


1622                 return TOKEN_NONE;
1623 
1624         mac = cp;
1625         maclen = roff_getname(r, &cp, ln, ppos);
1626 
1627         deftype = ROFFDEF_USER | ROFFDEF_REN;
1628         r->current_string = roff_getstrn(r, mac, maclen, &deftype);
1629         switch (deftype) {
1630         case ROFFDEF_USER:
1631                 t = ROFF_USERDEF;
1632                 break;
1633         case ROFFDEF_REN:
1634                 t = ROFF_RENAMED;
1635                 break;
1636         default:
1637                 t = roffhash_find(r->reqtab, mac, maclen);
1638                 break;
1639         }
1640         if (t != TOKEN_NONE)
1641                 *pos = cp - buf;





1642         return t;
1643 }
1644 
1645 /* --- handling of request blocks ----------------------------------------- */
1646 
1647 static enum rofferr
1648 roff_cblock(ROFF_ARGS)
1649 {
1650 
1651         /*
1652          * A block-close `..' should only be invoked as a child of an
1653          * ignore macro, otherwise raise a warning and just ignore it.
1654          */
1655 
1656         if (r->last == NULL) {
1657                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
1658                     ln, ppos, "..");
1659                 return ROFF_IGN;
1660         }
1661 


2498                 case 'i':
2499                         if (operand2 < *res)
2500                                 *res = operand2;
2501                         break;
2502                 case 'a':
2503                         if (operand2 > *res)
2504                                 *res = operand2;
2505                         break;
2506                 default:
2507                         abort();
2508                 }
2509         }
2510         return 1;
2511 }
2512 
2513 /* --- register management ------------------------------------------------ */
2514 
2515 void
2516 roff_setreg(struct roff *r, const char *name, int val, char sign)
2517 {







2518         struct roffreg  *reg;
2519 
2520         /* Search for an existing register with the same name. */
2521         reg = r->regtab;
2522 
2523         while (reg && strcmp(name, reg->key.p))

2524                 reg = reg->next;
2525 
2526         if (NULL == reg) {
2527                 /* Create a new register. */
2528                 reg = mandoc_malloc(sizeof(struct roffreg));
2529                 reg->key.p = mandoc_strdup(name);
2530                 reg->key.sz = strlen(name);
2531                 reg->val = 0;

2532                 reg->next = r->regtab;
2533                 r->regtab = reg;
2534         }
2535 
2536         if ('+' == sign)
2537                 reg->val += val;
2538         else if ('-' == sign)
2539                 reg->val -= val;
2540         else
2541                 reg->val = val;


2542 }
2543 
2544 /*
2545  * Handle some predefined read-only number registers.
2546  * For now, return -1 if the requested register is not predefined;
2547  * in case a predefined read-only register having the value -1
2548  * were to turn up, another special value would have to be chosen.
2549  */
2550 static int
2551 roff_getregro(const struct roff *r, const char *name)
2552 {
2553 
2554         switch (*name) {
2555         case '$':  /* Number of arguments of the last macro evaluated. */
2556                 return r->argc;
2557         case 'A':  /* ASCII approximation mode is always off. */
2558                 return 0;
2559         case 'g':  /* Groff compatibility mode is always on. */
2560                 return 1;
2561         case 'H':  /* Fixed horizontal resolution. */
2562                 return 24;
2563         case 'j':  /* Always adjust left margin only. */
2564                 return 0;
2565         case 'T':  /* Some output device is always defined. */
2566                 return 1;
2567         case 'V':  /* Fixed vertical resolution. */
2568                 return 40;
2569         default:
2570                 return -1;
2571         }
2572 }
2573 
2574 int
2575 roff_getreg(const struct roff *r, const char *name)
2576 {
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;
2591 }
2592 
2593 static int
2594 roff_getregn(const struct roff *r, const char *name, size_t len)
2595 {
2596         struct roffreg  *reg;
2597         int              val;
2598 
2599         if ('.' == name[0] && 2 == len) {
2600                 val = roff_getregro(r, name + 1);
2601                 if (-1 != val)
2602                         return val;
2603         }
2604 
2605         for (reg = r->regtab; reg; reg = reg->next)
2606                 if (len == reg->key.sz &&
2607                     0 == strncmp(name, reg->key.p, len))










2608                         return reg->val;


2609 

2610         return 0;
2611 }
2612 
2613 static int
2614 roff_hasregn(const struct roff *r, const char *name, size_t len)
2615 {
2616         struct roffreg  *reg;
2617         int              val;
2618 
2619         if ('.' == name[0] && 2 == len) {
2620                 val = roff_getregro(r, name + 1);
2621                 if (-1 != val)
2622                         return 1;
2623         }
2624 
2625         for (reg = r->regtab; reg; reg = reg->next)
2626                 if (len == reg->key.sz &&
2627                     0 == strncmp(name, reg->key.p, len))
2628                         return 1;
2629 
2630         return 0;
2631 }
2632 
2633 static void
2634 roff_freereg(struct roffreg *reg)
2635 {
2636         struct roffreg  *old_reg;
2637 
2638         while (NULL != reg) {
2639                 free(reg->key.p);
2640                 old_reg = reg;
2641                 reg = reg->next;
2642                 free(old_reg);
2643         }
2644 }
2645 
2646 static enum rofferr
2647 roff_nr(ROFF_ARGS)
2648 {
2649         char            *key, *val;
2650         size_t           keysz;
2651         int              iv;
2652         char             sign;
2653 
2654         key = val = buf->buf + pos;
2655         if (*key == '\0')
2656                 return ROFF_IGN;
2657 
2658         keysz = roff_getname(r, &val, ln, pos);
2659         if (key[keysz] == '\\')
2660                 return ROFF_IGN;
2661         key[keysz] = '\0';
2662 
2663         sign = *val;
2664         if (sign == '+' || sign == '-')
2665                 val++;
2666 
2667         if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
2668                 roff_setreg(r, key, iv, sign);

2669 







2670         return ROFF_IGN;
2671 }
2672 
2673 static enum rofferr
2674 roff_rr(ROFF_ARGS)
2675 {
2676         struct roffreg  *reg, **prev;
2677         char            *name, *cp;
2678         size_t           namesz;
2679 
2680         name = cp = buf->buf + pos;
2681         if (*name == '\0')
2682                 return ROFF_IGN;
2683         namesz = roff_getname(r, &cp, ln, pos);
2684         name[namesz] = '\0';
2685 
2686         prev = &r->regtab;
2687         while (1) {
2688                 reg = *prev;
2689                 if (reg == NULL || !strcmp(name, reg->key.p))


2774         }
2775         if ((r->options & mask) == 0)
2776                 for (t = tok; t < te; t++)
2777                         roff_setstr(r, roff_name[t], NULL, 0);
2778         return ROFF_CONT;
2779 }
2780 
2781 static enum rofferr
2782 roff_TE(ROFF_ARGS)
2783 {
2784         if (r->tbl == NULL) {
2785                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
2786                     ln, ppos, "TE");
2787                 return ROFF_IGN;
2788         }
2789         if (tbl_end(r->tbl) == 0) {
2790                 r->tbl = NULL;
2791                 free(buf->buf);
2792                 buf->buf = mandoc_strdup(".sp");
2793                 buf->sz = 4;

2794                 return ROFF_REPARSE;
2795         }
2796         r->tbl = NULL;
2797         return ROFF_IGN;
2798 }
2799 
2800 static enum rofferr
2801 roff_T_(ROFF_ARGS)
2802 {
2803 
2804         if (NULL == r->tbl)
2805                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
2806                     ln, ppos, "T&");
2807         else
2808                 tbl_restart(ln, ppos, r->tbl);
2809 
2810         return ROFF_IGN;
2811 }
2812 
2813 /*


3293                         ib = 0;
3294                         ie = r->argc - 1;
3295                 } else {  /* \\$1 .. \\$9 insert one argument */
3296                         ib = ie = *cp - '1';
3297                         if (ib < 0 || ib > 8)
3298                                 continue;
3299                 }
3300                 cp -= 2;
3301 
3302                 /*
3303                  * Prevent infinite recursion.
3304                  */
3305 
3306                 if (cp >= n2)
3307                         expand_count = 1;
3308                 else if (++expand_count > EXPAND_LIMIT) {
3309                         mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
3310                             ln, (int)(cp - n1), NULL);
3311                         free(buf->buf);
3312                         buf->buf = n1;

3313                         return ROFF_IGN;
3314                 }
3315 
3316                 /*
3317                  * Determine the size of the expanded argument,
3318                  * taking escaping of quotes into account.
3319                  */
3320 
3321                 asz = ie > ib ? ie - ib : 0;  /* for blanks */
3322                 for (i = ib; i <= ie; i++) {
3323                         for (ap = arg[i]; *ap != '\0'; ap++) {
3324                                 asz++;
3325                                 if (*ap == '"')
3326                                         asz += 3;
3327                         }
3328                 }
3329                 if (asz != 3) {
3330 
3331                         /*
3332                          * Determine the size of the rest of the


3387         buf->buf = n1;
3388         *offs = 0;
3389 
3390         return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
3391            ROFF_REPARSE : ROFF_APPEND;
3392 }
3393 
3394 /*
3395  * Calling a high-level macro that was renamed with .rn.
3396  * r->current_string has already been set up by roff_parse().
3397  */
3398 static enum rofferr
3399 roff_renamed(ROFF_ARGS)
3400 {
3401         char    *nbuf;
3402 
3403         buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string,
3404             buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
3405         free(buf->buf);
3406         buf->buf = nbuf;

3407         return ROFF_CONT;
3408 }
3409 
3410 static size_t
3411 roff_getname(struct roff *r, char **cpp, int ln, int pos)
3412 {
3413         char     *name, *cp;
3414         size_t    namesz;
3415 
3416         name = *cpp;
3417         if ('\0' == *name)
3418                 return 0;
3419 
3420         /* Read until end of name and terminate it with NUL. */
3421         for (cp = name; 1; cp++) {
3422                 if ('\0' == *cp || ' ' == *cp) {
3423                         namesz = cp - name;
3424                         break;
3425                 }
3426                 if ('\\' != *cp)


3520         i = 0;
3521         while (i < (int)stringsz) {
3522                 /*
3523                  * Rudimentary roff copy mode:
3524                  * Handle escaped backslashes.
3525                  */
3526                 if ('\\' == string[i] && '\\' == string[i + 1])
3527                         i++;
3528                 *c++ = string[i++];
3529         }
3530 
3531         /* Append terminating bytes. */
3532         if (1 < append)
3533                 *c++ = '\n';
3534 
3535         *c = '\0';
3536         n->val.sz = (int)(c - n->val.p);
3537 }
3538 
3539 static const char *
3540 roff_getstrn(const struct roff *r, const char *name, size_t len,
3541     int *deftype)
3542 {
3543         const struct roffkv     *n;
3544         int                      i;
3545         enum roff_tok            tok;
3546 
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                         }
3555                 }
3556         }
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                         }
3564                 }
3565         }
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                         }
3574                 }










3575         }
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                                 }
3584                         }
3585                 }
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                                 }
3593                         }
3594                 }









3595         }







3596         *deftype = 0;
3597         return NULL;
3598 }
3599 
3600 static void
3601 roff_freestr(struct roffkv *r)
3602 {
3603         struct roffkv    *n, *nn;
3604 
3605         for (n = r; n; n = nn) {
3606                 free(n->key.p);
3607                 free(n->val.p);
3608                 nn = n->next;
3609                 free(n);
3610         }
3611 }
3612 
3613 /* --- accessors and utility functions ------------------------------------ */
3614 
3615 /*


   1 /*      $Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */
   2 /*
   3  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
   4  * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
   5  *
   6  * Permission to use, copy, modify, and distribute this software for any
   7  * purpose with or without fee is hereby granted, provided that the above
   8  * copyright notice and this permission notice appear in all copies.
   9  *
  10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
  11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
  13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17  */
  18 #include "config.h"
  19 
  20 #include <sys/types.h>
  21 
  22 #include <assert.h>
  23 #include <ctype.h>
  24 #include <limits.h>


  29 #include <string.h>
  30 
  31 #include "mandoc.h"
  32 #include "mandoc_aux.h"
  33 #include "mandoc_ohash.h"
  34 #include "roff.h"
  35 #include "libmandoc.h"
  36 #include "roff_int.h"
  37 #include "libroff.h"
  38 
  39 /* Maximum number of string expansions per line, to break infinite loops. */
  40 #define EXPAND_LIMIT    1000
  41 
  42 /* Types of definitions of macros and strings. */
  43 #define ROFFDEF_USER    (1 << 1)  /* User-defined. */
  44 #define ROFFDEF_PRE     (1 << 2)  /* Predefined. */
  45 #define ROFFDEF_REN     (1 << 3)  /* Renamed standard macro. */
  46 #define ROFFDEF_STD     (1 << 4)  /* mdoc(7) or man(7) macro. */
  47 #define ROFFDEF_ANY     (ROFFDEF_USER | ROFFDEF_PRE | \
  48                          ROFFDEF_REN | ROFFDEF_STD)
  49 #define ROFFDEF_UNDEF   (1 << 5)  /* Completely undefined. */
  50 
  51 /* --- data types --------------------------------------------------------- */
  52 
  53 /*
  54  * An incredibly-simple string buffer.
  55  */
  56 struct  roffstr {
  57         char            *p; /* nil-terminated buffer */
  58         size_t           sz; /* saved strlen(p) */
  59 };
  60 
  61 /*
  62  * A key-value roffstr pair as part of a singly-linked list.
  63  */
  64 struct  roffkv {
  65         struct roffstr   key;
  66         struct roffstr   val;
  67         struct roffkv   *next; /* next in list */
  68 };
  69 
  70 /*
  71  * A single number register as part of a singly-linked list.
  72  */
  73 struct  roffreg {
  74         struct roffstr   key;
  75         int              val;
  76         int              step;
  77         struct roffreg  *next;
  78 };
  79 
  80 /*
  81  * Association of request and macro names with token IDs.
  82  */
  83 struct  roffreq {
  84         enum roff_tok    tok;
  85         char             name[];
  86 };
  87 
  88 struct  roff {
  89         struct mparse   *parse; /* parse point */
  90         struct roff_man *man; /* mdoc or man parser */
  91         struct roffnode *last; /* leaf of stack */
  92         int             *rstack; /* stack of inverted `ie' values */
  93         struct ohash    *reqtab; /* request lookup table */
  94         struct roffreg  *regtab; /* number registers */
  95         struct roffkv   *strtab; /* user-defined strings & macros */
  96         struct roffkv   *rentab; /* renamed strings & macros */


 166 static  void             roff_ccond(struct roff *, int, int);
 167 static  enum rofferr     roff_cond(ROFF_ARGS);
 168 static  enum rofferr     roff_cond_text(ROFF_ARGS);
 169 static  enum rofferr     roff_cond_sub(ROFF_ARGS);
 170 static  enum rofferr     roff_ds(ROFF_ARGS);
 171 static  enum rofferr     roff_ec(ROFF_ARGS);
 172 static  enum rofferr     roff_eo(ROFF_ARGS);
 173 static  enum rofferr     roff_eqndelim(struct roff *, struct buf *, int);
 174 static  int              roff_evalcond(struct roff *r, int, char *, int *);
 175 static  int              roff_evalnum(struct roff *, int,
 176                                 const char *, int *, int *, int);
 177 static  int              roff_evalpar(struct roff *, int,
 178                                 const char *, int *, int *, int);
 179 static  int              roff_evalstrcond(const char *, int *);
 180 static  void             roff_free1(struct roff *);
 181 static  void             roff_freereg(struct roffreg *);
 182 static  void             roff_freestr(struct roffkv *);
 183 static  size_t           roff_getname(struct roff *, char **, int, int);
 184 static  int              roff_getnum(const char *, int *, int *, int);
 185 static  int              roff_getop(const char *, int *, char *);
 186 static  int              roff_getregn(struct roff *,
 187                                 const char *, size_t, char);
 188 static  int              roff_getregro(const struct roff *,
 189                                 const char *name);
 190 static  const char      *roff_getstrn(struct roff *,
 191                                 const char *, size_t, int *);
 192 static  int              roff_hasregn(const struct roff *,
 193                                 const char *, size_t);
 194 static  enum rofferr     roff_insec(ROFF_ARGS);
 195 static  enum rofferr     roff_it(ROFF_ARGS);
 196 static  enum rofferr     roff_line_ignore(ROFF_ARGS);
 197 static  void             roff_man_alloc1(struct roff_man *);
 198 static  void             roff_man_free1(struct roff_man *);
 199 static  enum rofferr     roff_manyarg(ROFF_ARGS);
 200 static  enum rofferr     roff_nr(ROFF_ARGS);
 201 static  enum rofferr     roff_onearg(ROFF_ARGS);
 202 static  enum roff_tok    roff_parse(struct roff *, char *, int *,
 203                                 int, int);
 204 static  enum rofferr     roff_parsetext(struct roff *, struct buf *,
 205                                 int, int *);
 206 static  enum rofferr     roff_renamed(ROFF_ARGS);
 207 static  enum rofferr     roff_res(struct roff *, struct buf *, int, int);
 208 static  enum rofferr     roff_rm(ROFF_ARGS);
 209 static  enum rofferr     roff_rn(ROFF_ARGS);
 210 static  enum rofferr     roff_rr(ROFF_ARGS);
 211 static  void             roff_setregn(struct roff *, const char *,
 212                                 size_t, int, char, int);
 213 static  void             roff_setstr(struct roff *,
 214                                 const char *, const char *, int);
 215 static  void             roff_setstrn(struct roffkv **, const char *,
 216                                 size_t, const char *, size_t, int);
 217 static  enum rofferr     roff_so(ROFF_ARGS);
 218 static  enum rofferr     roff_tr(ROFF_ARGS);
 219 static  enum rofferr     roff_Dd(ROFF_ARGS);
 220 static  enum rofferr     roff_TE(ROFF_ARGS);
 221 static  enum rofferr     roff_TS(ROFF_ARGS);
 222 static  enum rofferr     roff_EQ(ROFF_ARGS);
 223 static  enum rofferr     roff_EN(ROFF_ARGS);
 224 static  enum rofferr     roff_T_(ROFF_ARGS);
 225 static  enum rofferr     roff_unsupp(ROFF_ARGS);
 226 static  enum rofferr     roff_userdef(ROFF_ARGS);
 227 
 228 /* --- constant data ------------------------------------------------------ */
 229 
 230 #define ROFFNUM_SCALE   (1 << 0)  /* Honour scaling in roff_getnum(). */
 231 #define ROFFNUM_WHITE   (1 << 1)  /* Skip whitespace in roff_evalnum(). */
 232 


 745         roffce_node = NULL;
 746         roffit_lines = 0;
 747         roffit_macro = NULL;
 748 }
 749 
 750 void
 751 roff_free(struct roff *r)
 752 {
 753         roff_free1(r);
 754         roffhash_free(r->reqtab);
 755         free(r);
 756 }
 757 
 758 struct roff *
 759 roff_alloc(struct mparse *parse, int options)
 760 {
 761         struct roff     *r;
 762 
 763         r = mandoc_calloc(1, sizeof(struct roff));
 764         r->parse = parse;
 765         r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
 766         r->options = options;
 767         r->format = options & (MPARSE_MDOC | MPARSE_MAN);
 768         r->rstackpos = -1;
 769         r->escape = '\\';
 770         return r;
 771 }
 772 
 773 /* --- syntax tree state data management ---------------------------------- */
 774 
 775 static void
 776 roff_man_free1(struct roff_man *man)
 777 {
 778 
 779         if (man->first != NULL)
 780                 roff_node_delete(man, man->first);
 781         free(man->meta.msec);
 782         free(man->meta.vol);
 783         free(man->meta.os);
 784         free(man->meta.arch);
 785         free(man->meta.title);


1105                 *dest = mandoc_strndup(cp, sz);
1106                 return;
1107         }
1108 
1109         mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
1110         free(*dest);
1111         *dest = cp;
1112 }
1113 
1114 /* --- main functions of the roff parser ---------------------------------- */
1115 
1116 /*
1117  * In the current line, expand escape sequences that tend to get
1118  * used in numerical expressions and conditional requests.
1119  * Also check the syntax of the remaining escape sequences.
1120  */
1121 static enum rofferr
1122 roff_res(struct roff *r, struct buf *buf, int ln, int pos)
1123 {
1124         char             ubuf[24]; /* buffer to print the number */
1125         struct roff_node *n;    /* used for header comments */
1126         const char      *start; /* start of the string to process */
1127         char            *stesc; /* start of an escape sequence ('\\') */
1128         char            *ep;    /* end of comment string */
1129         const char      *stnam; /* start of the name, after "[(*" */
1130         const char      *cp;    /* end of the name, e.g. before ']' */
1131         const char      *res;   /* the string to be substituted */
1132         char            *nbuf;  /* new buffer to copy buf->buf to */
1133         size_t           maxl;  /* expected length of the escape name */
1134         size_t           naml;  /* actual length of the escape name */
1135         enum mandoc_esc  esc;   /* type of the escape sequence */
1136         int              inaml; /* length returned from mandoc_escape() */
1137         int              expand_count;  /* to avoid infinite loops */
1138         int              npos;  /* position in numeric expression */
1139         int              arg_complete; /* argument not interrupted by eol */
1140         int              done;  /* no more input available */
1141         int              deftype; /* type of definition to paste */
1142         int              rcsid; /* kind of RCS id seen */
1143         char             sign;  /* increment number register */
1144         char             term;  /* character terminating the escape */
1145 
1146         /* Search forward for comments. */
1147 
1148         done = 0;
1149         start = buf->buf + pos;
1150         for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) {
1151                 if (stesc[0] != r->escape || stesc[1] == '\0')
1152                         continue;
1153                 stesc++;
1154                 if (*stesc != '"' && *stesc != '#')
1155                         continue;
1156 
1157                 /* Comment found, look for RCS id. */
1158 
1159                 rcsid = 0;
1160                 if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) {
1161                         rcsid = 1 << MANDOC_OS_OPENBSD;
1162                         cp += 8;
1163                 } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) {
1164                         rcsid = 1 << MANDOC_OS_NETBSD;
1165                         cp += 7;
1166                 }
1167                 if (cp != NULL &&
1168                     isalnum((unsigned char)*cp) == 0 &&
1169                     strchr(cp, '$') != NULL) {
1170                         if (r->man->meta.rcsids & rcsid)
1171                                 mandoc_msg(MANDOCERR_RCS_REP, r->parse,
1172                                     ln, stesc + 1 - buf->buf, stesc + 1);
1173                         r->man->meta.rcsids |= rcsid;
1174                 }
1175 
1176                 /* Handle trailing whitespace. */
1177 
1178                 ep = strchr(stesc--, '\0') - 1;
1179                 if (*ep == '\n') {
1180                         done = 1;
1181                         ep--;
1182                 }
1183                 if (*ep == ' ' || *ep == '\t')
1184                         mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
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 
1207                 while (stesc > start && stesc[-1] == ' ')
1208                         stesc--;
1209                 *stesc = '\0';
1210                 break;
1211         }
1212         if (stesc == start)
1213                 return ROFF_CONT;
1214         stesc--;
1215 
1216         /* Notice the end of the input. */
1217 
1218         if (*stesc == '\n') {
1219                 *stesc-- = '\0';
1220                 done = 1;
1221         }
1222 
1223         expand_count = 0;
1224         while (stesc >= start) {
1225 
1226                 /* Search backwards for the next backslash. */


1255                         *stesc-- = '\0';
1256                         if (done)
1257                                 continue;
1258                         else
1259                                 return ROFF_APPEND;
1260                 }
1261 
1262                 /* Decide whether to expand or to check only. */
1263 
1264                 term = '\0';
1265                 cp = stesc + 1;
1266                 switch (*cp) {
1267                 case '*':
1268                         res = NULL;
1269                         break;
1270                 case 'B':
1271                 case 'w':
1272                         term = cp[1];
1273                         /* FALLTHROUGH */
1274                 case 'n':
1275                         sign = cp[1];
1276                         if (sign == '+' || sign == '-')
1277                                 cp++;
1278                         res = ubuf;
1279                         break;
1280                 default:
1281                         esc = mandoc_escape(&cp, &stnam, &inaml);
1282                         if (esc == ESCAPE_ERROR ||
1283                             (esc == ESCAPE_SPECIAL &&
1284                              mchars_spec2cp(stnam, inaml) < 0))
1285                                 mandoc_vmsg(MANDOCERR_ESC_BAD,
1286                                     r->parse, ln, (int)(stesc - buf->buf),
1287                                     "%.*s", (int)(cp - stesc), stesc);
1288                         stesc--;
1289                         continue;
1290                 }
1291 
1292                 if (EXPAND_LIMIT < ++expand_count) {
1293                         mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
1294                             ln, (int)(stesc - buf->buf), NULL);
1295                         return ROFF_IGN;
1296                 }
1297 


1362                  */
1363 
1364                 switch (stesc[1]) {
1365                 case '*':
1366                         if (arg_complete) {
1367                                 deftype = ROFFDEF_USER | ROFFDEF_PRE;
1368                                 res = roff_getstrn(r, stnam, naml, &deftype);
1369                         }
1370                         break;
1371                 case 'B':
1372                         npos = 0;
1373                         ubuf[0] = arg_complete &&
1374                             roff_evalnum(r, ln, stnam, &npos,
1375                               NULL, ROFFNUM_SCALE) &&
1376                             stnam + npos + 1 == cp ? '1' : '0';
1377                         ubuf[1] = '\0';
1378                         break;
1379                 case 'n':
1380                         if (arg_complete)
1381                                 (void)snprintf(ubuf, sizeof(ubuf), "%d",
1382                                     roff_getregn(r, stnam, naml, sign));
1383                         else
1384                                 ubuf[0] = '\0';
1385                         break;
1386                 case 'w':
1387                         /* use even incomplete args */
1388                         (void)snprintf(ubuf, sizeof(ubuf), "%d",
1389                             24 * (int)naml);
1390                         break;
1391                 }
1392 
1393                 if (res == NULL) {
1394                         mandoc_vmsg(MANDOCERR_STR_UNDEF,
1395                             r->parse, ln, (int)(stesc - buf->buf),
1396                             "%.*s", (int)naml, stnam);
1397                         res = "";
1398                 } else if (buf->sz + strlen(res) > SHRT_MAX) {
1399                         mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
1400                             ln, (int)(stesc - buf->buf), NULL);
1401                         return ROFF_IGN;
1402                 }


1653                 return TOKEN_NONE;
1654 
1655         mac = cp;
1656         maclen = roff_getname(r, &cp, ln, ppos);
1657 
1658         deftype = ROFFDEF_USER | ROFFDEF_REN;
1659         r->current_string = roff_getstrn(r, mac, maclen, &deftype);
1660         switch (deftype) {
1661         case ROFFDEF_USER:
1662                 t = ROFF_USERDEF;
1663                 break;
1664         case ROFFDEF_REN:
1665                 t = ROFF_RENAMED;
1666                 break;
1667         default:
1668                 t = roffhash_find(r->reqtab, mac, maclen);
1669                 break;
1670         }
1671         if (t != TOKEN_NONE)
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         }
1678         return t;
1679 }
1680 
1681 /* --- handling of request blocks ----------------------------------------- */
1682 
1683 static enum rofferr
1684 roff_cblock(ROFF_ARGS)
1685 {
1686 
1687         /*
1688          * A block-close `..' should only be invoked as a child of an
1689          * ignore macro, otherwise raise a warning and just ignore it.
1690          */
1691 
1692         if (r->last == NULL) {
1693                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
1694                     ln, ppos, "..");
1695                 return ROFF_IGN;
1696         }
1697 


2534                 case 'i':
2535                         if (operand2 < *res)
2536                                 *res = operand2;
2537                         break;
2538                 case 'a':
2539                         if (operand2 > *res)
2540                                 *res = operand2;
2541                         break;
2542                 default:
2543                         abort();
2544                 }
2545         }
2546         return 1;
2547 }
2548 
2549 /* --- register management ------------------------------------------------ */
2550 
2551 void
2552 roff_setreg(struct roff *r, const char *name, int val, char sign)
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 {
2561         struct roffreg  *reg;
2562 
2563         /* Search for an existing register with the same name. */
2564         reg = r->regtab;
2565 
2566         while (reg != NULL && (reg->key.sz != len ||
2567             strncmp(reg->key.p, name, len) != 0))
2568                 reg = reg->next;
2569 
2570         if (NULL == reg) {
2571                 /* Create a new register. */
2572                 reg = mandoc_malloc(sizeof(struct roffreg));
2573                 reg->key.p = mandoc_strndup(name, len);
2574                 reg->key.sz = len;
2575                 reg->val = 0;
2576                 reg->step = 0;
2577                 reg->next = r->regtab;
2578                 r->regtab = reg;
2579         }
2580 
2581         if ('+' == sign)
2582                 reg->val += val;
2583         else if ('-' == sign)
2584                 reg->val -= val;
2585         else
2586                 reg->val = val;
2587         if (step != INT_MIN)
2588                 reg->step = step;
2589 }
2590 
2591 /*
2592  * Handle some predefined read-only number registers.
2593  * For now, return -1 if the requested register is not predefined;
2594  * in case a predefined read-only register having the value -1
2595  * were to turn up, another special value would have to be chosen.
2596  */
2597 static int
2598 roff_getregro(const struct roff *r, const char *name)
2599 {
2600 
2601         switch (*name) {
2602         case '$':  /* Number of arguments of the last macro evaluated. */
2603                 return r->argc;
2604         case 'A':  /* ASCII approximation mode is always off. */
2605                 return 0;
2606         case 'g':  /* Groff compatibility mode is always on. */
2607                 return 1;
2608         case 'H':  /* Fixed horizontal resolution. */
2609                 return 24;
2610         case 'j':  /* Always adjust left margin only. */
2611                 return 0;
2612         case 'T':  /* Some output device is always defined. */
2613                 return 1;
2614         case 'V':  /* Fixed vertical resolution. */
2615                 return 40;
2616         default:
2617                 return -1;
2618         }
2619 }
2620 
2621 int
2622 roff_getreg(struct roff *r, const char *name)
2623 {
2624         return roff_getregn(r, name, strlen(name), '\0');













2625 }
2626 
2627 static int
2628 roff_getregn(struct roff *r, const char *name, size_t len, char sign)
2629 {
2630         struct roffreg  *reg;
2631         int              val;
2632 
2633         if ('.' == name[0] && 2 == len) {
2634                 val = roff_getregro(r, name + 1);
2635                 if (-1 != val)
2636                         return val;
2637         }
2638 
2639         for (reg = r->regtab; reg; reg = reg->next) {
2640                 if (len == reg->key.sz &&
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                         }
2652                         return reg->val;
2653                 }
2654         }
2655 
2656         roff_setregn(r, name, len, 0, '\0', INT_MIN);
2657         return 0;
2658 }
2659 
2660 static int
2661 roff_hasregn(const struct roff *r, const char *name, size_t len)
2662 {
2663         struct roffreg  *reg;
2664         int              val;
2665 
2666         if ('.' == name[0] && 2 == len) {
2667                 val = roff_getregro(r, name + 1);
2668                 if (-1 != val)
2669                         return 1;
2670         }
2671 
2672         for (reg = r->regtab; reg; reg = reg->next)
2673                 if (len == reg->key.sz &&
2674                     0 == strncmp(name, reg->key.p, len))
2675                         return 1;
2676 
2677         return 0;
2678 }
2679 
2680 static void
2681 roff_freereg(struct roffreg *reg)
2682 {
2683         struct roffreg  *old_reg;
2684 
2685         while (NULL != reg) {
2686                 free(reg->key.p);
2687                 old_reg = reg;
2688                 reg = reg->next;
2689                 free(old_reg);
2690         }
2691 }
2692 
2693 static enum rofferr
2694 roff_nr(ROFF_ARGS)
2695 {
2696         char            *key, *val, *step;
2697         size_t           keysz;
2698         int              iv, is, len;
2699         char             sign;
2700 
2701         key = val = buf->buf + pos;
2702         if (*key == '\0')
2703                 return ROFF_IGN;
2704 
2705         keysz = roff_getname(r, &val, ln, pos);
2706         if (key[keysz] == '\\')
2707                 return ROFF_IGN;

2708 
2709         sign = *val;
2710         if (sign == '+' || sign == '-')
2711                 val++;
2712 
2713         len = 0;
2714         if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
2715                 return ROFF_IGN;
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);
2724         return ROFF_IGN;
2725 }
2726 
2727 static enum rofferr
2728 roff_rr(ROFF_ARGS)
2729 {
2730         struct roffreg  *reg, **prev;
2731         char            *name, *cp;
2732         size_t           namesz;
2733 
2734         name = cp = buf->buf + pos;
2735         if (*name == '\0')
2736                 return ROFF_IGN;
2737         namesz = roff_getname(r, &cp, ln, pos);
2738         name[namesz] = '\0';
2739 
2740         prev = &r->regtab;
2741         while (1) {
2742                 reg = *prev;
2743                 if (reg == NULL || !strcmp(name, reg->key.p))


2828         }
2829         if ((r->options & mask) == 0)
2830                 for (t = tok; t < te; t++)
2831                         roff_setstr(r, roff_name[t], NULL, 0);
2832         return ROFF_CONT;
2833 }
2834 
2835 static enum rofferr
2836 roff_TE(ROFF_ARGS)
2837 {
2838         if (r->tbl == NULL) {
2839                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
2840                     ln, ppos, "TE");
2841                 return ROFF_IGN;
2842         }
2843         if (tbl_end(r->tbl) == 0) {
2844                 r->tbl = NULL;
2845                 free(buf->buf);
2846                 buf->buf = mandoc_strdup(".sp");
2847                 buf->sz = 4;
2848                 *offs = 0;
2849                 return ROFF_REPARSE;
2850         }
2851         r->tbl = NULL;
2852         return ROFF_IGN;
2853 }
2854 
2855 static enum rofferr
2856 roff_T_(ROFF_ARGS)
2857 {
2858 
2859         if (NULL == r->tbl)
2860                 mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
2861                     ln, ppos, "T&");
2862         else
2863                 tbl_restart(ln, ppos, r->tbl);
2864 
2865         return ROFF_IGN;
2866 }
2867 
2868 /*


3348                         ib = 0;
3349                         ie = r->argc - 1;
3350                 } else {  /* \\$1 .. \\$9 insert one argument */
3351                         ib = ie = *cp - '1';
3352                         if (ib < 0 || ib > 8)
3353                                 continue;
3354                 }
3355                 cp -= 2;
3356 
3357                 /*
3358                  * Prevent infinite recursion.
3359                  */
3360 
3361                 if (cp >= n2)
3362                         expand_count = 1;
3363                 else if (++expand_count > EXPAND_LIMIT) {
3364                         mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
3365                             ln, (int)(cp - n1), NULL);
3366                         free(buf->buf);
3367                         buf->buf = n1;
3368                         *offs = 0;
3369                         return ROFF_IGN;
3370                 }
3371 
3372                 /*
3373                  * Determine the size of the expanded argument,
3374                  * taking escaping of quotes into account.
3375                  */
3376 
3377                 asz = ie > ib ? ie - ib : 0;  /* for blanks */
3378                 for (i = ib; i <= ie; i++) {
3379                         for (ap = arg[i]; *ap != '\0'; ap++) {
3380                                 asz++;
3381                                 if (*ap == '"')
3382                                         asz += 3;
3383                         }
3384                 }
3385                 if (asz != 3) {
3386 
3387                         /*
3388                          * Determine the size of the rest of the


3443         buf->buf = n1;
3444         *offs = 0;
3445 
3446         return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
3447            ROFF_REPARSE : ROFF_APPEND;
3448 }
3449 
3450 /*
3451  * Calling a high-level macro that was renamed with .rn.
3452  * r->current_string has already been set up by roff_parse().
3453  */
3454 static enum rofferr
3455 roff_renamed(ROFF_ARGS)
3456 {
3457         char    *nbuf;
3458 
3459         buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string,
3460             buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
3461         free(buf->buf);
3462         buf->buf = nbuf;
3463         *offs = 0;
3464         return ROFF_CONT;
3465 }
3466 
3467 static size_t
3468 roff_getname(struct roff *r, char **cpp, int ln, int pos)
3469 {
3470         char     *name, *cp;
3471         size_t    namesz;
3472 
3473         name = *cpp;
3474         if ('\0' == *name)
3475                 return 0;
3476 
3477         /* Read until end of name and terminate it with NUL. */
3478         for (cp = name; 1; cp++) {
3479                 if ('\0' == *cp || ' ' == *cp) {
3480                         namesz = cp - name;
3481                         break;
3482                 }
3483                 if ('\\' != *cp)


3577         i = 0;
3578         while (i < (int)stringsz) {
3579                 /*
3580                  * Rudimentary roff copy mode:
3581                  * Handle escaped backslashes.
3582                  */
3583                 if ('\\' == string[i] && '\\' == string[i + 1])
3584                         i++;
3585                 *c++ = string[i++];
3586         }
3587 
3588         /* Append terminating bytes. */
3589         if (1 < append)
3590                 *c++ = '\n';
3591 
3592         *c = '\0';
3593         n->val.sz = (int)(c - n->val.p);
3594 }
3595 
3596 static const char *
3597 roff_getstrn(struct roff *r, const char *name, size_t len,
3598     int *deftype)
3599 {
3600         const struct roffkv     *n;
3601         int                      found, i;
3602         enum roff_tok            tok;
3603 
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;
3615                 }
3616         }











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;
3627                 }
3628         }
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;
3639                 }
3640         }
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;
3652                         }
3653                 }
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;
3666                         }
3667                 }
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 
3686         *deftype = 0;
3687         return NULL;
3688 }
3689 
3690 static void
3691 roff_freestr(struct roffkv *r)
3692 {
3693         struct roffkv    *n, *nn;
3694 
3695         for (n = r; n; n = nn) {
3696                 free(n->key.p);
3697                 free(n->val.p);
3698                 nn = n->next;
3699                 free(n);
3700         }
3701 }
3702 
3703 /* --- accessors and utility functions ------------------------------------ */
3704 
3705 /*