=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.321 retrieving revision 1.326 diff -u -p -r1.321 -r1.326 --- mandoc/roff.c 2017/07/08 17:52:50 1.321 +++ mandoc/roff.c 2018/04/09 22:27:04 1.326 @@ -1,7 +1,7 @@ -/* $Id: roff.c,v 1.321 2017/07/08 17:52:50 schwarze Exp $ */ +/* $Id: roff.c,v 1.326 2018/04/09 22:27:04 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons - * Copyright (c) 2010-2015, 2017 Ingo Schwarze + * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -46,6 +46,7 @@ #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 --------------------------------------------------------- */ @@ -181,11 +182,10 @@ 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_getregn(struct roff *, const char *, size_t); static int roff_getregro(const struct roff *, const char *name); -static const char *roff_getstrn(const struct roff *, +static const char *roff_getstrn(struct roff *, const char *, size_t, int *); static int roff_hasregn(const struct roff *, const char *, size_t); @@ -206,6 +206,8 @@ static enum rofferr roff_res(struct roff *, struct bu 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); static void roff_setstr(struct roff *, const char *, const char *, int); static void roff_setstrn(struct roffkv **, const char *, @@ -1127,13 +1129,13 @@ roff_res(struct roff *r, struct buf *buf, int ln, int size_t maxl; /* expected length of the escape name */ size_t naml; /* actual length of the escape name */ enum mandoc_esc esc; /* type of the escape sequence */ - enum mandoc_os os_e; /* kind of RCS id seen */ int inaml; /* length returned from mandoc_escape() */ int expand_count; /* to avoid infinite loops */ 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 term; /* character terminating the escape */ /* Search forward for comments. */ @@ -1149,20 +1151,21 @@ roff_res(struct roff *r, struct buf *buf, int ln, int /* Comment found, look for RCS id. */ + rcsid = 0; if ((cp = strstr(stesc, "$" "OpenBSD")) != NULL) { - os_e = MANDOC_OS_OPENBSD; + rcsid = 1 << MANDOC_OS_OPENBSD; cp += 8; } else if ((cp = strstr(stesc, "$" "NetBSD")) != NULL) { - os_e = MANDOC_OS_NETBSD; + rcsid = 1 << MANDOC_OS_NETBSD; cp += 7; } if (cp != NULL && isalnum((unsigned char)*cp) == 0 && strchr(cp, '$') != NULL) { - if (r->man->meta.rcsids & (1 << os_e)) + if (r->man->meta.rcsids & rcsid) mandoc_msg(MANDOCERR_RCS_REP, r->parse, ln, stesc + 1 - buf->buf, stesc + 1); - r->man->meta.rcsids |= 1 << os_e; + r->man->meta.rcsids |= rcsid; } /* Handle trailing whitespace. */ @@ -1558,7 +1561,8 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, /* For now, let high level macros abort .ce mode. */ if (ctl && roffce_node != NULL && - (t == TOKEN_NONE || t == ROFF_EQ || t == ROFF_TS)) { + (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ || + t == ROFF_TH || t == ROFF_TS)) { r->man->last = roffce_node; r->man->next = ROFF_NEXT_SIBLING; roffce_lines = 0; @@ -1637,6 +1641,11 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln } 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; } @@ -2513,19 +2522,27 @@ roff_evalnum(struct roff *r, int ln, const char *v, void roff_setreg(struct roff *r, const char *name, int val, char sign) { + roff_setregn(r, name, strlen(name), val, sign); +} + +static void +roff_setregn(struct roff *r, const char *name, size_t len, + 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)) + 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_strdup(name); - reg->key.sz = strlen(name); + reg->key.p = mandoc_strndup(name, len); + reg->key.sz = len; reg->val = 0; reg->next = r->regtab; r->regtab = reg; @@ -2570,26 +2587,13 @@ roff_getregro(const struct roff *r, const char *name) } int -roff_getreg(const struct roff *r, const char *name) +roff_getreg(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; + return roff_getregn(r, name, strlen(name)); } static int -roff_getregn(const struct roff *r, const char *name, size_t len) +roff_getregn(struct roff *r, const char *name, size_t len) { struct roffreg *reg; int val; @@ -2605,6 +2609,7 @@ roff_getregn(const struct roff *r, const char *name, s 0 == strncmp(name, reg->key.p, len)) return reg->val; + roff_setregn(r, name, len, 0, '\0'); return 0; } @@ -2656,14 +2661,13 @@ roff_nr(ROFF_ARGS) 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); + roff_setregn(r, key, keysz, iv, sign); return ROFF_IGN; } @@ -2879,6 +2883,8 @@ roff_EQ(ROFF_ARGS) { struct roff_node *n; + if (r->man->macroset == MACROSET_MAN) + man_breakscope(r->man, ROFF_EQ); n = roff_node_alloc(r->man, ln, ppos, ROFFT_EQN, TOKEN_NONE); if (ln > r->man->last->line) n->flags |= NODE_LINE; @@ -3533,62 +3539,95 @@ roff_setstrn(struct roffkv **r, const char *name, size } static const char * -roff_getstrn(const struct roff *r, const char *name, size_t len, +roff_getstrn(struct roff *r, const char *name, size_t len, int *deftype) { const struct roffkv *n; - int i; + int found, 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; - } + 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; } } - 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; - } + 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; } } - 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; - } + 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 (*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_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') { - *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') + 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; }