diff options
Diffstat (limited to 'generic/tclLink.c')
-rw-r--r-- | generic/tclLink.c | 175 |
1 files changed, 131 insertions, 44 deletions
diff --git a/generic/tclLink.c b/generic/tclLink.c index f7125d5..588c750 100644 --- a/generic/tclLink.c +++ b/generic/tclLink.c @@ -67,6 +67,10 @@ typedef struct Link { static char * LinkTraceProc(ClientData clientData,Tcl_Interp *interp, const char *name1, const char *name2, int flags); static Tcl_Obj * ObjValue(Link *linkPtr); +static int GetInvalidIntOrBooleanFromObj(Tcl_Obj *objPtr, + int *intPtr); +static int GetInvalidDoubleOrBooleanFromObj(Tcl_Obj *objPtr, + double *doublePtr); /* * Convenience macro for accessing the value of the C variable pointed to by a @@ -259,7 +263,8 @@ LinkTraceProc( int flags) /* Miscellaneous additional information. */ { Link *linkPtr = clientData; - int changed, valueLength; + int changed; + size_t valueLength; const char *value; char **pp; Tcl_Obj *valueObj; @@ -380,9 +385,12 @@ LinkTraceProc( case TCL_LINK_INT: if (Tcl_GetIntFromObj(NULL, valueObj, &linkPtr->lastValue.i) != TCL_OK) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + 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; @@ -390,12 +398,15 @@ LinkTraceProc( case TCL_LINK_WIDE_INT: if (Tcl_GetWideIntFromObj(NULL, valueObj, &linkPtr->lastValue.w) != TCL_OK) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have integer value"; - } else { - LinkedVar(Tcl_WideInt) = linkPtr->lastValue.w; + return (char *) "variable must have integer or boolean value"; + } + linkPtr->lastValue.w = (Tcl_WideInt) valueInt; } + LinkedVar(Tcl_WideInt) = linkPtr->lastValue.w; break; case TCL_LINK_DOUBLE: @@ -404,13 +415,15 @@ LinkTraceProc( #ifdef ACCEPT_NAN if (valueObj->typePtr != &tclDoubleType) { #endif - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, - ObjValue(linkPtr), TCL_GLOBAL_ONLY); - return (char *) "variable must have real value"; + if (GetInvalidDoubleOrBooleanFromObj(valueObj, &linkPtr->lastValue.d) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have real or boolean value"; + } #ifdef ACCEPT_NAN - } else { - linkPtr->lastValue.d = valueObj->internalRep.doubleValue; } + linkPtr->lastValue.d = valueObj->internalRep.doubleValue; #endif } LinkedVar(double) = linkPtr->lastValue.d; @@ -429,9 +442,12 @@ LinkTraceProc( case TCL_LINK_CHAR: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < SCHAR_MIN || valueInt > SCHAR_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have char value"; + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have char or boolean value"; + } } linkPtr->lastValue.c = (char)valueInt; LinkedVar(char) = linkPtr->lastValue.c; @@ -440,9 +456,12 @@ LinkTraceProc( case TCL_LINK_UCHAR: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < 0 || valueInt > UCHAR_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned char value"; + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have unsigned char or boolean value"; + } } linkPtr->lastValue.uc = (unsigned char) valueInt; LinkedVar(unsigned char) = linkPtr->lastValue.uc; @@ -451,9 +470,12 @@ LinkTraceProc( case TCL_LINK_SHORT: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < SHRT_MIN || valueInt > SHRT_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have short value"; + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have short or boolean value"; + } } linkPtr->lastValue.s = (short)valueInt; LinkedVar(short) = linkPtr->lastValue.s; @@ -462,9 +484,12 @@ LinkTraceProc( case TCL_LINK_USHORT: if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK || valueInt < 0 || valueInt > USHRT_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned short value"; + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have unsigned short or boolean value"; + } } linkPtr->lastValue.us = (unsigned short)valueInt; LinkedVar(unsigned short) = linkPtr->lastValue.us; @@ -473,9 +498,13 @@ LinkTraceProc( case TCL_LINK_UINT: if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK || valueWide < 0 || valueWide > UINT_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned int value"; + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have unsigned int or boolean value"; + } + linkPtr->lastValue.ui = (unsigned int)valueInt; } else { linkPtr->lastValue.ui = (unsigned int)valueWide; } @@ -485,9 +514,13 @@ LinkTraceProc( case TCL_LINK_LONG: if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK || valueWide < LONG_MIN || valueWide > LONG_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have long value"; + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have long or boolean value"; + } + linkPtr->lastValue.l = (long)valueInt; } else { linkPtr->lastValue.l = (long)valueWide; } @@ -497,9 +530,13 @@ LinkTraceProc( case TCL_LINK_ULONG: if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK || valueWide < 0 || (Tcl_WideUInt) valueWide > ULONG_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned long value"; + if (GetInvalidIntOrBooleanFromObj(valueObj, &valueInt) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have unsigned long or boolean value"; + } + linkPtr->lastValue.ul = (unsigned long)valueInt; } else { linkPtr->lastValue.ul = (unsigned long)valueWide; } @@ -511,9 +548,13 @@ LinkTraceProc( * FIXME: represent as a bignum. */ if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have unsigned wide int value"; + 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 or boolean value"; + } + linkPtr->lastValue.uw = (Tcl_WideUInt)valueInt; } else { linkPtr->lastValue.uw = (Tcl_WideUInt)valueWide; } @@ -523,22 +564,24 @@ LinkTraceProc( case TCL_LINK_FLOAT: if (Tcl_GetDoubleFromObj(NULL, valueObj, &valueDouble) != TCL_OK || valueDouble < -FLT_MAX || valueDouble > FLT_MAX) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); - return (char *) "variable must have float value"; - } else { - linkPtr->lastValue.f = (float)valueDouble; + if (GetInvalidDoubleOrBooleanFromObj(valueObj, &valueDouble) + != TCL_OK) { + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + TCL_GLOBAL_ONLY); + return (char *) "variable must have float or boolean value"; + } } + linkPtr->lastValue.f = (float)valueDouble; LinkedVar(float) = linkPtr->lastValue.f; break; case TCL_LINK_STRING: - value = TclGetStringFromObj(valueObj, &valueLength); - valueLength++; + value = TclGetString(valueObj); + valueLength = valueObj->length + 1; pp = (char **) linkPtr->addr; *pp = ckrealloc(*pp, valueLength); - memcpy(*pp, value, (unsigned) valueLength); + memcpy(*pp, value, valueLength); break; default: @@ -633,6 +676,50 @@ ObjValue( return resultObj; } } +/* + * This function works almost the same as Tcl_GetBooleanFromObj(), only + * it doesn't have an interpreter to report errors, and it considers + * the character sequences "0x", "0b" and "0o" as valid, for purpose + * of the link functionality in Tcl. See bug [39f6304c2e]. + */ +int +GetInvalidIntOrBooleanFromObj(Tcl_Obj *objPtr, + int *intPtr) +{ + const char *str = TclGetString(objPtr); + if ((str[0] == '0') && strchr("xXbBoO", str[1]) && (str[2] == 0)){ + *intPtr = 0; + return TCL_OK; + } + return Tcl_GetBooleanFromObj(NULL, objPtr, intPtr); +} + +/* + * This function works almost the same as Tcl_GetBooleanFromObj(), only + * it returns a double in stead of an integer, it doesn't have an interpreter + * to report errors, and it considers the character sequences ".", "0x", "0b" + * and "0o" as valid, for purpose of the link functionality in Tcl. + * See bug [39f6304c2e]. + */ +int +GetInvalidDoubleOrBooleanFromObj(Tcl_Obj *objPtr, + double *doublePtr) +{ + int intValue, result; + const char *str = TclGetString(objPtr); + + if ((str[0] == '.') && (str[1] == 0)){ + *doublePtr = 0.0; + return TCL_OK; + } + result = GetInvalidIntOrBooleanFromObj(objPtr, &intValue); + if (result == TCL_OK) { + *doublePtr = (double) intValue; + } + return result; +} + + /* * Local Variables: |