summaryrefslogtreecommitdiffstats
path: root/generic/tkObj.c
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2023-09-01 11:11:20 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2023-09-01 11:11:20 (GMT)
commit90b909515c2a6ff8b67618bca674856b7d23182f (patch)
treee2eda6615e97ac6ec679199032f360b4a1bf46ce /generic/tkObj.c
parent3d4865351a5e9ec4af6a58463a3d7b02ab9cdab7 (diff)
downloadtk-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.c187
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;
}
/*