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