=================================================================== RCS file: /cvs/mandoc/roff_escape.c,v retrieving revision 1.6 retrieving revision 1.10 diff -u -p -r1.6 -r1.10 --- mandoc/roff_escape.c 2022/06/01 23:20:26 1.6 +++ mandoc/roff_escape.c 2022/06/05 13:54:09 1.10 @@ -1,4 +1,4 @@ -/* $OpenBSD: roff_escape.c,v 1.6 2022/06/01 23:20:26 schwarze Exp $ */ +/* $OpenBSD: roff_escape.c,v 1.10 2022/06/05 13:54:09 schwarze Exp $ */ /* * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2017, 2018, 2020, 2022 * Ingo Schwarze @@ -41,7 +41,8 @@ mandoc_escape(const char **rendarg, const char **rarg, int iarg, iendarg, iend; enum mandoc_esc rval; - rval = roff_escape(--*rendarg, 0, 0, NULL, &iarg, &iendarg, &iend); + rval = roff_escape(--*rendarg, 0, 0, + NULL, NULL, &iarg, &iendarg, &iend); assert(rval != ESCAPE_EXPAND); if (rarg != NULL) *rarg = *rendarg + iarg; @@ -63,20 +64,20 @@ mandoc_escape(const char **rendarg, const char **rarg, */ enum mandoc_esc roff_escape(const char *buf, const int ln, const int aesc, - int *resc, int *rarg, int *rendarg, int *rend) + int *resc, int *rnam, int *rarg, int *rendarg, int *rend) { int iesc; /* index of leading escape char */ + int inam; /* index of escape name */ int iarg; /* index beginning the argument */ int iendarg; /* index right after the argument */ int iend; /* index right after the sequence */ - int sesc, sarg, sendarg, send; /* for sub-escape */ + int sesc, snam, sarg, sendarg, send; /* for sub-escape */ int maxl; /* expected length of the argument */ int argl; /* actual length of the argument */ int c, i; /* for \[char...] parsing */ int valid_A; /* for \A parsing */ enum mandoc_esc rval; /* return value */ enum mandocerr err; /* diagnostic code */ - char esc_name; char term; /* byte terminating the argument */ /* @@ -84,21 +85,21 @@ roff_escape(const char *buf, const int ln, const int a * it only makes a difference in copy mode. */ - iesc = iarg = aesc; + iesc = inam = aesc; do { - iarg++; - } while (buf[iarg] == 'E'); + inam++; + } while (buf[inam] == 'E'); /* * Sort the following cases first by syntax category, * then by escape sequence type, and finally by ASCII code. */ - esc_name = buf[iarg]; - iendarg = iend = ++iarg; + iarg = iendarg = iend = inam + 1; maxl = INT_MAX; term = '\0'; - switch (esc_name) { + err = MANDOCERR_OK; + switch (buf[inam]) { /* Escape sequences taking no arguments at all. */ @@ -127,6 +128,7 @@ roff_escape(const char *buf, const int ln, const int a case '\0': iendarg = --iend; /* FALLTHROUGH */ + case '.': case '\\': default: iarg--; @@ -136,7 +138,6 @@ roff_escape(const char *buf, const int ln, const int a case ' ': case '\'': case '-': - case '.': case '0': case ':': case '_': @@ -269,12 +270,12 @@ roff_escape(const char *buf, const int ln, const int a if ((term == '\b' || (term == '\0' && maxl == INT_MAX)) && buf[iarg] == buf[iesc] && roff_escape(buf, ln, iendarg, - &sesc, &sarg, &sendarg, &send) == ESCAPE_EXPAND) + &sesc, &snam, &sarg, &sendarg, &send) == ESCAPE_EXPAND) goto out_sub; if (term == '\b') { - if ((esc_name == 'N' && isdigit((unsigned char)buf[iarg])) || - (esc_name == 'h' && strchr(" %&()*+-./0123456789:<=>", + if ((buf[inam] == 'N' && isdigit((unsigned char)buf[iarg])) || + (buf[inam] == 'h' && strchr(" %&()*+-./0123456789:<=>", buf[iarg]) != NULL)) { iendarg = iend = iarg + 1; rval = ESCAPE_ERROR; @@ -282,7 +283,7 @@ roff_escape(const char *buf, const int ln, const int a } term = buf[iarg++]; } else if (term == '\0' && maxl == INT_MAX) { - if (esc_name == 'n' && (buf[iarg] == '+' || buf[iarg] == '-')) + if (buf[inam] == 'n' && (buf[iarg] == '+' || buf[iarg] == '-')) iarg++; switch (buf[iarg]) { case '(': @@ -309,8 +310,11 @@ roff_escape(const char *buf, const int ln, const int a iendarg = iarg; while (maxl > 0) { if (buf[iendarg] == '\0') { + err = MANDOCERR_ESC_INCOMPLETE; + if (rval != ESCAPE_EXPAND) + rval = ESCAPE_ERROR; /* Ignore an incomplete argument except for \w. */ - if (esc_name != 'w') + if (buf[inam] != 'w') iendarg = iarg; break; } @@ -318,14 +322,14 @@ roff_escape(const char *buf, const int ln, const int a iend = iendarg + 1; break; } - if (esc_name == 'N' && + if (buf[inam] == 'N' && isdigit((unsigned char)buf[iendarg]) == 0) { iend = iendarg + 1; break; } if (buf[iendarg] == buf[iesc]) { switch (roff_escape(buf, ln, iendarg, - &sesc, &sarg, &sendarg, &send)) { + &sesc, &snam, &sarg, &sendarg, &send)) { case ESCAPE_EXPAND: goto out_sub; case ESCAPE_UNDEF: @@ -343,14 +347,11 @@ roff_escape(const char *buf, const int ln, const int a iend = ++iendarg; } } - if (resc != NULL && ((maxl != INT_MAX && maxl != 0) || - (term != '\0' && buf[iendarg] != term))) - mandoc_msg(MANDOCERR_ESC_BAD, ln, iesc, "%s", buf + iesc); /* Post-process depending on the content of the argument. */ argl = iendarg - iarg; - switch (esc_name) { + switch (buf[inam]) { case '*': if (resc == NULL && argl == 2 && buf[iarg] == '.' && buf[iarg + 1] == 'T') @@ -399,6 +400,7 @@ roff_escape(const char *buf, const int ln, const int a */ if (term != '\0' && argl == 1 && buf[iarg] != '-') { + err = MANDOCERR_ESC_BADCHAR; rval = ESCAPE_ERROR; break; } @@ -414,8 +416,10 @@ roff_escape(const char *buf, const int ln, const int a c = 0; for (i = iarg; i < iendarg; i++) c = 10 * c + (buf[i] - '0'); - if (c < 0x21 || (c > 0x7e && c < 0xa0) || c > 0xff) + if (c < 0x21 || (c > 0x7e && c < 0xa0) || c > 0xff) { + err = MANDOCERR_ESC_BADCHAR; break; + } iarg += 4; rval = ESCAPE_NUMBERED; break; @@ -431,13 +435,19 @@ roff_escape(const char *buf, const int ln, const int a if (buf[iarg] != 'u' || argl < 5 || argl > 7) break; if (argl == 7 && - (buf[iarg + 1] != '1' || buf[iarg + 2] != '0')) + (buf[iarg + 1] != '1' || buf[iarg + 2] != '0')) { + err = MANDOCERR_ESC_BADCHAR; break; - if (argl == 6 && buf[iarg + 1] == '0') + } + if (argl == 6 && buf[iarg + 1] == '0') { + err = MANDOCERR_ESC_BADCHAR; break; + } if (argl == 5 && buf[iarg + 1] == 'D' && - strchr("89ABCDEF", buf[iarg + 2]) != NULL) + strchr("89ABCDEF", buf[iarg + 2]) != NULL) { + err = MANDOCERR_ESC_BADCHAR; break; + } if ((int)strspn(buf + iarg + 1, "0123456789ABCDEFabcdef") + 1 == argl) rval = ESCAPE_UNICODE; @@ -449,12 +459,15 @@ roff_escape(const char *buf, const int ln, const int a out_sub: iesc = sesc; + inam = snam; iarg = sarg; iendarg = sendarg; iend = send; rval = ESCAPE_EXPAND; out: + if (rnam != NULL) + *rnam = inam; if (rarg != NULL) *rarg = iarg; if (rendarg != NULL) @@ -472,24 +485,26 @@ out: *resc = iesc; switch (rval) { case ESCAPE_ERROR: - err = MANDOCERR_ESC_BAD; + if (err == MANDOCERR_OK) + err = MANDOCERR_ESC_BAD; break; case ESCAPE_UNSUPP: err = MANDOCERR_ESC_UNSUPP; break; case ESCAPE_UNDEF: - if (esc_name == '\\') - return rval; - err = MANDOCERR_ESC_UNDEF; + if (buf[inam] != '\\' && buf[inam] != '.') + err = MANDOCERR_ESC_UNDEF; break; case ESCAPE_SPECIAL: if (mchars_spec2cp(buf + iarg, argl) >= 0) - return rval; - err = MANDOCERR_ESC_BAD; + err = MANDOCERR_OK; + else if (err == MANDOCERR_OK) + err = MANDOCERR_ESC_UNKCHAR; break; default: - return rval; + break; } - mandoc_msg(err, ln, iesc, "%.*s", iend - iesc, buf + iesc); + if (err != MANDOCERR_OK) + mandoc_msg(err, ln, iesc, "%.*s", iend - iesc, buf + iesc); return rval; }