⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclbasic.c

📁 CMX990 demonstration board (DE9901)
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 
 * tclBasic.c --
 *
 *	Contains the basic facilities for TCL command interpretation,
 *	including interpreter creation and deletion, command creation
 *	and deletion, and command parsing and execution.
 *
 * Copyright 1987-1992 Regents of the University of California
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies.  The University of California
 * makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without
 * express or implied warranty.
 *
 * $Id: tclBasic.c,v 1.1.1.1 2001/04/29 20:34:23 karll Exp $
 *
 */

#include "tclInt.h"
//#include <varargs.h>
#include <stdarg.h>

/*
 * The following structure defines all of the commands in the Tcl core,
 * and the C procedures that execute them.
 */

typedef struct {
  char *name;			/* Name of command. */
  Tcl_CmdProc *proc;		/* Procedure that executes command. */
} CmdInfo;

/*
 * Built-in commands, and the procedures associated with them:
 */

static CmdInfo builtInCmds[] = {
  /*
   * Commands in the generic core:
   */
  
  {"append",		Tcl_AppendCmd},
  {"array",		Tcl_ArrayCmd},
  {"break",		Tcl_BreakCmd},
  {"case",		Tcl_CaseCmd},
  {"catch",		Tcl_CatchCmd},
  {"concat",		Tcl_ConcatCmd},
  {"continue",	Tcl_ContinueCmd},
  {"error",		Tcl_ErrorCmd},
  {"eval",		Tcl_EvalCmd},
  {"expr",		Tcl_ExprCmd},
  {"for",		Tcl_ForCmd},
  {"foreach",		Tcl_ForeachCmd},
  {"format",		Tcl_FormatCmd},
  {"global",		Tcl_GlobalCmd},
  //    {"glob",		Tcl_GlobCmd},
  {"if",		Tcl_IfCmd},
  {"incr",		Tcl_IncrCmd},
  {"info",		Tcl_InfoCmd},
  {"join",		Tcl_JoinCmd},
  {"lappend",		Tcl_LappendCmd},
  {"lindex",		Tcl_LindexCmd},
  {"linsert",		Tcl_LinsertCmd},
  {"list",		Tcl_ListCmd},
  {"llength",		Tcl_LlengthCmd},
  {"lrange",		Tcl_LrangeCmd},
  {"lreplace",	Tcl_LreplaceCmd},
  {"lsearch",		Tcl_LsearchCmd},
  {"lsort",		Tcl_LsortCmd},
  {"proc",		Tcl_ProcCmd},
  {"regexp",		Tcl_RegexpCmd},
  {"regsub",		Tcl_RegsubCmd},
  {"rename",		Tcl_RenameCmd},
  {"return",		Tcl_ReturnCmd},
  {"scan",		Tcl_ScanCmd},
  {"set",		Tcl_SetCmd},
  {"split",		Tcl_SplitCmd},
  {"string",		Tcl_StringCmd},
  {"trace",		Tcl_TraceCmd},
  {"unset",		Tcl_UnsetCmd},
  {"uplevel",		Tcl_UplevelCmd},
  {"upvar",		Tcl_UpvarCmd},
  {"while",		Tcl_WhileCmd},
  
  /*
   * Commands in the UNIX core:
   */
  
#ifndef TCL_GENERIC_ONLY
  {"cd",		Tcl_CdCmd},
  {"close",		Tcl_CloseCmd},
  {"eof",		Tcl_EofCmd},
  //  {"exit",		Tcl_ExitCmd},
  {"file",		Tcl_FileCmd},
  {"flush",		Tcl_FlushCmd},
  {"gets",		Tcl_GetsCmd},
  {"open",		Tcl_OpenCmd},
  {"puts",		Tcl_PutsCmd},
  {"pwd",		Tcl_PwdCmd},
  {"read",		Tcl_ReadCmd},
  {"seek",		Tcl_SeekCmd},
  {"source",		Tcl_SourceCmd},
  {"tell",		Tcl_TellCmd},
#endif /* TCL_GENERIC_ONLY */
  {NULL,		(Tcl_CmdProc *) NULL}
};

/*
 *----------------------------------------------------------------------
 *
 * Tcl_CreateInterp --
 *
 *	Create a new TCL command interpreter.
 *
 * Results:
 *	The return value is a token for the interpreter, which may be
 *	used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
 *	Tcl_DeleteInterp.
 *
 * Side effects:
 *	The command interpreter is initialized with an empty variable
 *	table and the built-in commands.
 *
 *----------------------------------------------------------------------
 */

Tcl_Interp *Tcl_CreateInterp(void) {
  register Interp *iPtr;
  register Command *cmdPtr;
  register CmdInfo *cmdInfoPtr;
  int i;
  
  iPtr = (Interp *) ckalloc(sizeof(Interp));
  iPtr->result = iPtr->resultSpace;
  iPtr->freeProc = 0;
  iPtr->errorLine = 0;
  Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
  Tcl_InitHashTable(&iPtr->globalTable, TCL_STRING_KEYS);
  iPtr->numLevels = 0;
  iPtr->framePtr = NULL;
  iPtr->varFramePtr = NULL;
  iPtr->activeTracePtr = NULL;
  iPtr->numEvents = 0;
  iPtr->events = NULL;
  iPtr->curEvent = 0;
  iPtr->curEventNum = 0;
  iPtr->revPtr = NULL;
  iPtr->historyFirst = NULL;
  iPtr->revDisables = 1;
  iPtr->evalFirst = iPtr->evalLast = NULL;
  iPtr->appendResult = NULL;
  iPtr->appendAvl = 0;
  iPtr->appendUsed = 0;
  iPtr->numFiles = 0;
  iPtr->filePtrArray = NULL;
  for (i = 0; i < NUM_REGEXPS; i++) {
    iPtr->patterns[i] = NULL;
    iPtr->patLengths[i] = -1;
    iPtr->regexps[i] = NULL;
  }
  iPtr->cmdCount = 0;
  iPtr->noEval = 0;
  iPtr->scriptFile = NULL;
  iPtr->flags = 0;
  iPtr->tracePtr = NULL;
  iPtr->resultSpace[0] = 0;
  
  /*
   * Create the built-in commands.  Do it here, rather than calling
   * Tcl_CreateCommand, because it's faster (there's no need to
   * check for a pre-existing command by the same name).
   */
  
  for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
    int new;
    Tcl_HashEntry *hPtr;
    
    hPtr = Tcl_CreateHashEntry(&iPtr->commandTable,
                               cmdInfoPtr->name, &new);
    if (new) {
      cmdPtr = (Command *) ckalloc(sizeof(Command));
      cmdPtr->proc = cmdInfoPtr->proc;
      cmdPtr->clientData = (ClientData) NULL;
      cmdPtr->deleteProc = NULL;
      Tcl_SetHashValue(hPtr, cmdPtr);
    }
  }
  
#ifndef TCL_GENERIC_ONLY
  TclSetupEnv((Tcl_Interp *) iPtr);
#endif
  
  return (Tcl_Interp *) iPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DeleteInterp --
 *
 *	Delete an interpreter and free up all of the resources associated
 *	with it.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The interpreter is destroyed.  The caller should never again
 *	use the interp token.
 *
 *----------------------------------------------------------------------
 */

void Tcl_DeleteInterp(Tcl_Interp *interp)
  //  Tcl_Interp *interp;		/* Token for command interpreter (returned
  //				 * by a previous call to Tcl_CreateInterp). */
{
  Interp *iPtr = (Interp *) interp;
  Tcl_HashEntry *hPtr;
  Tcl_HashSearch search;
  register Command *cmdPtr;
  int i;
  
  /*
   * If the interpreter is in use, delay the deletion until later.
   */
  
  iPtr->flags |= DELETED;
  if (iPtr->numLevels != 0) {
    return;
  }
  
  /*
   * Free up any remaining resources associated with the
   * interpreter.
   */
  
  for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
       hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
    if (cmdPtr->deleteProc != NULL) { 
      (*cmdPtr->deleteProc)(cmdPtr->clientData);
    }
    ckfree((char *) cmdPtr);
  }
  Tcl_DeleteHashTable(&iPtr->commandTable);
  TclDeleteVars(iPtr, &iPtr->globalTable);
  if (iPtr->events != NULL) {
    int i;
    
    for (i = 0; i < iPtr->numEvents; i++) {
      ckfree(iPtr->events[i].command);
    }
    ckfree((char *) iPtr->events);
  }
  while (iPtr->revPtr != NULL) {
    HistoryRev *nextPtr = iPtr->revPtr->nextPtr;
    
    ckfree((char *) iPtr->revPtr);
    iPtr->revPtr = nextPtr;
  }
  if (iPtr->appendResult != NULL) {
    ckfree(iPtr->appendResult);
  }
#ifndef TCL_GENERIC_ONLY
  if (iPtr->numFiles > 0) {
    for (i = 0; i < iPtr->numFiles; i++) {
      OpenFile *filePtr;
      
      filePtr = iPtr->filePtrArray[i];
      if (filePtr == NULL) {
        continue;
      }
      if (i >= 3) {
        fclose(filePtr->f);
        if (filePtr->f2 != NULL) {
          fclose(filePtr->f2);
        }
        if (filePtr->numPids > 0) {
          /* Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr); */
          ckfree((char *) filePtr->pidPtr);
        }
      }
      ckfree((char *) filePtr);
    }
    ckfree((char *) iPtr->filePtrArray);
  }
#endif
  for (i = 0; i < NUM_REGEXPS; i++) {
    if (iPtr->patterns[i] == NULL) {
      break;
    }
    ckfree(iPtr->patterns[i]);
    ckfree((char *) iPtr->regexps[i]);
  }
  while (iPtr->tracePtr != NULL) {
    Trace *nextPtr = iPtr->tracePtr->nextPtr;
    
    ckfree((char *) iPtr->tracePtr);
    iPtr->tracePtr = nextPtr;
  }
  ckfree((char *) iPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_CreateCommand --
 *
 *	Define a new command in a command table.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	If a command named cmdName already exists for interp, it is
 *	deleted.  In the future, when cmdName is seen as the name of
 *	a command by Tcl_Eval, proc will be called.  When the command
 *	is deleted from the table, deleteProc will be called.  See the
 *	manual entry for details on the calling sequence.
 *
 *----------------------------------------------------------------------
 */

void Tcl_CreateCommand(Tcl_Interp *interp, char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc)
  //   Tcl_Interp *interp;	/* Token for command interpreter (returned
  //			         * by a previous call to Tcl_CreateInterp). */
  //char *cmdName;		/* Name of command. */
  //Tcl_CmdProc *proc;		/* Command procedure to associate with
  //			         * cmdName. */
  //ClientData clientData;	/* Arbitrary one-word value to pass to proc. */
  //Tcl_CmdDeleteProc *deleteProc;
  //			        /* If not NULL, gives a procedure to call when
  //			         * this command is deleted. */
{
  Interp *iPtr = (Interp *) interp;
  register Command *cmdPtr;
  Tcl_HashEntry *hPtr;
  int new;

  hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new);
  if (!new) {
    /*
     * Command already exists:  delete the old one.
     */

    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
    if (cmdPtr->deleteProc != NULL) {
      (*cmdPtr->deleteProc)(cmdPtr->clientData);
    }
  } else {
    cmdPtr = (Command *) ckalloc(sizeof(Command));
    Tcl_SetHashValue(hPtr, cmdPtr);
  }
  cmdPtr->proc = proc;
  cmdPtr->clientData = clientData;
  cmdPtr->deleteProc = deleteProc;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DeleteCommand --
 *
 *	Remove the given command from the given interpreter.
 *
 * Results:
 *	0 is returned if the command was deleted successfully.
 *	-1 is returned if there didn't exist a command by that
 *	name.
 *
 * Side effects:
 *	CmdName will no longer be recognized as a valid command for
 *	interp.
 *
 *----------------------------------------------------------------------
 */

int Tcl_DeleteCommand(Tcl_Interp *interp, char *cmdName)
  //  Tcl_Interp *interp;		/* Token for command interpreter (returned
  //			 * by a previous call to Tcl_CreateInterp). */
  //char *cmdName;		/* Name of command to remove. */
{
  Interp *iPtr = (Interp *) interp;
  Tcl_HashEntry *hPtr;
  Command *cmdPtr;

  hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
  if (hPtr == NULL) {
    return -1;
  }
  cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  if (cmdPtr->deleteProc != NULL) {
    (*cmdPtr->deleteProc)(cmdPtr->clientData);
  }
  ckfree((char *) cmdPtr);
  Tcl_DeleteHashEntry(hPtr);
  return 0;
}

/*
 *-----------------------------------------------------------------
 *
 * Tcl_Eval --
 *
 *	Parse and execute a command in the Tcl language.
 *
 * Results:
 *	The return value is one of the return codes defined in tcl.hd
 *	(such as TCL_OK), and interp->result contains a string value
 *	to supplement the return code.  The value of interp->result
 *	will persist only until the next call to Tcl_Eval:  copy it or
 *	lose it! *TermPtr is filled in with the character just after
 *	the last one that was part of the command (usually a NULL
 *	character or a closing bracket).
 *
 * Side effects:
 *	Almost certainly;  depends on the command.
 *
 *-----------------------------------------------------------------
 */

int Tcl_Eval(Tcl_Interp *interp, char *cmd, int flags, char **termPtr)
  //  Tcl_Interp *interp;		/* Token for command interpreter (returned
  //				 * by a previous call to Tcl_CreateInterp). */
  //char *cmd;			/* Pointer to TCL command to interpret. */
  //int flags;			/* OR-ed combination of flags like
  //				 * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
  //char **termPtr;		/* If non-NULL, fill in the address it points
  //                         * to with the address of the char. just after
  //                         * the last one that was part of cmd.  See
  //                         * the man page for details on this. */
{
  /*
   * The storage immediately below is used to generate a copy
   * of the command, after all argument substitutions.  Pv will
   * contain the argv values passed to the command procedure.
   */
  
# define NUM_CHARS 200
  char copyStorage[NUM_CHARS];
  ParseValue pv;
  char *oldBuffer;
  
  /*
   * This procedure generates an (argv, argc) array for the command,
   * It starts out with stack-allocated space but uses dynamically-
   * allocated storage to increase it if needed.
   */
  
#   define NUM_ARGS 10
  char *(argStorage[NUM_ARGS]);
  char **argv = argStorage;
  int argc;
  int argSize = NUM_ARGS;
  
  register char *src;			/* Points to current character
					 * in cmd. */
  char termChar;			/* Return when this character is found
					 * (either ']' or '\0').  Zero means
					 * that newlines terminate commands. */
  int result;				/* Return value. */
  register Interp *iPtr = (Interp *) interp;
  Tcl_HashEntry *hPtr;
  Command *cmdPtr;
  char *dummy;			/* Make termPtr point here if it was
                                 * originally NULL. */
  char *cmdStart;			/* Points to first non-blank char. in
					 * command (used in calling trace
					 * procedures). */
  char *ellipsis = "";		/* Used in setting errorInfo variable;
                                 * set to "..." to indicate that not
                                 * all of offending command is included
                                 * in errorInfo.  "" means that the
                                 * command is all there. */
  register Trace *tracePtr;
  
  /*
   * Initialize the result to an empty string and clear out any
   * error information.  This makes sure that we return an empty
   * result if there are no commands in the command string.
   */
  
  Tcl_FreeResult((Tcl_Interp *) iPtr);
  iPtr->result = iPtr->resultSpace;
  iPtr->resultSpace[0] = 0;
  result = TCL_OK;
  
  /*
   * Check depth of nested calls to Tcl_Eval:  if this gets too large,
   * it's probably because of an infinite loop somewhere.
   */
  
  iPtr->numLevels++;
  if (iPtr->numLevels > MAX_NESTING_DEPTH) {
    iPtr->numLevels--;
    iPtr->result =  "too many nested calls to Tcl_Eval (infinite loop?)";
    return TCL_ERROR;
  }
  
  /*
   * Initialize the area in which command copies will be assembled.
   */
  
  pv.buffer = copyStorage;
  pv.end = copyStorage + NUM_CHARS - 1;
  pv.expandProc = TclExpandParseValue;
  pv.clientData = (ClientData) NULL;
  
  src = cmd;
  if (flags & TCL_BRACKET_TERM) {
    termChar = ']';
  } else {
    termChar = 0;
  }
  if (termPtr == NULL) {
    termPtr = &dummy;
  }
  *termPtr = src;
  cmdStart = src;
  
  /*
   * There can be many sub-commands (separated by semi-colons or
   * newlines) in one command string.  This outer loop iterates over
   * individual commands.
   */
  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -