Values being overwritten in Tcl_HashTable
From
Kevin Walzer@kw@codebykevin.com to
comp.lang.tcl on Sun Nov 10 22:37:07 2024
From Newsgroup: comp.lang.tcl
I am trying to write mulitple key-value pairs to a Tcl_HashTable, but
when I call Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2)), it reads the
last value written to the hash table - even if that value is not
associated with the key that I am using.
Is there a best practice I am missing here? I thought that differing
keys would be tracked in the hash table and the Tcl_FindHashEntry call
would return different data depending on the key.
Tcl_ResetResult does not change the result in the interpreter, which
tells me the issue is with the table - calls to the key for "role" and
"name" return the value for "name" - seems like the "role" value has
been overwritten.
My C code is below. Any help is appreciated.
int
Tk_SetAccessibleRole(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 3) {
Tcl_WrongNumArgs(ip, 1, objv, "window? role?");
return TCL_ERROR;
}
Tk_Window win;
char *role;
Tcl_HashEntry *hPtr, *hPtr2;
Tcl_HashTable *AccessibleAttributes;
AccessibleAttributes = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(AccessibleAttributes,TCL_STRING_KEYS);
int isNew;
win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}
/* Set accessible role for window. */
hPtr=Tcl_CreateHashEntry(TkAccessibilityObject, win, &isNew);
Tcl_SetHashValue(hPtr, AccessibleAttributes);
hPtr2 = Tcl_CreateHashEntry(AccessibleAttributes, role, &isNew);
if (!isNew) {
Tcl_DecrRefCount(Tcl_GetHashValue(hPtr2));
}
Tcl_IncrRefCount(objv[2]);
Tcl_SetHashValue(hPtr2, objv[2]);
Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}
int
Tk_SetAccessibleName(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 3) {
Tcl_WrongNumArgs(ip, 1, objv, "window? name?");
return TCL_ERROR;
}
Tk_Window win;
char *name;
Tcl_HashEntry *hPtr, *hPtr2;
int isNew;
Tcl_HashTable *AccessibleAttributes;
win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}
/* Set accessible name for window. */
hPtr=Tcl_FindHashEntry(TkAccessibilityObject, win);
if (!hPtr) {
Tcl_AppendResult(ip, "No table found", (char *) NULL);
return TCL_ERROR;
}
AccessibleAttributes = Tcl_GetHashValue(hPtr);
hPtr2 = Tcl_CreateHashEntry(AccessibleAttributes, name, &isNew);
if (!isNew) {
Tcl_DecrRefCount(Tcl_GetHashValue(hPtr2));
}
Tcl_IncrRefCount(objv[2]);
Tcl_SetHashValue(hPtr2, objv[2]);
Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}
int
Tk_GetAccessibleRole(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 2) {
Tcl_WrongNumArgs(ip, 1, objv, "window?");
return TCL_ERROR;
}
Tk_Window win;
char *role;
Tcl_HashEntry *hPtr, *hPtr2;
Tcl_HashTable *AccessibleAttributes;
win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}
/* Get accessible role for window. */
hPtr=Tcl_FindHashEntry(TkAccessibilityObject, win);
if (!hPtr) {
Tcl_AppendResult(ip, "No table found", (char *) NULL);
return TCL_ERROR;
}
AccessibleAttributes = Tcl_GetHashValue(hPtr);
hPtr2=Tcl_FindHashEntry(AccessibleAttributes, (char*) role);
if (!hPtr2) {
Tcl_AppendResult(ip, "No role found", (char *) NULL);
return TCL_ERROR;
}
Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}
int
Tk_GetAccessibleName(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 2) {
Tcl_WrongNumArgs(ip, 1, objv, "window?");
return TCL_ERROR;
}
Tk_Window win;
char *name;
Tcl_HashEntry *hPtr, *hPtr2;
Tcl_HashTable *AccessibleAttributes;
win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}
/* Get accessible name for window. */
hPtr=Tcl_FindHashEntry(TkAccessibilityObject, win);
if (!hPtr) {
Tcl_AppendResult(ip, "No table found", (char *) NULL);
return TCL_ERROR;
}
AccessibleAttributes = Tcl_GetHashValue(hPtr);
hPtr2=Tcl_FindHashEntry(AccessibleAttributes, (char *) name);
if (!hPtr2) {
Tcl_AppendResult(ip, "No name found", (char *) NULL);
return TCL_ERROR;
}
Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}
--- Synchronet 3.20a-Linux NewsLink 1.114
From
Francois Vogel@francois.vogel.fv.NOSPAM@gmail.com to
Kevin Walzer on Mon Nov 11 23:23:20 2024
From Newsgroup: comp.lang.tcl
Le 11/11/2024 à 04:37, Kevin Walzer a écrit :
int
Tk_SetAccessibleRole(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 3) {
Tcl_WrongNumArgs(ip, 1, objv, "window? role?");
return TCL_ERROR;
}
Tk_Window win;
char *role;
Tcl_HashEntry *hPtr, *hPtr2;
Tcl_HashTable *AccessibleAttributes;
AccessibleAttributes = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(AccessibleAttributes,TCL_STRING_KEYS);
int isNew;
win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}
/* Set accessible role for window. */
hPtr=Tcl_CreateHashEntry(TkAccessibilityObject, win, &isNew);
Tcl_SetHashValue(hPtr, AccessibleAttributes);
hPtr2 = Tcl_CreateHashEntry(AccessibleAttributes, role, &isNew);
if (!isNew) {
Tcl_DecrRefCount(Tcl_GetHashValue(hPtr2));
}
Tcl_IncrRefCount(objv[2]);
Tcl_SetHashValue(hPtr2, objv[2]);
Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}
Without diving deep into your code, here a handful of quick observations
that may or may not be useful to you:
1. The canonical pattern for these kind of things is:
int isNew;
hPtr = Tcl_CreateHashEntry(tablePtr, key, &isNew);
if (isNew) {
myValue = ...; // get or create myValue from somewhere
Tcl_SetHashValue(hPtr, myValue);
} else {
myValue = (myValue *)Tcl_GetHashValue(hPtr);
}
Perhaps you should stick at it.
2. You are using the isNew flag twice without checking it the first time.
3. You are calling Tcl_CreateHashEntry twice, yes, but not with the same
hash table. Is this what is intended?
Regards,
Francois
--- Synchronet 3.20a-Linux NewsLink 1.114