From f9fb8c8daf918e57d3a50a0428623a5e5c260e70 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 4 Dec 2014 18:26:31 +0000 Subject: Stop using isalnum(.). Its results are not portable. Replace with our own private routine TclIsBareword() that does exactly what we want. --- generic/tclCompExpr.c | 15 ++++++++++----- generic/tclInt.h | 1 + generic/tclParse.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c index dde4e56..2470931 100644 --- a/generic/tclCompExpr.c +++ b/generic/tclCompExpr.c @@ -1920,8 +1920,7 @@ ParseLexeme( literal = Tcl_NewObj(); if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end, TCL_PARSE_NO_WHITESPACE) == TCL_OK) { - if (end < start + numBytes && !isalnum(UCHAR(*end)) - && UCHAR(*end) != '_') { + if (end < start + numBytes && !TclIsBareword(*end)) { number: TclInitStringRep(literal, start, end-start); @@ -1945,7 +1944,7 @@ ParseLexeme( if (literal->typePtr == &tclDoubleType) { const char *p = start; while (p < end) { - if (!isalnum(UCHAR(*p++))) { + if (!TclIsBareword(*p++)) { /* * The number has non-bareword characters, so we * must treat it as a number. @@ -1969,7 +1968,13 @@ ParseLexeme( } } - if (!isalnum(UCHAR(*start))) { + /* + * We reject leading underscores in bareword. No sensible reason why. + * Might be inspired by reserved identifier rules in C, which of course + * have no direct relevance here. + */ + + if (!TclIsBareword(*start) || *start == '_') { if (Tcl_UtfCharComplete(start, numBytes)) { scanned = Tcl_UtfToUniChar(start, &ch); } else { @@ -1983,7 +1988,7 @@ ParseLexeme( return scanned; } end = start; - while (numBytes && (isalnum(UCHAR(*end)) || (UCHAR(*end) == '_'))) { + while (numBytes && TclIsBareword(*end)) { end += 1; numBytes -= 1; } diff --git a/generic/tclInt.h b/generic/tclInt.h index dd66d76..255ee23 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2608,6 +2608,7 @@ MODULE_SCOPE void TclInitSubsystems(void); MODULE_SCOPE int TclInterpReady(Tcl_Interp *interp); MODULE_SCOPE int TclIsLocalScalar(const char *src, int len); MODULE_SCOPE int TclIsSpaceProc(char byte); +MODULE_SCOPE int TclIsBareword(char byte); MODULE_SCOPE int TclJoinThread(Tcl_ThreadId id, int *result); MODULE_SCOPE void TclLimitRemoveAllHandlers(Tcl_Interp *interp); MODULE_SCOPE Tcl_Obj * TclLindexList(Tcl_Interp *interp, diff --git a/generic/tclParse.c b/generic/tclParse.c index 90ec43d..025304c 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -628,6 +628,47 @@ TclIsSpaceProc( /* *---------------------------------------------------------------------- * + * TclIsBareword-- + * + * Report whether byte is one that can be part of a "bareword". + * This concept is named in expression parsing, where it determines + * what can be a legal function name, but is the same definition used + * in determining what variable names can be parsed as variable + * substitutions without the benefit of enclosing braces. The set of + * ASCII chars that are accepted are the numeric chars ('0'-'9'), + * the alphabetic chars ('a'-'z', 'A'-'Z') and underscore ('_'). + * + * Results: + * Returns 1, if byte is in the accepted set of chars, 0 otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclIsBareword( + char byte) +{ + if (byte < '0' || byte > 'z') { + return 0; + } + if (byte <= '9' || byte >= 'a') { + return 1; + } + if (byte == '_') { + return 1; + } + if (byte < 'A' || byte > 'Z') { + return 0; + } + return 1; +} + +/* + *---------------------------------------------------------------------- + * * ParseWhiteSpace -- * * Scans up to numBytes bytes starting at src, consuming white space @@ -1343,7 +1384,6 @@ Tcl_ParseVarName( { Tcl_Token *tokenPtr; register const char *src; - unsigned char c; int varIndex; unsigned array; @@ -1427,13 +1467,12 @@ Tcl_ParseVarName( tokenPtr->numComponents = 0; while (numBytes) { - c = UCHAR(*src); - if (isalnum(c) || (c == '_')) { /* INTL: ISO only, UCHAR. */ + if (TclIsBareword(*src)) { src += 1; numBytes -= 1; continue; } - if ((c == ':') && (numBytes != 1) && (src[1] == ':')) { + if ((src[0] == ':') && (numBytes != 1) && (src[1] == ':')) { src += 2; numBytes -= 2; while (numBytes && (*src == ':')) { -- cgit v0.12