Print this page
9718 update mandoc to 1.14.4
*** 1,9 ****
! /* $Id: roff.c,v 1.324 2017/07/14 17:16:16 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
! * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
--- 1,9 ----
! /* $Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
! * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
*** 44,53 ****
--- 44,54 ----
#define ROFFDEF_PRE (1 << 2) /* Predefined. */
#define ROFFDEF_REN (1 << 3) /* Renamed standard macro. */
#define ROFFDEF_STD (1 << 4) /* mdoc(7) or man(7) macro. */
#define ROFFDEF_ANY (ROFFDEF_USER | ROFFDEF_PRE | \
ROFFDEF_REN | ROFFDEF_STD)
+ #define ROFFDEF_UNDEF (1 << 5) /* Completely undefined. */
/* --- data types --------------------------------------------------------- */
/*
* An incredibly-simple string buffer.
*** 70,79 ****
--- 71,81 ----
* A single number register as part of a singly-linked list.
*/
struct roffreg {
struct roffstr key;
int val;
+ int step;
struct roffreg *next;
};
/*
* Association of request and macro names with token IDs.
*** 179,193 ****
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
static size_t roff_getname(struct roff *, char **, int, int);
static int roff_getnum(const char *, int *, int *, int);
static int roff_getop(const char *, int *, char *);
! static int roff_getregn(const struct roff *,
! const char *, size_t);
static int roff_getregro(const struct roff *,
const char *name);
! static const char *roff_getstrn(const struct roff *,
const char *, size_t, int *);
static int roff_hasregn(const struct roff *,
const char *, size_t);
static enum rofferr roff_insec(ROFF_ARGS);
static enum rofferr roff_it(ROFF_ARGS);
--- 181,195 ----
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
static size_t roff_getname(struct roff *, char **, int, int);
static int roff_getnum(const char *, int *, int *, int);
static int roff_getop(const char *, int *, char *);
! static int roff_getregn(struct roff *,
! const char *, size_t, char);
static int roff_getregro(const struct roff *,
const char *name);
! static const char *roff_getstrn(struct roff *,
const char *, size_t, int *);
static int roff_hasregn(const struct roff *,
const char *, size_t);
static enum rofferr roff_insec(ROFF_ARGS);
static enum rofferr roff_it(ROFF_ARGS);
*** 204,213 ****
--- 206,217 ----
static enum rofferr roff_renamed(ROFF_ARGS);
static enum rofferr roff_res(struct roff *, struct buf *, int, int);
static enum rofferr roff_rm(ROFF_ARGS);
static enum rofferr roff_rn(ROFF_ARGS);
static enum rofferr roff_rr(ROFF_ARGS);
+ static void roff_setregn(struct roff *, const char *,
+ size_t, int, char, int);
static void roff_setstr(struct roff *,
const char *, const char *, int);
static void roff_setstrn(struct roffkv **, const char *,
size_t, const char *, size_t, int);
static enum rofferr roff_so(ROFF_ARGS);
*** 756,766 ****
{
struct roff *r;
r = mandoc_calloc(1, sizeof(struct roff));
r->parse = parse;
! r->reqtab = roffhash_alloc(0, ROFF_USERDEF);
r->options = options;
r->format = options & (MPARSE_MDOC | MPARSE_MAN);
r->rstackpos = -1;
r->escape = '\\';
return r;
--- 760,770 ----
{
struct roff *r;
r = mandoc_calloc(1, sizeof(struct roff));
r->parse = parse;
! r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
r->options = options;
r->format = options & (MPARSE_MDOC | MPARSE_MAN);
r->rstackpos = -1;
r->escape = '\\';
return r;
*** 1116,1127 ****
--- 1120,1133 ----
*/
static enum rofferr
roff_res(struct roff *r, struct buf *buf, int ln, int pos)
{
char ubuf[24]; /* buffer to print the number */
+ struct roff_node *n; /* used for header comments */
const char *start; /* start of the string to process */
char *stesc; /* start of an escape sequence ('\\') */
+ char *ep; /* end of comment string */
const char *stnam; /* start of the name, after "[(*" */
const char *cp; /* end of the name, e.g. before ']' */
const char *res; /* the string to be substituted */
char *nbuf; /* new buffer to copy buf->buf to */
size_t maxl; /* expected length of the escape name */
*** 1132,1141 ****
--- 1138,1148 ----
int npos; /* position in numeric expression */
int arg_complete; /* argument not interrupted by eol */
int done; /* no more input available */
int deftype; /* type of definition to paste */
int rcsid; /* kind of RCS id seen */
+ char sign; /* increment number register */
char term; /* character terminating the escape */
/* Search forward for comments. */
done = 0;
*** 1166,1183 ****
r->man->meta.rcsids |= rcsid;
}
/* Handle trailing whitespace. */
! cp = strchr(stesc--, '\0') - 1;
! if (*cp == '\n') {
done = 1;
! cp--;
}
! if (*cp == ' ' || *cp == '\t')
mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
! ln, cp - buf->buf, NULL);
while (stesc > start && stesc[-1] == ' ')
stesc--;
*stesc = '\0';
break;
}
--- 1173,1211 ----
r->man->meta.rcsids |= rcsid;
}
/* Handle trailing whitespace. */
! ep = strchr(stesc--, '\0') - 1;
! if (*ep == '\n') {
done = 1;
! ep--;
}
! if (*ep == ' ' || *ep == '\t')
mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
! ln, ep - buf->buf, NULL);
!
! /*
! * Save comments preceding the title macro
! * in the syntax tree.
! */
!
! if (r->format == 0) {
! while (*ep == ' ' || *ep == '\t')
! ep--;
! ep[1] = '\0';
! n = roff_node_alloc(r->man,
! ln, stesc + 1 - buf->buf,
! ROFFT_COMMENT, TOKEN_NONE);
! n->string = mandoc_strdup(stesc + 2);
! roff_node_append(r->man, n);
! n->flags |= NODE_VALID | NODE_ENDED;
! r->man->next = ROFF_NEXT_SIBLING;
! }
!
! /* Discard comments. */
!
while (stesc > start && stesc[-1] == ' ')
stesc--;
*stesc = '\0';
break;
}
*** 1242,1251 ****
--- 1270,1282 ----
case 'B':
case 'w':
term = cp[1];
/* FALLTHROUGH */
case 'n':
+ sign = cp[1];
+ if (sign == '+' || sign == '-')
+ cp++;
res = ubuf;
break;
default:
esc = mandoc_escape(&cp, &stnam, &inaml);
if (esc == ESCAPE_ERROR ||
*** 1346,1356 ****
ubuf[1] = '\0';
break;
case 'n':
if (arg_complete)
(void)snprintf(ubuf, sizeof(ubuf), "%d",
! roff_getregn(r, stnam, naml));
else
ubuf[0] = '\0';
break;
case 'w':
/* use even incomplete args */
--- 1377,1387 ----
ubuf[1] = '\0';
break;
case 'n':
if (arg_complete)
(void)snprintf(ubuf, sizeof(ubuf), "%d",
! roff_getregn(r, stnam, naml, sign));
else
ubuf[0] = '\0';
break;
case 'w':
/* use even incomplete args */
*** 1637,1646 ****
--- 1668,1682 ----
t = roffhash_find(r->reqtab, mac, maclen);
break;
}
if (t != TOKEN_NONE)
*pos = cp - buf;
+ else if (deftype == ROFFDEF_UNDEF) {
+ /* Using an undefined macro defines it to be empty. */
+ roff_setstrn(&r->strtab, mac, maclen, "", 0, 0);
+ roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0);
+ }
return t;
}
/* --- handling of request blocks ----------------------------------------- */
*** 2513,2536 ****
/* --- register management ------------------------------------------------ */
void
roff_setreg(struct roff *r, const char *name, int val, char sign)
{
struct roffreg *reg;
/* Search for an existing register with the same name. */
reg = r->regtab;
! while (reg && strcmp(name, reg->key.p))
reg = reg->next;
if (NULL == reg) {
/* Create a new register. */
reg = mandoc_malloc(sizeof(struct roffreg));
! reg->key.p = mandoc_strdup(name);
! reg->key.sz = strlen(name);
reg->val = 0;
reg->next = r->regtab;
r->regtab = reg;
}
if ('+' == sign)
--- 2549,2581 ----
/* --- register management ------------------------------------------------ */
void
roff_setreg(struct roff *r, const char *name, int val, char sign)
{
+ roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
+ }
+
+ static void
+ roff_setregn(struct roff *r, const char *name, size_t len,
+ int val, char sign, int step)
+ {
struct roffreg *reg;
/* Search for an existing register with the same name. */
reg = r->regtab;
! while (reg != NULL && (reg->key.sz != len ||
! strncmp(reg->key.p, name, len) != 0))
reg = reg->next;
if (NULL == reg) {
/* Create a new register. */
reg = mandoc_malloc(sizeof(struct roffreg));
! reg->key.p = mandoc_strndup(name, len);
! reg->key.sz = len;
reg->val = 0;
+ reg->step = 0;
reg->next = r->regtab;
r->regtab = reg;
}
if ('+' == sign)
*** 2537,2546 ****
--- 2582,2593 ----
reg->val += val;
else if ('-' == sign)
reg->val -= val;
else
reg->val = val;
+ if (step != INT_MIN)
+ reg->step = step;
}
/*
* Handle some predefined read-only number registers.
* For now, return -1 if the requested register is not predefined;
*** 2570,2599 ****
return -1;
}
}
int
! roff_getreg(const struct roff *r, const char *name)
{
! struct roffreg *reg;
! int val;
!
! if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
! val = roff_getregro(r, name + 1);
! if (-1 != val)
! return val;
! }
!
! for (reg = r->regtab; reg; reg = reg->next)
! if (0 == strcmp(name, reg->key.p))
! return reg->val;
!
! return 0;
}
static int
! roff_getregn(const struct roff *r, const char *name, size_t len)
{
struct roffreg *reg;
int val;
if ('.' == name[0] && 2 == len) {
--- 2617,2633 ----
return -1;
}
}
int
! roff_getreg(struct roff *r, const char *name)
{
! return roff_getregn(r, name, strlen(name), '\0');
}
static int
! roff_getregn(struct roff *r, const char *name, size_t len, char sign)
{
struct roffreg *reg;
int val;
if ('.' == name[0] && 2 == len) {
*** 2600,2614 ****
val = roff_getregro(r, name + 1);
if (-1 != val)
return val;
}
! for (reg = r->regtab; reg; reg = reg->next)
if (len == reg->key.sz &&
! 0 == strncmp(name, reg->key.p, len))
return reg->val;
return 0;
}
static int
roff_hasregn(const struct roff *r, const char *name, size_t len)
--- 2634,2661 ----
val = roff_getregro(r, name + 1);
if (-1 != val)
return val;
}
! for (reg = r->regtab; reg; reg = reg->next) {
if (len == reg->key.sz &&
! 0 == strncmp(name, reg->key.p, len)) {
! switch (sign) {
! case '+':
! reg->val += reg->step;
! break;
! case '-':
! reg->val -= reg->step;
! break;
! default:
! break;
! }
return reg->val;
+ }
+ }
+ roff_setregn(r, name, len, 0, '\0', INT_MIN);
return 0;
}
static int
roff_hasregn(const struct roff *r, const char *name, size_t len)
*** 2644,2674 ****
}
static enum rofferr
roff_nr(ROFF_ARGS)
{
! char *key, *val;
size_t keysz;
! int iv;
char sign;
key = val = buf->buf + pos;
if (*key == '\0')
return ROFF_IGN;
keysz = roff_getname(r, &val, ln, pos);
if (key[keysz] == '\\')
return ROFF_IGN;
- key[keysz] = '\0';
sign = *val;
if (sign == '+' || sign == '-')
val++;
! if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
! roff_setreg(r, key, iv, sign);
return ROFF_IGN;
}
static enum rofferr
roff_rr(ROFF_ARGS)
--- 2691,2728 ----
}
static enum rofferr
roff_nr(ROFF_ARGS)
{
! char *key, *val, *step;
size_t keysz;
! int iv, is, len;
char sign;
key = val = buf->buf + pos;
if (*key == '\0')
return ROFF_IGN;
keysz = roff_getname(r, &val, ln, pos);
if (key[keysz] == '\\')
return ROFF_IGN;
sign = *val;
if (sign == '+' || sign == '-')
val++;
! len = 0;
! if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
! return ROFF_IGN;
+ step = val + len;
+ while (isspace((unsigned char)*step))
+ step++;
+ if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
+ is = INT_MIN;
+
+ roff_setregn(r, key, keysz, iv, sign, is);
return ROFF_IGN;
}
static enum rofferr
roff_rr(ROFF_ARGS)
*** 2789,2798 ****
--- 2843,2853 ----
if (tbl_end(r->tbl) == 0) {
r->tbl = NULL;
free(buf->buf);
buf->buf = mandoc_strdup(".sp");
buf->sz = 4;
+ *offs = 0;
return ROFF_REPARSE;
}
r->tbl = NULL;
return ROFF_IGN;
}
*** 3308,3317 ****
--- 3363,3373 ----
else if (++expand_count > EXPAND_LIMIT) {
mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
ln, (int)(cp - n1), NULL);
free(buf->buf);
buf->buf = n1;
+ *offs = 0;
return ROFF_IGN;
}
/*
* Determine the size of the expanded argument,
*** 3402,3411 ****
--- 3458,3468 ----
buf->sz = mandoc_asprintf(&nbuf, ".%s%s%s", r->current_string,
buf->buf[pos] == '\0' ? "" : " ", buf->buf + pos) + 1;
free(buf->buf);
buf->buf = nbuf;
+ *offs = 0;
return ROFF_CONT;
}
static size_t
roff_getname(struct roff *r, char **cpp, int ln, int pos)
*** 3535,3600 ****
*c = '\0';
n->val.sz = (int)(c - n->val.p);
}
static const char *
! roff_getstrn(const struct roff *r, const char *name, size_t len,
int *deftype)
{
const struct roffkv *n;
! int i;
enum roff_tok tok;
! if (*deftype & ROFFDEF_USER) {
for (n = r->strtab; n != NULL; n = n->next) {
! if (strncmp(name, n->key.p, len) == 0 &&
! n->key.p[len] == '\0' &&
! n->val.p != NULL) {
*deftype = ROFFDEF_USER;
return n->val.p;
}
}
- }
- if (*deftype & ROFFDEF_PRE) {
- for (i = 0; i < PREDEFS_MAX; i++) {
- if (strncmp(name, predefs[i].name, len) == 0 &&
- predefs[i].name[len] == '\0') {
- *deftype = ROFFDEF_PRE;
- return predefs[i].str;
- }
- }
- }
- if (*deftype & ROFFDEF_REN) {
for (n = r->rentab; n != NULL; n = n->next) {
! if (strncmp(name, n->key.p, len) == 0 &&
! n->key.p[len] == '\0' &&
! n->val.p != NULL) {
*deftype = ROFFDEF_REN;
return n->val.p;
}
}
}
! if (*deftype & ROFFDEF_STD) {
if (r->man->macroset != MACROSET_MAN) {
for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
! if (strncmp(name, roff_name[tok], len) == 0 &&
! roff_name[tok][len] == '\0') {
*deftype = ROFFDEF_STD;
return NULL;
}
}
}
if (r->man->macroset != MACROSET_MDOC) {
for (tok = MAN_TH; tok < MAN_MAX; tok++) {
! if (strncmp(name, roff_name[tok], len) == 0 &&
! roff_name[tok][len] == '\0') {
*deftype = ROFFDEF_STD;
return NULL;
}
}
}
}
*deftype = 0;
return NULL;
}
static void
--- 3592,3690 ----
*c = '\0';
n->val.sz = (int)(c - n->val.p);
}
static const char *
! roff_getstrn(struct roff *r, const char *name, size_t len,
int *deftype)
{
const struct roffkv *n;
! int found, i;
enum roff_tok tok;
! found = 0;
for (n = r->strtab; n != NULL; n = n->next) {
! if (strncmp(name, n->key.p, len) != 0 ||
! n->key.p[len] != '\0' || n->val.p == NULL)
! continue;
! if (*deftype & ROFFDEF_USER) {
*deftype = ROFFDEF_USER;
return n->val.p;
+ } else {
+ found = 1;
+ break;
}
}
for (n = r->rentab; n != NULL; n = n->next) {
! if (strncmp(name, n->key.p, len) != 0 ||
! n->key.p[len] != '\0' || n->val.p == NULL)
! continue;
! if (*deftype & ROFFDEF_REN) {
*deftype = ROFFDEF_REN;
return n->val.p;
+ } else {
+ found = 1;
+ break;
}
}
+ for (i = 0; i < PREDEFS_MAX; i++) {
+ if (strncmp(name, predefs[i].name, len) != 0 ||
+ predefs[i].name[len] != '\0')
+ continue;
+ if (*deftype & ROFFDEF_PRE) {
+ *deftype = ROFFDEF_PRE;
+ return predefs[i].str;
+ } else {
+ found = 1;
+ break;
}
! }
if (r->man->macroset != MACROSET_MAN) {
for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
! if (strncmp(name, roff_name[tok], len) != 0 ||
! roff_name[tok][len] != '\0')
! continue;
! if (*deftype & ROFFDEF_STD) {
*deftype = ROFFDEF_STD;
return NULL;
+ } else {
+ found = 1;
+ break;
}
}
}
if (r->man->macroset != MACROSET_MDOC) {
for (tok = MAN_TH; tok < MAN_MAX; tok++) {
! if (strncmp(name, roff_name[tok], len) != 0 ||
! roff_name[tok][len] != '\0')
! continue;
! if (*deftype & ROFFDEF_STD) {
*deftype = ROFFDEF_STD;
return NULL;
+ } else {
+ found = 1;
+ break;
}
}
}
+
+ if (found == 0 && *deftype != ROFFDEF_ANY) {
+ if (*deftype & ROFFDEF_REN) {
+ /*
+ * This might still be a request,
+ * so do not treat it as undefined yet.
+ */
+ *deftype = ROFFDEF_UNDEF;
+ return NULL;
}
+
+ /* Using an undefined string defines it to be empty. */
+
+ roff_setstrn(&r->strtab, name, len, "", 0, 0);
+ roff_setstrn(&r->rentab, name, len, NULL, 0, 0);
+ }
+
*deftype = 0;
return NULL;
}
static void