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

📄 tclxdbg.c

📁 CMX990 demonstration board (DE9901)
💻 C
字号:
/*
 * tclXdebug.c --
 *
 * Tcl command execution trace command.
 *-----------------------------------------------------------------------------
 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
 *
 * 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.  Karl Lehenbauer and
 * Mark Diekhans make no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 *-----------------------------------------------------------------------------
 * $Id: tclXdbg.c,v 1.1.1.1 2001/04/29 20:35:20 karll Exp $
 *-----------------------------------------------------------------------------
 */

#include "tclExtdInt.h"
#include <stdio.h>

/*
 * Client data structure for the cmdtrace command.
 */
#define ARG_TRUNCATE_SIZE 40
#define CMD_TRUNCATE_SIZE 60

typedef struct traceInfo_t {
  Tcl_Interp *interp;
  Tcl_Trace   traceHolder;
  int         noEval;
  int         noTruncate;
  int         procCalls;
  int         flush;
  int         depth;
  FILE       *filePtr;          /* File to output trace to. */
} traceInfo_t, *traceInfo_pt;

/*
 * Prototypes of internal functions.
 */
static void PrintStr _ANSI_ARGS_((FILE *filePtr,
                                  char *string,
                                  int   numChars));

static void PrintArg _ANSI_ARGS_((FILE *filePtr,
                                  char *argStr,
                                  int   noTruncate));

static void TraceCode  _ANSI_ARGS_((traceInfo_pt traceInfoPtr,
                                    int          level,
                                    char        *command,
                                    int          argc,
                                    char       **argv));

static void CmdTraceRoutine _ANSI_ARGS_((ClientData    clientData,
                                         Tcl_Interp   *interp,
                                         int           level,
                                         char         *command,
                                         Tcl_CmdProc  *cmdProc,
                                         ClientData    cmdClientData,
                                         int           argc,
                                         char        **argv));

static void CleanUpDebug _ANSI_ARGS_((ClientData clientData));


/*
 *-----------------------------------------------------------------------------
 *
 * PrintStr --
 *     Print an string, truncating it to the specified number of characters.
 * If the string contains newlines, \n is substituted.
 *
 *-----------------------------------------------------------------------------
 */
static void PrintStr (FILE *filePtr, char *string, int numChars) {
  int idx;

  for (idx = 0; idx < numChars; idx++) {
    if (string [idx] == '\n') {
      putc ('\\', filePtr);
      putc ('n', filePtr);
    } else
      putc (string [idx], filePtr);
  }
  if (numChars < strlen (string))
    fprintf (filePtr, "...");
}

/*
 *-----------------------------------------------------------------------------
 *
 * PrintArg --
 *     Print an argument string, truncating and adding "..." if its longer
 *     then ARG_TRUNCATE_SIZE.  If the string contains white spaces, quote
 *     it with angle brackets.
 *
 *-----------------------------------------------------------------------------
 */
static void PrintArg (FILE *filePtr, char *argStr, int noTruncate) {
  int idx, argLen, printLen;
  int quote_it;

  argLen = strlen (argStr);
  printLen = argLen;
  if ((!noTruncate) && (printLen > ARG_TRUNCATE_SIZE))
    printLen = ARG_TRUNCATE_SIZE;

  quote_it = (printLen == 0);

  for (idx = 0; idx < printLen; idx++)
    if (isspace (argStr [idx])) {
      quote_it = TRUE;
      break;
    }

  if (quote_it) 
    putc ('{', filePtr);
  PrintStr (filePtr, argStr, printLen);
  if (quote_it) 
    putc ('}', filePtr);
}

/*
 *-----------------------------------------------------------------------------
 *
 * TraceCode --
 *    Print out a trace of a code line.  Level is used for indenting
 * and marking lines and may be eval or procedure level.
 * 
 *-----------------------------------------------------------------------------
 */
static void TraceCode (traceInfo_pt traceInfoPtr, int level, char *command, int argc, char **argv) {
  int idx, cmdLen, printLen;

  fprintf (traceInfoPtr->filePtr, "%2d:", level);

  if (level > 20)
    level = 20;
  for (idx = 0; idx < level; idx++) 
    fprintf (traceInfoPtr->filePtr, "  ");

  if (traceInfoPtr->noEval) {
    cmdLen = printLen = strlen (command);
    if ((!traceInfoPtr->noTruncate) && (printLen > CMD_TRUNCATE_SIZE))
      printLen = CMD_TRUNCATE_SIZE;

    PrintStr (traceInfoPtr->filePtr, command, printLen);
  } else {
    for (idx = 0; idx < argc; idx++) {
      if (idx > 0)
        putc (' ', traceInfoPtr->filePtr);
      PrintArg (traceInfoPtr->filePtr, argv[idx], 
                traceInfoPtr->noTruncate);
    }
  }

  putc ('\n', traceInfoPtr->filePtr);
  if (traceInfoPtr->flush)
    fflush (traceInfoPtr->filePtr);
  
}

/*
 *-----------------------------------------------------------------------------
 *
 * CmdTraceRoutine --
 *  Routine called by Tcl_Eval to trace a command.
 *
 *-----------------------------------------------------------------------------
 */
static void CmdTraceRoutine (ClientData clientData, Tcl_Interp *interp, int level,
                             char *command, Tcl_CmdProc *cmdProc, ClientData cmdClientData, 
                             int argc, char **argv) {
  Interp       *iPtr = (Interp *) interp;
  traceInfo_pt  traceInfoPtr = (traceInfo_pt) clientData;
  int           procLevel;

  if (!traceInfoPtr->procCalls) {
    TraceCode (traceInfoPtr, level, command, argc, argv);
  } else {
    if (TclFindProc (iPtr, argv [0]) != NULL) {
      procLevel = (iPtr->varFramePtr == NULL) ? 0 : 
        iPtr->varFramePtr->level;
      TraceCode (traceInfoPtr, procLevel, command, argc, argv);
    }
  }
}

/*
 *-----------------------------------------------------------------------------
 *
 * Tcl_CmdtraceCmd --
 *     Implements the TCL trace command:
 *     cmdtrace level|on [noeval] [notruncate] [flush] [procs] [filehdl]
 *     cmdtrace off
 *     cmdtrace depth
 *
 * Results:
 *  Standard TCL results.
 *
 *-----------------------------------------------------------------------------
 */
static int Tcl_CmdtraceCmd (ClientData clientData, Tcl_Interp *interp, int argc, char **argv) {
  //  Interp       *iPtr = (Interp *) interp;
  traceInfo_pt  infoPtr = (traceInfo_pt) clientData;
  int           idx;
  char         *fileHandle;

  if (argc < 2)
    goto argumentError;

  /*
   * Handle `depth' sub-command.
   */
  if (STREQU (argv[1], "depth")) {
    if (argc != 2)
      goto argumentError;
    sprintf(interp->result, "%d", infoPtr->depth);
    return TCL_OK;
  }

  /*
   * If a trace is in progress, delete it now.
   */
  if (infoPtr->traceHolder != NULL) {
    Tcl_DeleteTrace(interp, infoPtr->traceHolder);
    infoPtr->depth = 0;
    infoPtr->traceHolder = NULL;
  }

  /*
   * Handle off sub-command.
   */
  if (STREQU (argv[1], "off")) {
    if (argc != 2)
      goto argumentError;
    return TCL_OK;
  }

  infoPtr->noEval     = FALSE;
  infoPtr->noTruncate = FALSE;
  infoPtr->procCalls  = FALSE;
  infoPtr->flush      = FALSE;
  infoPtr->filePtr    = stdout;
  fileHandle          = NULL;

  for (idx = 2; idx < argc; idx++) {
    if (STREQU (argv[idx], "notruncate")) {
      if (infoPtr->noTruncate)
        goto argumentError;
      infoPtr->noTruncate = TRUE;
      continue;
    }
    if (STREQU (argv[idx], "noeval")) {
      if (infoPtr->noEval)
        goto argumentError;
      infoPtr->noEval = TRUE;
      continue;
    }
    if (STREQU (argv[idx], "flush")) {
      if (infoPtr->flush)
        goto argumentError;
      infoPtr->flush = TRUE;
      continue;
    }
    if (STREQU (argv[idx], "procs")) {
      if (infoPtr->procCalls)
        goto argumentError;
      infoPtr->procCalls = TRUE;
      continue;
    }
    if (STRNEQU (argv[idx], "std", 3) || 
        STRNEQU (argv[idx], "file", 4)) {
      if (fileHandle != NULL)
        goto argumentError;
      fileHandle = argv [idx];
      continue;
    }
    goto invalidOption;
  }

  if (STREQU (argv[1], "on")) {
    infoPtr->depth = MAXINT;
  } else {
    if (Tcl_GetInt(interp, argv[1], &(infoPtr->depth)) != TCL_OK)
      return TCL_ERROR;
  }
  if (fileHandle != NULL) {
#ifndef TCL_GENERIC_ONLY
    OpenFile *tclFilePtr;

    if (TclGetOpenFile (interp, fileHandle, &tclFilePtr) != TCL_OK)
      return TCL_ERROR;
    if (!tclFilePtr->writable) {
      Tcl_AppendResult (interp, "file not writable: ", fileHandle,
                        (char *) NULL);
      return TCL_ERROR;
    }
    infoPtr->filePtr = tclFilePtr->f;
#else
    Tcl_AppendResult(interp, "file not open: ", fileHandle,
                     (char *) NULL);
    return TCL_ERROR;
#endif
  }
    
  infoPtr->traceHolder = Tcl_CreateTrace (interp, infoPtr->depth,
                                          CmdTraceRoutine,
                                          (ClientData) infoPtr);
  return TCL_OK;

 argumentError:
  Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
                    " level | on [noeval] [notruncate] [flush] [procs]",
                    "[handle] | off | depth", (char *) NULL);
  return TCL_ERROR;

 invalidOption:
  Tcl_AppendResult (interp, "invalid option: expected ",
                    "one of \"noeval\", \"notruncate\", \"procs\", ",
                    "\"flush\" or a file handle", (char *) NULL);
  return TCL_ERROR;
}

/*
 *-----------------------------------------------------------------------------
 *
 *  CleanUpDebug --
 *
 *  Release the client data area when the trace command is deleted.
 *
 *-----------------------------------------------------------------------------
 */
static void CleanUpDebug (ClientData clientData) {
  traceInfo_pt infoPtr = (traceInfo_pt) clientData;

  if (infoPtr->traceHolder != NULL)
    Tcl_DeleteTrace (infoPtr->interp, infoPtr->traceHolder);
  ckfree ((char *) infoPtr);
}

/*
 *-----------------------------------------------------------------------------
 *
 *  Tcl_InitDebug --
 *
 *  Initialize the TCL debugging commands.
 *
 *-----------------------------------------------------------------------------
 */
void Tcl_InitDebug(Tcl_Interp *interp) {
  traceInfo_pt infoPtr;

  infoPtr = (traceInfo_pt) ckalloc (sizeof (traceInfo_t));

  infoPtr->interp      = interp;
  infoPtr->traceHolder = NULL;
  infoPtr->noEval      = FALSE;
  infoPtr->noTruncate  = FALSE;
  infoPtr->procCalls   = FALSE;
  infoPtr->flush       = FALSE;
  infoPtr->depth       = 0;

  Tcl_CreateCommand (interp, "cmdtrace", Tcl_CmdtraceCmd, 
                     (ClientData)infoPtr, CleanUpDebug);
}

⌨️ 快捷键说明

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