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