tclInterp.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:70k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclInterp.c --
  3.  *
  4.  * This file implements the "interp" command which allows creation
  5.  * and manipulation of Tcl interpreters from within Tcl scripts.
  6.  *
  7.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclInterp.c,v 1.20.2.4 2008/01/30 10:46:56 msofer Exp $
  13.  */
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16. #include <stdio.h>
  17. /*
  18.  * Counter for how many aliases were created (global)
  19.  */
  20. static int aliasCounter = 0;
  21. TCL_DECLARE_MUTEX(cntMutex)
  22. /*
  23.  * struct Alias:
  24.  *
  25.  * Stores information about an alias. Is stored in the slave interpreter
  26.  * and used by the source command to find the target command in the master
  27.  * when the source command is invoked.
  28.  */
  29. typedef struct Alias {
  30.     Tcl_Obj *namePtr; /* Name of alias command in slave interp. */
  31.     Tcl_Interp *targetInterp; /* Interp in which target command will be
  32.  * invoked. */
  33.     Tcl_Command slaveCmd; /* Source command in slave interpreter,
  34.  * bound to command that invokes the target
  35.  * command in the target interpreter. */
  36.     Tcl_HashEntry *aliasEntryPtr;
  37. /* Entry for the alias hash table in slave.
  38.                                  * This is used by alias deletion to remove
  39.                                  * the alias from the slave interpreter
  40.                                  * alias table. */
  41.     Tcl_HashEntry *targetEntryPtr;
  42. /* Entry for target command in master.
  43.                                  * This is used in the master interpreter to
  44.                                  * map back from the target command to aliases
  45.                                  * redirecting to it. Random access to this
  46.                                  * hash table is never required - we are using
  47.                                  * a hash table only for convenience. */
  48.     int objc;                   /* Count of Tcl_Obj in the prefix of the
  49.  * target command to be invoked in the
  50.  * target interpreter. Additional arguments
  51.  * specified when calling the alias in the
  52.  * slave interp will be appended to the prefix
  53.  * before the command is invoked. */
  54.     Tcl_Obj *objPtr;            /* The first actual prefix object - the target
  55.  * command name; this has to be at the end of the 
  56.  * structure, which will be extended to accomodate 
  57.  * the remaining objects in the prefix. */
  58. } Alias;
  59. /*
  60.  *
  61.  * struct Slave:
  62.  *
  63.  * Used by the "interp" command to record and find information about slave
  64.  * interpreters. Maps from a command name in the master to information about
  65.  * a slave interpreter, e.g. what aliases are defined in it.
  66.  */
  67. typedef struct Slave {
  68.     Tcl_Interp *masterInterp; /* Master interpreter for this slave. */
  69.     Tcl_HashEntry *slaveEntryPtr;
  70. /* Hash entry in masters slave table for
  71.                                  * this slave interpreter.  Used to find
  72.                                  * this record, and used when deleting the
  73.                                  * slave interpreter to delete it from the
  74.                                  * master's table. */
  75.     Tcl_Interp *slaveInterp; /* The slave interpreter. */
  76.     Tcl_Command interpCmd; /* Interpreter object command. */
  77.     Tcl_HashTable aliasTable; /* Table which maps from names of commands
  78.                                  * in slave interpreter to struct Alias
  79.                                  * defined below. */
  80. } Slave;
  81. /*
  82.  * struct Target:
  83.  *
  84.  * Maps from master interpreter commands back to the source commands in slave
  85.  * interpreters. This is needed because aliases can be created between sibling
  86.  * interpreters and must be deleted when the target interpreter is deleted. In
  87.  * case they would not be deleted the source interpreter would be left with a
  88.  * "dangling pointer". One such record is stored in the Master record of the
  89.  * master interpreter (in the targetTable hashtable, see below) with the
  90.  * master for each alias which directs to a command in the master. These
  91.  * records are used to remove the source command for an from a slave if/when
  92.  * the master is deleted.
  93.  */
  94. typedef struct Target {
  95.     Tcl_Command slaveCmd; /* Command for alias in slave interp. */
  96.     Tcl_Interp *slaveInterp; /* Slave Interpreter. */
  97. } Target;
  98. /*
  99.  * struct Master:
  100.  *
  101.  * This record is used for two purposes: First, slaveTable (a hashtable)
  102.  * maps from names of commands to slave interpreters. This hashtable is
  103.  * used to store information about slave interpreters of this interpreter,
  104.  * to map over all slaves, etc. The second purpose is to store information
  105.  * about all aliases in slaves (or siblings) which direct to target commands
  106.  * in this interpreter (using the targetTable hashtable).
  107.  * 
  108.  * NB: the flags field in the interp structure, used with SAFE_INTERP
  109.  * mask denotes whether the interpreter is safe or not. Safe
  110.  * interpreters have restricted functionality, can only create safe slave
  111.  * interpreters and can only load safe extensions.
  112.  */
  113. typedef struct Master {
  114.     Tcl_HashTable slaveTable; /* Hash table for slave interpreters.
  115.                                  * Maps from command names to Slave records. */
  116.     Tcl_HashTable targetTable; /* Hash table for Target Records. Contains
  117.                                  * all Target records which denote aliases
  118.                                  * from slaves or sibling interpreters that
  119.                                  * direct to commands in this interpreter. This
  120.                                  * table is used to remove dangling pointers
  121.                                  * from the slave (or sibling) interpreters
  122.                                  * when this interpreter is deleted. */
  123. } Master;
  124. /*
  125.  * The following structure keeps track of all the Master and Slave information
  126.  * on a per-interp basis.
  127.  */
  128. typedef struct InterpInfo {
  129.     Master master; /* Keeps track of all interps for which this
  130.  * interp is the Master. */
  131.     Slave slave; /* Information necessary for this interp to
  132.  * function as a slave. */
  133. } InterpInfo;
  134. /*
  135.  * Prototypes for local static procedures:
  136.  */
  137. static int AliasCreate _ANSI_ARGS_((Tcl_Interp *interp,
  138.     Tcl_Interp *slaveInterp, Tcl_Interp *masterInterp,
  139.     Tcl_Obj *namePtr, Tcl_Obj *targetPtr, int objc,
  140.     Tcl_Obj *CONST objv[]));
  141. static int AliasDelete _ANSI_ARGS_((Tcl_Interp *interp,
  142.     Tcl_Interp *slaveInterp, Tcl_Obj *namePtr));
  143. static int AliasDescribe _ANSI_ARGS_((Tcl_Interp *interp,
  144.     Tcl_Interp *slaveInterp, Tcl_Obj *objPtr));
  145. static int AliasList _ANSI_ARGS_((Tcl_Interp *interp,
  146.             Tcl_Interp *slaveInterp));
  147. static int AliasObjCmd _ANSI_ARGS_((ClientData dummy,
  148.     Tcl_Interp *currentInterp, int objc,
  149.             Tcl_Obj *CONST objv[]));
  150. static void AliasObjCmdDeleteProc _ANSI_ARGS_((
  151.     ClientData clientData));
  152. static Tcl_Interp * GetInterp _ANSI_ARGS_((Tcl_Interp *interp,
  153.     Tcl_Obj *pathPtr));
  154. static Tcl_Interp * GetInterp2 _ANSI_ARGS_((Tcl_Interp *interp, int objc,
  155.     Tcl_Obj *CONST objv[]));
  156. static void InterpInfoDeleteProc _ANSI_ARGS_((
  157.     ClientData clientData, Tcl_Interp *interp));
  158. static Tcl_Interp * SlaveCreate _ANSI_ARGS_((Tcl_Interp *interp,
  159.             Tcl_Obj *pathPtr, int safe));
  160. static int SlaveEval _ANSI_ARGS_((Tcl_Interp *interp,
  161.     Tcl_Interp *slaveInterp, int objc,
  162.     Tcl_Obj *CONST objv[]));
  163. static int SlaveExpose _ANSI_ARGS_((Tcl_Interp *interp,
  164.     Tcl_Interp *slaveInterp, int objc,
  165.     Tcl_Obj *CONST objv[]));
  166. static int SlaveHide _ANSI_ARGS_((Tcl_Interp *interp,
  167.     Tcl_Interp *slaveInterp, int objc,
  168.     Tcl_Obj *CONST objv[]));
  169. static int SlaveHidden _ANSI_ARGS_((Tcl_Interp *interp,
  170.     Tcl_Interp *slaveInterp));
  171. static int SlaveInvokeHidden _ANSI_ARGS_((Tcl_Interp *interp,
  172.     Tcl_Interp *slaveInterp, int global, int objc,
  173.     Tcl_Obj *CONST objv[]));
  174. static int SlaveMarkTrusted _ANSI_ARGS_((Tcl_Interp *interp,
  175.     Tcl_Interp *slaveInterp));
  176. static int SlaveObjCmd _ANSI_ARGS_((ClientData dummy,
  177.     Tcl_Interp *interp, int objc,
  178.     Tcl_Obj *CONST objv[]));
  179. static void SlaveObjCmdDeleteProc _ANSI_ARGS_((
  180.     ClientData clientData));
  181. static int SlaveRecursionLimit _ANSI_ARGS_((Tcl_Interp *interp,
  182.     Tcl_Interp *slaveInterp, int objc,
  183.     Tcl_Obj *CONST objv[]));
  184. /*
  185.  *---------------------------------------------------------------------------
  186.  *
  187.  * TclInterpInit --
  188.  *
  189.  * Initializes the invoking interpreter for using the master, slave
  190.  * and safe interp facilities.  This is called from inside
  191.  * Tcl_CreateInterp().
  192.  *
  193.  * Results:
  194.  * Always returns TCL_OK for backwards compatibility.
  195.  *
  196.  * Side effects:
  197.  * Adds the "interp" command to an interpreter and initializes the
  198.  * interpInfoPtr field of the invoking interpreter.
  199.  *
  200.  *---------------------------------------------------------------------------
  201.  */
  202. int
  203. TclInterpInit(interp)
  204.     Tcl_Interp *interp; /* Interpreter to initialize. */
  205. {
  206.     InterpInfo *interpInfoPtr;
  207.     Master *masterPtr;
  208.     Slave *slavePtr;
  209.     interpInfoPtr = (InterpInfo *) ckalloc(sizeof(InterpInfo));
  210.     ((Interp *) interp)->interpInfo = (ClientData) interpInfoPtr;
  211.     masterPtr = &interpInfoPtr->master;
  212.     Tcl_InitHashTable(&masterPtr->slaveTable, TCL_STRING_KEYS);
  213.     Tcl_InitHashTable(&masterPtr->targetTable, TCL_ONE_WORD_KEYS);
  214.     slavePtr = &interpInfoPtr->slave;
  215.     slavePtr->masterInterp = NULL;
  216.     slavePtr->slaveEntryPtr = NULL;
  217.     slavePtr->slaveInterp = interp;
  218.     slavePtr->interpCmd = NULL;
  219.     Tcl_InitHashTable(&slavePtr->aliasTable, TCL_STRING_KEYS);
  220.     Tcl_CreateObjCommand(interp, "interp", Tcl_InterpObjCmd, NULL, NULL);
  221.     Tcl_CallWhenDeleted(interp, InterpInfoDeleteProc, NULL);
  222.     return TCL_OK;
  223. }
  224. /*
  225.  *---------------------------------------------------------------------------
  226.  *
  227.  * InterpInfoDeleteProc --
  228.  *
  229.  * Invoked when an interpreter is being deleted.  It releases all
  230.  * storage used by the master/slave/safe interpreter facilities.
  231.  *
  232.  * Results:
  233.  * None.
  234.  *
  235.  * Side effects:
  236.  * Cleans up storage.  Sets the interpInfoPtr field of the interp
  237.  * to NULL.
  238.  *
  239.  *---------------------------------------------------------------------------
  240.  */
  241. static void
  242. InterpInfoDeleteProc(clientData, interp)
  243.     ClientData clientData; /* Ignored. */
  244.     Tcl_Interp *interp; /* Interp being deleted.  All commands for
  245.  * slave interps should already be deleted. */
  246. {
  247.     InterpInfo *interpInfoPtr;
  248.     Slave *slavePtr;
  249.     Master *masterPtr;
  250.     Tcl_HashSearch hSearch;
  251.     Tcl_HashEntry *hPtr;
  252.     Target *targetPtr;
  253.     interpInfoPtr = (InterpInfo *) ((Interp *) interp)->interpInfo;
  254.     /*
  255.      * There shouldn't be any commands left.
  256.      */
  257.     masterPtr = &interpInfoPtr->master;
  258.     if (masterPtr->slaveTable.numEntries != 0) {
  259. panic("InterpInfoDeleteProc: still exist commands");
  260.     }
  261.     Tcl_DeleteHashTable(&masterPtr->slaveTable);
  262.     /*
  263.      * Tell any interps that have aliases to this interp that they should
  264.      * delete those aliases.  If the other interp was already dead, it
  265.      * would have removed the target record already. 
  266.      */
  267.     hPtr = Tcl_FirstHashEntry(&masterPtr->targetTable, &hSearch);
  268.     while (hPtr != NULL) {
  269. targetPtr = (Target *) Tcl_GetHashValue(hPtr);
  270. Tcl_DeleteCommandFromToken(targetPtr->slaveInterp,
  271. targetPtr->slaveCmd);
  272. hPtr = Tcl_NextHashEntry(&hSearch);
  273.     }
  274.     Tcl_DeleteHashTable(&masterPtr->targetTable);
  275.     slavePtr = &interpInfoPtr->slave;
  276.     if (slavePtr->interpCmd != NULL) {
  277. /*
  278.  * Tcl_DeleteInterp() was called on this interpreter, rather
  279.  * "interp delete" or the equivalent deletion of the command in the
  280.  * master.  First ensure that the cleanup callback doesn't try to
  281.  * delete the interp again.
  282.  */
  283. slavePtr->slaveInterp = NULL;
  284.         Tcl_DeleteCommandFromToken(slavePtr->masterInterp,
  285. slavePtr->interpCmd);
  286.     }
  287.     /*
  288.      * There shouldn't be any aliases left.
  289.      */
  290.     if (slavePtr->aliasTable.numEntries != 0) {
  291. panic("InterpInfoDeleteProc: still exist aliases");
  292.     }
  293.     Tcl_DeleteHashTable(&slavePtr->aliasTable);
  294.     ckfree((char *) interpInfoPtr);    
  295. }
  296. /*
  297.  *----------------------------------------------------------------------
  298.  *
  299.  * Tcl_InterpObjCmd --
  300.  *
  301.  * This procedure is invoked to process the "interp" Tcl command.
  302.  * See the user documentation for details on what it does.
  303.  *
  304.  * Results:
  305.  * A standard Tcl result.
  306.  *
  307.  * Side effects:
  308.  * See the user documentation.
  309.  *
  310.  *----------------------------------------------------------------------
  311.  */
  312. /* ARGSUSED */
  313. int
  314. Tcl_InterpObjCmd(clientData, interp, objc, objv)
  315.     ClientData clientData; /* Unused. */
  316.     Tcl_Interp *interp; /* Current interpreter. */
  317.     int objc; /* Number of arguments. */
  318.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  319. {
  320.     int index;
  321.     static CONST char *options[] = {
  322.         "alias", "aliases", "create", "delete", 
  323. "eval", "exists", "expose", "hide", 
  324. "hidden", "issafe", "invokehidden", "marktrusted", 
  325. "recursionlimit", "slaves", "share",
  326. "target", "transfer",
  327.         NULL
  328.     };
  329.     enum option {
  330. OPT_ALIAS, OPT_ALIASES, OPT_CREATE, OPT_DELETE,
  331. OPT_EVAL, OPT_EXISTS, OPT_EXPOSE, OPT_HIDE,
  332. OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHID, OPT_MARKTRUSTED,
  333. OPT_RECLIMIT, OPT_SLAVES, OPT_SHARE,
  334. OPT_TARGET, OPT_TRANSFER
  335.     };
  336.     if (objc < 2) {
  337.         Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
  338.         return TCL_ERROR;
  339.     }
  340.     if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, 
  341.     &index) != TCL_OK) {
  342. return TCL_ERROR;
  343.     }
  344.     switch ((enum option) index) {
  345. case OPT_ALIAS: {
  346.     Tcl_Interp *slaveInterp, *masterInterp;
  347.     if (objc < 4) {
  348. aliasArgs:
  349. Tcl_WrongNumArgs(interp, 2, objv,
  350. "slavePath slaveCmd ?masterPath masterCmd? ?args ..?");
  351. return TCL_ERROR;
  352.     }
  353.     slaveInterp = GetInterp(interp, objv[2]);
  354.     if (slaveInterp == (Tcl_Interp *) NULL) {
  355. return TCL_ERROR;
  356.     }
  357.     if (objc == 4) {
  358. return AliasDescribe(interp, slaveInterp, objv[3]);
  359.     }
  360.     if ((objc == 5) && (Tcl_GetString(objv[4])[0] == '')) {
  361. return AliasDelete(interp, slaveInterp, objv[3]);
  362.     }
  363.     if (objc > 5) {
  364. masterInterp = GetInterp(interp, objv[4]);
  365. if (masterInterp == (Tcl_Interp *) NULL) {
  366.     return TCL_ERROR;
  367. }
  368. if (Tcl_GetString(objv[5])[0] == '') {
  369.     if (objc == 6) {
  370. return AliasDelete(interp, slaveInterp, objv[3]);
  371.     }
  372. } else {
  373.     return AliasCreate(interp, slaveInterp, masterInterp,
  374.     objv[3], objv[5], objc - 6, objv + 6);
  375. }
  376.     }
  377.     goto aliasArgs;
  378. }
  379. case OPT_ALIASES: {
  380.     Tcl_Interp *slaveInterp;
  381.     slaveInterp = GetInterp2(interp, objc, objv);
  382.     if (slaveInterp == NULL) {
  383. return TCL_ERROR;
  384.     }
  385.     return AliasList(interp, slaveInterp);
  386. }
  387. case OPT_CREATE: {
  388.     int i, last, safe;
  389.     Tcl_Obj *slavePtr;
  390.     char buf[16 + TCL_INTEGER_SPACE];
  391.     static CONST char *options[] = {
  392. "-safe", "--", NULL
  393.     };
  394.     enum option {
  395. OPT_SAFE, OPT_LAST
  396.     };
  397.     safe = Tcl_IsSafe(interp);
  398.     
  399.     /*
  400.      * Weird historical rules: "-safe" is accepted at the end, too.
  401.      */
  402.     slavePtr = NULL;
  403.     last = 0;
  404.     for (i = 2; i < objc; i++) {
  405. if ((last == 0) && (Tcl_GetString(objv[i])[0] == '-')) {
  406.     if (Tcl_GetIndexFromObj(interp, objv[i], options, "option",
  407.     0, &index) != TCL_OK) {
  408. return TCL_ERROR;
  409.     }
  410.     if (index == OPT_SAFE) {
  411. safe = 1;
  412. continue;
  413.     }
  414.     i++;
  415.     last = 1;
  416. }
  417. if (slavePtr != NULL) {
  418.     Tcl_WrongNumArgs(interp, 2, objv, "?-safe? ?--? ?path?");
  419.     return TCL_ERROR;
  420. }
  421. if (i < objc) {
  422.     slavePtr = objv[i];
  423. }
  424.     }
  425.     buf[0] = '';
  426.     if (slavePtr == NULL) {
  427. /*
  428.  * Create an anonymous interpreter -- we choose its name and
  429.  * the name of the command. We check that the command name
  430.  * that we use for the interpreter does not collide with an
  431.  * existing command in the master interpreter.
  432.  */
  433. for (i = 0; ; i++) {
  434.     Tcl_CmdInfo cmdInfo;
  435.     
  436.     sprintf(buf, "interp%d", i);
  437.     if (Tcl_GetCommandInfo(interp, buf, &cmdInfo) == 0) {
  438. break;
  439.     }
  440. }
  441. slavePtr = Tcl_NewStringObj(buf, -1);
  442.     }
  443.     if (SlaveCreate(interp, slavePtr, safe) == NULL) {
  444. if (buf[0] != '') {
  445.     Tcl_DecrRefCount(slavePtr);
  446. }
  447. return TCL_ERROR;
  448.     }
  449.     Tcl_SetObjResult(interp, slavePtr);
  450.     return TCL_OK;
  451. }
  452. case OPT_DELETE: {
  453.     int i;
  454.     InterpInfo *iiPtr;
  455.     Tcl_Interp *slaveInterp;
  456.     
  457.     for (i = 2; i < objc; i++) {
  458. slaveInterp = GetInterp(interp, objv[i]);
  459. if (slaveInterp == NULL) {
  460.     return TCL_ERROR;
  461. } else if (slaveInterp == interp) {
  462.     Tcl_ResetResult(interp);
  463.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  464.     "cannot delete the current interpreter",
  465.     (char *) NULL);
  466.     return TCL_ERROR;
  467. }
  468. iiPtr = (InterpInfo *) ((Interp *) slaveInterp)->interpInfo;
  469. Tcl_DeleteCommandFromToken(iiPtr->slave.masterInterp,
  470. iiPtr->slave.interpCmd);
  471.     }
  472.     return TCL_OK;
  473. }
  474. case OPT_EVAL: {
  475.     Tcl_Interp *slaveInterp;
  476.     if (objc < 4) {
  477. Tcl_WrongNumArgs(interp, 2, objv, "path arg ?arg ...?");
  478. return TCL_ERROR;
  479.     }
  480.     slaveInterp = GetInterp(interp, objv[2]);
  481.     if (slaveInterp == NULL) {
  482. return TCL_ERROR;
  483.     }
  484.     return SlaveEval(interp, slaveInterp, objc - 3, objv + 3);
  485. }
  486. case OPT_EXISTS: {
  487.     int exists;
  488.     Tcl_Interp *slaveInterp;
  489.     exists = 1;
  490.     slaveInterp = GetInterp2(interp, objc, objv);
  491.     if (slaveInterp == NULL) {
  492. if (objc > 3) {
  493.     return TCL_ERROR;
  494. }
  495. Tcl_ResetResult(interp);
  496. exists = 0;
  497.     }
  498.     Tcl_SetIntObj(Tcl_GetObjResult(interp), exists);
  499.     return TCL_OK;
  500. }
  501. case OPT_EXPOSE: {
  502.     Tcl_Interp *slaveInterp;
  503.     if ((objc < 4) || (objc > 5)) {
  504. Tcl_WrongNumArgs(interp, 2, objv,
  505. "path hiddenCmdName ?cmdName?");
  506. return TCL_ERROR;
  507.     }
  508.     slaveInterp = GetInterp(interp, objv[2]);
  509.     if (slaveInterp == NULL) {
  510. return TCL_ERROR;
  511.     }
  512.     return SlaveExpose(interp, slaveInterp, objc - 3, objv + 3);
  513. }
  514. case OPT_HIDE: {
  515.     Tcl_Interp *slaveInterp; /* A slave. */
  516.     if ((objc < 4) || (objc > 5)) {
  517. Tcl_WrongNumArgs(interp, 2, objv,
  518. "path cmdName ?hiddenCmdName?");
  519. return TCL_ERROR;
  520.     }
  521.     slaveInterp = GetInterp(interp, objv[2]);
  522.     if (slaveInterp == (Tcl_Interp *) NULL) {
  523. return TCL_ERROR;
  524.     }
  525.     return SlaveHide(interp, slaveInterp, objc - 3, objv + 3);
  526. }
  527. case OPT_HIDDEN: {
  528.     Tcl_Interp *slaveInterp; /* A slave. */
  529.     slaveInterp = GetInterp2(interp, objc, objv);
  530.     if (slaveInterp == NULL) {
  531. return TCL_ERROR;
  532.     }
  533.     return SlaveHidden(interp, slaveInterp);
  534. }
  535. case OPT_ISSAFE: {
  536.     Tcl_Interp *slaveInterp;
  537.     slaveInterp = GetInterp2(interp, objc, objv);
  538.     if (slaveInterp == NULL) {
  539. return TCL_ERROR;
  540.     }
  541.     Tcl_SetIntObj(Tcl_GetObjResult(interp), Tcl_IsSafe(slaveInterp));
  542.     return TCL_OK;
  543. }
  544. case OPT_INVOKEHID: {
  545.     int i, index, global;
  546.     Tcl_Interp *slaveInterp;
  547.     static CONST char *hiddenOptions[] = {
  548. "-global", "--", NULL
  549.     };
  550.     enum hiddenOption {
  551. OPT_GLOBAL, OPT_LAST
  552.     };
  553.     global = 0;
  554.     for (i = 3; i < objc; i++) {
  555. if (Tcl_GetString(objv[i])[0] != '-') {
  556.     break;
  557. }
  558. if (Tcl_GetIndexFromObj(interp, objv[i], hiddenOptions,
  559. "option", 0, &index) != TCL_OK) {
  560.     return TCL_ERROR;
  561. }
  562. if (index == OPT_GLOBAL) {
  563.     global = 1;
  564. } else {
  565.     i++;
  566.     break;
  567. }
  568.     }
  569.     if (objc - i < 1) {
  570. Tcl_WrongNumArgs(interp, 2, objv,
  571. "path ?-global? ?--? cmd ?arg ..?");
  572. return TCL_ERROR;
  573.     }
  574.     slaveInterp = GetInterp(interp, objv[2]);
  575.     if (slaveInterp == (Tcl_Interp *) NULL) {
  576. return TCL_ERROR;
  577.     }
  578.     return SlaveInvokeHidden(interp, slaveInterp, global, objc - i,
  579.     objv + i);
  580. }
  581. case OPT_MARKTRUSTED: {
  582.     Tcl_Interp *slaveInterp;
  583.     if (objc != 3) {
  584. Tcl_WrongNumArgs(interp, 2, objv, "path");
  585. return TCL_ERROR;
  586.     }
  587.     slaveInterp = GetInterp(interp, objv[2]);
  588.     if (slaveInterp == NULL) {
  589. return TCL_ERROR;
  590.     }
  591.     return SlaveMarkTrusted(interp, slaveInterp);
  592. }
  593. case OPT_RECLIMIT: {
  594.     Tcl_Interp *slaveInterp;
  595.     if (objc != 3 && objc != 4) {
  596. Tcl_WrongNumArgs(interp, 2, objv, "path ?newlimit?");
  597. return TCL_ERROR;
  598.     }
  599.     slaveInterp = GetInterp(interp, objv[2]);
  600.     if (slaveInterp == NULL) {
  601. return TCL_ERROR;
  602.     }
  603.     return SlaveRecursionLimit(interp, slaveInterp, objc - 3, objv + 3);
  604. }
  605. case OPT_SLAVES: {
  606.     Tcl_Interp *slaveInterp;
  607.     InterpInfo *iiPtr;
  608.     Tcl_Obj *resultPtr;
  609.     Tcl_HashEntry *hPtr;
  610.     Tcl_HashSearch hashSearch;
  611.     char *string;
  612.     
  613.     slaveInterp = GetInterp2(interp, objc, objv);
  614.     if (slaveInterp == NULL) {
  615. return TCL_ERROR;
  616.     }
  617.     iiPtr = (InterpInfo *) ((Interp *) slaveInterp)->interpInfo;
  618.     resultPtr = Tcl_GetObjResult(interp);
  619.     hPtr = Tcl_FirstHashEntry(&iiPtr->master.slaveTable, &hashSearch);
  620.     for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&hashSearch)) {
  621. string = Tcl_GetHashKey(&iiPtr->master.slaveTable, hPtr);
  622. Tcl_ListObjAppendElement(NULL, resultPtr,
  623. Tcl_NewStringObj(string, -1));
  624.     }
  625.     return TCL_OK;
  626. }
  627. case OPT_SHARE: {
  628.     Tcl_Interp *slaveInterp; /* A slave. */
  629.     Tcl_Interp *masterInterp; /* Its master. */
  630.     Tcl_Channel chan;
  631.     if (objc != 5) {
  632. Tcl_WrongNumArgs(interp, 2, objv, "srcPath channelId destPath");
  633. return TCL_ERROR;
  634.     }
  635.     masterInterp = GetInterp(interp, objv[2]);
  636.     if (masterInterp == NULL) {
  637. return TCL_ERROR;
  638.     }
  639.     chan = Tcl_GetChannel(masterInterp, Tcl_GetString(objv[3]),
  640.     NULL);
  641.     if (chan == NULL) {
  642. TclTransferResult(masterInterp, TCL_OK, interp);
  643. return TCL_ERROR;
  644.     }
  645.     slaveInterp = GetInterp(interp, objv[4]);
  646.     if (slaveInterp == NULL) {
  647. return TCL_ERROR;
  648.     }
  649.     Tcl_RegisterChannel(slaveInterp, chan);
  650.     return TCL_OK;
  651. }
  652. case OPT_TARGET: {
  653.     Tcl_Interp *slaveInterp;
  654.     InterpInfo *iiPtr;
  655.     Tcl_HashEntry *hPtr;
  656.     Alias *aliasPtr;
  657.     char *aliasName;
  658.     if (objc != 4) {
  659. Tcl_WrongNumArgs(interp, 2, objv, "path alias");
  660. return TCL_ERROR;
  661.     }
  662.     slaveInterp = GetInterp(interp, objv[2]);
  663.     if (slaveInterp == NULL) {
  664. return TCL_ERROR;
  665.     }
  666.     aliasName = Tcl_GetString(objv[3]);
  667.     iiPtr = (InterpInfo *) ((Interp *) slaveInterp)->interpInfo;
  668.     hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName);
  669.     if (hPtr == NULL) {
  670. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  671. "alias "", aliasName, "" in path "",
  672. Tcl_GetString(objv[2]), "" not found",
  673. (char *) NULL);
  674. return TCL_ERROR;
  675.     }
  676.     aliasPtr = (Alias *) Tcl_GetHashValue(hPtr);
  677.     if (Tcl_GetInterpPath(interp, aliasPtr->targetInterp) != TCL_OK) {
  678. Tcl_ResetResult(interp);
  679. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  680. "target interpreter for alias "", aliasName,
  681. "" in path "", Tcl_GetString(objv[2]),
  682. "" is not my descendant", (char *) NULL);
  683. return TCL_ERROR;
  684.     }
  685.     return TCL_OK;
  686. }
  687. case OPT_TRANSFER: {
  688.     Tcl_Interp *slaveInterp; /* A slave. */
  689.     Tcl_Interp *masterInterp; /* Its master. */
  690.     Tcl_Channel chan;
  691.     
  692.     if (objc != 5) {
  693. Tcl_WrongNumArgs(interp, 2, objv,
  694. "srcPath channelId destPath");
  695. return TCL_ERROR;
  696.     }
  697.     masterInterp = GetInterp(interp, objv[2]);
  698.     if (masterInterp == NULL) {
  699. return TCL_ERROR;
  700.     }
  701.     chan = Tcl_GetChannel(masterInterp, Tcl_GetString(objv[3]), NULL);
  702.     if (chan == NULL) {
  703. TclTransferResult(masterInterp, TCL_OK, interp);
  704. return TCL_ERROR;
  705.     }
  706.     slaveInterp = GetInterp(interp, objv[4]);
  707.     if (slaveInterp == NULL) {
  708. return TCL_ERROR;
  709.     }
  710.     Tcl_RegisterChannel(slaveInterp, chan);
  711.     if (Tcl_UnregisterChannel(masterInterp, chan) != TCL_OK) {
  712. TclTransferResult(masterInterp, TCL_OK, interp);
  713. return TCL_ERROR;
  714.     }
  715.     return TCL_OK;
  716. }
  717.     }
  718.     return TCL_OK;
  719. }
  720. /*
  721.  *---------------------------------------------------------------------------
  722.  *
  723.  * GetInterp2 --
  724.  *
  725.  * Helper function for Tcl_InterpObjCmd() to convert the interp name
  726.  * potentially specified on the command line to an Tcl_Interp.
  727.  *
  728.  * Results:
  729.  * The return value is the interp specified on the command line,
  730.  * or the interp argument itself if no interp was specified on the
  731.  * command line.  If the interp could not be found or the wrong
  732.  * number of arguments was specified on the command line, the return
  733.  * value is NULL and an error message is left in the interp's result.
  734.  *
  735.  * Side effects:
  736.  * None.
  737.  *
  738.  *---------------------------------------------------------------------------
  739.  */
  740.  
  741. static Tcl_Interp *
  742. GetInterp2(interp, objc, objv)
  743.     Tcl_Interp *interp; /* Default interp if no interp was specified
  744.  * on the command line. */
  745.     int objc; /* Number of arguments. */
  746.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  747. {
  748.     if (objc == 2) {
  749. return interp;
  750.     } else if (objc == 3) {
  751. return GetInterp(interp, objv[2]);
  752.     } else {
  753. Tcl_WrongNumArgs(interp, 2, objv, "?path?");
  754. return NULL;
  755.     }
  756. }
  757. /*
  758.  *----------------------------------------------------------------------
  759.  *
  760.  * Tcl_CreateAlias --
  761.  *
  762.  * Creates an alias between two interpreters.
  763.  *
  764.  * Results:
  765.  * A standard Tcl result.
  766.  *
  767.  * Side effects:
  768.  * Creates a new alias, manipulates the result field of slaveInterp.
  769.  *
  770.  *----------------------------------------------------------------------
  771.  */
  772. int
  773. Tcl_CreateAlias(slaveInterp, slaveCmd, targetInterp, targetCmd, argc, argv)
  774.     Tcl_Interp *slaveInterp; /* Interpreter for source command. */
  775.     CONST char *slaveCmd; /* Command to install in slave. */
  776.     Tcl_Interp *targetInterp; /* Interpreter for target command. */
  777.     CONST char *targetCmd; /* Name of target command. */
  778.     int argc; /* How many additional arguments? */
  779.     CONST char * CONST *argv; /* These are the additional args. */
  780. {
  781.     Tcl_Obj *slaveObjPtr, *targetObjPtr;
  782.     Tcl_Obj **objv;
  783.     int i;
  784.     int result;
  785.     
  786.     objv = (Tcl_Obj **) ckalloc((unsigned) sizeof(Tcl_Obj *) * argc);
  787.     for (i = 0; i < argc; i++) {
  788.         objv[i] = Tcl_NewStringObj(argv[i], -1);
  789.         Tcl_IncrRefCount(objv[i]);
  790.     }
  791.     
  792.     slaveObjPtr = Tcl_NewStringObj(slaveCmd, -1);
  793.     Tcl_IncrRefCount(slaveObjPtr);
  794.     targetObjPtr = Tcl_NewStringObj(targetCmd, -1);
  795.     Tcl_IncrRefCount(targetObjPtr);
  796.     result = AliasCreate(slaveInterp, slaveInterp, targetInterp, slaveObjPtr,
  797.     targetObjPtr, argc, objv);
  798.     for (i = 0; i < argc; i++) {
  799. Tcl_DecrRefCount(objv[i]);
  800.     }
  801.     ckfree((char *) objv);
  802.     Tcl_DecrRefCount(targetObjPtr);
  803.     Tcl_DecrRefCount(slaveObjPtr);
  804.     return result;
  805. }
  806. /*
  807.  *----------------------------------------------------------------------
  808.  *
  809.  * Tcl_CreateAliasObj --
  810.  *
  811.  * Object version: Creates an alias between two interpreters.
  812.  *
  813.  * Results:
  814.  * A standard Tcl result.
  815.  *
  816.  * Side effects:
  817.  * Creates a new alias.
  818.  *
  819.  *----------------------------------------------------------------------
  820.  */
  821. int
  822. Tcl_CreateAliasObj(slaveInterp, slaveCmd, targetInterp, targetCmd, objc, objv)
  823.     Tcl_Interp *slaveInterp; /* Interpreter for source command. */
  824.     CONST char *slaveCmd; /* Command to install in slave. */
  825.     Tcl_Interp *targetInterp; /* Interpreter for target command. */
  826.     CONST char *targetCmd; /* Name of target command. */
  827.     int objc; /* How many additional arguments? */
  828.     Tcl_Obj *CONST objv[]; /* Argument vector. */
  829. {
  830.     Tcl_Obj *slaveObjPtr, *targetObjPtr;
  831.     int result;
  832.     slaveObjPtr = Tcl_NewStringObj(slaveCmd, -1);
  833.     Tcl_IncrRefCount(slaveObjPtr);
  834.     targetObjPtr = Tcl_NewStringObj(targetCmd, -1);
  835.     Tcl_IncrRefCount(targetObjPtr);
  836.     result = AliasCreate(slaveInterp, slaveInterp, targetInterp, slaveObjPtr,
  837.     targetObjPtr, objc, objv);
  838.     Tcl_DecrRefCount(slaveObjPtr);
  839.     Tcl_DecrRefCount(targetObjPtr);
  840.     return result;
  841. }
  842. /*
  843.  *----------------------------------------------------------------------
  844.  *
  845.  * Tcl_GetAlias --
  846.  *
  847.  * Gets information about an alias.
  848.  *
  849.  * Results:
  850.  * A standard Tcl result. 
  851.  *
  852.  * Side effects:
  853.  * None.
  854.  *
  855.  *----------------------------------------------------------------------
  856.  */
  857. int
  858. Tcl_GetAlias(interp, aliasName, targetInterpPtr, targetNamePtr, argcPtr,
  859.         argvPtr)
  860.     Tcl_Interp *interp; /* Interp to start search from. */
  861.     CONST char *aliasName; /* Name of alias to find. */
  862.     Tcl_Interp **targetInterpPtr; /* (Return) target interpreter. */
  863.     CONST char **targetNamePtr; /* (Return) name of target command. */
  864.     int *argcPtr; /* (Return) count of addnl args. */
  865.     CONST char ***argvPtr; /* (Return) additional arguments. */
  866. {
  867.     InterpInfo *iiPtr;
  868.     Tcl_HashEntry *hPtr;
  869.     Alias *aliasPtr;
  870.     int i, objc;
  871.     Tcl_Obj **objv;
  872.     
  873.     iiPtr = (InterpInfo *) ((Interp *) interp)->interpInfo;
  874.     hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName);
  875.     if (hPtr == NULL) {
  876.         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  877.                 "alias "", aliasName, "" not found", (char *) NULL);
  878. return TCL_ERROR;
  879.     }
  880.     aliasPtr = (Alias *) Tcl_GetHashValue(hPtr);
  881.     objc = aliasPtr->objc;
  882.     objv = &aliasPtr->objPtr;
  883.     if (targetInterpPtr != NULL) {
  884. *targetInterpPtr = aliasPtr->targetInterp;
  885.     }
  886.     if (targetNamePtr != NULL) {
  887. *targetNamePtr = Tcl_GetString(objv[0]);
  888.     }
  889.     if (argcPtr != NULL) {
  890. *argcPtr = objc - 1;
  891.     }
  892.     if (argvPtr != NULL) {
  893.         *argvPtr = (CONST char **) 
  894. ckalloc((unsigned) sizeof(CONST char *) * (objc - 1));
  895.         for (i = 1; i < objc; i++) {
  896.             (*argvPtr)[i - 1] = Tcl_GetString(objv[i]);
  897.         }
  898.     }
  899.     return TCL_OK;
  900. }
  901. /*
  902.  *----------------------------------------------------------------------
  903.  *
  904.  * Tcl_GetAliasObj --
  905.  *
  906.  * Object version: Gets information about an alias.
  907.  *
  908.  * Results:
  909.  * A standard Tcl result.
  910.  *
  911.  * Side effects:
  912.  * None.
  913.  *
  914.  *----------------------------------------------------------------------
  915.  */
  916. int
  917. Tcl_GetAliasObj(interp, aliasName, targetInterpPtr, targetNamePtr, objcPtr,
  918.         objvPtr)
  919.     Tcl_Interp *interp; /* Interp to start search from. */
  920.     CONST char *aliasName; /* Name of alias to find. */
  921.     Tcl_Interp **targetInterpPtr; /* (Return) target interpreter. */
  922.     CONST char **targetNamePtr; /* (Return) name of target command. */
  923.     int *objcPtr; /* (Return) count of addnl args. */
  924.     Tcl_Obj ***objvPtr; /* (Return) additional args. */
  925. {
  926.     InterpInfo *iiPtr;
  927.     Tcl_HashEntry *hPtr;
  928.     Alias *aliasPtr;
  929.     int objc;
  930.     Tcl_Obj **objv;
  931.     iiPtr = (InterpInfo *) ((Interp *) interp)->interpInfo;
  932.     hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName);
  933.     if (hPtr == (Tcl_HashEntry *) NULL) {
  934.         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  935.                 "alias "", aliasName, "" not found", (char *) NULL);
  936.         return TCL_ERROR;
  937.     }
  938.     aliasPtr = (Alias *) Tcl_GetHashValue(hPtr);
  939.     objc = aliasPtr->objc;
  940.     objv = &aliasPtr->objPtr;
  941.     if (targetInterpPtr != (Tcl_Interp **) NULL) {
  942.         *targetInterpPtr = aliasPtr->targetInterp;
  943.     }
  944.     if (targetNamePtr != (CONST char **) NULL) {
  945.         *targetNamePtr = Tcl_GetString(objv[0]);
  946.     }
  947.     if (objcPtr != (int *) NULL) {
  948.         *objcPtr = objc - 1;
  949.     }
  950.     if (objvPtr != (Tcl_Obj ***) NULL) {
  951.         *objvPtr = objv + 1;
  952.     }
  953.     return TCL_OK;
  954. }
  955. /*
  956.  *----------------------------------------------------------------------
  957.  *
  958.  * TclPreventAliasLoop --
  959.  *
  960.  * When defining an alias or renaming a command, prevent an alias
  961.  * loop from being formed.
  962.  *
  963.  * Results:
  964.  * A standard Tcl object result.
  965.  *
  966.  * Side effects:
  967.  * If TCL_ERROR is returned, the function also stores an error message
  968.  * in the interpreter's result object.
  969.  *
  970.  * NOTE:
  971.  * This function is public internal (instead of being static to
  972.  * this file) because it is also used from TclRenameCommand.
  973.  *
  974.  *----------------------------------------------------------------------
  975.  */
  976. int
  977. TclPreventAliasLoop(interp, cmdInterp, cmd)
  978.     Tcl_Interp *interp; /* Interp in which to report errors. */
  979.     Tcl_Interp *cmdInterp; /* Interp in which the command is
  980.                                          * being defined. */
  981.     Tcl_Command cmd;                    /* Tcl command we are attempting
  982.                                          * to define. */
  983. {
  984.     Command *cmdPtr = (Command *) cmd;
  985.     Alias *aliasPtr, *nextAliasPtr;
  986.     Tcl_Command aliasCmd;
  987.     Command *aliasCmdPtr;
  988.     /*
  989.      * If we are not creating or renaming an alias, then it is
  990.      * always OK to create or rename the command.
  991.      */
  992.     
  993.     if (cmdPtr->objProc != AliasObjCmd) {
  994.         return TCL_OK;
  995.     }
  996.     /*
  997.      * OK, we are dealing with an alias, so traverse the chain of aliases.
  998.      * If we encounter the alias we are defining (or renaming to) any in
  999.      * the chain then we have a loop.
  1000.      */
  1001.     aliasPtr = (Alias *) cmdPtr->objClientData;
  1002.     nextAliasPtr = aliasPtr;
  1003.     while (1) {
  1004. Tcl_Obj *cmdNamePtr;
  1005.         /*
  1006.          * If the target of the next alias in the chain is the same as
  1007.          * the source alias, we have a loop.
  1008.  */
  1009. if (Tcl_InterpDeleted(nextAliasPtr->targetInterp)) {
  1010.     /*
  1011.      * The slave interpreter can be deleted while creating the alias.
  1012.      * [Bug #641195]
  1013.      */
  1014.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1015.     "cannot define or rename alias "",
  1016.     Tcl_GetString(aliasPtr->namePtr),
  1017.     "": interpreter deleted", (char *) NULL);
  1018.     return TCL_ERROR;
  1019. }
  1020. cmdNamePtr = nextAliasPtr->objPtr;
  1021. aliasCmd = Tcl_FindCommand(nextAliasPtr->targetInterp,
  1022.                 Tcl_GetString(cmdNamePtr),
  1023. Tcl_GetGlobalNamespace(nextAliasPtr->targetInterp),
  1024. /*flags*/ 0);
  1025.         if (aliasCmd == (Tcl_Command) NULL) {
  1026.             return TCL_OK;
  1027.         }
  1028. aliasCmdPtr = (Command *) aliasCmd;
  1029.         if (aliasCmdPtr == cmdPtr) {
  1030.             Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1031.     "cannot define or rename alias "",
  1032.     Tcl_GetString(aliasPtr->namePtr),
  1033.     "": would create a loop", (char *) NULL);
  1034.             return TCL_ERROR;
  1035.         }
  1036.         /*
  1037.  * Otherwise, follow the chain one step further. See if the target
  1038.          * command is an alias - if so, follow the loop to its target
  1039.          * command. Otherwise we do not have a loop.
  1040.  */
  1041.         if (aliasCmdPtr->objProc != AliasObjCmd) {
  1042.             return TCL_OK;
  1043.         }
  1044.         nextAliasPtr = (Alias *) aliasCmdPtr->objClientData;
  1045.     }
  1046.     /* NOTREACHED */
  1047. }
  1048. /*
  1049.  *----------------------------------------------------------------------
  1050.  *
  1051.  * AliasCreate --
  1052.  *
  1053.  * Helper function to do the work to actually create an alias.
  1054.  *
  1055.  * Results:
  1056.  * A standard Tcl result.
  1057.  *
  1058.  * Side effects:
  1059.  * An alias command is created and entered into the alias table
  1060.  * for the slave interpreter.
  1061.  *
  1062.  *----------------------------------------------------------------------
  1063.  */
  1064. static int
  1065. AliasCreate(interp, slaveInterp, masterInterp, namePtr, targetNamePtr,
  1066. objc, objv)
  1067.     Tcl_Interp *interp; /* Interp for error reporting. */
  1068.     Tcl_Interp *slaveInterp; /* Interp where alias cmd will live or from
  1069.  * which alias will be deleted. */
  1070.     Tcl_Interp *masterInterp; /* Interp in which target command will be
  1071.  * invoked. */
  1072.     Tcl_Obj *namePtr; /* Name of alias cmd. */
  1073.     Tcl_Obj *targetNamePtr; /* Name of target cmd. */
  1074.     int objc; /* Additional arguments to store */
  1075.     Tcl_Obj *CONST objv[]; /* with alias. */
  1076. {
  1077.     Alias *aliasPtr;
  1078.     Tcl_HashEntry *hPtr;
  1079.     Target *targetPtr;
  1080.     Slave *slavePtr;
  1081.     Master *masterPtr;
  1082.     Tcl_Obj **prefv;
  1083.     int new, i;
  1084.     aliasPtr = (Alias *) ckalloc((unsigned) (sizeof(Alias) 
  1085.             + objc * sizeof(Tcl_Obj *)));
  1086.     aliasPtr->namePtr = namePtr;
  1087.     Tcl_IncrRefCount(aliasPtr->namePtr);
  1088.     aliasPtr->targetInterp = masterInterp;
  1089.     aliasPtr->objc = objc + 1;
  1090.     prefv = &aliasPtr->objPtr;
  1091.     *prefv = targetNamePtr;
  1092.     Tcl_IncrRefCount(targetNamePtr);
  1093.     for (i = 0; i < objc; i++) {
  1094. *(++prefv) = objv[i];
  1095. Tcl_IncrRefCount(objv[i]);
  1096.     }
  1097.     Tcl_Preserve(slaveInterp);
  1098.     Tcl_Preserve(masterInterp);
  1099.     aliasPtr->slaveCmd = Tcl_CreateObjCommand(slaveInterp,
  1100.     Tcl_GetString(namePtr), AliasObjCmd, (ClientData) aliasPtr,
  1101.     AliasObjCmdDeleteProc);
  1102.     if (TclPreventAliasLoop(interp, slaveInterp,
  1103.     aliasPtr->slaveCmd) != TCL_OK) {
  1104. /*
  1105.  * Found an alias loop!  The last call to Tcl_CreateObjCommand made
  1106.  * the alias point to itself.  Delete the command and its alias
  1107.  * record.  Be careful to wipe out its client data first, so the
  1108.  * command doesn't try to delete itself.
  1109.  */
  1110. Command *cmdPtr;
  1111. Tcl_DecrRefCount(aliasPtr->namePtr);
  1112. Tcl_DecrRefCount(targetNamePtr);
  1113. for (i = 0; i < objc; i++) {
  1114.     Tcl_DecrRefCount(objv[i]);
  1115. }
  1116. cmdPtr = (Command *) aliasPtr->slaveCmd;
  1117. cmdPtr->clientData = NULL;
  1118. cmdPtr->deleteProc = NULL;
  1119. cmdPtr->deleteData = NULL;
  1120. Tcl_DeleteCommandFromToken(slaveInterp, aliasPtr->slaveCmd);
  1121. ckfree((char *) aliasPtr);
  1122. /*
  1123.  * The result was already set by TclPreventAliasLoop.
  1124.  */
  1125. Tcl_Release(slaveInterp);
  1126. Tcl_Release(masterInterp);
  1127. return TCL_ERROR;
  1128.     }
  1129.     /*
  1130.      * Make an entry in the alias table. If it already exists delete
  1131.      * the alias command. Then retry.
  1132.      */
  1133.     slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave;
  1134.     while (1) {
  1135. Alias *oldAliasPtr;
  1136. char *string;
  1137. string = Tcl_GetString(namePtr);
  1138. hPtr = Tcl_CreateHashEntry(&slavePtr->aliasTable, string, &new);
  1139. if (new != 0) {
  1140.     break;
  1141. }
  1142. oldAliasPtr = (Alias *) Tcl_GetHashValue(hPtr);
  1143. Tcl_DeleteCommandFromToken(slaveInterp, oldAliasPtr->slaveCmd);
  1144.     }
  1145.     aliasPtr->aliasEntryPtr = hPtr;
  1146.     Tcl_SetHashValue(hPtr, (ClientData) aliasPtr);
  1147.     
  1148.     /*
  1149.      * Create the new command. We must do it after deleting any old command,
  1150.      * because the alias may be pointing at a renamed alias, as in:
  1151.      *
  1152.      * interp alias {} foo {} bar # Create an alias "foo"
  1153.      * rename foo zop # Now rename the alias
  1154.      * interp alias {} foo {} zop # Now recreate "foo"...
  1155.      */
  1156.     targetPtr = (Target *) ckalloc((unsigned) sizeof(Target));
  1157.     targetPtr->slaveCmd = aliasPtr->slaveCmd;
  1158.     targetPtr->slaveInterp = slaveInterp;
  1159.     Tcl_MutexLock(&cntMutex);
  1160.     masterPtr = &((InterpInfo *) ((Interp *) masterInterp)->interpInfo)->master;
  1161.     do {
  1162.         hPtr = Tcl_CreateHashEntry(&masterPtr->targetTable,
  1163.                 (char *) aliasCounter, &new);
  1164. aliasCounter++;
  1165.     } while (new == 0);
  1166.     Tcl_MutexUnlock(&cntMutex);
  1167.     Tcl_SetHashValue(hPtr, (ClientData) targetPtr);
  1168.     aliasPtr->targetEntryPtr = hPtr;
  1169.     Tcl_SetObjResult(interp, namePtr);
  1170.     Tcl_Release(slaveInterp);
  1171.     Tcl_Release(masterInterp);
  1172.     return TCL_OK;
  1173. }
  1174. /*
  1175.  *----------------------------------------------------------------------
  1176.  *
  1177.  * AliasDelete --
  1178.  *
  1179.  * Deletes the given alias from the slave interpreter given.
  1180.  *
  1181.  * Results:
  1182.  * A standard Tcl result.
  1183.  *
  1184.  * Side effects:
  1185.  * Deletes the alias from the slave interpreter.
  1186.  *
  1187.  *----------------------------------------------------------------------
  1188.  */
  1189. static int
  1190. AliasDelete(interp, slaveInterp, namePtr)
  1191.     Tcl_Interp *interp; /* Interpreter for result & errors. */
  1192.     Tcl_Interp *slaveInterp; /* Interpreter containing alias. */
  1193.     Tcl_Obj *namePtr; /* Name of alias to delete. */
  1194. {
  1195.     Slave *slavePtr;
  1196.     Alias *aliasPtr;
  1197.     Tcl_HashEntry *hPtr;
  1198.     /*
  1199.      * If the alias has been renamed in the slave, the master can still use
  1200.      * the original name (with which it was created) to find the alias to
  1201.      * delete it.
  1202.      */
  1203.     slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave;
  1204.     hPtr = Tcl_FindHashEntry(&slavePtr->aliasTable, Tcl_GetString(namePtr));
  1205.     if (hPtr == NULL) {
  1206. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "alias "",
  1207. Tcl_GetString(namePtr), "" not found", NULL);
  1208.         return TCL_ERROR;
  1209.     }
  1210.     aliasPtr = (Alias *) Tcl_GetHashValue(hPtr);
  1211.     Tcl_DeleteCommandFromToken(slaveInterp, aliasPtr->slaveCmd);
  1212.     return TCL_OK;
  1213. }
  1214. /*
  1215.  *----------------------------------------------------------------------
  1216.  *
  1217.  * AliasDescribe --
  1218.  *
  1219.  * Sets the interpreter's result object to a Tcl list describing
  1220.  * the given alias in the given interpreter: its target command
  1221.  * and the additional arguments to prepend to any invocation
  1222.  * of the alias.
  1223.  *
  1224.  * Results:
  1225.  * A standard Tcl result.
  1226.  *
  1227.  * Side effects:
  1228.  * None.
  1229.  *
  1230.  *----------------------------------------------------------------------
  1231.  */
  1232. static int
  1233. AliasDescribe(interp, slaveInterp, namePtr)
  1234.     Tcl_Interp *interp; /* Interpreter for result & errors. */
  1235.     Tcl_Interp *slaveInterp; /* Interpreter containing alias. */
  1236.     Tcl_Obj *namePtr; /* Name of alias to describe. */
  1237. {
  1238.     Slave *slavePtr;
  1239.     Tcl_HashEntry *hPtr;
  1240.     Alias *aliasPtr;
  1241.     Tcl_Obj *prefixPtr;
  1242.     /*
  1243.      * If the alias has been renamed in the slave, the master can still use
  1244.      * the original name (with which it was created) to find the alias to
  1245.      * describe it.
  1246.      */
  1247.     slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave;
  1248.     hPtr = Tcl_FindHashEntry(&slavePtr->aliasTable, Tcl_GetString(namePtr));
  1249.     if (hPtr == NULL) {
  1250.         return TCL_OK;
  1251.     }
  1252.     aliasPtr = (Alias *) Tcl_GetHashValue(hPtr);
  1253.     prefixPtr = Tcl_NewListObj(aliasPtr->objc, &aliasPtr->objPtr);
  1254.     Tcl_SetObjResult(interp, prefixPtr);
  1255.     return TCL_OK;
  1256. }
  1257. /*
  1258.  *----------------------------------------------------------------------
  1259.  *
  1260.  * AliasList --
  1261.  *
  1262.  * Computes a list of aliases defined in a slave interpreter.
  1263.  *
  1264.  * Results:
  1265.  * A standard Tcl result.
  1266.  *
  1267.  * Side effects:
  1268.  * None.
  1269.  *
  1270.  *----------------------------------------------------------------------
  1271.  */
  1272. static int
  1273. AliasList(interp, slaveInterp)
  1274.     Tcl_Interp *interp; /* Interp for data return. */
  1275.     Tcl_Interp *slaveInterp; /* Interp whose aliases to compute. */
  1276. {
  1277.     Tcl_HashEntry *entryPtr;
  1278.     Tcl_HashSearch hashSearch;
  1279.     Tcl_Obj *resultPtr;
  1280.     Alias *aliasPtr;
  1281.     Slave *slavePtr;
  1282.     slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave;
  1283.     resultPtr = Tcl_GetObjResult(interp);
  1284.     entryPtr = Tcl_FirstHashEntry(&slavePtr->aliasTable, &hashSearch);
  1285.     for ( ; entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&hashSearch)) {
  1286.         aliasPtr = (Alias *) Tcl_GetHashValue(entryPtr);
  1287.         Tcl_ListObjAppendElement(NULL, resultPtr, aliasPtr->namePtr);
  1288.     }
  1289.     return TCL_OK;
  1290. }
  1291. /*
  1292.  *----------------------------------------------------------------------
  1293.  *
  1294.  * AliasObjCmd --
  1295.  *
  1296.  * This is the procedure that services invocations of aliases in a
  1297.  * slave interpreter. One such command exists for each alias. When
  1298.  * invoked, this procedure redirects the invocation to the target
  1299.  * command in the master interpreter as designated by the Alias
  1300.  * record associated with this command.
  1301.  *
  1302.  * Results:
  1303.  * A standard Tcl result.
  1304.  *
  1305.  * Side effects:
  1306.  * Causes forwarding of the invocation; all possible side effects
  1307.  * may occur as a result of invoking the command to which the
  1308.  * invocation is forwarded.
  1309.  *
  1310.  *----------------------------------------------------------------------
  1311.  */
  1312. static int
  1313. AliasObjCmd(clientData, interp, objc, objv)
  1314.     ClientData clientData; /* Alias record. */
  1315.     Tcl_Interp *interp; /* Current interpreter. */
  1316.     int objc; /* Number of arguments. */
  1317.     Tcl_Obj *CONST objv[]; /* Argument vector. */
  1318. {
  1319. #define ALIAS_CMDV_PREALLOC 10
  1320.     Tcl_Interp *targetInterp;
  1321.     Alias *aliasPtr;
  1322.     int result, prefc, cmdc, i;
  1323.     Tcl_Obj **prefv, **cmdv;
  1324.     Tcl_Obj *cmdArr[ALIAS_CMDV_PREALLOC];
  1325.     aliasPtr = (Alias *) clientData;
  1326.     targetInterp = aliasPtr->targetInterp;
  1327.     /*
  1328.      * Append the arguments to the command prefix and invoke the command
  1329.      * in the target interp's global namespace.
  1330.      */
  1331.      
  1332.     prefc = aliasPtr->objc;
  1333.     prefv = &aliasPtr->objPtr;
  1334.     cmdc = prefc + objc - 1;
  1335.     if (cmdc <= ALIAS_CMDV_PREALLOC) {
  1336. cmdv = cmdArr;
  1337.     } else {
  1338. cmdv = (Tcl_Obj **) ckalloc((unsigned) (cmdc * sizeof(Tcl_Obj *)));
  1339.     }
  1340.     prefv = &aliasPtr->objPtr;
  1341.     memcpy((VOID *) cmdv, (VOID *) prefv, 
  1342.             (size_t) (prefc * sizeof(Tcl_Obj *)));
  1343.     memcpy((VOID *) (cmdv+prefc), (VOID *) (objv+1), 
  1344.     (size_t) ((objc-1) * sizeof(Tcl_Obj *)));
  1345.     Tcl_ResetResult(targetInterp);
  1346.     for (i=0; i<cmdc; i++) {
  1347. Tcl_IncrRefCount(cmdv[i]);
  1348.     }
  1349.     if (targetInterp != interp) {
  1350. Tcl_Preserve((ClientData) targetInterp);
  1351. result = Tcl_EvalObjv(targetInterp, cmdc, cmdv, TCL_EVAL_INVOKE);
  1352. TclTransferResult(targetInterp, result, interp);
  1353. Tcl_Release((ClientData) targetInterp);
  1354.     } else {
  1355. result = Tcl_EvalObjv(targetInterp, cmdc, cmdv, TCL_EVAL_INVOKE);
  1356.     }
  1357.     for (i=0; i<cmdc; i++) {
  1358. Tcl_DecrRefCount(cmdv[i]);
  1359.     }
  1360.     if (cmdv != cmdArr) {
  1361. ckfree((char *) cmdv);
  1362.     }
  1363.     return result;        
  1364. #undef ALIAS_CMDV_PREALLOC
  1365. }
  1366. /*
  1367.  *----------------------------------------------------------------------
  1368.  *
  1369.  * AliasObjCmdDeleteProc --
  1370.  *
  1371.  * Is invoked when an alias command is deleted in a slave. Cleans up
  1372.  * all storage associated with this alias.
  1373.  *
  1374.  * Results:
  1375.  * None.
  1376.  *
  1377.  * Side effects:
  1378.  * Deletes the alias record and its entry in the alias table for
  1379.  * the interpreter.
  1380.  *
  1381.  *----------------------------------------------------------------------
  1382.  */
  1383. static void
  1384. AliasObjCmdDeleteProc(clientData)
  1385.     ClientData clientData; /* The alias record for this alias. */
  1386. {
  1387.     Alias *aliasPtr;
  1388.     Target *targetPtr;
  1389.     int i;
  1390.     Tcl_Obj **objv;
  1391.     aliasPtr = (Alias *) clientData;
  1392.     
  1393.     Tcl_DecrRefCount(aliasPtr->namePtr);
  1394.     objv = &aliasPtr->objPtr;
  1395.     for (i = 0; i < aliasPtr->objc; i++) {
  1396. Tcl_DecrRefCount(objv[i]);
  1397.     }
  1398.     Tcl_DeleteHashEntry(aliasPtr->aliasEntryPtr);
  1399.     targetPtr = (Target *) Tcl_GetHashValue(aliasPtr->targetEntryPtr);
  1400.     ckfree((char *) targetPtr);
  1401.     Tcl_DeleteHashEntry(aliasPtr->targetEntryPtr);
  1402.     ckfree((char *) aliasPtr);
  1403. }
  1404. /*
  1405.  *----------------------------------------------------------------------
  1406.  *
  1407.  * Tcl_CreateSlave --
  1408.  *
  1409.  * Creates a slave interpreter. The slavePath argument denotes the
  1410.  * name of the new slave relative to the current interpreter; the
  1411.  * slave is a direct descendant of the one-before-last component of
  1412.  * the path, e.g. it is a descendant of the current interpreter if
  1413.  * the slavePath argument contains only one component. Optionally makes
  1414.  * the slave interpreter safe.
  1415.  *
  1416.  * Results:
  1417.  * Returns the interpreter structure created, or NULL if an error
  1418.  * occurred.
  1419.  *
  1420.  * Side effects:
  1421.  * Creates a new interpreter and a new interpreter object command in
  1422.  * the interpreter indicated by the slavePath argument.
  1423.  *
  1424.  *----------------------------------------------------------------------
  1425.  */
  1426. Tcl_Interp *
  1427. Tcl_CreateSlave(interp, slavePath, isSafe)
  1428.     Tcl_Interp *interp; /* Interpreter to start search at. */
  1429.     CONST char *slavePath; /* Name of slave to create. */
  1430.     int isSafe; /* Should new slave be "safe" ? */
  1431. {
  1432.     Tcl_Obj *pathPtr;
  1433.     Tcl_Interp *slaveInterp;
  1434.     pathPtr = Tcl_NewStringObj(slavePath, -1);
  1435.     slaveInterp = SlaveCreate(interp, pathPtr, isSafe);
  1436.     Tcl_DecrRefCount(pathPtr);
  1437.     return slaveInterp;
  1438. }
  1439. /*
  1440.  *----------------------------------------------------------------------
  1441.  *
  1442.  * Tcl_GetSlave --
  1443.  *
  1444.  * Finds a slave interpreter by its path name.
  1445.  *
  1446.  * Results:
  1447.  * Returns a Tcl_Interp * for the named interpreter or NULL if not
  1448.  * found.
  1449.  *
  1450.  * Side effects:
  1451.  * None.
  1452.  *
  1453.  *----------------------------------------------------------------------
  1454.  */
  1455. Tcl_Interp *
  1456. Tcl_GetSlave(interp, slavePath)
  1457.     Tcl_Interp *interp; /* Interpreter to start search from. */
  1458.     CONST char *slavePath; /* Path of slave to find. */
  1459. {
  1460.     Tcl_Obj *pathPtr;
  1461.     Tcl_Interp *slaveInterp;
  1462.     pathPtr = Tcl_NewStringObj(slavePath, -1);
  1463.     slaveInterp = GetInterp(interp, pathPtr);
  1464.     Tcl_DecrRefCount(pathPtr);
  1465.     return slaveInterp;
  1466. }
  1467. /*
  1468.  *----------------------------------------------------------------------
  1469.  *
  1470.  * Tcl_GetMaster --
  1471.  *
  1472.  * Finds the master interpreter of a slave interpreter.
  1473.  *
  1474.  * Results:
  1475.  * Returns a Tcl_Interp * for the master interpreter or NULL if none.
  1476.  *
  1477.  * Side effects:
  1478.  * None.
  1479.  *
  1480.  *----------------------------------------------------------------------
  1481.  */
  1482. Tcl_Interp *
  1483. Tcl_GetMaster(interp)
  1484.     Tcl_Interp *interp; /* Get the master of this interpreter. */
  1485. {
  1486.     Slave *slavePtr; /* Slave record of this interpreter. */
  1487.     if (interp == (Tcl_Interp *) NULL) {
  1488.         return NULL;
  1489.     }
  1490.     slavePtr = &((InterpInfo *) ((Interp *) interp)->interpInfo)->slave;
  1491.     return slavePtr->masterInterp;
  1492. }
  1493. /*
  1494.  *----------------------------------------------------------------------
  1495.  *
  1496.  * Tcl_GetInterpPath --
  1497.  *
  1498.  * Sets the result of the asking interpreter to a proper Tcl list
  1499.  * containing the names of interpreters between the asking and
  1500.  * target interpreters. The target interpreter must be either the
  1501.  * same as the asking interpreter or one of its slaves (including
  1502.  * recursively).
  1503.  *
  1504.  * Results:
  1505.  * TCL_OK if the target interpreter is the same as, or a descendant
  1506.  * of, the asking interpreter; TCL_ERROR else. This way one can
  1507.  * distinguish between the case where the asking and target interps
  1508.  * are the same (an empty list is the result, and TCL_OK is returned)
  1509.  * and when the target is not a descendant of the asking interpreter
  1510.  * (in which case the Tcl result is an error message and the function
  1511.  * returns TCL_ERROR).
  1512.  *
  1513.  * Side effects:
  1514.  * None.
  1515.  *
  1516.  *----------------------------------------------------------------------
  1517.  */
  1518. int
  1519. Tcl_GetInterpPath(askingInterp, targetInterp)
  1520.     Tcl_Interp *askingInterp; /* Interpreter to start search from. */
  1521.     Tcl_Interp *targetInterp; /* Interpreter to find. */
  1522. {
  1523.     InterpInfo *iiPtr;
  1524.     
  1525.     if (targetInterp == askingInterp) {
  1526.         return TCL_OK;
  1527.     }
  1528.     if (targetInterp == NULL) {
  1529. return TCL_ERROR;
  1530.     }
  1531.     iiPtr = (InterpInfo *) ((Interp *) targetInterp)->interpInfo;
  1532.     if (Tcl_GetInterpPath(askingInterp, iiPtr->slave.masterInterp) != TCL_OK) {
  1533.         return TCL_ERROR;
  1534.     }
  1535.     Tcl_AppendElement(askingInterp,
  1536.     Tcl_GetHashKey(&iiPtr->master.slaveTable,
  1537.     iiPtr->slave.slaveEntryPtr));
  1538.     return TCL_OK;
  1539. }
  1540. /*
  1541.  *----------------------------------------------------------------------
  1542.  *
  1543.  * GetInterp --
  1544.  *
  1545.  * Helper function to find a slave interpreter given a pathname.
  1546.  *
  1547.  * Results:
  1548.  * Returns the slave interpreter known by that name in the calling
  1549.  * interpreter, or NULL if no interpreter known by that name exists. 
  1550.  *
  1551.  * Side effects:
  1552.  * Assigns to the pointer variable passed in, if not NULL.
  1553.  *
  1554.  *----------------------------------------------------------------------
  1555.  */
  1556. static Tcl_Interp *
  1557. GetInterp(interp, pathPtr)
  1558.     Tcl_Interp *interp; /* Interp. to start search from. */
  1559.     Tcl_Obj *pathPtr; /* List object containing name of interp. to 
  1560.  * be found. */
  1561. {
  1562.     Tcl_HashEntry *hPtr; /* Search element. */
  1563.     Slave *slavePtr; /* Interim slave record. */
  1564.     Tcl_Obj **objv;
  1565.     int objc, i;
  1566.     Tcl_Interp *searchInterp; /* Interim storage for interp. to find. */
  1567.     InterpInfo *masterInfoPtr;
  1568.     if (Tcl_ListObjGetElements(interp, pathPtr, &objc, &objv) != TCL_OK) {
  1569. return NULL;
  1570.     }
  1571.     searchInterp = interp;
  1572.     for (i = 0; i < objc; i++) {
  1573. masterInfoPtr = (InterpInfo *) ((Interp *) searchInterp)->interpInfo;
  1574.         hPtr = Tcl_FindHashEntry(&masterInfoPtr->master.slaveTable,
  1575. Tcl_GetString(objv[i]));
  1576.         if (hPtr == NULL) {
  1577.     searchInterp = NULL;
  1578.     break;
  1579. }
  1580.         slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
  1581.         searchInterp = slavePtr->slaveInterp;
  1582.         if (searchInterp == NULL) {
  1583.     break;
  1584. }
  1585.     }
  1586.     if (searchInterp == NULL) {
  1587. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1588. "could not find interpreter "",
  1589.                 Tcl_GetString(pathPtr), """, (char *) NULL);
  1590.     }
  1591.     return searchInterp;
  1592. }
  1593. /*
  1594.  *----------------------------------------------------------------------
  1595.  *
  1596.  * SlaveCreate --
  1597.  *
  1598.  * Helper function to do the actual work of creating a slave interp
  1599.  * and new object command. Also optionally makes the new slave
  1600.  * interpreter "safe".
  1601.  *
  1602.  * Results:
  1603.  * Returns the new Tcl_Interp * if successful or NULL if not. If failed,
  1604.  * the result of the invoking interpreter contains an error message.
  1605.  *
  1606.  * Side effects:
  1607.  * Creates a new slave interpreter and a new object command.
  1608.  *
  1609.  *----------------------------------------------------------------------
  1610.  */
  1611. static Tcl_Interp *
  1612. SlaveCreate(interp, pathPtr, safe)
  1613.     Tcl_Interp *interp; /* Interp. to start search from. */
  1614.     Tcl_Obj *pathPtr; /* Path (name) of slave to create. */
  1615.     int safe; /* Should we make it "safe"? */
  1616. {
  1617.     Tcl_Interp *masterInterp, *slaveInterp;
  1618.     Slave *slavePtr;
  1619.     InterpInfo *masterInfoPtr;
  1620.     Tcl_HashEntry *hPtr;
  1621.     char *path;
  1622.     int new, objc;
  1623.     Tcl_Obj **objv;
  1624.     if (Tcl_ListObjGetElements(interp, pathPtr, &objc, &objv) != TCL_OK) {
  1625. return NULL;
  1626.     }
  1627.     if (objc < 2) {
  1628. masterInterp = interp;
  1629. path = Tcl_GetString(pathPtr);
  1630.     } else {
  1631. Tcl_Obj *objPtr;
  1632. objPtr = Tcl_NewListObj(objc - 1, objv);
  1633. masterInterp = GetInterp(interp, objPtr);
  1634. Tcl_DecrRefCount(objPtr);
  1635. if (masterInterp == NULL) {
  1636.     return NULL;
  1637. }
  1638. path = Tcl_GetString(objv[objc - 1]);
  1639.     }
  1640.     if (safe == 0) {
  1641. safe = Tcl_IsSafe(masterInterp);
  1642.     }
  1643.     masterInfoPtr = (InterpInfo *) ((Interp *) masterInterp)->interpInfo;
  1644.     hPtr = Tcl_CreateHashEntry(&masterInfoPtr->master.slaveTable, path, &new);
  1645.     if (new == 0) {
  1646.         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1647.                 "interpreter named "", path,
  1648. "" already exists, cannot create", (char *) NULL);
  1649.         return NULL;
  1650.     }
  1651.     slaveInterp = Tcl_CreateInterp();
  1652.     slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave;
  1653.     slavePtr->masterInterp = masterInterp;
  1654.     slavePtr->slaveEntryPtr = hPtr;
  1655.     slavePtr->slaveInterp = slaveInterp;
  1656.     slavePtr->interpCmd = Tcl_CreateObjCommand(masterInterp, path,
  1657.             SlaveObjCmd, (ClientData) slaveInterp, SlaveObjCmdDeleteProc);
  1658.     Tcl_InitHashTable(&slavePtr->aliasTable, TCL_STRING_KEYS);
  1659.     Tcl_SetHashValue(hPtr, (ClientData) slavePtr);
  1660.     Tcl_SetVar(slaveInterp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
  1661.     
  1662.     /*
  1663.      * Inherit the recursion limit.
  1664.      */
  1665.     ((Interp *) slaveInterp)->maxNestingDepth =
  1666. ((Interp *) masterInterp)->maxNestingDepth ;
  1667.     if (safe) {
  1668.         if (Tcl_MakeSafe(slaveInterp) == TCL_ERROR) {
  1669.             goto error;
  1670.         }
  1671.     } else {
  1672.         if (Tcl_Init(slaveInterp) == TCL_ERROR) {
  1673.             goto error;
  1674.         }
  1675. /*
  1676.  * This will create the "memory" command in slave interpreters
  1677.  * if we compiled with TCL_MEM_DEBUG, otherwise it does nothing.
  1678.  */
  1679. Tcl_InitMemory(slaveInterp);
  1680.     }
  1681.     return slaveInterp;
  1682.     error:
  1683.     TclTransferResult(slaveInterp, TCL_ERROR, interp);
  1684.     Tcl_DeleteInterp(slaveInterp);
  1685.     return NULL;
  1686. }
  1687. /*
  1688.  *----------------------------------------------------------------------
  1689.  *
  1690.  * SlaveObjCmd --
  1691.  *
  1692.  * Command to manipulate an interpreter, e.g. to send commands to it
  1693.  * to be evaluated. One such command exists for each slave interpreter.
  1694.  *
  1695.  * Results:
  1696.  * A standard Tcl result.
  1697.  *
  1698.  * Side effects:
  1699.  * See user documentation for details.
  1700.  *
  1701.  *----------------------------------------------------------------------
  1702.  */
  1703. static int
  1704. SlaveObjCmd(clientData, interp, objc, objv)
  1705.     ClientData clientData; /* Slave interpreter. */
  1706.     Tcl_Interp *interp; /* Current interpreter. */
  1707.     int objc; /* Number of arguments. */
  1708.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1709. {
  1710.     Tcl_Interp *slaveInterp;
  1711.     int index;
  1712.     static CONST char *options[] = {
  1713.         "alias", "aliases", "eval", "expose",
  1714.         "hide", "hidden", "issafe", "invokehidden",
  1715.         "marktrusted", "recursionlimit", NULL
  1716.     };
  1717.     enum options {
  1718. OPT_ALIAS, OPT_ALIASES, OPT_EVAL, OPT_EXPOSE,
  1719. OPT_HIDE, OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHIDDEN,
  1720. OPT_MARKTRUSTED, OPT_RECLIMIT
  1721.     };
  1722.     
  1723.     slaveInterp = (Tcl_Interp *) clientData;
  1724.     if (slaveInterp == NULL) {
  1725. panic("SlaveObjCmd: interpreter has been deleted");
  1726.     }
  1727.     if (objc < 2) {
  1728.         Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
  1729.         return TCL_ERROR;
  1730.     }
  1731.     if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0,
  1732.     &index) != TCL_OK) {
  1733. return TCL_ERROR;
  1734.     }
  1735.     switch ((enum options) index) {
  1736. case OPT_ALIAS: {
  1737.     if (objc > 2) {
  1738. if (objc == 3) {
  1739.     return AliasDescribe(interp, slaveInterp, objv[2]);
  1740. }
  1741. if (Tcl_GetString(objv[3])[0] == '') {
  1742.     if (objc == 4) {
  1743. return AliasDelete(interp, slaveInterp, objv[2]);
  1744.     }
  1745. } else {
  1746.     return AliasCreate(interp, slaveInterp, interp, objv[2],
  1747.     objv[3], objc - 4, objv + 4);
  1748. }
  1749.     }
  1750.     Tcl_WrongNumArgs(interp, 2, objv,
  1751.     "aliasName ?targetName? ?args..?");
  1752.             return TCL_ERROR;
  1753. }
  1754. case OPT_ALIASES: {
  1755.     if (objc != 2) {
  1756. Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
  1757. return TCL_ERROR;
  1758.     }
  1759.     return AliasList(interp, slaveInterp);
  1760. }
  1761. case OPT_EVAL: {
  1762.     if (objc < 3) {
  1763. Tcl_WrongNumArgs(interp, 2, objv, "arg ?arg ...?");
  1764. return TCL_ERROR;
  1765.     }
  1766.     return SlaveEval(interp, slaveInterp, objc - 2, objv + 2);
  1767. }
  1768.         case OPT_EXPOSE: {
  1769.     if ((objc < 3) || (objc > 4)) {
  1770. Tcl_WrongNumArgs(interp, 2, objv, "hiddenCmdName ?cmdName?");
  1771. return TCL_ERROR;
  1772.     }
  1773.             return SlaveExpose(interp, slaveInterp, objc - 2, objv + 2);
  1774. }
  1775. case OPT_HIDE: {
  1776.     if ((objc < 3) || (objc > 4)) {
  1777. Tcl_WrongNumArgs(interp, 2, objv, "cmdName ?hiddenCmdName?");
  1778. return TCL_ERROR;
  1779.     }
  1780.             return SlaveHide(interp, slaveInterp, objc - 2, objv + 2);
  1781. }
  1782.         case OPT_HIDDEN: {
  1783.     if (objc != 2) {
  1784. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  1785. return TCL_ERROR;
  1786.     }
  1787.             return SlaveHidden(interp, slaveInterp);
  1788. }
  1789.         case OPT_ISSAFE: {
  1790.     if (objc != 2) {
  1791. Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
  1792. return TCL_ERROR;
  1793.     }
  1794.     Tcl_SetIntObj(Tcl_GetObjResult(interp), Tcl_IsSafe(slaveInterp));
  1795.     return TCL_OK;
  1796. }
  1797.         case OPT_INVOKEHIDDEN: {
  1798.     int global, i, index;
  1799.     static CONST char *hiddenOptions[] = {
  1800. "-global", "--", NULL
  1801.     };
  1802.     enum hiddenOption {
  1803. OPT_GLOBAL, OPT_LAST
  1804.     };
  1805.     global = 0;
  1806.     for (i = 2; i < objc; i++) {
  1807. if (Tcl_GetString(objv[i])[0] != '-') {
  1808.     break;
  1809. }
  1810. if (Tcl_GetIndexFromObj(interp, objv[i], hiddenOptions,
  1811. "option", 0, &index) != TCL_OK) {
  1812.     return TCL_ERROR;
  1813. }
  1814. if (index == OPT_GLOBAL) {
  1815.     global = 1;
  1816. } else {
  1817.     i++;
  1818.     break;
  1819. }
  1820.     }
  1821.     if (objc - i < 1) {
  1822. Tcl_WrongNumArgs(interp, 2, objv,
  1823. "?-global? ?--? cmd ?arg ..?");
  1824. return TCL_ERROR;
  1825.     }
  1826.     return SlaveInvokeHidden(interp, slaveInterp, global, objc - i,
  1827.     objv + i);
  1828. }
  1829. case OPT_MARKTRUSTED: {
  1830.     if (objc != 2) {
  1831. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  1832. return TCL_ERROR;
  1833.     }
  1834.             return SlaveMarkTrusted(interp, slaveInterp);
  1835. }
  1836. case OPT_RECLIMIT: {
  1837.     if (objc != 2 && objc != 3) {
  1838. Tcl_WrongNumArgs(interp, 2, objv, "?newlimit?");
  1839. return TCL_ERROR;
  1840.     }
  1841.     return SlaveRecursionLimit(interp, slaveInterp, objc - 2, objv + 2);
  1842. }
  1843.     }
  1844.     return TCL_ERROR;
  1845. }
  1846. /*
  1847.  *----------------------------------------------------------------------
  1848.  *
  1849.  * SlaveObjCmdDeleteProc --
  1850.  *
  1851.  * Invoked when an object command for a slave interpreter is deleted;
  1852.  * cleans up all state associated with the slave interpreter and destroys
  1853.  * the slave interpreter.
  1854.  *
  1855.  * Results:
  1856.  * None.
  1857.  *
  1858.  * Side effects:
  1859.  * Cleans up all state associated with the slave interpreter and
  1860.  * destroys the slave interpreter.
  1861.  *
  1862.  *----------------------------------------------------------------------
  1863.  */
  1864. static void
  1865. SlaveObjCmdDeleteProc(clientData)
  1866.     ClientData clientData; /* The SlaveRecord for the command. */
  1867. {
  1868.     Slave *slavePtr; /* Interim storage for Slave record. */
  1869.     Tcl_Interp *slaveInterp; /* And for a slave interp. */
  1870.     slaveInterp = (Tcl_Interp *) clientData;
  1871.     slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave;
  1872.     /*
  1873.      * Unlink the slave from its master interpreter.
  1874.      */
  1875.     Tcl_DeleteHashEntry(slavePtr->slaveEntryPtr);
  1876.     /*
  1877.      * Set to NULL so that when the InterpInfo is cleaned up in the slave
  1878.      * it does not try to delete the command causing all sorts of grief.
  1879.      * See SlaveRecordDeleteProc().
  1880.      */
  1881.     slavePtr->interpCmd = NULL;
  1882.     if (slavePtr->slaveInterp != NULL) {
  1883. Tcl_DeleteInterp(slavePtr->slaveInterp);
  1884.     }
  1885. }
  1886. /*
  1887.  *----------------------------------------------------------------------
  1888.  *
  1889.  * SlaveEval --
  1890.  *
  1891.  * Helper function to evaluate a command in a slave interpreter.
  1892.  *
  1893.  * Results:
  1894.  * A standard Tcl result.
  1895.  *
  1896.  * Side effects:
  1897.  * Whatever the command does.
  1898.  *
  1899.  *----------------------------------------------------------------------
  1900.  */
  1901. static int
  1902. SlaveEval(interp, slaveInterp, objc, objv)
  1903.     Tcl_Interp *interp; /* Interp for error return. */
  1904.     Tcl_Interp *slaveInterp; /* The slave interpreter in which command
  1905.  * will be evaluated. */
  1906.     int objc; /* Number of arguments. */
  1907.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1908. {
  1909.     int result;
  1910.     Tcl_Obj *objPtr;
  1911.     
  1912.     Tcl_Preserve((ClientData) slaveInterp);
  1913.     Tcl_AllowExceptions(slaveInterp);
  1914.     if (objc == 1) {
  1915. #ifndef TCL_TIP280
  1916. result = Tcl_EvalObjEx(slaveInterp, objv[0], 0);
  1917. #else
  1918.         /* TIP #280 : Make invoker available to eval'd script */
  1919.         Interp* iPtr = (Interp*) interp;
  1920. result = TclEvalObjEx(slaveInterp, objv[0], 0, iPtr->cmdFramePtr,0);
  1921. #endif
  1922.     } else {
  1923. objPtr = Tcl_ConcatObj(objc, objv);
  1924. Tcl_IncrRefCount(objPtr);
  1925. result = Tcl_EvalObjEx(slaveInterp, objPtr, 0);
  1926. Tcl_DecrRefCount(objPtr);
  1927.     }
  1928.     TclTransferResult(slaveInterp, result, interp);
  1929.     Tcl_Release((ClientData) slaveInterp);
  1930.     return result;
  1931. }
  1932. /*
  1933.  *----------------------------------------------------------------------
  1934.  *
  1935.  * SlaveExpose --
  1936.  *
  1937.  * Helper function to expose a command in a slave interpreter.
  1938.  *
  1939.  * Results:
  1940.  * A standard Tcl result.
  1941.  *
  1942.  * Side effects:
  1943.  * After this call scripts in the slave will be able to invoke
  1944.  * the newly exposed command.
  1945.  *
  1946.  *----------------------------------------------------------------------
  1947.  */
  1948. static int
  1949. SlaveExpose(interp, slaveInterp, objc, objv)
  1950.     Tcl_Interp *interp; /* Interp for error return. */
  1951.     Tcl_Interp *slaveInterp; /* Interp in which command will be exposed. */
  1952.     int objc; /* Number of arguments. */
  1953.     Tcl_Obj *CONST objv[]; /* Argument strings. */
  1954. {
  1955.     char *name;
  1956.     
  1957.     if (Tcl_IsSafe(interp)) {
  1958. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1959. "permission denied: safe interpreter cannot expose commands",
  1960. (char *) NULL);
  1961. return TCL_ERROR;
  1962.     }
  1963.     name = Tcl_GetString(objv[(objc == 1) ? 0 : 1]);
  1964.     if (Tcl_ExposeCommand(slaveInterp, Tcl_GetString(objv[0]),
  1965.     name) != TCL_OK) {
  1966. TclTransferResult(slaveInterp, TCL_ERROR, interp);
  1967. return TCL_ERROR;
  1968.     }
  1969.     return TCL_OK;
  1970. }
  1971. /*
  1972.  *----------------------------------------------------------------------
  1973.  *
  1974.  * SlaveRecursionLimit --
  1975.  *
  1976.  * Helper function to set/query the Recursion limit of an interp
  1977.  *
  1978.  * Results:
  1979.  * A standard Tcl result.
  1980.  *
  1981.  * Side effects:
  1982.  *      When (objc == 1), slaveInterp will be set to a new recursion
  1983.  * limit of objv[0].
  1984.  *
  1985.  *----------------------------------------------------------------------
  1986.  */
  1987. static int
  1988. SlaveRecursionLimit(interp, slaveInterp, objc, objv)
  1989.     Tcl_Interp *interp; /* Interp for error return. */
  1990.     Tcl_Interp *slaveInterp; /* Interp in which limit is set/queried. */
  1991.     int objc; /* Set or Query. */
  1992.     Tcl_Obj *CONST objv[]; /* Argument strings. */
  1993. {
  1994.     Interp *iPtr;
  1995.     int limit;
  1996.     if (objc) {
  1997. if (Tcl_IsSafe(interp)) {
  1998.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1999.     "permission denied: ",
  2000.     "safe interpreters cannot change recursion limit",
  2001.     (char *) NULL);
  2002.     return TCL_ERROR;
  2003. }
  2004. if (Tcl_GetIntFromObj(interp, objv[0], &limit) == TCL_ERROR) {
  2005.     return TCL_ERROR;
  2006. }
  2007. if (limit <= 0) {
  2008.     Tcl_SetObjResult(interp, Tcl_NewStringObj(
  2009.     "recursion limit must be > 0", -1));
  2010.     return TCL_ERROR;
  2011. }
  2012. Tcl_SetRecursionLimit(slaveInterp, limit);
  2013. iPtr = (Interp *) slaveInterp;
  2014. if (interp == slaveInterp && iPtr->numLevels > limit) {
  2015.     Tcl_SetObjResult(interp, Tcl_NewStringObj(
  2016.     "falling back due to new recursion limit", -1));
  2017.     return TCL_ERROR;
  2018. }
  2019. Tcl_SetObjResult(interp, objv[0]);
  2020.         return TCL_OK;
  2021.     } else {
  2022. limit = Tcl_SetRecursionLimit(slaveInterp, 0);
  2023. Tcl_SetObjResult(interp, Tcl_NewIntObj(limit));
  2024.         return TCL_OK;
  2025.     }
  2026. }
  2027. /*
  2028.  *----------------------------------------------------------------------
  2029.  *
  2030.  * SlaveHide --
  2031.  *
  2032.  * Helper function to hide a command in a slave interpreter.
  2033.  *
  2034.  * Results:
  2035.  * A standard Tcl result.
  2036.  *
  2037.  * Side effects:
  2038.  * After this call scripts in the slave will no longer be able
  2039.  * to invoke the named command.
  2040.  *
  2041.  *----------------------------------------------------------------------
  2042.  */
  2043. static int
  2044. SlaveHide(interp, slaveInterp, objc, objv)
  2045.     Tcl_Interp *interp; /* Interp for error return. */
  2046.     Tcl_Interp *slaveInterp; /* Interp in which command will be exposed. */
  2047.     int objc; /* Number of arguments. */
  2048.     Tcl_Obj *CONST objv[]; /* Argument strings. */
  2049. {
  2050.     char *name;
  2051.     
  2052.     if (Tcl_IsSafe(interp)) {
  2053. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  2054. "permission denied: safe interpreter cannot hide commands",
  2055. (char *) NULL);
  2056. return TCL_ERROR;
  2057.     }
  2058.     name = Tcl_GetString(objv[(objc == 1) ? 0 : 1]);
  2059.     if (Tcl_HideCommand(slaveInterp, Tcl_GetString(objv[0]),
  2060.     name) != TCL_OK) {
  2061. TclTransferResult(slaveInterp, TCL_ERROR, interp);
  2062. return TCL_ERROR;
  2063.     }
  2064.     return TCL_OK;
  2065. }
  2066. /*
  2067.  *----------------------------------------------------------------------
  2068.  *
  2069.  * SlaveHidden --
  2070.  *
  2071.  * Helper function to compute list of hidden commands in a slave
  2072.  * interpreter.
  2073.  *
  2074.  * Results:
  2075.  * A standard Tcl result.
  2076.  *
  2077.  * Side effects:
  2078.  * None.
  2079.  *
  2080.  *----------------------------------------------------------------------
  2081.  */
  2082. static int
  2083. SlaveHidden(interp, slaveInterp)
  2084.     Tcl_Interp *interp; /* Interp for data return. */
  2085.     Tcl_Interp *slaveInterp; /* Interp whose hidden commands to query. */
  2086. {
  2087.     Tcl_Obj *listObjPtr; /* Local object pointer. */
  2088.     Tcl_HashTable *hTblPtr; /* For local searches. */
  2089.     Tcl_HashEntry *hPtr; /* For local searches. */
  2090.     Tcl_HashSearch hSearch; /* For local searches. */
  2091.     
  2092.     listObjPtr = Tcl_GetObjResult(interp);
  2093.     hTblPtr = ((Interp *) slaveInterp)->hiddenCmdTablePtr;
  2094.     if (hTblPtr != (Tcl_HashTable *) NULL) {
  2095. for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
  2096.      hPtr != (Tcl_HashEntry *) NULL;
  2097.      hPtr = Tcl_NextHashEntry(&hSearch)) {
  2098.     Tcl_ListObjAppendElement(NULL, listObjPtr,
  2099.     Tcl_NewStringObj(Tcl_GetHashKey(hTblPtr, hPtr), -1));
  2100. }
  2101.     }
  2102.     return TCL_OK;
  2103. }
  2104. /*
  2105.  *----------------------------------------------------------------------
  2106.  *
  2107.  * SlaveInvokeHidden --
  2108.  *
  2109.  * Helper function to invoke a hidden command in a slave interpreter.
  2110.  *
  2111.  * Results:
  2112.  * A standard Tcl result.
  2113.  *
  2114.  * Side effects:
  2115.  * Whatever the hidden command does.
  2116.  *
  2117.  *----------------------------------------------------------------------
  2118.  */
  2119. static int
  2120. SlaveInvokeHidden(interp, slaveInterp, global, objc, objv)
  2121.     Tcl_Interp *interp; /* Interp for error return. */
  2122.     Tcl_Interp *slaveInterp; /* The slave interpreter in which command
  2123.  * will be invoked. */
  2124.     int global; /* Non-zero to invoke in global namespace. */
  2125.     int objc; /* Number of arguments. */
  2126.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  2127. {
  2128.     int result;
  2129.     
  2130.     if (Tcl_IsSafe(interp)) {
  2131. Tcl_SetStringObj(Tcl_GetObjResult(interp),
  2132. "not allowed to invoke hidden commands from safe interpreter",
  2133. -1);
  2134. return TCL_ERROR;
  2135.     }
  2136.     Tcl_Preserve((ClientData) slaveInterp);
  2137.     Tcl_AllowExceptions(slaveInterp);
  2138.     
  2139.     if (global) {
  2140.         result = TclObjInvokeGlobal(slaveInterp, objc, objv,
  2141.                 TCL_INVOKE_HIDDEN);
  2142.     } else {
  2143.         result = TclObjInvoke(slaveInterp, objc, objv, TCL_INVOKE_HIDDEN);
  2144.     }
  2145.     TclTransferResult(slaveInterp, result, interp);
  2146.     Tcl_Release((ClientData) slaveInterp);
  2147.     return result;        
  2148. }
  2149. /*
  2150.  *----------------------------------------------------------------------
  2151.  *
  2152.  * SlaveMarkTrusted --
  2153.  *
  2154.  * Helper function to mark a slave interpreter as trusted (unsafe).
  2155.  *
  2156.  * Results:
  2157.  * A standard Tcl result.
  2158.  *
  2159.  * Side effects:
  2160.  * After this call the hard-wired security checks in the core no
  2161.  * longer prevent the slave from performing certain operations.
  2162.  *
  2163.  *----------------------------------------------------------------------
  2164.  */
  2165. static int
  2166. SlaveMarkTrusted(interp, slaveInterp)
  2167.     Tcl_Interp *interp; /* Interp for error return. */
  2168.     Tcl_Interp *slaveInterp; /* The slave interpreter which will be
  2169.  * marked trusted. */
  2170. {
  2171.     if (Tcl_IsSafe(interp)) {
  2172. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  2173. "permission denied: safe interpreter cannot mark trusted",
  2174. (char *) NULL);
  2175. return TCL_ERROR;
  2176.     }
  2177.     ((Interp *) slaveInterp)->flags &= ~SAFE_INTERP;
  2178.     return TCL_OK;
  2179. }
  2180. /*
  2181.  *----------------------------------------------------------------------
  2182.  *
  2183.  * Tcl_IsSafe --
  2184.  *
  2185.  * Determines whether an interpreter is safe
  2186.  *
  2187.  * Results:
  2188.  * 1 if it is safe, 0 if it is not.
  2189.  *
  2190.  * Side effects:
  2191.  * None.
  2192.  *
  2193.  *----------------------------------------------------------------------
  2194.  */
  2195. int
  2196. Tcl_IsSafe(interp)
  2197.     Tcl_Interp *interp; /* Is this interpreter "safe" ? */
  2198. {
  2199.     Interp *iPtr;
  2200.     if (interp == (Tcl_Interp *) NULL) {
  2201.         return 0;
  2202.     }
  2203.     iPtr = (Interp *) interp;
  2204.     return ( (iPtr->flags) & SAFE_INTERP ) ? 1 : 0 ;
  2205. }
  2206. /*
  2207.  *----------------------------------------------------------------------
  2208.  *
  2209.  * Tcl_MakeSafe --
  2210.  *
  2211.  * Makes its argument interpreter contain only functionality that is
  2212.  * defined to be part of Safe Tcl. Unsafe commands are hidden, the
  2213.  * env array is unset, and the standard channels are removed.
  2214.  *
  2215.  * Results:
  2216.  * None.
  2217.  *
  2218.  * Side effects:
  2219.  * Hides commands in its argument interpreter, and removes settings
  2220.  * and channels.
  2221.  *
  2222.  *----------------------------------------------------------------------
  2223.  */
  2224. int
  2225. Tcl_MakeSafe(interp)
  2226.     Tcl_Interp *interp; /* Interpreter to be made safe. */
  2227. {
  2228.     Tcl_Channel chan; /* Channel to remove from
  2229.                                                  * safe interpreter. */
  2230.     Interp *iPtr = (Interp *) interp;
  2231.     TclHideUnsafeCommands(interp);
  2232.     
  2233.     iPtr->flags |= SAFE_INTERP;
  2234.     /*
  2235.      *  Unsetting variables : (which should not have been set 
  2236.      *  in the first place, but...)
  2237.      */
  2238.     /*
  2239.      * No env array in a safe slave.
  2240.      */
  2241.     Tcl_UnsetVar(interp, "env", TCL_GLOBAL_ONLY);
  2242.     /* 
  2243.      * Remove unsafe parts of tcl_platform
  2244.      */
  2245.     Tcl_UnsetVar2(interp, "tcl_platform", "os", TCL_GLOBAL_ONLY);
  2246.     Tcl_UnsetVar2(interp, "tcl_platform", "osVersion", TCL_GLOBAL_ONLY);
  2247.     Tcl_UnsetVar2(interp, "tcl_platform", "machine", TCL_GLOBAL_ONLY);
  2248.     Tcl_UnsetVar2(interp, "tcl_platform", "user", TCL_GLOBAL_ONLY);
  2249.     /*
  2250.      * Unset path informations variables
  2251.      * (the only one remaining is [info nameofexecutable])
  2252.      */
  2253.     Tcl_UnsetVar(interp, "tclDefaultLibrary", TCL_GLOBAL_ONLY);
  2254.     Tcl_UnsetVar(interp, "tcl_library", TCL_GLOBAL_ONLY);
  2255.     Tcl_UnsetVar(interp, "tcl_pkgPath", TCL_GLOBAL_ONLY);
  2256.     
  2257.     /*
  2258.      * Remove the standard channels from the interpreter; safe interpreters
  2259.      * do not ordinarily have access to stdin, stdout and stderr.
  2260.      *
  2261.      * NOTE: These channels are not added to the interpreter by the
  2262.      * Tcl_CreateInterp call, but may be added later, by another I/O
  2263.      * operation. We want to ensure that the interpreter does not have
  2264.      * these channels even if it is being made safe after being used for
  2265.      * some time..
  2266.      */
  2267.     chan = Tcl_GetStdChannel(TCL_STDIN);
  2268.     if (chan != (Tcl_Channel) NULL) {
  2269.         Tcl_UnregisterChannel(interp, chan);
  2270.     }
  2271.     chan = Tcl_GetStdChannel(TCL_STDOUT);
  2272.     if (chan != (Tcl_Channel) NULL) {
  2273.         Tcl_UnregisterChannel(interp, chan);
  2274.     }
  2275.     chan = Tcl_GetStdChannel(TCL_STDERR);
  2276.     if (chan != (Tcl_Channel) NULL) {
  2277.         Tcl_UnregisterChannel(interp, chan);
  2278.     }
  2279.     return TCL_OK;
  2280. }