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

📄 tclbasic.c

📁 CMX990 demonstration board (DE9901)
💻 C
📖 第 1 页 / 共 2 页
字号:
  while (*src != termChar) {
    iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET);
    
    /*
     * Skim off leading white space and semi-colons, and skip
     * comments.
     */
    
    while (1) {
      register char c = *src;
      
      if ((CHAR_TYPE(c) != TCL_SPACE) && (c != ';') && (c != '\n')) {
        break;
      }
      src += 1;
    }
    if (*src == '#') {
      for (src++; *src != 0; src++) {
        if ((*src == '\n') && (src[-1] != '\\')) {
          src++;
          break;
        }
      }
      continue;
    }
    cmdStart = src;
    
    /*
     * Parse the words of the command, generating the argc and
     * argv for the command procedure.  May have to call
     * TclParseWords several times, expanding the argv array
     * between calls.
     */
    
    pv.next = oldBuffer = pv.buffer;
    argc = 0;
    while (1) {
      int newArgs, maxArgs;
      char **newArgv;
      int i;
      
      /*
       * Note:  the "- 2" below guarantees that we won't use the
       * last two argv slots here.  One is for a NULL pointer to
       * mark the end of the list, and the other is to leave room
       * for inserting the command name "unknown" as the first
       * argument (see below).
       */
      
      maxArgs = argSize - argc - 2;
      result = TclParseWords((Tcl_Interp *) iPtr, src, flags,
                             maxArgs, termPtr, &newArgs, &argv[argc], &pv);
      src = *termPtr;
      if (result != TCL_OK) {
        ellipsis = "...";
        goto done;
      }
      
      /*
       * Careful!  Buffer space may have gotten reallocated while
       * parsing words.  If this happened, be sure to update all
       * of the older argv pointers to refer to the new space.
       */
      
      if (oldBuffer != pv.buffer) {
        int i;
        
        for (i = 0; i < argc; i++) {
          argv[i] = pv.buffer + (argv[i] - oldBuffer);
        }
        oldBuffer = pv.buffer;
      }
      argc += newArgs;
      if (newArgs < maxArgs) {
        argv[argc] = (char *) NULL;
        break;
      }
      
      /*
       * Args didn't all fit in the current array.  Make it bigger.
       */
      
      argSize *= 2;
      newArgv = (char **)
        ckalloc((unsigned) argSize * sizeof(char *));
      for (i = 0; i < argc; i++) {
        newArgv[i] = argv[i];
      }
      if (argv != argStorage) {
        ckfree((char *) argv);
      }
      argv = newArgv;
    }
    
    /*
     * If this is an empty command (or if we're just parsing
     * commands without evaluating them), then just skip to the
     * next command.
     */
    
    if ((argc == 0) || iPtr->noEval) {
      continue;
    }
    argv[argc] = NULL;
    
    /*
     * Save information for the history module, if needed.
     */
    
    if (flags & TCL_RECORD_BOUNDS) {
      iPtr->evalFirst = cmdStart;
      iPtr->evalLast = src-1;
    }
    
    /*
     * Find the procedure to execute this command.  If there isn't
     * one, then see if there is a command "unknown".  If so,
     * invoke it instead, passing it the words of the original
     * command as arguments.
     */
    
    hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]);
    if (hPtr == NULL) {
      int i;
      
      hPtr = Tcl_FindHashEntry(&iPtr->commandTable, "unknown");
      if (hPtr == NULL) {
        Tcl_ResetResult(interp);
        Tcl_AppendResult(interp, "invalid command name: \"",
                         argv[0], "\"", (char *) NULL);
        result = TCL_ERROR;
        goto done;
      }
      for (i = argc; i >= 0; i--) {
        argv[i+1] = argv[i];
      }
      argv[0] = "unknown";
      argc++;
    }
    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
    
    /*
     * Call trace procedures, if any.
     */
    
    for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
         tracePtr = tracePtr->nextPtr) {
      char saved;
      
      if (tracePtr->level < iPtr->numLevels) {
        continue;
      }
      saved = *src;
      *src = 0;
      (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
                        cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
      *src = saved;
    }
    
    /*
     * At long last, invoke the command procedure.  Reset the
     * result to its default empty value first (it could have
     * gotten changed by earlier commands in the same command
     * string).
     */
    
    iPtr->cmdCount++;
    Tcl_FreeResult(iPtr);
    iPtr->result = iPtr->resultSpace;
    iPtr->resultSpace[0] = 0;
    result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
    if (result != TCL_OK) {
      break;
    }
  }
  
  /*
   * Free up any extra resources that were allocated.
   */
  
 done:
  if (pv.buffer != copyStorage) {
    ckfree((char *) pv.buffer);
  }
  if (argv != argStorage) {
    ckfree((char *) argv);
  }
  iPtr->numLevels--;
  if (iPtr->numLevels == 0) {
    if (result == TCL_RETURN) {
      result = TCL_OK;
    }
    if ((result != TCL_OK) && (result != TCL_ERROR)) {
      Tcl_ResetResult(interp);
      if (result == TCL_BREAK) {
        iPtr->result = "invoked \"break\" outside of a loop";
      } else if (result == TCL_CONTINUE) {
        iPtr->result = "invoked \"continue\" outside of a loop";
      } else {
        iPtr->result = iPtr->resultSpace;
        sprintf(iPtr->resultSpace, "command returned bad code: %d",
                result);
      }
      result = TCL_ERROR;
    }
    if (iPtr->flags & DELETED) {
      Tcl_DeleteInterp(interp);
    }
  }
  
  /*
   * If an error occurred, record information about what was being
   * executed when the error occurred.
   */
  
  if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
    int numChars;
    register char *p;
    
    /*
     * Compute the line number where the error occurred.
     */
    
    iPtr->errorLine = 1;
    for (p = cmd; p != cmdStart; p++) {
      if (*p == '\n') {
        iPtr->errorLine++;
      }
    }
    for ( ; isspace(*p) || (*p == ';'); p++) {
      if (*p == '\n') {
        iPtr->errorLine++;
      }
    }
    
    /*
     * Figure out how much of the command to print in the error
     * message (up to a certain number of characters, or up to
     * the first new-line).
     */
    
    numChars = src - cmdStart;
    if (numChars > (NUM_CHARS-50)) {
      numChars = NUM_CHARS-50;
      ellipsis = " ...";
    }
    
    if (!(iPtr->flags & ERR_IN_PROGRESS)) {
      sprintf(copyStorage, "\n    while executing\n\"%.*s%s\"",
              numChars, cmdStart, ellipsis);
    } else {
      sprintf(copyStorage, "\n    invoked from within\n\"%.*s%s\"",
              numChars, cmdStart, ellipsis);
    }
    Tcl_AddErrorInfo(interp, copyStorage);
    iPtr->flags &= ~ERR_ALREADY_LOGGED;
  } else {
    iPtr->flags &= ~ERR_ALREADY_LOGGED;
  }
  return result;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_CreateTrace --
 *
 *	Arrange for a procedure to be called to trace command execution.
 *
 * Results:
 *	The return value is a token for the trace, which may be passed
 *	to Tcl_DeleteTrace to eliminate the trace.
 *
 * Side effects:
 *	From now on, proc will be called just before a command procedure
 *	is called to execute a Tcl command.  Calls to proc will have the
 *	following form:
 *
 *	void
 *	proc(clientData, interp, level, command, cmdProc, cmdClientData,
 *		argc, argv)
 *	    ClientData clientData;
 *	    Tcl_Interp *interp;
 *	    int level;
 *	    char *command;
 *	    int (*cmdProc)();
 *	    ClientData cmdClientData;
 *	    int argc;
 *	    char **argv;
 *	{
 *	}
 *
 *	The clientData and interp arguments to proc will be the same
 *	as the corresponding arguments to this procedure.  Level gives
 *	the nesting level of command interpretation for this interpreter
 *	(0 corresponds to top level).  Command gives the ASCII text of
 *	the raw command, cmdProc and cmdClientData give the procedure that
 *	will be called to process the command and the ClientData value it
 *	will receive, and argc and argv give the arguments to the
 *	command, after any argument parsing and substitution.  Proc
 *	does not return a value.
 *
 *----------------------------------------------------------------------
 */

Tcl_Trace Tcl_CreateTrace(Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData)
  //    Tcl_Interp *interp;		/* Interpreter in which to create the trace. */
  //    int level;			/* Only call proc for commands at nesting level
  //				 * <= level (1 => top level). */
  //    Tcl_CmdTraceProc *proc;	/* Procedure to call before executing each
  //			 * command. */
  //    ClientData clientData;	/* Arbitrary one-word value to pass to proc. */
{
  register Trace *tracePtr;
  register Interp *iPtr = (Interp *) interp;
    
  tracePtr = (Trace *) ckalloc(sizeof(Trace));
  tracePtr->level = level;
  tracePtr->proc = proc;
  tracePtr->clientData = clientData;
  tracePtr->nextPtr = iPtr->tracePtr;
  iPtr->tracePtr = tracePtr;

  return (Tcl_Trace) tracePtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DeleteTrace --
 *
 *	Remove a trace.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	From now on there will be no more calls to the procedure given
 *	in trace.
 *
 *----------------------------------------------------------------------
 */

void Tcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace)
  //  Tcl_Interp *interp;		/* Interpreter that contains trace. */
  //Tcl_Trace trace;		/* Token for trace (returned previously by
  //				 * Tcl_CreateTrace). */
{
  register Interp *iPtr = (Interp *) interp;
  register Trace *tracePtr = (Trace *) trace;
  register Trace *tracePtr2;

  if (iPtr->tracePtr == tracePtr) {
    iPtr->tracePtr = tracePtr->nextPtr;
    ckfree((char *) tracePtr);
  } else {
    for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
         tracePtr2 = tracePtr2->nextPtr) {
      if (tracePtr2->nextPtr == tracePtr) {
        tracePtr2->nextPtr = tracePtr->nextPtr;
        ckfree((char *) tracePtr);
        return;
      }
    }
  }
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_AddErrorInfo --
 *
 *	Add information to a message being accumulated that describes
 *	the current error.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The contents of message are added to the "errorInfo" variable.
 *	If Tcl_Eval has been called since the current value of errorInfo
 *	was set, errorInfo is cleared before adding the new message.
 *
 *----------------------------------------------------------------------
 */

void Tcl_AddErrorInfo(Tcl_Interp *interp, char *message)
  // Tcl_Interp *interp;		/* Interpreter to which error information
  //				 * pertains. */
  //char *message;		/* Message to record. */
{
  register Interp *iPtr = (Interp *) interp;

  /*
   * If an error is already being logged, then the new errorInfo
   * is the concatenation of the old info and the new message.
   * If this is the first piece of info for the error, then the
   * new errorInfo is the concatenation of the message in
   * interp->result and the new message.
   */

  if (!(iPtr->flags & ERR_IN_PROGRESS)) {
    Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
		TCL_GLOBAL_ONLY);
    iPtr->flags |= ERR_IN_PROGRESS;

    /*
     * If the errorCode variable wasn't set by the code that generated
     * the error, set it to "NONE".
     */

    if (!(iPtr->flags & ERROR_CODE_SET)) {
      (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
                         TCL_GLOBAL_ONLY);
    }
  }
  Tcl_SetVar2(interp, "errorInfo", (char *) NULL, message,
              TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_VarEval --
 *
 *	Given a variable number of string arguments, concatenate them
 *	all together and execute the result as a Tcl command.
 *
 * Results:
 *	A standard Tcl return result.  An error message or other
 *	result may be left in interp->result.
 *
 * Side effects:
 *	Depends on what was done by the command.
 *
 *----------------------------------------------------------------------
 */
int Tcl_VarEval(Tcl_Interp *iPtr, ...)
  /* Interpreter in which to execute command. */
  /* One or more strings to concatenate,
   * terminated with a NULL string. */
{
  va_list argList;
#define FIXED_SIZE 200
  char fixedSpace[FIXED_SIZE+1];
  int spaceAvl, spaceUsed, length;
  char *string, *cmd;
  Tcl_Interp *interp;
  int result;

  /*
   * Copy the strings one after the other into a single larger
   * string.  Use stack-allocated space for small commands, but if
   * the commands gets too large than call ckalloc to create the
   * space.
   */

  va_start(argList, iPtr);
  interp = iPtr;
  spaceAvl = FIXED_SIZE;
  spaceUsed = 0;
  cmd = fixedSpace;
  while (1) {
    string = va_arg(argList, char *);
    if (string == NULL) {
      break;
    }
    length = strlen(string);
    if ((spaceUsed + length) > spaceAvl) {
      char *new;

      spaceAvl = spaceUsed + length;
      spaceAvl += spaceAvl/2;
      new = ckalloc((unsigned) spaceAvl);
      memcpy((VOID *) new, (VOID *) cmd, spaceUsed);
      if (cmd != fixedSpace) {
        ckfree(cmd);
      }
      cmd = new;
    }
    strcpy(cmd + spaceUsed, string);
    spaceUsed += length;
  }
  va_end(argList);
  cmd[spaceUsed] = '\0';

  result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
  if (cmd != fixedSpace) {
    ckfree(cmd);
  }
  return result;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GlobalEval --
 *
 *	Evaluate a command at global level in an interpreter.
 *
 * Results:
 *	A standard Tcl result is returned, and interp->result is
 *	modified accordingly.
 *
 * Side effects:
 *	The command string is executed in interp, and the execution
 *	is carried out in the variable context of global level (no
 *	procedures active), just as if an "uplevel #0" command were
 *	being executed.
 *
 *----------------------------------------------------------------------
 */

int Tcl_GlobalEval(Tcl_Interp *interp, char *command)
  // Tcl_Interp *interp;		/* Interpreter in which to evaluate command. */
  //char *command;		/* Command to evaluate. */
{
  register Interp *iPtr = (Interp *) interp;
  int result;
  CallFrame *savedVarFramePtr;

  savedVarFramePtr = iPtr->varFramePtr;
  iPtr->varFramePtr = NULL;
  result = Tcl_Eval(interp, command, 0, (char **) NULL);
  iPtr->varFramePtr = savedVarFramePtr;
  return result;
}

⌨️ 快捷键说明

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