diff options
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | regress/roff/string/Makefile | 4 | ||||
-rw-r--r-- | regress/roff/string/undef.in | 69 | ||||
-rw-r--r-- | regress/roff/string/undef.out_ascii | 37 | ||||
-rw-r--r-- | regress/roff/string/undef.out_lint | 2 | ||||
-rw-r--r-- | roff.c | 123 |
6 files changed, 191 insertions, 48 deletions
@@ -87,10 +87,6 @@ are mere guesses, and some may be wrong. Found by naddy@ in devel/cutils cobfusc(1) Mon, 16 Feb 2015 19:10:52 +0100 loc *** exist *** algo *** size ** imp * -- using undefined strings or macros defines them to be empty - wl@ Mon, 14 Nov 2011 14:37:01 +0000 - loc * exist * algo * size * imp * - --- missing mdoc features ---------------------------------------------- - .Bl -column .Xo support is missing diff --git a/regress/roff/string/Makefile b/regress/roff/string/Makefile index 354a7a75..eda8c8ad 100644 --- a/regress/roff/string/Makefile +++ b/regress/roff/string/Makefile @@ -1,7 +1,7 @@ # $OpenBSD: Makefile,v 1.6 2014/07/06 19:08:57 schwarze Exp $ -REGRESS_TARGETS = escape infinite name std zerolength -LINT_TARGETS = name std +REGRESS_TARGETS = escape infinite name std undef zerolength +LINT_TARGETS = name std undef # The infinite test fails badly with groff-1.20.1: # It fails to print the following text. diff --git a/regress/roff/string/undef.in b/regress/roff/string/undef.in new file mode 100644 index 00000000..d84a67c6 --- /dev/null +++ b/regress/roff/string/undef.in @@ -0,0 +1,69 @@ +.\" $OpenBSD: std.in,v 1.2 2017/07/04 14:53:27 schwarze Exp $ +.TH STRING-UNDEF 1 "April 9, 2018" +.SH NAME +string-undef - expanding undefined strings +.SH DESCRIPTION +.SS User defined string +The sting "mys" is +.ie dmys defined +.el undefined +and remains +.ie dmys defined. +.el undefined. +.PP +Its value is "\*[mys]", and now it is +.ie dmys defined, +.el undefined, +and its value is still "\*[mys]". +.PP +.ds mys newval +After redefining it to "\*[mys]", it is of course still +.ie dmys defined. +.el undefined. +.PP +.rm mys +After removing the definition, it is now +.ie dmys defined. +.el undefined. +.SS User defined macro +The macro "mym" is +.ie dmym defined. +.el undefined. +.PP +It has no effect: +.mym +But now it is +.ie dmym defined. +.el undefined. +.PP +.de mym +neweffect +.. +After defining it as: +.mym +it is of course still +.ie dmym defined. +.el undefined. +.PP +.rm mym +After removing the definition, it is now +.ie dmym defined. +.el undefined. +.SS Renamed macro +The standard .BR macro is +.ie dBR defined, +.el undefined, +and it +.BR works . +.PP +.rn BR newBR +After renaming it, the new name is +.ie dnewBR defined, +.el undefined, +and +.newBR works . +.SS Predefined string +A predefined string is +.ie dR defined +.el undefined +and has the value "\*R". diff --git a/regress/roff/string/undef.out_ascii b/regress/roff/string/undef.out_ascii new file mode 100644 index 00000000..6e7bd01f --- /dev/null +++ b/regress/roff/string/undef.out_ascii @@ -0,0 +1,37 @@ +STRING-UNDEF(1) General Commands Manual STRING-UNDEF(1) + + + +NNAAMMEE + string-undef - expanding undefined strings + +DDEESSCCRRIIPPTTIIOONN + UUsseerr ddeeffiinneedd ssttrriinngg + The sting "mys" is undefined and remains undefined. + + Its value is "", and now it is defined, and its value is still "". + + After redefining it to "newval", it is of course still defined. + + After removing the definition, it is now undefined. + + UUsseerr ddeeffiinneedd mmaaccrroo + The macro "mym" is undefined. + + It has no effect: But now it is defined. + + After defining it as: neweffect it is of course still defined. + + After removing the definition, it is now undefined. + + RReennaammeedd mmaaccrroo + The standard .BR macro is defined, and it wwoorrkkss. + + After renaming it, the new name is defined, and wwoorrkkss. + + PPrreeddeeffiinneedd ssttrriinngg + A predefined string is defined and has the value "(R)". + + + +OpenBSD April 9, 2018 STRING-UNDEF(1) diff --git a/regress/roff/string/undef.out_lint b/regress/roff/string/undef.out_lint new file mode 100644 index 00000000..320ec604 --- /dev/null +++ b/regress/roff/string/undef.out_lint @@ -0,0 +1,2 @@ +mandoc: undef.in:14:15: WARNING: undefined string, using "": mys +mandoc: undef.in:34:2: ERROR: skipping unknown macro: .mym @@ -1,7 +1,7 @@ /* $Id$ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org> + * 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 @@ -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 --------------------------------------------------------- */ @@ -185,7 +186,7 @@ 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 *, +static const char *roff_getstrn(struct roff *, const char *, size_t, int *); static int roff_hasregn(const struct roff *, const char *, size_t); @@ -1639,6 +1640,11 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) } 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; } @@ -3537,62 +3543,95 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz, } 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; } |