Posted to tcl by emiliano at Thu Oct 31 16:11:33 GMT 2024view pretty
#include <tcl.h>
#include <tk.h>
typedef int (HashSubCmd)(ClientData, Tcl_Interp *, int, Tcl_Obj *const []);
static HashSubCmd GetOp;
static HashSubCmd SetOp;
static HashSubCmd DeleteOp;
static int
Hash_Cmd(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
static const struct HashCmds {
char *name;
HashSubCmd *subCmd;
} hashCmds[] = {
{"delete", DeleteOp},
{"get", GetOp},
{"set", SetOp},
{NULL, NULL}
};
int index;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObjStruct(interp, objv[1], hashCmds,
sizeof(struct HashCmds), "subcommand", 0, &index) != TCL_OK) {
return TCL_ERROR;
}
return hashCmds[index].subCmd(clientdata, interp, objc, objv);
}
static int
SetOp(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientdata;
Tk_Window tkwin;
int isNew;
Tcl_Size size;
Tcl_HashEntry *entryPtr;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "window dict");
return TCL_ERROR;
}
tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), Tk_MainWindow(interp));
if (! tkwin) {
return TCL_ERROR;
}
if ( Tcl_DictObjSize(interp, objv[3], &size) != TCL_OK) {
return TCL_ERROR;
}
entryPtr = Tcl_CreateHashEntry(tablePtr, tkwin, &isNew);
if (! isNew) {
Tcl_DecrRefCount(Tcl_GetHashValue(entryPtr));
}
Tcl_IncrRefCount(objv[3]);
Tcl_SetHashValue(entryPtr, objv[3]);
Tcl_SetObjResult(interp, objv[3]);
return TCL_OK;
}
static int
GetOp(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientdata;
Tk_Window tkwin;
Tcl_HashEntry *entryPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "window");
return TCL_ERROR;
}
tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), Tk_MainWindow(interp));
if (! tkwin) {
return TCL_ERROR;
}
entryPtr = Tcl_FindHashEntry(tablePtr, tkwin);
if (! entryPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("can't find entry for window %s",
Tcl_GetString(objv[2])));
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_GetHashValue(entryPtr));
return TCL_OK;
}
static int
DeleteOp(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientdata;
Tk_Window tkwin;
Tcl_HashEntry *entryPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "window");
return TCL_ERROR;
}
tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), Tk_MainWindow(interp));
if (! tkwin) {
return TCL_ERROR;
}
entryPtr = Tcl_FindHashEntry(tablePtr, tkwin);
if (! entryPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("can't find entry for window %s",
Tcl_GetString(objv[2])));
return TCL_ERROR;
}
Tcl_DecrRefCount(Tcl_GetHashValue(entryPtr));
Tcl_DeleteHashEntry(entryPtr);
return TCL_OK;
}
void
Hash_DeleteProc(ClientData clientData)
{
Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientData;
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
for (entryPtr = Tcl_FirstHashEntry(tablePtr, &search); entryPtr != NULL;
entryPtr = Tcl_NextHashEntry(&search)) {
Tcl_DecrRefCount(Tcl_GetHashValue(entryPtr));
Tcl_DeleteHashEntry(entryPtr);
}
Tcl_DeleteHashTable(tablePtr);
ckfree(tablePtr);
return;
}
/*
* Hashsample_Init -- Called when Tcl loads your extension.
*/
int DLLEXPORT
Hashsample_Init(Tcl_Interp *interp)
{
Tcl_HashTable *tablePtr;
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tk_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgProvide(interp, "Hashsample", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
tablePtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(tablePtr, TCL_ONE_WORD_KEYS);
Tcl_CreateObjCommand(interp, "hash", Hash_Cmd, tablePtr, Hash_DeleteProc);
return TCL_OK;
}
/*
emiliano@LE-PB01:~$ gcc -shared -fPIC -o libhashsample.so -DUSE_TCL_STUBS -DUSE_TK_STUBS -I/home/emiliano/tcl9/include hash_sample.c -L/home/emiliano/tcl9/lib -ltclstub -ltkstub
emiliano@LE-PB01:~$ /home/emiliano/tcl9/bin/tclsh9.0
% load ./libhashsample.so
% hash get .
can't find entry for window .
% hash set . foo
missing value to go with key
% hash set . "this is a test"
this is a test
% hash get .
this is a test
% hash delete .
% hash get .
can't find entry for window .
*/