OpenFPGA/libs/EXTERNAL/tcl8.6.12/pkgs/itcl4.2.2/generic/itclBase.c

599 lines
19 KiB
C
Raw Normal View History

2022-06-07 11:15:20 -05:00
/*
* itclBase.c --
*
* This file contains the C-implemented startup part of an
* Itcl implemenatation
*
* Copyright (c) 2007 by Arnulf P. Wiedemann
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <stdlib.h>
#include "itclInt.h"
static Tcl_NamespaceDeleteProc FreeItclObjectInfo;
static Tcl_ObjCmdProc ItclSetHullWindowName;
static Tcl_ObjCmdProc ItclCheckSetItclHull;
MODULE_SCOPE const ItclStubs itclStubs;
static int Initialize(Tcl_Interp *interp);
static const char initScript[] =
"namespace eval ::itcl {\n"
" proc _find_init {} {\n"
" global env tcl_library\n"
" variable library\n"
" variable patchLevel\n"
" rename _find_init {}\n"
" if {[info exists library]} {\n"
" lappend dirs $library\n"
" } else {\n"
" set dirs {}\n"
" if {[info exists env(ITCL_LIBRARY)]} {\n"
" lappend dirs $env(ITCL_LIBRARY)\n"
" }\n"
" lappend dirs [file join [file dirname $tcl_library] itcl$patchLevel]\n"
" set bindir [file dirname [info nameofexecutable]]\n"
" lappend dirs [file join . library]\n"
" lappend dirs [file join $bindir .. lib itcl$patchLevel]\n"
" lappend dirs [file join $bindir .. library]\n"
" lappend dirs [file join $bindir .. .. library]\n"
" lappend dirs [file join $bindir .. .. itcl library]\n"
" lappend dirs [file join $bindir .. .. .. itcl library]\n"
" lappend dirs [file join $bindir .. .. itcl-ng itcl library]\n"
" # On *nix, check the directories in the tcl_pkgPath\n"
" # XXX JH - this looks unnecessary, maybe Darwin only?\n"
" if {[string equal $::tcl_platform(platform) \"unix\"]} {\n"
" foreach d $::tcl_pkgPath {\n"
" lappend dirs $d\n"
" lappend dirs [file join $d itcl$patchLevel]\n"
" }\n"
" }\n"
" }\n"
" foreach i $dirs {\n"
" set library $i\n"
" if {![catch {uplevel #0 [list source [file join $i itcl.tcl]]}]} {\n"
" set library $i\n"
" return\n"
" }\n"
" }\n"
" set msg \"Can't find a usable itcl.tcl in the following directories:\n\"\n"
" append msg \" $dirs\n\"\n"
" append msg \"This probably means that Itcl/Tcl weren't installed properly.\n\"\n"
" append msg \"If you know where the Itcl library directory was installed,\n\"\n"
" append msg \"you can set the environment variable ITCL_LIBRARY to point\n\"\n"
" append msg \"to the library directory.\n\"\n"
" error $msg\n"
" }\n"
" _find_init\n"
"}";
/*
* The following script is used to initialize Itcl in a safe interpreter.
*/
static const char safeInitScript[] =
"proc ::itcl::local {class name args} {\n"
" set ptr [uplevel [list $class $name] $args]\n"
" uplevel [list set itcl-local-$ptr $ptr]\n"
" set cmd [uplevel namespace which -command $ptr]\n"
" uplevel [list trace variable itcl-local-$ptr u \"::itcl::delete object $cmd; list\"]\n"
" return $ptr\n"
"}";
static const char *clazzClassScript =
"::oo::class create ::itcl::clazz {\n"
" superclass ::oo::class\n"
" method unknown args {\n"
" ::tailcall ::itcl::parser::handleClass [::lindex [::info level 0] 0] [self] {*}$args\n"
" }\n"
" unexport create new unknown\n"
"}";
#define ITCL_IS_ENSEMBLE 0x1
#ifdef ITCL_DEBUG_C_INTERFACE
extern void RegisterDebugCFunctions( Tcl_Interp * interp);
#endif
static Tcl_ObjectMetadataDeleteProc Demolition;
static const Tcl_ObjectMetadataType canary = {
TCL_OO_METADATA_VERSION_CURRENT,
"Itcl Foundations",
Demolition,
NULL
};
void
Demolition(
void *clientData)
{
ItclObjectInfo *infoPtr = (ItclObjectInfo *)clientData;
infoPtr->clazzObjectPtr = NULL;
infoPtr->clazzClassPtr = NULL;
}
static const Tcl_ObjectMetadataType objMDT = {
TCL_OO_METADATA_VERSION_CURRENT,
"ItclObject",
ItclDeleteObjectMetadata, /* Not really used yet */
NULL
};
static Tcl_MethodCallProc RootCallProc;
const Tcl_MethodType itclRootMethodType = {
TCL_OO_METHOD_VERSION_CURRENT,
"itcl root method",
RootCallProc,
NULL,
NULL
};
static int
RootCallProc(
void *clientData,
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Object oPtr = Tcl_ObjectContextObject(context);
ItclObject *ioPtr = (ItclObject *)Tcl_ObjectGetMetadata(oPtr, &objMDT);
ItclRootMethodProc *proc = (ItclRootMethodProc *)clientData;
return (*proc)(ioPtr, interp, objc, objv);
}
/*
* ------------------------------------------------------------------------
* Initialize()
*
* that is the starting point when loading the library
* it initializes all internal stuff
*
* ------------------------------------------------------------------------
*/
static int
Initialize (
Tcl_Interp *interp)
{
Tcl_Namespace *nsPtr;
Tcl_Namespace *itclNs;
Tcl_HashEntry *hPtr;
ItclObjectInfo *infoPtr;
const char * ret;
char *res_option;
int opt;
int isNew;
Tcl_Class tclCls;
Tcl_Object clazzObjectPtr, root;
Tcl_Obj *objPtr, *resPtr;
if (Tcl_InitStubs(interp, "8.6", 0) == NULL) {
return TCL_ERROR;
}
ret = TclOOInitializeStubs(interp, "1.0");
if (ret == NULL) {
return TCL_ERROR;
}
objPtr = Tcl_NewStringObj("::oo::class", -1);
Tcl_IncrRefCount(objPtr);
clazzObjectPtr = Tcl_GetObjectFromObj(interp, objPtr);
if (!clazzObjectPtr || !(tclCls = Tcl_GetObjectAsClass(clazzObjectPtr))) {
Tcl_DecrRefCount(objPtr);
return TCL_ERROR;
}
Tcl_DecrRefCount(objPtr);
infoPtr = (ItclObjectInfo*)Itcl_Alloc(sizeof(ItclObjectInfo));
nsPtr = Tcl_CreateNamespace(interp, ITCL_NAMESPACE, infoPtr, FreeItclObjectInfo);
if (nsPtr == NULL) {
Itcl_Free(infoPtr);
Tcl_Panic("Itcl: cannot create namespace: \"%s\" \n", ITCL_NAMESPACE);
}
nsPtr = Tcl_CreateNamespace(interp, ITCL_INTDICTS_NAMESPACE,
NULL, NULL);
if (nsPtr == NULL) {
Itcl_Free(infoPtr);
Tcl_Panic("Itcl: cannot create namespace: \"%s::internal::dicts\" \n",
ITCL_NAMESPACE);
}
/*
* Create the top-level data structure for tracking objects.
* Store this as "associated data" for easy access, but link
* it to the itcl namespace for ownership.
*/
infoPtr->interp = interp;
infoPtr->class_meta_type = (Tcl_ObjectMetadataType *)ckalloc(
sizeof(Tcl_ObjectMetadataType));
infoPtr->class_meta_type->version = TCL_OO_METADATA_VERSION_CURRENT;
infoPtr->class_meta_type->name = "ItclClass";
infoPtr->class_meta_type->deleteProc = ItclDeleteClassMetadata;
infoPtr->class_meta_type->cloneProc = NULL;
infoPtr->object_meta_type = &objMDT;
Tcl_InitHashTable(&infoPtr->objects, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&infoPtr->objectCmds, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&infoPtr->classes, TCL_ONE_WORD_KEYS);
Tcl_InitObjHashTable(&infoPtr->nameClasses);
Tcl_InitHashTable(&infoPtr->namespaceClasses, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&infoPtr->procMethods, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&infoPtr->instances, TCL_STRING_KEYS);
Tcl_InitHashTable(&infoPtr->frameContext, TCL_ONE_WORD_KEYS);
Tcl_InitObjHashTable(&infoPtr->classTypes);
infoPtr->ensembleInfo = (EnsembleInfo *)ckalloc(sizeof(EnsembleInfo));
memset(infoPtr->ensembleInfo, 0, sizeof(EnsembleInfo));
Tcl_InitHashTable(&infoPtr->ensembleInfo->ensembles, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&infoPtr->ensembleInfo->subEnsembles, TCL_ONE_WORD_KEYS);
infoPtr->ensembleInfo->numEnsembles = 0;
infoPtr->protection = ITCL_DEFAULT_PROTECT;
infoPtr->currClassFlags = 0;
infoPtr->buildingWidget = 0;
infoPtr->typeDestructorArgumentPtr = Tcl_NewStringObj("", -1);
Tcl_IncrRefCount(infoPtr->typeDestructorArgumentPtr);
infoPtr->lastIoPtr = NULL;
Tcl_SetVar2(interp, ITCL_NAMESPACE"::internal::dicts::classes", NULL, "", 0);
Tcl_SetVar2(interp, ITCL_NAMESPACE"::internal::dicts::objects", NULL, "", 0);
Tcl_SetVar2(interp, ITCL_NAMESPACE"::internal::dicts::classOptions", NULL, "", 0);
Tcl_SetVar2(interp,
ITCL_NAMESPACE"::internal::dicts::classDelegatedOptions", NULL, "", 0);
Tcl_SetVar2(interp,
ITCL_NAMESPACE"::internal::dicts::classComponents", NULL, "", 0);
Tcl_SetVar2(interp,
ITCL_NAMESPACE"::internal::dicts::classVariables", NULL, "", 0);
Tcl_SetVar2(interp,
ITCL_NAMESPACE"::internal::dicts::classFunctions", NULL, "", 0);
Tcl_SetVar2(interp,
ITCL_NAMESPACE"::internal::dicts::classDelegatedFunctions", NULL, "", 0);
hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes,
(char *)Tcl_NewStringObj("class", -1), &isNew);
Tcl_SetHashValue(hPtr, ITCL_CLASS);
hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes,
(char *)Tcl_NewStringObj("type", -1), &isNew);
Tcl_SetHashValue(hPtr, ITCL_TYPE);
hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes,
(char *)Tcl_NewStringObj("widget", -1), &isNew);
Tcl_SetHashValue(hPtr, ITCL_WIDGET);
hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes,
(char *)Tcl_NewStringObj("widgetadaptor", -1), &isNew);
Tcl_SetHashValue(hPtr, ITCL_WIDGETADAPTOR);
hPtr = Tcl_CreateHashEntry(&infoPtr->classTypes,
(char *)Tcl_NewStringObj("extendedclass", -1), &isNew);
Tcl_SetHashValue(hPtr, ITCL_ECLASS);
res_option = getenv("ITCL_USE_OLD_RESOLVERS");
if (res_option == NULL) {
opt = 1;
} else {
opt = atoi(res_option);
}
infoPtr->useOldResolvers = opt;
Itcl_InitStack(&infoPtr->clsStack);
Tcl_SetAssocData(interp, ITCL_INTERP_DATA, NULL, infoPtr);
Itcl_PreserveData(infoPtr);
root = Tcl_NewObjectInstance(interp, tclCls, "::itcl::Root",
NULL, 0, NULL, 0);
Tcl_NewMethod(interp, Tcl_GetObjectAsClass(root),
Tcl_NewStringObj("unknown", -1), 0, &itclRootMethodType,
(void *)ItclUnknownGuts);
Tcl_NewMethod(interp, Tcl_GetObjectAsClass(root),
Tcl_NewStringObj("ItclConstructBase", -1), 0,
&itclRootMethodType, (void *)ItclConstructGuts);
Tcl_NewMethod(interp, Tcl_GetObjectAsClass(root),
Tcl_NewStringObj("info", -1), 1,
&itclRootMethodType, (void *)ItclInfoGuts);
/* first create the Itcl base class as root of itcl classes */
if (Tcl_EvalEx(interp, clazzClassScript, -1, 0) != TCL_OK) {
Tcl_Panic("cannot create Itcl root class ::itcl::clazz");
}
resPtr = Tcl_GetObjResult(interp);
/*
* Tcl_GetObjectFromObject can call Tcl_SetObjResult, so increment the
* refcount first.
*/
Tcl_IncrRefCount(resPtr);
clazzObjectPtr = Tcl_GetObjectFromObj(interp, resPtr);
Tcl_DecrRefCount(resPtr);
if (clazzObjectPtr == NULL) {
Tcl_AppendResult(interp,
"ITCL: cannot get Object for ::itcl::clazz for class \"",
"::itcl::clazz", "\"", NULL);
return TCL_ERROR;
}
Tcl_ObjectSetMetadata(clazzObjectPtr, &canary, infoPtr);
infoPtr->clazzObjectPtr = clazzObjectPtr;
infoPtr->clazzClassPtr = Tcl_GetObjectAsClass(clazzObjectPtr);
/*
* Initialize the ensemble package first, since we need this
* for other parts of [incr Tcl].
*/
if (Itcl_EnsembleInit(interp) != TCL_OK) {
return TCL_ERROR;
}
Itcl_ParseInit(interp, infoPtr);
/*
* Create "itcl::builtin" namespace for commands that
* are automatically built into class definitions.
*/
if (Itcl_BiInit(interp, infoPtr) != TCL_OK) {
return TCL_ERROR;
}
/*
* Export all commands in the "itcl" namespace so that they
* can be imported with something like "namespace import itcl::*"
*/
itclNs = Tcl_FindNamespace(interp, "::itcl", NULL,
TCL_LEAVE_ERR_MSG);
/*
* This was changed from a glob export (itcl::*) to explicit
* command exports, so that the itcl::is command can *not* be
* exported. This is done for concern that the itcl::is command
* imported might be confusing ("is").
*/
if (!itclNs ||
(Tcl_Export(interp, itclNs, "body", /* reset */ 1) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "class", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "code", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "configbody", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "delete", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "delete_helper", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "ensemble", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "filter", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "find", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "forward", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "local", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "mixin", 0) != TCL_OK) ||
(Tcl_Export(interp, itclNs, "scope", 0) != TCL_OK)) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp,
ITCL_NAMESPACE"::internal::commands::sethullwindowname",
ItclSetHullWindowName, infoPtr, NULL);
Tcl_CreateObjCommand(interp,
ITCL_NAMESPACE"::internal::commands::checksetitclhull",
ItclCheckSetItclHull, infoPtr, NULL);
/*
* Set up the variables containing version info.
*/
Tcl_SetVar2(interp, "::itcl::version", NULL, ITCL_VERSION, TCL_NAMESPACE_ONLY);
Tcl_SetVar2(interp, "::itcl::patchLevel", NULL, ITCL_PATCH_LEVEL,
TCL_NAMESPACE_ONLY);
#ifdef ITCL_DEBUG_C_INTERFACE
RegisterDebugCFunctions(interp);
#endif
/*
* Package is now loaded.
*/
Tcl_PkgProvideEx(interp, "Itcl", ITCL_PATCH_LEVEL, &itclStubs);
return Tcl_PkgProvideEx(interp, "itcl", ITCL_PATCH_LEVEL, &itclStubs);
}
/*
* ------------------------------------------------------------------------
* Itcl_Init()
*
* Invoked whenever a new INTERPRETER is created to install the
* [incr Tcl] package. Usually invoked within Tcl_AppInit() at
* the start of execution.
*
* Creates the "::itcl" namespace and installs access commands for
* creating classes and querying info.
*
* Returns TCL_OK on success, or TCL_ERROR (along with an error
* message in the interpreter) if anything goes wrong.
* ------------------------------------------------------------------------
*/
int
Itcl_Init (
Tcl_Interp *interp)
{
if (Initialize(interp) != TCL_OK) {
return TCL_ERROR;
}
return Tcl_EvalEx(interp, initScript, -1, 0);
}
/*
* ------------------------------------------------------------------------
* Itcl_SafeInit()
*
* Invoked whenever a new SAFE INTERPRETER is created to install
* the [incr Tcl] package.
*
* Creates the "::itcl" namespace and installs access commands for
* creating classes and querying info.
*
* Returns TCL_OK on success, or TCL_ERROR (along with an error
* message in the interpreter) if anything goes wrong.
* ------------------------------------------------------------------------
*/
int
Itcl_SafeInit (
Tcl_Interp *interp)
{
if (Initialize(interp) != TCL_OK) {
return TCL_ERROR;
}
return Tcl_EvalEx(interp, safeInitScript, -1, 0);
}
/*
* ------------------------------------------------------------------------
* ItclSetHullWindowName()
*
*
* ------------------------------------------------------------------------
*/
static int
ItclSetHullWindowName(
void *clientData, /* infoPtr */
Tcl_Interp *dummy, /* current interpreter */
int objc, /* number of arguments */
Tcl_Obj *const objv[]) /* argument objects */
{
ItclObjectInfo *infoPtr;
(void)dummy;
infoPtr = (ItclObjectInfo *)clientData;
if ((infoPtr->currIoPtr != NULL) && (objc > 1)) {
infoPtr->currIoPtr->hullWindowNamePtr = objv[1];
Tcl_IncrRefCount(infoPtr->currIoPtr->hullWindowNamePtr);
}
return TCL_OK;
}
/*
* ------------------------------------------------------------------------
* ItclCheckSetItclHull()
*
*
* ------------------------------------------------------------------------
*/
static int
ItclCheckSetItclHull(
void *clientData, /* infoPtr */
Tcl_Interp *interp, /* current interpreter */
int objc, /* number of arguments */
Tcl_Obj *const objv[]) /* argument objects */
{
Tcl_HashEntry *hPtr;
Tcl_Obj *objPtr;
ItclObject *ioPtr;
ItclVariable *ivPtr;
ItclObjectInfo *infoPtr;
const char *valueStr;
if (objc < 3) {
Tcl_AppendResult(interp, "ItclCheckSetItclHull wrong # args should be ",
"<objectName> <value>", NULL);
return TCL_ERROR;
}
/*
* This is an internal command, and is never called with an
* objectName value other than the empty list. Check that with
* an assertion so alternative handling can be removed.
*/
assert( strlen(Tcl_GetString(objv[1])) == 0);
infoPtr = (ItclObjectInfo *)clientData;
{
ioPtr = infoPtr->currIoPtr;
if (ioPtr == NULL) {
Tcl_AppendResult(interp, "ItclCheckSetItclHull cannot find object",
NULL);
return TCL_ERROR;
}
}
objPtr = Tcl_NewStringObj("itcl_hull", -1);
hPtr = Tcl_FindHashEntry(&ioPtr->iclsPtr->variables, (char *)objPtr);
Tcl_DecrRefCount(objPtr);
if (hPtr == NULL) {
Tcl_AppendResult(interp, "ItclCheckSetItclHull cannot find itcl_hull",
" variable for object \"", Tcl_GetString(objv[1]), "\"", NULL);
return TCL_ERROR;
}
ivPtr = (ItclVariable *)Tcl_GetHashValue(hPtr);
valueStr = Tcl_GetString(objv[2]);
if (strcmp(valueStr, "2") == 0) {
ivPtr->initted = 2;
} else {
if (strcmp(valueStr, "0") == 0) {
ivPtr->initted = 0;
} else {
Tcl_AppendResult(interp, "ItclCheckSetItclHull bad value \"",
valueStr, "\"", NULL);
return TCL_ERROR;
}
}
return TCL_OK;
}
/*
* ------------------------------------------------------------------------
* FreeItclObjectInfo()
*
* called when an interp is deleted to free up memory
*
* ------------------------------------------------------------------------
*/
static void
FreeItclObjectInfo(
void *clientData)
{
ItclObjectInfo *infoPtr = (ItclObjectInfo *)clientData;
Tcl_DeleteHashTable(&infoPtr->instances);
Tcl_DeleteHashTable(&infoPtr->classTypes);
Tcl_DeleteHashTable(&infoPtr->procMethods);
Tcl_DeleteHashTable(&infoPtr->objectCmds);
Tcl_DeleteHashTable(&infoPtr->classes);
Tcl_DeleteHashTable(&infoPtr->nameClasses);
Tcl_DeleteHashTable(&infoPtr->namespaceClasses);
assert (infoPtr->infoVarsPtr == NULL);
assert (infoPtr->infoVars4Ptr == NULL);
if (infoPtr->typeDestructorArgumentPtr) {
Tcl_DecrRefCount(infoPtr->typeDestructorArgumentPtr);
infoPtr->typeDestructorArgumentPtr = NULL;
}
/* cleanup ensemble info */
if (infoPtr->ensembleInfo) {
Tcl_DeleteHashTable(&infoPtr->ensembleInfo->ensembles);
Tcl_DeleteHashTable(&infoPtr->ensembleInfo->subEnsembles);
ItclFinishEnsemble(infoPtr);
ckfree((char *)infoPtr->ensembleInfo);
infoPtr->ensembleInfo = NULL;
}
if (infoPtr->class_meta_type) {
ckfree((char *)infoPtr->class_meta_type);
infoPtr->class_meta_type = NULL;
}
/* clean up list pool */
Itcl_FinishList();
Itcl_ReleaseData(infoPtr);
}