/*
* tclInterp.c --
*
* This file implements the "interp" command which allows creation
* and manipulation of Tcl interpreters from within Tcl scripts.
*
* Copyright (c) 1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tclInterp.c 1.79 96/09/20 17:20:16
*/
#include <ast.h>
#include <stdio.h>
#include "tclInt.h"
#include "tclPort.h"
/*
* Counter for how many aliases were created (global)
*/
static int aliasCounter = 0;
/*
*
* struct Slave:
*
* Used by the "interp" command to record and find information about slave
* interpreters. Maps from a command name in the master to information about
* a slave interpreter, e.g. what aliases are defined in it.
*/
typedef struct {
* this slave interpreter. Used to find
* this record, and used when deleting the
* slave interpreter to delete it from the
* masters table. */
* in slave interpreter to struct Alias
* defined below. */
} Slave;
/*
* struct Alias:
*
* Stores information about an alias. Is stored in the slave interpreter
* and used by the source command to find the target command in the master
* when the source command is invoked.
*/
typedef struct {
* This is used by alias deletion to remove
* the alias from the slave interpreter
* alias table. */
* This is used in the master interpreter to
* map back from the target command to aliases
* redirecting to it. Random access to this
* hash table is never required - we are using
* a hash table only for convenience. */
} Alias;
/*
* struct Target:
*
* Maps from master interpreter commands back to the source commands in slave
* interpreters. This is needed because aliases can be created between sibling
* interpreters and must be deleted when the target interpreter is deleted. In
* case they would not be deleted the source interpreter would be left with a
* "dangling pointer". One such record is stored in the Master record of the
* master interpreter (in the targetTable hashtable, see below) with the
* master for each alias which directs to a command in the master. These
* the master is deleted.
*/
typedef struct {
} Target;
/*
* struct Master:
*
* This record is used for three purposes: First, slaveTable (a hashtable)
* maps from names of commands to slave interpreters. This hashtable is
* used to store information about slave interpreters of this interpreter,
* to map over all slaves, etc. The second purpose is to store information
* about all aliases in slaves (or siblings) which direct to target commands
* in this interpreter (using the targetTable hashtable). The third field in
* the record, isSafe, denotes whether the interpreter is safe or not. Safe
* interpreters have restricted functionality, can only create safe slave
* interpreters and can only load safe extensions.
*/
typedef struct {
* Maps from command names to Slave records. */
* all Target records which denote aliases
* from slaves or sibling interpreters that
* direct to commands in this interpreter. This
* table is used to remove dangling pointers
* from the slave (or sibling) interpreters
* when this interpreter is deleted. */
} Master;
/*
* Prototypes for local static procedures:
*/
static void AliasCmdDeleteProc _ANSI_ARGS_((
char *path));
Master **masterPtrPtr));
char *aliasName));
static void MasterRecordDeleteProc _ANSI_ARGS_((
static void SlaveObjectDeleteProc _ANSI_ARGS_((
static void SlaveRecordDeleteProc _ANSI_ARGS_((
/*
* These are all the Tcl core commands which are available in a safe
* interpeter:
*/
static char *TclCommandsToKeep[] = {
"after", "append", "array",
"break",
"case", "catch", "clock", "close", "concat", "continue",
"eof", "error", "eval", "expr",
"fblocked", "fileevent", "flush", "for", "foreach", "format",
"gets", "global",
"history",
"if", "incr", "info", "interp",
"join",
"lappend", "lindex", "linsert", "list", "llength",
"lower", "lrange", "lreplace", "lsearch", "lsort",
"package", "pid", "proc", "puts",
"read", "regexp", "regsub", "rename", "return",
"scan", "seek", "set", "split", "string", "subst", "switch",
"tell", "time", "trace",
"unset", "unsupported0", "update", "uplevel", "upvar",
"vwait",
"while",
NULL};
static int TclCommandsToKeepCt =
(sizeof (TclCommandsToKeep) / sizeof (char *)) -1 ;
/*
*----------------------------------------------------------------------
*
* TclPreventAliasLoop --
*
* When defining an alias or renaming a command, prevent an alias
* loop from being formed.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* If TCL_ERROR is returned, the function also sets interp->result
* to an error message.
*
* NOTE:
* This function is public internal (instead of being static to
* this file) because it is also used from Tcl_RenameCmd.
*
*----------------------------------------------------------------------
*/
int
* being defined. */
char *cmdName; /* Name of Tcl command we are
* attempting to define. */
* command being created. */
* command to be created. */
{
/*
* If we are not creating or renaming an alias, then it is
* always OK to create or rename the command.
*/
return TCL_OK;
}
/*
* OK, we are dealing with an alias, so traverse the chain of aliases.
* If we encounter the alias we are defining (or renaming to) any in
* the chain then we have a loop.
*/
while (1) {
/*
* If the target of the next alias in the chain is the same as the
* source alias, we have a loop.
*/
(char *) NULL);
return TCL_ERROR;
}
/*
* Otherwise, follow the chain one step further. If the target
* command is undefined then there is no loop.
*/
return TCL_OK;
}
/*
* See if the target command is an alias - if so, follow the
* loop to its target command. Otherwise we do not have a loop.
*/
return TCL_OK;
}
}
/* NOTREACHED */
}
/*
*----------------------------------------------------------------------
*
* MakeSafe --
*
* Makes its argument interpreter contain only functionality that is
* defined to be part of Safe Tcl.
*
* Results:
* None.
*
* Side effects:
* Removes commands from its argument interpreter.
*
*----------------------------------------------------------------------
*/
static int
{
* to be made safe. */
* safe interpreter. */
/*
* Below, Tcl_Eval sets interp->result, so we do not.
*/
return TCL_ERROR;
}
for (i = 0; i < argc; i++) {
for (keep = 0, j = 0; j < TclCommandsToKeepCt; j++) {
keep = 1;
break;
}
}
if (keep == 0) {
}
}
NULL);
panic("MakeSafe: could not find master record");
}
return TCL_ERROR;
}
/*
* Remove the standard channels from the interpreter; safe interpreters
* do not ordinarily have access to stdin, stdout and stderr.
*
* NOTE: These channels are not added to the interpreter by the
* Tcl_CreateInterp call, but may be added later, by another I/O
* operation. We want to ensure that the interpreter does not have
* these channels even if it is being made safe after being used for
* some time..
*/
}
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* GetInterp --
*
* Helper function to find a slave interpreter given a pathname.
*
* Results:
* Returns the slave interpreter known by that name in the calling
* interpreter, or NULL if no interpreter known by that name exists.
*
* Side effects:
* Assigns to the pointer variable passed in, if not NULL.
*
*----------------------------------------------------------------------
*/
static Tcl_Interp *
char *path; /* The path (name) of interp. to be found. */
{
return (Tcl_Interp *) NULL;
}
return (Tcl_Interp *) NULL;
}
return (Tcl_Interp *) NULL;
}
"tclMasterRecord", NULL);
return (Tcl_Interp *) NULL;
}
}
return searchInterp;
}
/*
*----------------------------------------------------------------------
*
* CreateSlave --
*
* Helper function to do the actual work of creating a slave interp
* and new object command. Also optionally makes the new slave
* interpreter "safe".
*
* Results:
* Returns the new Tcl_Interp * if successful or NULL if not. If failed,
* the result of the invoking interpreter contains an error message.
*
* Side effects:
* Creates a new slave interpreter and a new object command.
*
*----------------------------------------------------------------------
*/
static Tcl_Interp *
char *slavePath; /* Path (name) of slave to create. */
int safe; /* Should we make it "safe"? */
{
NULL);
panic("CreatSlave: could not find master record");
}
return (Tcl_Interp *) NULL;
}
if (argc < 2) {
if (argc == 1) {
}
} else {
"\" not found", (char *) NULL);
ckfree((char *) masterPath);
return (Tcl_Interp *) NULL;
}
ckfree((char *) masterPath);
if (!safe) {
}
}
if (new == 0) {
"\" already exists, cannot create", (char *) NULL);
return (Tcl_Interp *) NULL;
}
panic("CreateSlave: out of memory while creating a new interpreter");
}
NULL, TCL_GLOBAL_ONLY));
slaveInterp->freeProc = 0;
} else {
}
}
return slaveInterp;
}
/*
*----------------------------------------------------------------------
*
* CreateInterpObject -
*
* Helper function to do the actual work of creating a new interpreter
* and an object command.
*
* Results:
* A Tcl result.
*
* Side effects:
* See user documentation for details.
*
*----------------------------------------------------------------------
*/
static int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int i; /* Loop counter. */
panic("CreateInterpObject: could not find master record");
}
moreFlags = 1;
" create ?-safe? ?--? ?path?\"", (char *) NULL);
return TCL_ERROR;
}
for (i = 2; i < argc; i++) {
&& (len > 1)){
safe = 1;
moreFlags = 0;
} else {
"\": should be -safe", (char *) NULL);
return TCL_ERROR;
}
} else {
}
}
}
return TCL_OK;
} else {
/*
* CreateSlave already set interp->result if there was an error,
* so we do not do it here.
*/
return TCL_ERROR;
}
}
/*
*----------------------------------------------------------------------
*
* DeleteOneInterpObject --
*
* Helper function for DeleteInterpObject. It deals with deleting one
* interpreter at a time.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Deletes an interpreter and its interpreter object command.
*
*----------------------------------------------------------------------
*/
static int
char *path; /* Path of interpreter to delete. */
{
* path (name) of interp. to delete. */
panic("DeleteInterpObject: could not find master record");
}
"\"", (char *) NULL);
return TCL_ERROR;
}
if (localArgc < 2) {
if (localArgc == 0) {
slaveName = "";
} else {
}
} else {
"\" not found", (char *) NULL);
ckfree((char *) masterPath);
return TCL_ERROR;
}
ckfree((char *) masterPath);
}
"\" not found", (char *) NULL);
return TCL_ERROR;
}
"\" not found", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* DeleteInterpObject --
*
* Helper function to do the work of deleting zero or more
* interpreters and their interpreter object commands.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Deletes interpreters and their interpreter object command.
*
*----------------------------------------------------------------------
*/
static int
int argc; /* Number of arguments in vector. */
char **argv; /* Contains path to interps to
* delete. */
{
int i;
for (i = 2; i < argc; i++) {
return TCL_ERROR;
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* AliasHelper --
*
* Helper function to do the work to actually create an alias or
* delete an alias.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* An alias command is created and entered into the alias table
* for the slave interpreter.
*
*----------------------------------------------------------------------
*/
static int
* or from which alias will be
* deleted. */
char *aliasName; /* Name of alias cmd. */
char *targetName; /* Name of target cmd. */
int argc; /* Additional arguments to store */
char **argv; /* with alias. */
{
* to delete. */
int i; /* Loop index. */
* to source command in slave. */
* to target command in master. */
/*
* Fix it up if there is no slave record. This can happen if someone
* uses "" as the source for an alias.
*/
}
if (argc != 0) {
return TCL_ERROR;
}
}
for (i = 0; i < argc; i++) {
}
}
for (i = 0; i < argc; i++) {
}
}
return TCL_ERROR;
}
/*
* Make an entry in the alias table. If it already exists delete
* the alias command. Then retry.
*/
do {
if (new == 0) {
/*
* The hash entry should be deleted by the Tcl_DeleteCommand
* above, in its command deletion callback (most likely this
* will be AliasCmdDeleteProc, which does the deletion).
*/
}
} while (new == 0);
/*
* Create the new command. We must do it after deleting any old command,
* because the alias may be pointing at a renamed alias, as in:
*
* interp alias {} foo {} bar # Create an alias "foo"
* rename foo zop # Now rename the alias
* interp alias {} foo {} zop # Now recreate "foo"...
*/
do {
(char *) aliasCounter, &new);
aliasCounter++;
} while (new == 0);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* SlaveAliasHelper -
*
* Handles the different forms of the "interp alias" command:
* - interp alias slavePath aliasName
* Describes an alias.
* - interp alias slavePath aliasName {}
* Deletes an alias.
* - interp alias slavePath srcCmd masterPath targetCmd args...
* Creates an alias.
*
* Results:
* A Tcl result.
*
* Side effects:
* See user documentation for details.
*
*----------------------------------------------------------------------
*/
static int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
panic("SlaveAliasHelper: could not find master record");
}
if (argc < 4) {
" alias slavePath slaveCmd masterPath masterCmd ?args ..?\"",
(char *) NULL);
return TCL_ERROR;
}
return TCL_ERROR;
}
if (argc == 4) {
}
}
if (argc < 6) {
" alias slavePath slaveCmd masterPath masterCmd ?args ..?\"",
(char *) NULL);
return TCL_ERROR;
}
return TCL_ERROR;
}
}
/*
*----------------------------------------------------------------------
*
* DescribeAlias --
*
* Sets interp->result to a Tcl list describing the given alias in the
* given interpreter: its target command and the additional arguments
* to prepend to any invocation of the alias.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
char *aliasName; /* Name of alias to describe. */
{
int i; /* Loop variable. */
NULL);
/*
* It's possible that the interpreter still does not have a slave
* record. If so, create such a record now. This is only possible
* for interpreters that were created with Tcl_CreateInterp, not
* those created with Tcl_CreateSlave, so this interpreter does
* not have a master.
*/
}
return TCL_OK;
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* DeleteAlias --
*
* Deletes the given alias from the slave interpreter given.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Deletes the alias from the slave interpreter.
*
*----------------------------------------------------------------------
*/
static int
char *aliasName; /* Name of alias to delete. */
{
NULL);
(char *) NULL);
return TCL_ERROR;
}
/*
* Get the alias from the alias table, determine the current
* true name of the alias (it may have been renamed!) and then
* delete the true command name. The deleteProc on the alias
* command will take care of removing the entry from the alias
* table.
*/
(char *) NULL);
return TCL_ERROR;
}
/*
* NOTE: The deleteProc for this command will delete the
* alias from the hash table. The deleteProc will also
* delete the target information from the master interpreter
* target table.
*/
panic("DeleteAlias: did not find alias to be deleted");
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetInterpPath --
*
* Sets the result of the asking interpreter to a proper Tcl list
* containing the names of interpreters between the asking and
* target interpreters. The target interpreter must be either the
* same as the asking interpreter or one of its slaves (including
* recursively).
*
* Results:
* TCL_OK if the target interpreter is the same as, or a descendant
* of, the asking interpreter; TCL_ERROR else. This way one can
* distinguish between the case where the asking and target interps
* are the same (an empty list is the result, and TCL_OK is returned)
* and when the target is not a descendant of the asking interpreter
* (in which case the Tcl result is an error message and the function
* returns TCL_ERROR).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
{
if (targetInterp == askingInterp) {
return TCL_OK;
}
return TCL_ERROR;
}
NULL);
return TCL_ERROR;
}
/*
* AskingInterp->result was set by recursive call.
*/
return TCL_ERROR;
}
"tclMasterRecord", NULL);
panic("Tcl_GetInterpPath: could not find master record");
}
slavePtr->slaveEntry));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* GetTarget --
*
* Sets the result of the invoking interpreter to a path name for
* the target interpreter of an alias in one of the slaves.
*
* Results:
* TCL_OK if the target interpreter of the alias is a slave of the
* invoking interpreter, TCL_ERROR else.
*
* Side effects:
* Sets the result of the invoking interpreter.
*
*----------------------------------------------------------------------
*/
static int
char *path; /* The path of the interp to find. */
char *aliasName; /* The target of this allias. */
{
NULL);
panic("GetTarget: could not find master record");
}
return TCL_ERROR;
}
NULL);
panic("GetTarget: could not find slave record");
}
return TCL_ERROR;
}
panic("GetTarget: could not find alias record");
}
(char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_InterpCmd --
*
* This procedure is invoked to process the "interp" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
if (argc < 2) {
" cmd ?arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
panic("Tcl_InterpCmd: could not find master record");
}
if (cmdName[0] == 'a') {
}
return TCL_ERROR;
}
if (argc == 3) {
return TCL_ERROR;
}
} else {
}
"tclSlaveRecord", NULL);
return TCL_OK;
}
}
return TCL_OK;
}
}
}
}
if (cmdName[0] == 'e') {
if (argc < 4) {
" eval path arg ?arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
"\" not found", (char *) NULL);
return TCL_ERROR;
}
/*
* Now make the result and any error information accessible. We
* have to be careful because the slave interpreter and the current
* interpreter can be the same - do not destroy the result.. This
* can happen if an interpreter contains an alias which is directed
* at a target command in the same interpreter.
*/
if (interp != slaveInterp) {
/*
* An error occurred, so transfer error information from
* the target interpreter back to our interpreter. Must
* clear interp's result before calling Tcl_AddErrorInfo,
* since Tcl_AddErrorInfo will store the interp's result in
* errorInfo before appending slaveInterp's $errorInfo;
* we've already got everything we need in the slave
* interpreter's $errorInfo.
*/
}
slaveInterp->freeProc = 0;
} else {
}
}
return result;
}
if (argc > 3) {
" exists ?path?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
(Tcl_Interp *) NULL) {
} else {
}
} else {
}
return TCL_OK;
}
}
if (cmdName[0] == 'i') {
if (argc > 3) {
" issafe ?path?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
&masterPtr);
"\" not found", (char *) NULL);
return TCL_ERROR;
}
}
} else {
}
return TCL_OK;
}
}
if (cmdName[0] == 's') {
" slaves ?path?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
(Tcl_Interp *) NULL) {
"\" not found", (char *) NULL);
return TCL_ERROR;
}
}
}
return TCL_OK;
}
if (argc != 5) {
" share srcPath channelId destPath\"", (char *) NULL);
return TCL_ERROR;
}
"\" not found", (char *) NULL);
return TCL_ERROR;
}
"\" not found", (char *) NULL);
return TCL_ERROR;
}
if (interp != masterInterp) {
(char *) NULL);
}
return TCL_ERROR;
}
return TCL_OK;
}
}
if (argc != 4) {
" target path alias\"", (char *) NULL);
return TCL_ERROR;
}
}
if (argc != 5) {
" transfer srcPath channelId destPath\"", (char *) NULL);
return TCL_ERROR;
}
"\" not found", (char *) NULL);
return TCL_ERROR;
}
"\" not found", (char *) NULL);
return TCL_ERROR;
}
if (interp != masterInterp) {
}
return TCL_ERROR;
}
if (interp != masterInterp) {
}
return TCL_ERROR;
}
return TCL_OK;
}
"\": should be alias, aliases, create, delete, exists, eval, ",
"issafe, share, slaves, target or transfer", (char *) NULL);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* SlaveObjectCmd --
*
* Command to manipulate an interpreter, e.g. to send commands to it
* to be evaluated. One such command exists for each slave interpreter.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See user documentation for details.
*
*----------------------------------------------------------------------
*/
static int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
* interpreter. */
if (argc < 2) {
" cmd ?arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
(char *) NULL);
return TCL_ERROR;
}
"tclSlaveRecord", NULL);
panic("SlaveObjectCmd: could not find slave record");
}
if (cmdName[0] == 'a') {
switch (argc-2) {
case 0:
argv[0], " alias aliasName ?targetName? ?args..?",
(char *) NULL);
return TCL_ERROR;
case 1:
/*
* Return the name of the command in the current
* interpreter for which the argument is an alias in the
* slave interpreter, and the list of saved arguments
*/
default:
"tclMasterRecord", NULL);
panic("SlaveObjectCmd: could not find master record");
}
}
}
/*
* Return the names of all the aliases created in the
* slave interpreter.
*/
&hSearch);
}
return TCL_OK;
}
}
if (cmdName[0] == 'e') {
if (argc < 3) {
" eval arg ?arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
/*
* Make the result and any error information accessible. We have
* to be careful because the slave interpreter and the current
* interpreter can be the same - do not destroy the result.. This
* can happen if an interpreter contains an alias which is directed
* at a target command in the same interpreter.
*/
if (interp != slaveInterp) {
/*
* An error occurred, so transfer error information from the
* destination interpreter back to our interpreter. Clear
* interp's result before calling Tcl_AddErrorInfo, since
* Tcl_AddErrorInfo stores the interp's result in errorInfo
* before appending slaveInterp's $errorInfo;
* we've already got everything we need in the slave
* interpreter's $errorInfo.
*/
(char *) NULL, TCL_GLOBAL_ONLY),
}
slaveInterp->freeProc = 0;
} else {
}
}
return result;
}
}
if (cmdName[0] == 'i') {
if (argc > 2) {
" issafe\"", (char *) NULL);
return TCL_ERROR;
}
"tclMasterRecord", NULL);
panic("SlaveObjectCmd: could not find master record");
}
} else {
}
return TCL_OK;
}
}
"\": should be alias, aliases, eval, or issafe", (char *) NULL);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* SlaveObjectDeleteProc --
*
* Invoked when an object command for a slave interpreter is deleted;
* cleans up all state associated with the slave interpreter and destroys
* the slave interpreter.
*
* Results:
* None.
*
* Side effects:
* Cleans up all state associated with the slave interpreter and
* destroys the slave interpreter.
*
*----------------------------------------------------------------------
*/
static void
{
panic("SlaveObjectDeleteProc: could not find slave record");
}
/*
* Delete the entry in the slave table in the master interpreter now.
* This is to avoid an infinite loop in the Master hash table cleanup in
* the master interpreter. This can happen if this slave is being deleted
* because the master is being deleted and the slave deletion is deferred
* because it is still active.
*/
/*
* Set to NULL so that when the slave record is cleaned up in the slave
* it does not try to delete the command causing all sorts of grief.
* See SlaveRecordDeleteProc().
*/
/*
* Destroy the interpreter - this will cause all the deleteProcs for
* all commands (including aliases) to run.
*
* NOTE: WE ASSUME THAT THE INTERPRETER HAS NOT BEEN DELETED YET!!
*/
}
/*
*----------------------------------------------------------------------
*
* AliasCmd --
*
* This is the procedure that services invocations of aliases in a
* slave interpreter. One such command exists for each alias. When
* invoked, this procedure redirects the invocation to the target
* command in the master interpreter as designated by the Alias
* record associated with this command.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Causes forwarding of the invocation; all possible side effects
* may occur as a result of invoking the command to which the
* invocation is forwarded.
*
*----------------------------------------------------------------------
*/
static int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
&cmdInfo);
if (result == 0) {
return TCL_ERROR;
}
} else {
for (i = 0, j = 1; i < addArgc; i++, j++) {
}
for (i = 1; i < argc; i++, j++) {
}
}
/*
* Invoke the redirected command in the target interpreter. Note
* that we are not calling eval because of possible security holes with
* $ substitution and bracketed command evaluation.
*
* We duplicate some code here from Tcl_Eval to implement recursion
* level counting and correct deletion of the target interpreter if
* that was requested but delayed because of in-progress evaluations.
*/
if (result == TCL_RETURN) {
}
} else if (result == TCL_CONTINUE) {
} else {
result);
}
}
}
/*
* Clean up any locally allocated argument vector structure.
*/
}
/*
*
* NOTE: Need to be careful if the target interpreter and the current
* interpreter are the same - must not destroy result. This may happen
* if an alias is created which redirects to a command in the same
* interpreter as the one in which the source command will be defined.
* Also: We cannot use aliasPtr any more because the alias may have
* been deleted.
*/
/*
* An error occurred, so transfer error information from the
* destination interpreter back to our interpreter. Some tricky
* points:
* 1. Must call Tcl_AddErrorInfo in destination interpreter to
* make sure that the errorInfo variable has been initialized
* (it's initialized lazily and might not have been initialized
* yet).
* 2. Must clear interp's result before calling Tcl_AddErrorInfo,
* since Tcl_AddErrorInfo will store the interp's result in
* errorInfo before appending aliasPtr->interp's $errorInfo;
* we've already got everything we need in the redirected
* interpreter's $errorInfo.
*/
}
}
} else {
}
}
return result;
}
/*
*----------------------------------------------------------------------
*
* AliasCmdDeleteProc --
*
* Is invoked when an alias command is deleted in a slave. Cleans up
* all storage associated with this alias.
*
* Results:
* None.
*
* Side effects:
* Deletes the alias record and its entry in the alias table for
* the interpreter.
*
*----------------------------------------------------------------------
*/
static void
{
int i; /* Loop counter. */
}
}
}
/*
*----------------------------------------------------------------------
*
* MasterRecordDeleteProc -
*
* Is invoked when an interpreter (which is using the "interp" facility)
* is deleted, and it cleans up the storage associated with the
* "tclMasterRecord" assoc-data entry.
*
* Results:
* None.
*
* Side effects:
* Cleans up storage.
*
*----------------------------------------------------------------------
*/
static void
{
}
}
}
/*
*----------------------------------------------------------------------
*
* SlaveRecordDeleteProc --
*
* Is invoked when an interpreter (which is using the interp facility)
* is deleted, and it cleans up the storage associated with the
* tclSlaveRecord assoc-data entry.
*
* Results:
* None
*
* Side effects:
* Cleans up storage.
*
*----------------------------------------------------------------------
*/
static void
{
/*
* In every case that we call SetAssocData on "tclSlaveRecord",
* slavePtr is not NULL. Otherwise we panic.
*/
panic("SlaveRecordDeleteProc: NULL slavePtr");
}
/*
* The interpCmd has not been deleted in the master yet, since
* it's callback sets interpCmd to NULL.
*
* Probably Tcl_DeleteInterp() was called on this interpreter directly,
* rather than via "interp delete", or equivalent (deletion of the
* command in the master).
*
* Perform the cleanup done by SlaveObjectDeleteProc() directly,
* and turn off the callback now (since we are about to free slavePtr
* and this interpreter is going away, while the deletion of commands
* in the master may be deferred).
*/
/*
* Get the command name from the master interpreter instead of
* relying on the stored name; the command may have been renamed.
*/
}
/*
* If there are any aliases, delete those now. This removes any
* dependency on the order of deletion between commands and the
* slave record.
*/
/*
* The call to Tcl_DeleteCommand will release the storage
* occuppied by the hash entry and the alias record.
* NOTE that we cannot use the alias name directly because its
* storage will be deleted in the command deletion callback. Hence
* we must use the name for the command as stored in the hash table.
*/
}
/*
* Finally dispose of the hash table and the slave record.
*/
}
/*
*----------------------------------------------------------------------
*
* TclInterpInit --
*
* Initializes the invoking interpreter for using the "interp"
* facility. This is called from inside Tcl_Init.
*
* Results:
* None.
*
* Side effects:
* Adds the "interp" command to an interpreter and initializes several
* records in the associated data of the invoking interpreter.
*
*----------------------------------------------------------------------
*/
int
{
(ClientData) masterPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_IsSafe --
*
* Determines whether an interpreter is safe
*
* Results:
* 1 if it is safe, 0 if it is not.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
{
return 0;
}
panic("Tcl_IsSafe: could not find master record");
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_MakeSafe --
*
* Makes an interpreter safe.
*
* Results:
* TCL_OK if it succeeds, TCL_ERROR else.
*
* Side effects:
* Removes functionality from an interpreter.
*
*----------------------------------------------------------------------
*/
int
{
return TCL_ERROR;
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_CreateSlave --
*
* Creates a slave interpreter. The slavePath argument denotes the
* name of the new slave relative to the current interpreter; the
* slave is a direct descendant of the one-before-last component of
* the path, e.g. it is a descendant of the current interpreter if
* the slavePath argument contains only one component. Optionally makes
* the slave interpreter safe.
*
* Results:
* Returns the interpreter structure created, or NULL if an error
* occurred.
*
* Side effects:
* Creates a new interpreter and a new interpreter object command in
* the interpreter indicated by the slavePath argument.
*
*----------------------------------------------------------------------
*/
char *slavePath; /* Name of slave to create. */
int isSafe; /* Should new slave be "safe" ? */
{
return NULL;
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetSlave --
*
* Finds a slave interpreter by its path name.
*
* Results:
* Returns a Tcl_Interp * for the named interpreter or NULL if not
* found.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char *slavePath; /* Path of slave to find. */
{
return NULL;
}
panic("Tcl_GetSlave: could not find master record");
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetMaster --
*
* Finds the master interpreter of a slave interpreter.
*
* Results:
* Returns a Tcl_Interp * for the master interpreter or NULL if none.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
{
return NULL;
}
return NULL;
}
return slavePtr->masterInterp;
}
/*
*----------------------------------------------------------------------
*
* Tcl_CreateAlias --
*
* Creates an alias between two interpreters.
*
* Results:
* TCL_OK if successful, TCL_ERROR if failed. If TCL_ERROR is returned
* the result of slaveInterp will contain an error message.
*
* Side effects:
* Creates a new alias, manipulates the result field of slaveInterp.
*
*----------------------------------------------------------------------
*/
int
char *slaveCmd; /* Command to install in slave. */
char *targetCmd; /* Name of target command. */
int argc; /* How many additional arguments? */
char **argv; /* These are the additional args. */
{
return TCL_ERROR;
}
NULL);
panic("Tcl_CreateAlias: could not find master record");
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetAlias --
*
* Gets information about an alias.
*
* Results:
* TCL_OK if successful, TCL_ERROR else. If TCL_ERROR is returned, the
* result field of the interpreter given as argument will contain an
* error message.
*
* Side effects:
* Manipulates the result field of the interpreter given as argument.
*
*----------------------------------------------------------------------
*/
int
char *aliasName; /* Name of alias to find. */
char **targetNamePtr; /* (Return) name of target command. */
int *argcPtr; /* (Return) count of addnl args. */
char ***argvPtr; /* (Return) additional arguments. */
{
return TCL_ERROR;
}
panic("Tcl_GetAlias: could not find slave record");
}
(char *) NULL);
return TCL_ERROR;
}
}
if (targetNamePtr != (char **) NULL) {
}
}
}
return TCL_OK;
}