summaryrefslogtreecommitdiffstats
path: root/generic/tkConfig.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tkConfig.c')
-rw-r--r--generic/tkConfig.c249
1 files changed, 108 insertions, 141 deletions
diff --git a/generic/tkConfig.c b/generic/tkConfig.c
index f2eaa33..9c159e6 100644
--- a/generic/tkConfig.c
+++ b/generic/tkConfig.c
@@ -27,11 +27,16 @@
#include "tkFont.h"
/*
- * The following definition is an AssocData key used to keep track of all of
- * the option tables that have been created for an interpreter.
+ * The following definition keeps track of all of
+ * the option tables that have been created for a thread.
*/
-#define OPTION_HASH_KEY "TkOptionTable"
+typedef struct ThreadSpecificData {
+ int initialized; /* 0 means table below needs initializing. */
+ Tcl_HashTable hashTable;
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+
/*
* The following two structures are used along with Tk_OptionSpec structures
@@ -63,7 +68,7 @@ typedef struct TkOption {
struct TkOption *synonymPtr;
/* For synonym options, this points to the
* master entry. */
- struct Tk_ObjCustomOption *custom;
+ const struct Tk_ObjCustomOption *custom;
/* For TK_OPTION_CUSTOM. */
} extra;
int flags; /* Miscellaneous flag values; see below for
@@ -113,8 +118,6 @@ typedef struct OptionTable {
static int DoObjConfig(Tcl_Interp *interp, char *recordPtr,
Option *optionPtr, Tcl_Obj *valuePtr,
Tk_Window tkwin, Tk_SavedOption *savePtr);
-static void DestroyOptionHashTable(ClientData clientData,
- Tcl_Interp *interp);
static void FreeResources(Option *optionPtr, Tcl_Obj *objPtr,
char *internalPtr, Tk_Window tkwin);
static Tcl_Obj * GetConfigList(char *recordPtr,
@@ -125,7 +128,8 @@ static Option * GetOption(const char *name, OptionTable *tablePtr);
static Option * GetOptionFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, OptionTable *tablePtr);
static int ObjectIsEmpty(Tcl_Obj *objPtr);
-static int SetOptionFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
+static void FreeOptionInternalRep(Tcl_Obj *objPtr);
+static void DupOptionInternalRep(Tcl_Obj *, Tcl_Obj *);
/*
* The structure below defines an object type that is used to cache the result
@@ -134,12 +138,12 @@ static int SetOptionFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
* the internalPtr2 field points to the entry that matched.
*/
-Tcl_ObjType tkOptionObjType = {
+static const Tcl_ObjType optionObjType = {
"option", /* name */
- NULL, /* freeIntRepProc */
- NULL, /* dupIntRepProc */
+ FreeOptionInternalRep, /* freeIntRepProc */
+ DupOptionInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
- SetOptionFromAny /* setFromAnyProc */
+ NULL /* setFromAnyProc */
};
/*
@@ -168,31 +172,26 @@ Tk_CreateOptionTable(
/* Static information about the configuration
* options. */
{
- Tcl_HashTable *hashTablePtr;
Tcl_HashEntry *hashEntryPtr;
int newEntry;
OptionTable *tablePtr;
const Tk_OptionSpec *specPtr, *specPtr2;
Option *optionPtr;
int numOptions, i;
+ ThreadSpecificData *tsdPtr =
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
/*
- * We use an AssocData value in the interpreter to keep a hash table of
- * all the option tables we've created for this application. This is used
- * for two purposes. First, it allows us to share the tables (e.g. in
- * several chains) and second, we use the deletion callback for the
- * AssocData to delete all the option tables when the interpreter is
- * deleted. The code below finds the hash table or creates a new one if it
+ * We use an TSD in the thread to keep a hash table of
+ * all the option tables we've created for this application. This is
+ * used for allowing us to share the tables (e.g. in several chains).
+ * The code below finds the hash table or creates a new one if it
* doesn't already exist.
*/
- hashTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, OPTION_HASH_KEY,
- NULL);
- if (hashTablePtr == NULL) {
- hashTablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
- Tcl_InitHashTable(hashTablePtr, TCL_ONE_WORD_KEYS);
- Tcl_SetAssocData(interp, OPTION_HASH_KEY, DestroyOptionHashTable,
- (ClientData) hashTablePtr);
+ if (!tsdPtr->initialized) {
+ Tcl_InitHashTable(&tsdPtr->hashTable, TCL_ONE_WORD_KEYS);
+ tsdPtr->initialized = 1;
}
/*
@@ -200,10 +199,10 @@ Tk_CreateOptionTable(
* reuse the existing table.
*/
- hashEntryPtr = Tcl_CreateHashEntry(hashTablePtr, (char *) templatePtr,
+ hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->hashTable, (char *) templatePtr,
&newEntry);
if (!newEntry) {
- tablePtr = (OptionTable *) Tcl_GetHashValue(hashEntryPtr);
+ tablePtr = Tcl_GetHashValue(hashEntryPtr);
tablePtr->refCount++;
return (Tk_OptionTable) tablePtr;
}
@@ -217,8 +216,7 @@ Tk_CreateOptionTable(
for (specPtr = templatePtr; specPtr->type != TK_OPTION_END; specPtr++) {
numOptions++;
}
- tablePtr = (OptionTable *) (ckalloc(sizeof(OptionTable)
- + (numOptions * sizeof(Option))));
+ tablePtr = ckalloc(sizeof(OptionTable) + (numOptions * sizeof(Option)));
tablePtr->refCount = 1;
tablePtr->hashEntryPtr = hashEntryPtr;
tablePtr->nextPtr = NULL;
@@ -268,7 +266,7 @@ Tk_CreateOptionTable(
|| (specPtr->type == TK_OPTION_BORDER))
&& (specPtr->clientData != NULL)) {
optionPtr->extra.monoColorPtr =
- Tcl_NewStringObj((char *) specPtr->clientData, -1);
+ Tcl_NewStringObj(specPtr->clientData, -1);
Tcl_IncrRefCount(optionPtr->extra.monoColorPtr);
}
@@ -276,8 +274,8 @@ Tk_CreateOptionTable(
/*
* Get the custom parsing, etc., functions.
*/
- optionPtr->extra.custom =
- (Tk_ObjCustomOption *) specPtr->clientData;
+
+ optionPtr->extra.custom = specPtr->clientData;
}
}
if (((specPtr->type == TK_OPTION_STRING)
@@ -301,8 +299,8 @@ Tk_CreateOptionTable(
*/
if (specPtr->clientData != NULL) {
- tablePtr->nextPtr = (OptionTable *) Tk_CreateOptionTable(interp,
- (Tk_OptionSpec *) specPtr->clientData);
+ tablePtr->nextPtr = (OptionTable *)
+ Tk_CreateOptionTable(interp, specPtr->clientData);
}
return (Tk_OptionTable) tablePtr;
@@ -355,60 +353,7 @@ Tk_DeleteOptionTable(
}
}
Tcl_DeleteHashEntry(tablePtr->hashEntryPtr);
- ckfree((char *) tablePtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DestroyOptionHashTable --
- *
- * This function is the deletion callback associated with the AssocData
- * entry created by Tk_CreateOptionTable. It is invoked when an
- * interpreter is deleted, and deletes all of the option tables
- * associated with that interpreter.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The option hash table is destroyed along with all of the OptionTable
- * structures that it refers to.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DestroyOptionHashTable(
- ClientData clientData, /* The hash table we are destroying */
- Tcl_Interp *interp) /* The interpreter we are destroying */
-{
- Tcl_HashTable *hashTablePtr = (Tcl_HashTable *) clientData;
- Tcl_HashSearch search;
- Tcl_HashEntry *hashEntryPtr;
- OptionTable *tablePtr;
-
- for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
- hashEntryPtr != NULL;
- hashEntryPtr = Tcl_NextHashEntry(&search)) {
- tablePtr = (OptionTable *) Tcl_GetHashValue(hashEntryPtr);
-
- /*
- * The following statements do two tricky things:
- * 1. They ensure that the option table is deleted, even if there are
- * outstanding references to it.
- * 2. They ensure that Tk_DeleteOptionTable doesn't delete other
- * tables chained from this one; we'll do it when we come across
- * the hash table entry for the chained table (in fact, the chained
- * table may already have been deleted).
- */
-
- tablePtr->refCount = 1;
- tablePtr->nextPtr = NULL;
- Tk_DeleteOptionTable((Tk_OptionTable) tablePtr);
- }
- Tcl_DeleteHashTable(hashTablePtr);
- ckfree((char *) hashTablePtr);
+ ckfree(tablePtr);
}
/*
@@ -710,7 +655,8 @@ DoObjConfig(
break;
}
case TK_OPTION_STRING: {
- char *newStr, *value;
+ char *newStr;
+ const char *value;
int length;
if (nullOK && ObjectIsEmpty(valuePtr)) {
@@ -719,7 +665,7 @@ DoObjConfig(
if (internalPtr != NULL) {
if (valuePtr != NULL) {
value = Tcl_GetStringFromObj(valuePtr, &length);
- newStr = ckalloc((unsigned) (length + 1));
+ newStr = ckalloc(length + 1);
strcpy(newStr, value);
} else {
newStr = NULL;
@@ -732,8 +678,8 @@ DoObjConfig(
case TK_OPTION_STRING_TABLE: {
int newValue;
- if (Tcl_GetIndexFromObj(interp, valuePtr,
- (const char **) optionPtr->specPtr->clientData,
+ if (Tcl_GetIndexFromObjStruct(interp, valuePtr,
+ optionPtr->specPtr->clientData, sizeof(char *),
optionPtr->specPtr->optionName+1, 0, &newValue) != TCL_OK) {
return TCL_ERROR;
}
@@ -930,7 +876,7 @@ DoObjConfig(
break;
}
case TK_OPTION_CUSTOM: {
- Tk_ObjCustomOption *custom = optionPtr->extra.custom;
+ const Tk_ObjCustomOption *custom = optionPtr->extra.custom;
if (custom->setProc(custom->clientData, interp, tkwin,
&valuePtr, recordPtr, optionPtr->specPtr->internalOffset,
@@ -940,16 +886,13 @@ DoObjConfig(
break;
}
- {
- char buf[40+TCL_INTEGER_SPACE];
-
default:
- sprintf(buf, "bad config table: unknown type %d",
- optionPtr->specPtr->type);
- Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad config table: unknown type %d",
+ optionPtr->specPtr->type));
+ Tcl_SetErrorCode(interp, "TK", "BAD_CONFIG", NULL);
return TCL_ERROR;
}
- }
/*
* Release resources associated with the old value, if we're not returning
@@ -1002,7 +945,7 @@ ObjectIsEmpty(
if (objPtr->bytes != NULL) {
return (objPtr->length == 0);
}
- Tcl_GetStringFromObj(objPtr, &length);
+ (void)Tcl_GetStringFromObj(objPtr, &length);
return (length == 0);
}
@@ -1121,13 +1064,13 @@ GetOptionFromObj(
OptionTable *tablePtr) /* Table in which to look up objPtr. */
{
Option *bestPtr;
- char *name;
+ const char *name;
/*
* First, check to see if the object already has the answer cached.
*/
- if (objPtr->typePtr == &tkOptionObjType) {
+ if (objPtr->typePtr == &optionObjType) {
if (objPtr->internalRep.twoPtrValue.ptr1 == (void *) tablePtr) {
return (Option *) objPtr->internalRep.twoPtrValue.ptr2;
}
@@ -1149,12 +1092,15 @@ GetOptionFromObj(
}
objPtr->internalRep.twoPtrValue.ptr1 = (void *) tablePtr;
objPtr->internalRep.twoPtrValue.ptr2 = (void *) bestPtr;
- objPtr->typePtr = &tkOptionObjType;
+ objPtr->typePtr = &optionObjType;
+ tablePtr->refCount++;
return bestPtr;
error:
if (interp != NULL) {
- Tcl_AppendResult(interp, "unknown option \"", name, "\"", NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "unknown option \"%s\"", name));
+ Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", name, NULL);
}
return NULL;
}
@@ -1199,32 +1145,55 @@ TkGetOptionSpec(
/*
*----------------------------------------------------------------------
*
- * SetOptionFromAny --
+ * FreeOptionInternalRep --
*
- * This function is called to convert a Tcl object to option internal
- * form. However, this doesn't make sense (need to have a table of
- * options in order to do the conversion) so the function always
- * generates an error.
+ * Part of the option Tcl object type implementation. Frees the storage
+ * associated with a option object's internal representation unless it
+ * is still in use.
*
* Results:
- * The return value is always TCL_ERROR, and an error message is left in
- * interp's result if interp isn't NULL.
+ * None.
*
* Side effects:
- * None.
+ * The option object's internal rep is marked invalid and its memory
+ * gets freed unless it is still in use somewhere. In that case the
+ * cleanup is delayed until the last reference goes away.
*
*----------------------------------------------------------------------
*/
-static int
-SetOptionFromAny(
- Tcl_Interp *interp, /* Used for error reporting if not NULL. */
- register Tcl_Obj *objPtr) /* The object to convert. */
+static void
+FreeOptionInternalRep(
+ register Tcl_Obj *objPtr) /* Object whose internal rep to free. */
{
- Tcl_AppendToObj(Tcl_GetObjResult(interp),
- "can't convert value to option except via GetOptionFromObj API",
- -1);
- return TCL_ERROR;
+ register Tk_OptionTable tablePtr = (Tk_OptionTable) objPtr->internalRep.twoPtrValue.ptr1;
+
+ Tk_DeleteOptionTable(tablePtr);
+ objPtr->typePtr = NULL;
+ objPtr->internalRep.twoPtrValue.ptr1 = NULL;
+ objPtr->internalRep.twoPtrValue.ptr2 = NULL;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DupOptionInternalRep --
+ *
+ * When a cached option object is duplicated, this is called to update the
+ * internal reps.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+DupOptionInternalRep(
+ Tcl_Obj *srcObjPtr, /* The object we are copying from. */
+ Tcl_Obj *dupObjPtr) /* The object we are copying to. */
+{
+ register OptionTable *tablePtr = (OptionTable *) srcObjPtr->internalRep.twoPtrValue.ptr1;
+ tablePtr->refCount++;
+ dupObjPtr->typePtr = srcObjPtr->typePtr;
+ dupObjPtr->internalRep = srcObjPtr->internalRep;
}
/*
@@ -1304,9 +1273,10 @@ Tk_SetOptions(
if (objc < 2) {
if (interp != NULL) {
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "value for \"", Tcl_GetStringFromObj(*objv, NULL),
- "\" missing", NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "value for \"%s\" missing",
+ Tcl_GetString(*objv)));
+ Tcl_SetErrorCode(interp, "TK", "VALUE_MISSING", NULL);
goto error;
}
}
@@ -1317,7 +1287,7 @@ Tk_SetOptions(
* more space.
*/
- newSavePtr = (Tk_SavedOptions *) ckalloc(sizeof(Tk_SavedOptions));
+ newSavePtr = ckalloc(sizeof(Tk_SavedOptions));
newSavePtr->recordPtr = recordPtr;
newSavePtr->tkwin = tkwin;
newSavePtr->numItems = 0;
@@ -1328,11 +1298,9 @@ Tk_SetOptions(
if (DoObjConfig(interp, recordPtr, optionPtr, objv[1], tkwin,
(savePtr != NULL) ? &lastSavePtr->items[lastSavePtr->numItems]
: NULL) != TCL_OK) {
- char msg[100];
-
- sprintf(msg, "\n (processing \"%.40s\" option)",
- Tcl_GetStringFromObj(*objv, NULL));
- Tcl_AddErrorInfo(interp, msg);
+ Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
+ "\n (processing \"%.40s\" option)",
+ Tcl_GetString(*objv)));
goto error;
}
if (savePtr != NULL) {
@@ -1393,7 +1361,7 @@ Tk_RestoreSavedOptions(
if (savePtr->nextPtr != NULL) {
Tk_RestoreSavedOptions(savePtr->nextPtr);
- ckfree((char *) savePtr->nextPtr);
+ ckfree(savePtr->nextPtr);
savePtr->nextPtr = NULL;
}
for (i = savePtr->numItems - 1; i >= 0; i--) {
@@ -1433,6 +1401,7 @@ Tk_RestoreSavedOptions(
if (specPtr->internalOffset >= 0) {
register char *ptr = (char *) &savePtr->items[i].internalForm;
+ CLANG_ASSERT(internalPtr);
switch (specPtr->type) {
case TK_OPTION_BOOLEAN:
*((int *) internalPtr) = *((int *) ptr);
@@ -1484,7 +1453,7 @@ Tk_RestoreSavedOptions(
*((Tk_Window *) internalPtr) = *((Tk_Window *) ptr);
break;
case TK_OPTION_CUSTOM: {
- Tk_ObjCustomOption *custom = optionPtr->extra.custom;
+ const Tk_ObjCustomOption *custom = optionPtr->extra.custom;
if (custom->restoreProc != NULL) {
custom->restoreProc(custom->clientData, savePtr->tkwin,
@@ -1527,7 +1496,7 @@ Tk_FreeSavedOptions(
if (savePtr->nextPtr != NULL) {
Tk_FreeSavedOptions(savePtr->nextPtr);
- ckfree((char *) savePtr->nextPtr);
+ ckfree(savePtr->nextPtr);
}
for (count = savePtr->numItems,
savedOptionPtr = &savePtr->items[savePtr->numItems-1];
@@ -1709,7 +1678,7 @@ FreeResources(
}
break;
case TK_OPTION_CUSTOM: {
- Tk_ObjCustomOption *custom = optionPtr->extra.custom;
+ const Tk_ObjCustomOption *custom = optionPtr->extra.custom;
if (internalFormExists && custom->freeProc != NULL) {
custom->freeProc(custom->clientData, tkwin, internalPtr);
}
@@ -1729,7 +1698,6 @@ FreeResources(
* single option or all the configuration options in a table.
*
* Results:
-
* This function normally returns a pointer to an object. If namePtr
* isn't NULL, then the result object is a list with five elements: the
* option's name, its database name, database class, default value, and
@@ -2000,7 +1968,7 @@ GetObjectForOption(
break;
}
case TK_OPTION_CUSTOM: {
- Tk_ObjCustomOption *custom = optionPtr->extra.custom;
+ const Tk_ObjCustomOption *custom = optionPtr->extra.custom;
objPtr = custom->getProc(custom->clientData, tkwin, recordPtr,
optionPtr->specPtr->internalOffset);
@@ -2106,15 +2074,14 @@ TkDebugConfig(
* interpreter anymore. */
{
OptionTable *tablePtr = (OptionTable *) table;
- Tcl_HashTable *hashTablePtr;
Tcl_HashEntry *hashEntryPtr;
Tcl_HashSearch search;
Tcl_Obj *objPtr;
+ ThreadSpecificData *tsdPtr =
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
objPtr = Tcl_NewObj();
- hashTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, OPTION_HASH_KEY,
- NULL);
- if (hashTablePtr == NULL) {
+ if (!tablePtr || !tsdPtr->initialized) {
return objPtr;
}
@@ -2123,7 +2090,7 @@ TkDebugConfig(
* want still is valid.
*/
- for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
+ for (hashEntryPtr = Tcl_FirstHashEntry(&tsdPtr->hashTable, &search);
hashEntryPtr != NULL;
hashEntryPtr = Tcl_NextHashEntry(&search)) {
if (tablePtr == (OptionTable *) Tcl_GetHashValue(hashEntryPtr)) {