diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-09-01 11:11:20 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-09-01 11:11:20 (GMT) |
commit | 90b909515c2a6ff8b67618bca674856b7d23182f (patch) | |
tree | e2eda6615e97ac6ec679199032f360b4a1bf46ce /generic/tkObj.c | |
parent | 3d4865351a5e9ec4af6a58463a3d7b02ab9cdab7 (diff) | |
download | tk-90b909515c2a6ff8b67618bca674856b7d23182f.zip tk-90b909515c2a6ff8b67618bca674856b7d23182f.tar.gz tk-90b909515c2a6ff8b67618bca674856b7d23182f.tar.bz2 |
Proposed fix for [6cc8002951]: numeric parameter errors depending on whether string vs double/int rep. Please review
Diffstat (limited to 'generic/tkObj.c')
-rw-r--r-- | generic/tkObj.c | 187 |
1 files changed, 77 insertions, 110 deletions
diff --git a/generic/tkObj.c b/generic/tkObj.c index 0abf534..3d912ce 100644 --- a/generic/tkObj.c +++ b/generic/tkObj.c @@ -40,20 +40,6 @@ typedef struct PixelRep { ((PixelRep *) (objPtr)->internalRep.twoPtrValue.ptr2) /* - * One of these structures is created per thread to store thread-specific - * data. In this case, it is used to contain references to selected - * Tcl_ObjTypes that we can use as screen distances without conversion. The - * "dataKey" below is used to locate the ThreadSpecificData for the current - * thread. - */ - -typedef struct { - const Tcl_ObjType *doubleTypePtr; - const Tcl_ObjType *intTypePtr; -} ThreadSpecificData; -static Tcl_ThreadDataKey dataKey; - -/* * The following structure is the internal representation for mm objects. */ @@ -87,7 +73,6 @@ static void DupWindowInternalRep(Tcl_Obj *srcPtr,Tcl_Obj*copyPtr); static void FreeMMInternalRep(Tcl_Obj *objPtr); static void FreePixelInternalRep(Tcl_Obj *objPtr); static void FreeWindowInternalRep(Tcl_Obj *objPtr); -static ThreadSpecificData *GetTypeCache(void); static void UpdateStringOfMM(Tcl_Obj *objPtr); static int SetMMFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); static int SetPixelFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); @@ -137,42 +122,6 @@ static const Tcl_ObjType windowObjType = { /* *---------------------------------------------------------------------- * - * GetTypeCache -- - * - * Get (and build if necessary) the cache of useful Tcl object types for - * comparisons in the conversion functions. This allows optimized checks - * for standard cases. - * - *---------------------------------------------------------------------- - */ - -static ThreadSpecificData * -GetTypeCache(void) -{ - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - - if (tsdPtr->doubleTypePtr == NULL) { - /* Smart initialization of doubleTypePtr/intTypePtr without - * hash-table lookup or creating complete Tcl_Obj's */ - Tcl_Obj obj; - obj.length = 3; - obj.bytes = (char *)"0.0"; - obj.typePtr = NULL; - Tcl_GetDoubleFromObj(NULL, &obj, &obj.internalRep.doubleValue); - tsdPtr->doubleTypePtr = obj.typePtr; - obj.bytes += 2; - obj.length = 1; - obj.typePtr = NULL; - Tcl_GetLongFromObj(NULL, &obj, &obj.internalRep.longValue); - tsdPtr->intTypePtr = obj.typePtr; - } - return tsdPtr; -} - -/* - *---------------------------------------------------------------------- - * * GetPixelsFromObjEx -- * * Attempt to return a pixel value from the Tcl object "objPtr". If the @@ -215,21 +164,13 @@ GetPixelsFromObjEx( */ if (objPtr->typePtr != &pixelObjType) { - ThreadSpecificData *typeCache = GetTypeCache(); - if (objPtr->typePtr == typeCache->doubleTypePtr) { - (void) Tcl_GetDoubleFromObj(interp, objPtr, &d); + if (Tcl_GetDoubleFromObj(NULL, objPtr, &d) == TCL_OK) { if (dblPtr != NULL) { *dblPtr = d; } *intPtr = (int) (d<0 ? d-0.5 : d+0.5); return TCL_OK; - } else if (objPtr->typePtr == typeCache->intTypePtr) { - (void) Tcl_GetIntFromObj(interp, objPtr, intPtr); - if (dblPtr) { - *dblPtr = (double) (*intPtr); - } - return TCL_OK; } } @@ -453,39 +394,73 @@ SetPixelFromAny( Tcl_Obj *objPtr) /* The object to convert. */ { const Tcl_ObjType *typePtr; - const char *string; + char *string; char *rest; double d; int i, units; - string = Tcl_GetString(objPtr); + if (Tcl_GetIntFromObj(NULL, objPtr, &units) == TCL_OK) { + d = (double) units; + units = -1; - d = strtod(string, &rest); - if (rest == string) { - goto error; - } - while ((*rest != '\0') && isspace(UCHAR(*rest))) { - rest++; - } + /* + * In the case of ints, we need to ensure that a valid string exists + * in order for int-but-not-string objects to be converted back to + * ints again from pixel obj types. + */ - switch (*rest) { - case '\0': + (void) Tcl_GetString(objPtr); + } else if (Tcl_GetDoubleFromObj(NULL, objPtr, &d) == TCL_OK) { units = -1; + } else { + char savechar; + string = Tcl_GetString(objPtr); + + rest = string + strlen(string); + while ((rest > string) && isspace(UCHAR(rest[-1]))) { + --rest; /* skip all spaces at the end */ + } + if (rest > string) { + --rest; /* point to the character just before the last space */ + } + if (rest == string) { + error: + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad screen distance \"%.50s\"", string)); + Tcl_SetErrorCode(interp, "TK", "VALUE", "PIXELS", NULL); + } + return TCL_ERROR; + } + + switch (*rest) { + case 'm': + if (rest[-1] == 'c') { + --rest; + units = 1; /* For compatibility, accept undocumented "cm" as well */ + } else { + units = 0; + } break; - case 'm': - units = 0; - break; - case 'c': - units = 1; + case 'c': + units = 1; break; - case 'i': - units = 2; + case 'i': + units = 2; break; - case 'p': - units = 3; + case 'p': + units = 3; break; - default: - goto error; + default: + goto error; + } + savechar = *rest; + *rest = '\0'; + if (Tcl_GetDouble(NULL, string, &d) != TCL_OK) { + *rest = savechar; + goto error; + } + *rest = savechar; } /* @@ -512,14 +487,6 @@ SetPixelFromAny( SET_COMPLEXPIXEL(objPtr, pixelPtr); } return TCL_OK; - - error: - if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad screen distance \"%.50s\"", string)); - Tcl_SetErrorCode(interp, "TK", "VALUE", "PIXELS", NULL); - } - return TCL_ERROR; } /* @@ -708,19 +675,14 @@ SetMMFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr) /* The object to convert. */ { - ThreadSpecificData *typeCache = GetTypeCache(); const Tcl_ObjType *typePtr; - const char *string; + char *string; char *rest; double d; int units; MMRep *mmPtr; - if (objPtr->typePtr == typeCache->doubleTypePtr) { - Tcl_GetDoubleFromObj(interp, objPtr, &d); - units = -1; - } else if (objPtr->typePtr == typeCache->intTypePtr) { - Tcl_GetIntFromObj(interp, objPtr, &units); + if (Tcl_GetIntFromObj(NULL, objPtr, &units) == TCL_OK) { d = (double) units; units = -1; @@ -731,34 +693,32 @@ SetMMFromAny( */ (void) Tcl_GetString(objPtr); + } else if (Tcl_GetDoubleFromObj(NULL, objPtr, &d) == TCL_OK) { + units = -1; } else { + char savechar; + /* * It wasn't a known int or double, so parse it. */ string = Tcl_GetString(objPtr); - d = strtod(string, &rest); + rest = string + strlen(string); + while ((rest > string) && isspace(UCHAR(rest[-1]))) { + --rest; /* skip all spaces at the end */ + } + if (rest > string) { + --rest; /* point to the character just before the last space */ + } if (rest == string) { - /* - * Must copy string before resetting the result in case a caller - * is trying to convert the interpreter's result to mms. - */ - error: Tcl_SetObjResult(interp, Tcl_ObjPrintf( "bad screen distance \"%s\"", string)); Tcl_SetErrorCode(interp, "TK", "VALUE", "DISTANCE", NULL); return TCL_ERROR; } - while ((*rest != '\0') && isspace(UCHAR(*rest))) { - rest++; - } - switch (*rest) { - case '\0': - units = -1; - break; case 'c': units = 0; break; @@ -774,6 +734,13 @@ SetMMFromAny( default: goto error; } + savechar = *rest; + *rest = '\0'; + if (Tcl_GetDouble(NULL, string, &d) != TCL_OK) { + *rest = savechar; + goto error; + } + *rest = savechar; } /* |