Index: doc/GetInt.3 ================================================================== --- doc/GetInt.3 +++ doc/GetInt.3 @@ -87,14 +87,14 @@ .QW \fB,\fR as a decimal point is not supported nor should any other sort of inter-digit separator be present. .PP \fBTcl_GetBoolean\fR expects \fIsrc\fR to specify a boolean -value. If \fIsrc\fR is any of \fB0\fR, \fBfalse\fR, +value. If \fIsrc\fR is any of \fB0\fR, \fB-\fR, \fBfalse\fR, \fBno\fR, or \fBoff\fR, then \fBTcl_GetBoolean\fR stores a zero value at \fI*boolPtr\fR. -If \fIsrc\fR is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR, +If \fIsrc\fR is any of \fB1\fR, \fB+\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR, then 1 is stored at \fI*boolPtr\fR. Any of these values may be abbreviated, and upper-case spellings are also acceptable. .SH KEYWORDS Index: generic/tclGet.c ================================================================== --- generic/tclGet.c +++ generic/tclGet.c @@ -123,11 +123,11 @@ int Tcl_GetBoolean( Tcl_Interp *interp, /* Interpreter used for error reporting. */ const char *src, /* String containing one of the boolean values - * 1, 0, true, false, yes, no, on, off. */ + * 1, 0, +, -, true, false, yes, no, on, off. */ int *boolPtr) /* Place to store converted result, which will * be 0 or 1. */ { Tcl_Obj obj; int code; Index: generic/tclLink.c ================================================================== --- generic/tclLink.c +++ generic/tclLink.c @@ -65,11 +65,11 @@ */ static char * LinkTraceProc(ClientData clientData,Tcl_Interp *interp, const char *name1, const char *name2, int flags); static Tcl_Obj * ObjValue(Link *linkPtr); -static int GetInvalidIntFromObj(Tcl_Obj *objPtr, +static int GetInvalidIntOrBooleanFromObj(Tcl_Obj *objPtr, int *intPtr); static int GetInvalidDoubleFromObj(Tcl_Obj *objPtr, double *doublePtr); /* @@ -382,28 +382,28 @@ switch (linkPtr->type) { case TCL_LINK_INT: if (Tcl_GetIntFromObj(NULL, valueObj, &linkPtr->lastValue.i) != TCL_OK) { - if (GetInvalidIntFromObj(valueObj, &linkPtr->lastValue.i) + if (GetInvalidIntOrBooleanFromObj(valueObj, &linkPtr->lastValue.i) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have integer value"; + return (char *) "variable must have integer or boolean value"; } } LinkedVar(int) = linkPtr->lastValue.i; break; case TCL_LINK_WIDE_INT: if (Tcl_GetWideIntFromObj(NULL, valueObj, &linkPtr->lastValue.w) != TCL_OK) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have integer value"; + return (char *) "variable must have integer or boolean value"; } linkPtr->lastValue.w = (Tcl_WideInt) valueInt; } LinkedVar(Tcl_WideInt) = linkPtr->lastValue.w; break; @@ -439,71 +439,71 @@ break; case TCL_LINK_CHAR: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < SCHAR_MIN || valueInt > SCHAR_MAX) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have char value"; + return (char *) "variable must have char or boolean value"; } } linkPtr->lastValue.c = (char)valueInt; LinkedVar(char) = linkPtr->lastValue.c; break; case TCL_LINK_UCHAR: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < 0 || valueInt > UCHAR_MAX) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned char value"; + return (char *) "variable must have unsigned char or boolean value"; } } linkPtr->lastValue.uc = (unsigned char) valueInt; LinkedVar(unsigned char) = linkPtr->lastValue.uc; break; case TCL_LINK_SHORT: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < SHRT_MIN || valueInt > SHRT_MAX) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have short value"; + return (char *) "variable must have short or boolean value"; } } linkPtr->lastValue.s = (short)valueInt; LinkedVar(short) = linkPtr->lastValue.s; break; case TCL_LINK_USHORT: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < 0 || valueInt > USHRT_MAX) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned short value"; + return (char *) "variable must have unsigned short or boolean value"; } } linkPtr->lastValue.us = (unsigned short)valueInt; LinkedVar(unsigned short) = linkPtr->lastValue.us; break; case TCL_LINK_UINT: if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK || valueWide < 0 || valueWide > UINT_MAX) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned int value"; + return (char *) "variable must have unsigned int or boolean value"; } linkPtr->lastValue.ui = (unsigned int)valueInt; } else { linkPtr->lastValue.ui = (unsigned int)valueWide; } @@ -511,15 +511,15 @@ break; case TCL_LINK_LONG: if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK || valueWide < LONG_MIN || valueWide > LONG_MAX) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have long value"; + return (char *) "variable must have long or boolean value"; } linkPtr->lastValue.l = (long)valueInt; } else { linkPtr->lastValue.l = (long)valueWide; } @@ -527,15 +527,15 @@ break; case TCL_LINK_ULONG: if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK || valueWide < 0 || (Tcl_WideUInt) valueWide > ULONG_MAX) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned long value"; + return (char *) "variable must have unsigned long or boolean value"; } linkPtr->lastValue.ul = (unsigned long)valueInt; } else { linkPtr->lastValue.ul = (unsigned long)valueWide; } @@ -545,15 +545,15 @@ case TCL_LINK_WIDE_UINT: /* * FIXME: represent as a bignum. */ if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK) { - if (GetInvalidIntFromObj(valueObj, &valueInt) + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) != TCL_OK) { Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned wide int value"; + return (char *) "variable must have unsigned wide int or boolean value"; } linkPtr->lastValue.uw = (Tcl_WideUInt)valueInt; } else { linkPtr->lastValue.uw = (Tcl_WideUInt)valueWide; } @@ -686,21 +686,20 @@ SetInvalidRealFromAny /* setFromAnyProc */ }; static int SetInvalidRealFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr) { - int length; const char *str; const char *endPtr; - str = TclGetStringFromObj(objPtr, &length); - if ((length == 1) && (str[0] == '.')){ + str = TclGetString(objPtr); + if ((objPtr->length == 1) && (str[0] == '.')){ objPtr->typePtr = &invalidRealType; objPtr->internalRep.doubleValue = 0.0; return TCL_OK; } - if (TclParseNumber(NULL, objPtr, NULL, str, length, &endPtr, + if (TclParseNumber(NULL, objPtr, NULL, str, objPtr->length, &endPtr, TCL_PARSE_DECIMAL_ONLY) == TCL_OK) { /* If number is followed by [eE][+-]?, then it is an invalid * double, but it could be the start of a valid double. */ if (*endPtr == 'e' || *endPtr == 'E') { ++endPtr; @@ -718,31 +717,27 @@ return TCL_ERROR; } /* - * This function checks for integer representations, which are valid - * when linking with C variables, but which are invalid in other - * contexts in Tcl. Handled are "", "+", "-", "0x", "0b" and "0o" - * (upperand lowercase). See bug [39f6304c2e]. + * This function checks for integer or boolean representations, + * which are valid when linking with C variables, but which are + * invalid in other contexts in Tcl. Handled are "", "0x", "0b" + * and "0o" (upperand lowercase). See bug [39f6304c2e]. */ int -GetInvalidIntFromObj(Tcl_Obj *objPtr, +GetInvalidIntOrBooleanFromObj(Tcl_Obj *objPtr, int *intPtr) { - int length; - const char *str = TclGetStringFromObj(objPtr, &length); - - if ((length == 1) && strchr("+-", str[0])) { - *intPtr = (str[0] == '+'); - return TCL_OK; - } else if ((length == 0) || - ((length == 2) && (str[0] == '0') && strchr("xXbBoO", str[1]))) { + const char *str = TclGetString(objPtr); + + if ((objPtr->length == 0) || + ((objPtr->length == 2) && (str[0] == '0') && strchr("xXbBoO", str[1]))) { *intPtr = 0; return TCL_OK; } - return TCL_ERROR; + return Tcl_GetBooleanFromObj(NULL, objPtr, intPtr); } /* * This function checks for double representations, which are valid * when linking with C variables, but which are invalid in other @@ -751,26 +746,31 @@ */ int GetInvalidDoubleFromObj(Tcl_Obj *objPtr, double *doublePtr) { - int intValue, result; + const char *str; if ((objPtr->typePtr == &invalidRealType) || (SetInvalidRealFromAny(NULL, objPtr) == TCL_OK)) { *doublePtr = objPtr->internalRep.doubleValue; return TCL_OK; } - result = GetInvalidIntFromObj(objPtr, &intValue); - if (result == TCL_OK) { - *doublePtr = (double) intValue; + str = TclGetString(objPtr); + if ((objPtr->length == 1) && strchr("+-", str[0])) { + *doublePtr = (double)(str[0] == '+'); + return TCL_OK; + } else if ((objPtr->length == 0) || + ((objPtr->length == 2) && (str[0] == '0') && strchr("xXbBoO", str[1]))) { + *doublePtr = 0.0; + return TCL_OK; } - return result; + return TCL_ERROR; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ Index: generic/tclObj.c ================================================================== --- generic/tclObj.c +++ generic/tclObj.c @@ -2002,13 +2002,14 @@ static int ParseBoolean( register Tcl_Obj *objPtr) /* The object to parse/convert. */ { - int i, length, newBool; + int newBool; char lowerCase[6]; - const char *str = TclGetStringFromObj(objPtr, &length); + const char *str = TclGetString(objPtr); + size_t i, length = objPtr->length; if ((length == 0) || (length > 5)) { /* * Longest valid boolean string rep. is "false". */ @@ -2026,10 +2027,22 @@ case '1': if (length == 1) { newBool = 1; goto numericBoolean; } + return TCL_ERROR; + case '-': + if (length == 1) { + newBool = 0; + goto goodBoolean; + } + return TCL_ERROR; + case '+': + if (length == 1) { + newBool = 1; + goto goodBoolean; + } return TCL_ERROR; } /* * Force to lower case for case-insensitive detection. Filter out known @@ -2080,18 +2093,15 @@ newBool = 0; goto goodBoolean; } return TCL_ERROR; case 'o': - if (length < 2) { - return TCL_ERROR; - } - if (strncmp(lowerCase, "on", (size_t) length) == 0) { - newBool = 1; + if (strncmp(lowerCase, "off", (size_t) length) == 0) { + newBool = 0; goto goodBoolean; - } else if (strncmp(lowerCase, "off", (size_t) length) == 0) { - newBool = 0; + } else if (strncmp(lowerCase, "on", (size_t) length) == 0) { + newBool = 1; goto goodBoolean; } return TCL_ERROR; default: return TCL_ERROR; Index: tests/link.test ================================================================== --- tests/link.test +++ tests/link.test @@ -65,11 +65,11 @@ testlink delete } -constraints {testlink} -body { testlink set 43 1.23 4 - 56785678 64 250 30000 60000 0xbeefbabe 12321 32123 3.25 1231231234 testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1 list [catch {set int 09a} msg] $msg $int -} -result {1 {can't set "int": variable must have integer value} 43} +} -result {1 {can't set "int": variable must have integer or boolean value} 43} test link-2.3 {writing bad values into variables} -setup { testlink delete } -constraints {testlink} -body { testlink set 43 1.23 4 - 56785678 64 250 30000 60000 0xbeefbabe 12321 32123 3.25 1231231234 testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1 @@ -86,11 +86,11 @@ testlink delete } -constraints {testlink} -body { testlink set 43 1.23 4 - 56785678 64 250 30000 60000 0xbeefbabe 12321 32123 3.25 1231231234 testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1 list [catch {set wide gorp} msg] $msg $bool -} -result {1 {can't set "wide": variable must have integer value} 1} +} -result {1 {can't set "wide": variable must have integer or boolean value} 1} test link-2.6 {writing C variables from Tcl} -constraints {testlink} -setup { testlink delete } -body { testlink set 43 1.21 4 - 56785678 64 250 30000 60000 0xbaadbeef 12321 32123 3.25 1231231234 testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1 @@ -307,11 +307,11 @@ set y abc } testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1 testlink set -4 {} {} {} {} {} {} {} {} {} {} {} {} {} list [catch x msg] $msg $int -} -result {1 {can't set "y": variable must have integer value} -4} +} -result {1 {can't set "y": variable must have integer or boolean value} -4} test link-7.5 {access to linked variables via upvar} -setup { testlink delete } -constraints {testlink} -body { proc x {} { upvar real y @@ -340,11 +340,11 @@ set y abc } testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1 testlink set -4 16.3 1 {} 778899 {} {} {} {} {} {} {} {} {} list [catch x msg] $msg $wide -} -result {1 {can't set "y": variable must have integer value} 778899} +} -result {1 {can't set "y": variable must have integer or boolean value} 778899} test link-8.1 {Tcl_UpdateLinkedVar procedure} {testlink} { proc x args { global x int real bool string wide lappend x $args $int $real $bool $string $wide