home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / ObjectTcl-1.1 / Otcl.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-30  |  22.5 KB  |  811 lines

  1. /*  _ __ ___ _
  2.  * | |\ /  /| |  $Id: Otcl.C,v 1.9 1995/06/16 13:03:59 deans Exp $
  3.  * | | /  / | |  Copyright (C) 1995 IXI Limited.
  4.  * |_|/__/_\|_|  IXI Limited, Cambridge, England.
  5.  *
  6.  * Component   : Otcl.C
  7.  *
  8.  * Author      : Dean Sheehan (deans@x.co.uk)
  9.  *
  10.  * Description : Contains the implementation of the Otcl class that is the
  11.  *               actual extension package for Tcl.
  12.  *
  13.  * License     :
  14.             Object Tcl License & Copyright
  15.             ------------------------------
  16.  
  17. IXI Object Tcl software, both binary and source (hereafter, Software) is copyrighted by IXI Limited (IXI), and ownership remains with IXI. 
  18.  
  19. IXI grants you (herafter, Licensee) a license to use the Software for academic, research and internal business purposes only, without a fee. Licensee may distribute the binary and source code (if required) to third parties provided that the copyright notice and this statement appears on all copies and that no charge is associated with such copies. 
  20.  
  21. Licensee may make derivative works. However, if Licensee distributes any derivative work based on or derived from the Software, then Licensee will (1) notify IXI regarding its distribution of the derivative work, and (2) clearly notify users that such derivative work is a modified version and not the original IXI Object Tcl distributed by IXI. IXI strongly recommends that Licensee provide IXI the right to incorporate such modifications into future releases of the Software under these license terms. 
  22.  
  23. Any Licensee wishing to make commercial use of the Software should contact IXI, to negotiate an appropriate license for such commercial use. Commercial use includes (1) integration of all or part of the source code into a product for sale or license by or on behalf of Licensee to third parties, or (2) distribution of the binary code or source code to third parties that need it to utilize a commercial product sold or licensed by or on behalf of Licensee. 
  24.  
  25. IXI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. IXI SHALL NOT BE LIABLE FOR ANY DAMAGES WHATSOEVER SUFFERED BY THE USERS OF THIS SOFTWARE. 
  26.  
  27. Copyright (C) 1995, IXI Limited 
  28.  
  29. By using or copying this Software, Licensee agrees to abide by the copyright law and all other applicable laws of England and the U.S., including, but not limited to, export control laws, and the terms of this license. IXI shall have the right to terminate this license immediately by written notice upon Licensee's breach of, or non-compliance with, any of its terms. Licensee may be held legally responsible for any copyright infringement that is caused or encouraged by Licensee's failure to abide by the terms of this license. 
  30.  
  31. Comments and questions are welcome and can be sent to
  32. otcl@x.co.uk 
  33.  
  34. For more information on copyright and licensing issues, contact: 
  35. Legal Department, IXI Limited, Vision Park, Cambridge CB4 4ZR,
  36. ENGLAND. 
  37.  
  38.  *
  39.  */
  40.  
  41. // System Includes
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44.  
  45. // Tcl Includes
  46. #include <tclInt.h>
  47.  
  48. #include "Otcl.H"
  49. #include "OtclClass.H"
  50. #include "OtclObjMgr.H"
  51. #include "OtclObject.H"
  52.  
  53. #ifdef OTCL_DP
  54. #include "OtclOserver.H"
  55.  
  56. #ifdef _WINDOWS
  57. #include <winsock.h>
  58. #endif
  59.  
  60. #endif
  61.  
  62. // Class Attribute Definitions
  63. Tcl_Interp *Otcl::tclInterp = NULL;
  64. Otcl *Otcl::otclPtr = NULL;
  65.  
  66. Otcl::Otcl (Tcl_Interp *interp, int &result, OtclObjMgr *om)
  67. {
  68.    placeCommandsInScope(interp);
  69.    Tcl_InitHashTable(&classes,TCL_STRING_KEYS);
  70.  
  71. #ifdef OTCL_DP
  72.    Tcl_InitHashTable(&remoteClasses,TCL_STRING_KEYS);
  73. #endif
  74.  
  75.    objMgr = om;
  76.  
  77.    tclInterp = interp;
  78.    otclPtr = this;
  79.  
  80.    // Register all of the available Otcl bound C++ classes
  81.    // with this Otcl extension.
  82.    OtclClassCpp::registerWithOtcl(this);
  83.  
  84.    char *otclLibrary = getenv("OTCL_LIBRARY");
  85.    if (otclLibrary == NULL)
  86.    {
  87.       otclLibrary = OTCL_LIBRARY;
  88.    }
  89.    Tcl_SetVar(interp,"otcl_library",otclLibrary,TCL_GLOBAL_ONLY);
  90.  
  91.    char initCmd[] =
  92.       "if [file exists $otcl_library/otcl.tcl] {\n\
  93.           source $otcl_library/otcl.tcl\n\
  94.        } else {\n\
  95.           set msg \"can't find $otcl_library/otcl.tcl; perhaps you \"\n\
  96.           append msg \"need to\\ninstall Object Tcl or set your \"\n\
  97.           append msg \" OTCL_LIBRARY environment variable?\"\n\
  98.           error $msg\n\
  99.       }";
  100.  
  101.    result = Tcl_Eval(interp,initCmd);
  102.  
  103. #ifdef OTCL_DP
  104. #ifdef _WINDOWS
  105.    if (result == TCL_OK)
  106.    {
  107.       WORD wVersionRequest = 0x0101;
  108.       WSDATA wsaData;
  109.  
  110.       int err = WSAStartup(wVersionRequested,&wsaData);
  111.       if (err != 0)
  112.       {
  113.          Otcl::setTclError(interp,"Winsock initialisition error %d.",err);
  114.          result = TCL_ERROR;
  115.       }
  116.    }
  117. #endif
  118. #endif
  119. }
  120.  
  121. Otcl::~Otcl ()
  122. {
  123.    // Cleanup all the classes in the Hash Table
  124.    Tcl_HashEntry *entry;
  125.    Tcl_HashSearch search;
  126.    OtclClass *otclc;
  127.    for (entry = Tcl_FirstHashEntry(&classes,&search);
  128.         entry != NULL;
  129.         entry = Tcl_NextHashEntry(&search))
  130.    {
  131.       otclc = (OtclClass*)(Tcl_GetHashValue(entry));
  132.  
  133.       // Not all OtclClass objects registered are owned by this Otcl object
  134.       // as CPP OtclClasses are registered with all Otcl object in this
  135.       // process.
  136.       if (otclc->shouldDelete())
  137.       {
  138.          delete otclc;
  139.       }
  140.    }
  141.  
  142.    // Cleanup the Hash Table.
  143.    Tcl_DeleteHashTable(&classes);
  144.  
  145. #ifdef OTCL_DP
  146.    // clear up remoteClasses as well.
  147.    OtclRemoteClass *otclrc;
  148.    for (entry = Tcl_FirstHashEntry(&remoteClasses,&search);
  149.         entry != NULL;
  150.         entry = Tcl_NextHashEntry(&search))
  151.    {
  152.       otclrc = (OtclRemoteClass*)(Tcl_GetHashValue(entry));
  153.       delete otclrc;
  154.    }
  155.  
  156.    // Cleanup the Hash Table.
  157.    Tcl_DeleteHashTable(&remoteClasses);
  158. #endif
  159.  
  160. }
  161.  
  162. int Otcl::classInterfaceCmd (ClientData cd, Tcl_Interp *interp,
  163.                              int argc, char *argv[])
  164. {
  165.    Otcl *otcl = (Otcl*)cd;
  166.    return otcl->classInterface(interp,argc,argv);
  167. }
  168.  
  169. int Otcl::classImplementationCmd (ClientData cd, Tcl_Interp *interp,
  170.                                   int argc, char *argv[])
  171. {
  172.    Otcl *otcl = (Otcl*)cd;
  173.    return otcl->classImplementation(interp,argc,argv);
  174. }
  175.  
  176. int Otcl::instantiateCmd (ClientData cd, Tcl_Interp *interp,
  177.                           int argc, char *argv[])
  178. {
  179.    Otcl *otcl = (Otcl*)cd;
  180.    return otcl->instantiate(interp,argc,argv);
  181. }
  182.  
  183. int Otcl::discardCmd (ClientData cd, Tcl_Interp *interp,
  184.                       int argc, char *argv[])
  185. {
  186.    Otcl *otcl = (Otcl*)cd;
  187.    return otcl->discard(interp,argc,argv);
  188. }
  189.  
  190. int Otcl::otclCmd (ClientData cd, Tcl_Interp *interp,
  191.                    int argc, char *argv[])
  192. {
  193.    Otcl *otcl = (Otcl*)cd;
  194.    return otcl->otcl(interp,argc,argv);
  195. }
  196.  
  197. int Otcl::otclNopCmd (ClientData, Tcl_Interp *interp, int argc, char *argv[])
  198. {
  199.    Tcl_SetResult(interp,Tcl_Merge(argc-1,&argv[1]),TCL_DYNAMIC);
  200.    return TCL_OK;
  201. }
  202.  
  203. int Otcl::classCmd (ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
  204. {
  205.    ARGC_MIN(2)
  206.    {
  207.       return Otcl::setTclError(interp,ARGS_CLASS_CMD_ERR);
  208.    }
  209.    OtclClass *otclc = (OtclClass*)cd;
  210.    return otclc->classMethod(interp,argc,argv);
  211. }
  212.  
  213. int Otcl::classInterface (Tcl_Interp *interp, int argc, char *argv[])
  214. {
  215.    ARGC_MIN(2)
  216.    {
  217.       return Otcl::setTclError(interp,ARGS_CLASS_INTERFACE_ERR);
  218.    }
  219.  
  220.    // First argument is the name of the new class (argv[0] is command name)
  221.    int newEntry;
  222.    Tcl_HashEntry *hashEntry = Tcl_CreateHashEntry(&classes,argv[1],&newEntry);
  223.    if (newEntry != 1)
  224.    {
  225.       // Found entry already so must have already interfaced the class!
  226.       return Otcl::setTclError(interp,CLASS_ALREADY_INTERFACED_ERR,argv[1]);
  227.    }
  228.  
  229.    // Create a new OtclClass object to record the Class interface and later the
  230.    // class internals.
  231.    OtclClassOtcl *otclClass = new OtclClassOtcl(argv[1],this);
  232.    Tcl_SetHashValue(hashEntry,(ClientData)otclClass);
  233.  
  234.    // Remove the global Otcl commands as we are now about the evaluate
  235.    // the interface commands.
  236.    removeCommandsFromScope(interp);
  237.  
  238.    int returnCode = otclClass->parseInterface(interp,argc,argv);
  239.  
  240.    if (returnCode != TCL_OK)
  241.    {
  242.       // Remove the class from the hash table
  243.       Tcl_DeleteHashEntry(hashEntry);
  244.       delete otclClass;
  245.    }
  246.  
  247.    // Return from evaluating interface so place the global Otcl commands back
  248.    // in scope.
  249.    placeCommandsInScope(interp);
  250.  
  251.    return returnCode;
  252. }
  253.  
  254. int Otcl::classImplementation (Tcl_Interp *interp, int argc, char *argv[])
  255. {
  256.    ARGC_MIN(2)
  257.    {
  258.       return Otcl::setTclError(interp,ARGS_CLASS_IMPLEMENTATION_ERR);
  259.    }
  260.  
  261.    // First argument is the name of the existing class (argv[0] is command nm)
  262.    int newEntry;
  263.    Tcl_HashEntry *hashEntry = Tcl_CreateHashEntry(&classes,argv[1],&newEntry);
  264.    if (newEntry == 1)
  265.    {
  266.       // Couldn't find the entry so couldn't have interfaced the class yet!
  267.       Otcl::setTclResult(interp,CLASS_IMP_BEFORE_INT_ERR,argv[1]);
  268.  
  269.       // Cleanup the entry that would have been made.
  270.       Tcl_DeleteHashEntry(hashEntry);
  271.       return TCL_ERROR;
  272.    }
  273.  
  274.    OtclClassOtcl *otclClass = (OtclClassOtcl*)Tcl_GetHashValue(hashEntry);
  275.  
  276.    // Remove the global Otcl commands as we are now about the evaluate
  277.    // the implementation commands.
  278.    removeCommandsFromScope(interp);
  279.  
  280.    int returnCode = otclClass->parseImplementation(interp,argc,argv);
  281.  
  282.    if (returnCode != TCL_OK)
  283.    {
  284.       Tcl_DeleteHashEntry(hashEntry);
  285.       delete otclClass;
  286.    }
  287.  
  288.    // Return from evaluating implem so place the gloabl Otcl commands back
  289.    // in scope.
  290.    placeCommandsInScope(interp);
  291.  
  292.    return returnCode;
  293. }
  294.  
  295. int Otcl::instantiate (Tcl_Interp *interp, int argc, char *argv[])
  296. {
  297.    ARGC_MIN(2)
  298.    {
  299.       return Otcl::setTclError(interp,ARGS_INSTANTIATE_ERR);
  300.    }
  301.  
  302.    // Look up the class named as the second argument (arg[1]).
  303.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classes,argv[1]);
  304.    if (hashEntry == NULL)
  305.    {
  306.  
  307. #ifdef OTCL_DP
  308.       // look to see if it is a remote class
  309.       hashEntry = Tcl_FindHashEntry(&remoteClasses,argv[1]);
  310.       if (hashEntry != NULL)
  311.       {
  312.          OtclRemoteClass *otclrc =(OtclRemoteClass*)Tcl_GetHashValue(hashEntry);
  313.          return otclrc->instantiate(interp,argc-2,(argc > 2 ? &argv[2] : NULL));
  314.       }
  315. #endif
  316.  
  317.       Otcl::setTclResult(interp,CLASS_UNDEFINED_ERR,argv[1]);
  318.       return TCL_ERROR;
  319.    }
  320.    OtclClass *otclc = (OtclClass*)Tcl_GetHashValue(hashEntry);
  321.  
  322.    return otclc->instantiate(interp,argc-2,(argc > 2 ? &argv[2] : NULL),
  323.                              objMgr);
  324. }
  325.  
  326. int Otcl::instantiate (Tcl_Interp *interp, char *className,
  327.                        int argc, char *argv[])
  328. {
  329.    // Look up the class named
  330.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classes,className);
  331.    if (hashEntry == NULL)
  332.    {
  333. #ifdef OTCL_DP
  334.       // look to see if it is a remote class
  335.       hashEntry = Tcl_FindHashEntry(&remoteClasses,className);
  336.       if (hashEntry != NULL)
  337.       {
  338.          OtclRemoteClass *otclrc =(OtclRemoteClass*)Tcl_GetHashValue(hashEntry);
  339.          return otclrc->instantiate(interp,argc,argv);
  340.       }
  341. #endif
  342.       Otcl::setTclResult(interp,CLASS_UNDEFINED_ERR,className);
  343.       return TCL_ERROR;
  344.    }
  345.    OtclClass *otclc = (OtclClass*)Tcl_GetHashValue(hashEntry);
  346.  
  347.    return otclc->instantiate(interp,argc,argv,objMgr);
  348. }
  349.  
  350. int Otcl::discard (Tcl_Interp *interp, int argc, char *argv[])
  351. {
  352.    ARGC_VALUE(2)
  353.    {
  354.       return Otcl::setTclError(interp,ARGS_DISCARD_ERR);
  355.    }
  356.  
  357.    return discard(interp,argv[1],OTCL_FALSE);
  358. }
  359.  
  360. int Otcl::discard (Tcl_Interp *interp, char *symRef, int fromCpp)
  361. {
  362.    OtclObject *otclo = objMgr->unManageObject(symRef,interp);
  363.    if (otclo == NULL)
  364.    {
  365.  
  366. #ifdef OTCL_DP
  367.       // Check to see if it is a remote object
  368.       if (strchr(symRef,'@') != 0)
  369.       {
  370.         // It is a remote object that hasn't been used yet and therefore
  371.         // doesn't have a proxy
  372.         return OtclRemoteObject::discard(interp,symRef); 
  373.       }
  374. #endif
  375.  
  376.       Otcl::setTclResult(interp,UNKNOWN_OBJECT_ERR,symRef);
  377.       return TCL_ERROR;
  378.    }
  379.  
  380.    // OtclObject::discard also 'deletes' but it allows us to return
  381.    // values...
  382.    return otclo->discard(interp,fromCpp);
  383. }
  384.  
  385. int Otcl::otcl (Tcl_Interp *interp, int argc, char *argv[])
  386. {
  387.    ARGC_MIN(2)
  388.    {
  389.       return Otcl::setTclError(interp,ARGS_OTCL_ERR);
  390.    }
  391.  
  392.    if (strcmp(argv[1],"clear") == 0)
  393.    {
  394.       return clear(interp);
  395.    }
  396.  
  397. #ifdef OTCL_DP
  398.    if (strcmp(argv[1],"oserver") == 0)
  399.    {
  400.       return OtclOserver::oserverCmd(interp,argc,argv);
  401.    }
  402.    if (strcmp(argv[1],"remoteObject") == 0)
  403.    {
  404.       return remoteObject(interp,argc,argv);
  405.    }
  406.    if (strcmp(argv[1],"remoteClass") == 0)
  407.    {
  408.       return remoteClass(interp,argc,argv);
  409.    }
  410. #endif
  411.  
  412.    return Otcl::setTclError(interp,UNKNOWN_OTCL_COMMAND_ERR,argv[1]);
  413. }
  414.  
  415. int Otcl::clear (Tcl_Interp *)
  416. {
  417.    // Cleanup all the classes in the Hash Table
  418.    Tcl_HashEntry *entry;
  419.    Tcl_HashSearch search;
  420.    OtclClass *otclc;
  421.    for (entry = Tcl_FirstHashEntry(&classes,&search);
  422.         entry != NULL;
  423.         entry = Tcl_NextHashEntry(&search))
  424.    {
  425.       otclc = (OtclClass*)(Tcl_GetHashValue(entry));
  426.  
  427.       // Not all OtclClass objects registered are owned by this Otcl object
  428.       // as CPP OtclClasses are registered with all Otcl object in this
  429.       // process.
  430.       if (otclc->shouldDelete())
  431.       {
  432.          delete otclc;
  433.       }
  434.    }
  435.  
  436.    Tcl_DeleteHashTable(&classes);
  437.    Tcl_InitHashTable(&classes,TCL_STRING_KEYS);
  438.  
  439.    // Register all of the available Otcl bound C++ classes
  440.    // with this Otcl extension.
  441.    OtclClassCpp::registerWithOtcl(this);
  442.  
  443.    return TCL_OK;
  444. }
  445.  
  446. void Otcl::placeCommandsInScope (Tcl_Interp *interp)
  447. {
  448.    Tcl_CreateCommand(interp,CLASS_INTERFACE_CMD,Otcl::classInterfaceCmd,
  449.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  450.  
  451.    Tcl_CreateCommand(interp,CLASS_IMPLEMENTATION_CMD,
  452.                      Otcl::classImplementationCmd,
  453.                     (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  454.  
  455.    Tcl_CreateCommand(interp,INSTANTIATE_CMD,Otcl::instantiateCmd,
  456.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  457.  
  458.    Tcl_CreateCommand(interp,DISCARD_CMD,Otcl::discardCmd,
  459.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  460.  
  461.    Tcl_CreateCommand(interp,OTCL_CMD,Otcl::otclCmd,
  462.                      (ClientData)this,(Tcl_CmdDeleteProc*)NULL);
  463.  
  464.    Tcl_CreateCommand(interp,OTCL_NOP_CMD,Otcl::otclNopCmd,
  465.                      (ClientData)NULL,(Tcl_CmdDeleteProc*)NULL);
  466.  
  467. }
  468.  
  469. void Otcl::removeCommandsFromScope (Tcl_Interp *interp)
  470. {
  471.    Tcl_DeleteCommand(interp,CLASS_INTERFACE_CMD);
  472.    Tcl_DeleteCommand(interp,CLASS_IMPLEMENTATION_CMD); 
  473.    Tcl_DeleteCommand(interp,INSTANTIATE_CMD); 
  474.    Tcl_DeleteCommand(interp,DISCARD_CMD); 
  475.    Tcl_DeleteCommand(interp,OTCL_CMD);
  476.    Tcl_DeleteCommand(interp,OTCL_NOP_CMD);
  477. }
  478.  
  479. void Otcl::registerOtclClassCpp (OtclClassCpp *otclClassCpp)
  480. {
  481.    int newEntry;
  482.    Tcl_HashEntry *hashEntry = Tcl_CreateHashEntry(&classes,
  483.                                                otclClassCpp->giveName(),
  484.                                                   &newEntry);
  485.    if (newEntry != 1)
  486.    {
  487.       fprintf(stderr,"Name clash while registering %s C++ class with Object Tcl.\n",otclClassCpp->giveName());
  488.       exit(1);
  489.    }
  490.  
  491.    Tcl_SetHashValue(hashEntry,(ClientData)otclClassCpp);
  492.  
  493.    Tcl_CreateCommand(tclInterp,otclClassCpp->giveName(),Otcl::classCmd,
  494.                      (ClientData)otclClassCpp,(Tcl_CmdDeleteProc*)NULL);
  495. }
  496.  
  497. // Code taken from Tcl7.3 distribution - funtcion CallTraces in tclVar.c
  498. char *Otcl::callTraces (Interp *iPtr, Var *arrayPtr, Var *varPtr,
  499.                         char *part1, char *part2, int flags)
  500. {
  501.    VarTrace *tracePtr;
  502.    ActiveVarTrace active;
  503.    char *result;
  504.  
  505.    /*
  506.     * If there are already similar trace procedures active for the
  507.     * variable, don't call them again.
  508.     */
  509.  
  510.    if (varPtr->flags & VAR_TRACE_ACTIVE)
  511.    {
  512.       return NULL;
  513.    }
  514.    varPtr->flags |= VAR_TRACE_ACTIVE;
  515.    varPtr->refCount++;
  516.  
  517.    /*
  518.     * Invoke traces on the array containing the variable, if relevant.
  519.     */
  520.  
  521.    result = NULL;
  522.    active.nextPtr = iPtr->activeTracePtr;
  523.    iPtr->activeTracePtr = &active;
  524.    if (arrayPtr != NULL)
  525.    {
  526.       arrayPtr->refCount++;
  527.       active.varPtr = arrayPtr;
  528.       for (tracePtr = arrayPtr->tracePtr;  tracePtr != NULL;
  529.            tracePtr = active.nextTracePtr)
  530.       {
  531.          active.nextTracePtr = tracePtr->nextPtr;
  532.          if (!(tracePtr->flags & flags))
  533.          {
  534.             continue;
  535.          }
  536.          result = (*tracePtr->traceProc)(tracePtr->clientData,
  537.                     (Tcl_Interp *) iPtr, part1, part2, flags);
  538.          if (result != NULL)
  539.          {
  540.             if (flags & TCL_TRACE_UNSETS) 
  541.             {
  542.                result = NULL;
  543.             }
  544.             else
  545.             {
  546.                goto done;
  547.             }
  548.          }
  549.       }
  550.    }
  551.  
  552.    /*
  553.     * Invoke traces on the variable itself.
  554.     */
  555.  
  556.    if (flags & TCL_TRACE_UNSETS)
  557.    {
  558.       flags |= TCL_TRACE_DESTROYED;
  559.    }
  560.    active.varPtr = varPtr;
  561.    for (tracePtr = varPtr->tracePtr; tracePtr != NULL;
  562.         tracePtr = active.nextTracePtr)
  563.    {
  564.       active.nextTracePtr = tracePtr->nextPtr;
  565.       if (!(tracePtr->flags & flags))
  566.       {
  567.          continue;
  568.       }
  569.       result = (*tracePtr->traceProc)(tracePtr->clientData,
  570.                 (Tcl_Interp *) iPtr, part1, part2, flags);
  571.       if (result != NULL)
  572.       {
  573.          if (flags & TCL_TRACE_UNSETS) {
  574.             result = NULL;
  575.          }
  576.          else
  577.          {
  578.             goto done;
  579.          }
  580.       }
  581.    }
  582.  
  583.    /*
  584.     * Restore the variable's flags, remove the record of our active
  585.     * traces, and then return.
  586.     */
  587.  
  588. done:
  589.    if (arrayPtr != NULL)
  590.    {
  591.       arrayPtr->refCount--;
  592.    }
  593.    varPtr->flags &= ~VAR_TRACE_ACTIVE;
  594.    varPtr->refCount--;
  595.    iPtr->activeTracePtr = active.nextPtr;
  596.    return result;
  597. }
  598.  
  599. // Code Taken from Tcl7.3 distribution DeleteArray function from tclVar.c
  600. void Otcl::deleteArray (Interp *iPtr, char *arrayName, Var *varPtr, int flags)
  601. {
  602.    Tcl_HashSearch search;
  603.    Tcl_HashEntry *hPtr;
  604.    Var *elPtr;
  605.    ActiveVarTrace *activePtr;
  606.  
  607.    ArraySearch *searchPtr;
  608.    while (varPtr->searchPtr != NULL)
  609.    {
  610.       searchPtr = varPtr->searchPtr;
  611.       varPtr->searchPtr = searchPtr->nextPtr;
  612.       ckfree((char *) searchPtr);
  613.    }
  614.  
  615.    for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
  616.         hPtr != NULL; hPtr = Tcl_NextHashEntry(&search))
  617.    {
  618.       elPtr = (Var *) Tcl_GetHashValue(hPtr);
  619.       if (elPtr->valueSpace != 0)
  620.       {
  621.          /*
  622.           * SPECIAL TRICK:  it's possible that the interpreter's result
  623.           * currently points to this element (for example, a "set" or
  624.           * "lappend" command was the last command in a procedure that's
  625.           * being returned from).  If this is the case, then just pass
  626.           * ownership of the value string to the Tcl interpreter.
  627.           */
  628.  
  629.          if (iPtr->result == elPtr->value.string)
  630.          {
  631.             iPtr->freeProc = (Tcl_FreeProc *) free;
  632.          }
  633.          else
  634.          {
  635.             ckfree(elPtr->value.string);
  636.          }
  637.          elPtr->valueSpace = 0;
  638.       }
  639.       elPtr->hPtr = NULL;
  640.       if (elPtr->tracePtr != NULL)
  641.       {
  642.          elPtr->flags &= ~VAR_TRACE_ACTIVE;
  643.          (void) Otcl::callTraces(iPtr,(Var *) NULL, elPtr, arrayName,
  644.                     Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), flags);
  645.          while (elPtr->tracePtr != NULL)
  646.          {
  647.             VarTrace *tracePtr = elPtr->tracePtr;
  648.             elPtr->tracePtr = tracePtr->nextPtr;
  649.             ckfree((char *) tracePtr);
  650.          }
  651.          for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
  652.               activePtr = activePtr->nextPtr)
  653.          {
  654.             if (activePtr->varPtr == elPtr)
  655.             {
  656.                activePtr->nextTracePtr = NULL;
  657.             }
  658.          }
  659.       }
  660.       elPtr->flags = VAR_UNDEFINED;
  661.       if (elPtr->refCount == 0)
  662.       {
  663.          ckfree((char *) elPtr);
  664.       }
  665.    }
  666.    Tcl_DeleteHashTable(varPtr->value.tablePtr);
  667.    ckfree((char *) varPtr->value.tablePtr);
  668. }
  669.  
  670. OtclClass *Otcl::giveOtclClass (char *name)
  671. {
  672.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classes,name);
  673.    if (hashEntry != NULL)
  674.    {
  675.       return (OtclClass*)Tcl_GetHashValue(hashEntry);
  676.    }
  677.    return NULL;
  678. }
  679.  
  680. void *Otcl::obrefToCpp (char *obref, char *cppClassName)
  681. {
  682.    int returnCode;
  683.    OtclObject *otclObject = objMgr->dereference(obref,tclInterp,returnCode);
  684.    if (otclObject)
  685.    {
  686.       return otclObject->toCpp(cppClassName);
  687.    }
  688.    else if (returnCode == TCL_OK)
  689.    {
  690.       return NULL;
  691.    }
  692.    else
  693.    {
  694.       return this;
  695.    }
  696. }
  697.  
  698. #if 0
  699. static void
  700. InterpDelete (ClientData clientData,
  701.               Tcl_Interp *interp)
  702. {
  703.     Otcl *obj = (Otcl *) clientData;
  704.     delete obj;
  705. }
  706. #endif
  707.  
  708. int
  709. Otcl_Init (Tcl_Interp *interp)
  710. {
  711.     int result;
  712.     Otcl *obj = new Otcl(interp, result, new OtclObjMgrCmd);
  713. #if 0
  714.     Tcl_CallWhenDeleted (interp, InterpDelete, (ClientData) obj);
  715. #endif
  716.     return result;
  717. }
  718.  
  719. OtclObject *Otcl::createObjectWrapper (OtclPart *part)
  720. {
  721.    OtclObject *otclo = new OtclObject();
  722.    char *symbolicRef = otclPtr->objMgr->manageObject(otclo,tclInterp);
  723.    if (symbolicRef == NULL)
  724.    {
  725.       delete otclo;
  726.       return NULL;
  727.    }
  728.  
  729.    otclo->setSelf(symbolicRef);
  730.  
  731.    otclo->setPart(part);
  732.  
  733.    return otclo;
  734. }
  735.  
  736. void Otcl::setObjectReferenceSuffix (char *suffix)
  737. {
  738.    objMgr->setObjectReferenceSuffix(suffix);
  739. }
  740.  
  741. OtclObject *Otcl::giveOtclObject (char *symRef, Tcl_Interp *interp,
  742.                                   int &returnCode)
  743. {
  744.    return objMgr->dereference(symRef,interp,returnCode);
  745. }
  746.  
  747. #ifdef OTCL_DP
  748.  
  749. int Otcl::remoteObject (Tcl_Interp *interp, int argc, char *argv[])
  750. {
  751.    ARGC_VALUE(3)
  752.    {
  753.       return Otcl::setTclError(interp,ARGS_REMOTE_OBJECT_ERR);
  754.    }
  755.  
  756.    int result;
  757.    OtclRemoteObject *otclo = new OtclRemoteObject(argv[2],result,interp);
  758.    if (result != TCL_OK)
  759.    {
  760.       delete otclo;
  761.       return TCL_ERROR;
  762.    }
  763.    if (!objMgr->manageObject(otclo,argv[2],interp))
  764.    {
  765.       Otcl::setTclResult(interp,COULDNT_MANAGE_OBJECT_ERR,"remote object");
  766.       delete otclo;
  767.       return TCL_ERROR;
  768.    }
  769.    return TCL_OK;
  770. }
  771.  
  772. int Otcl::remoteClass (Tcl_Interp *interp, int argc, char *argv[])
  773. {
  774.    ARGC_RANGE(4,5)
  775.    {
  776.       return Otcl::setTclError(interp,ARGS_REMOTE_CLASS_ERR);
  777.    }
  778.  
  779.    char *realName = argv[2];
  780.    if (argc == 5)
  781.    {
  782.       realName = argv[4];
  783.    }
  784.  
  785.    // Check we don't have it as an internal class
  786.    Tcl_HashEntry *hashEntry = Tcl_FindHashEntry(&classes,argv[2]);
  787.    if (hashEntry != NULL)
  788.    {
  789.       return Otcl::setTclError(interp,REMOTE_CLASS_INTERNAL_CLASS_CLASH_ERR,
  790.                                argv[2]);
  791.    }
  792.  
  793.    // Check to see if we have it as a remote class
  794.    int newEntry;
  795.    hashEntry = Tcl_CreateHashEntry(&remoteClasses,argv[2],&newEntry);
  796.    if (newEntry == 1)
  797.    {
  798.       Tcl_SetHashValue(hashEntry,new OtclRemoteClass(interp,realName,argv[3]));
  799.    }
  800.    else
  801.    {
  802.       // Change the server for this remote class
  803.       OtclRemoteClass *otclrc = (OtclRemoteClass*)Tcl_GetHashValue(hashEntry);
  804.       otclrc->setAddress(argv[3],realName);
  805.    }
  806.  
  807.    return TCL_OK;
  808. }
  809.  
  810. #endif
  811.