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 /*
|