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

📄 tclutil.c

📁 CMX990 demonstration board (DE9901)
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 
 * tclUtil.c --
 *
 *	This file contains utility procedures that are used by many Tcl
 *	commands.
 *
 * Copyright 1987-1991 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: tclUtil.c,v 1.1.1.1 2001/04/29 20:35:11 karll Exp $
 */

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

/*
 * The following values are used in the flags returned by Tcl_ScanElement
 * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
 * defined in tcl.h;  make sure its value doesn't overlap with any of the
 * values below.
 *
 * TCL_DONT_USE_BRACES -	1 means the string mustn't be enclosed in
 *				braces (e.g. it contains unmatched braces,
 *				or ends in a backslash character, or user
 *				just doesn't want braces);  handle all
 *				special characters by adding backslashes.
 * USE_BRACES -			1 means the string contains a special
 *				character that can be handled simply by
 *				enclosing the entire argument in braces.
 * BRACES_UNMATCHED -		1 means that braces aren't properly matched
 *				in the argument.
 */

#define USE_BRACES		2
#define BRACES_UNMATCHED	4

/*
 * The variable below is set to NULL before invoking regexp functions
 * and checked after those functions.  If an error occurred then regerror
 * will set the variable to point to a (static) error message.  This
 * mechanism unfortunately does not support multi-threading, but then
 * neither does the rest of the regexp facilities.
 */

char *tclRegexpError = NULL;

/*
 * Function prototypes for local procedures in this file:
 */

static void SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
                                           int newSpace));

/*
 *----------------------------------------------------------------------
 *
 * TclFindElement --
 *
 *	Given a pointer into a Tcl list, locate the first (or next)
 *	element in the list.
 *
 * Results:
 *	The return value is normally TCL_OK, which means that the
 *	element was successfully located.  If TCL_ERROR is returned
 *	it means that list didn't have proper list structure;
 *	interp->result contains a more detailed error message.
 *
 *	If TCL_OK is returned, then *elementPtr will be set to point
 *	to the first element of list, and *nextPtr will be set to point
 *	to the character just after any white space following the last
 *	character that's part of the element.  If this is the last argument
 *	in the list, then *nextPtr will point to the NULL character at the
 *	end of list.  If sizePtr is non-NULL, *sizePtr is filled in with
 *	the number of characters in the element.  If the element is in
 *	braces, then *elementPtr will point to the character after the
 *	opening brace and *sizePtr will not include either of the braces.
 *	If there isn't an element in the list, *sizePtr will be zero, and
 *	both *elementPtr and *termPtr will refer to the null character at
 *	the end of list.  Note:  this procedure does NOT collapse backslash
 *	sequences.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int TclFindElement(Tcl_Interp *interp, char *list, char **elementPtr, char **nextPtr, int *sizePtr, int *bracePtr)
  //  Tcl_Interp *interp;		/* Interpreter to use for error reporting. */
  //register char *list;	/* String containing Tcl list with zero
  //                         * or more elements (possibly in braces). */
  //char **elementPtr;		/* Fill in with location of first significant
  //				 * character in first element of list. */
  //char **nextPtr;		/* Fill in with location of character just
  //                         * after all white space following end of
  //                       * argument (i.e. next argument or end of
  //                      * list). */
  //int *sizePtr;		/* If non-zero, fill in with size of
  //                       * element. */
  //int *bracePtr;		/* If non-zero fill in with non-zero/zero
  //                      * to indicate that arg was/wasn't
  //                      * in braces. */
{
  register char *p;
  int openBraces = 0;
  int inQuotes = 0;
  int size;

  /*
   * Skim off leading white space and check for an opening brace or
   * quote.   Note:  use of "isascii" below and elsewhere in this
   * procedure is a temporary hack (7/27/90) because Mx uses characters
   * with the high-order bit set for some things.  This should probably
   * be changed back eventually, or all of Tcl should call isascii.
   */

  while (isprint(*list) && isspace(*list)) {
    list++;
  }
  if (*list == '{') {
    openBraces = 1;
    list++;
  } else if (*list == '"') {
    inQuotes = 1;
    list++;
  }
  if (bracePtr != 0) {
    *bracePtr = openBraces;
  }
  p = list;

  /*
   * Find the end of the element (either a space or a close brace or
   * the end of the string).
   */

  while (1) {
    switch (*p) {

      /*
       * Open brace: don't treat specially unless the element is
       * in braces.  In this case, keep a nesting count.
       */

    case '{':
      if (openBraces != 0) {
        openBraces++;
      }
      break;

      /*
       * Close brace: if element is in braces, keep nesting
       * count and quit when the last close brace is seen.
       */

    case '}':
      if (openBraces == 1) {
        char *p2;

        size = p - list;
        p++;
        if ((isprint(*p) && isspace(*p)) || (*p == 0)) {
          goto done;
        }
        for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
             p2++) {
          /* null body */
        }
        Tcl_ResetResult(interp);
        sprintf(interp->result,
                "list element in braces followed by \"%.*s\" instead of space",
                (int)(p2-p), p);
        return TCL_ERROR;
      } else if (openBraces != 0) {
        openBraces--;
      }
      break;

      /*
       * Backslash:  skip over everything up to the end of the
       * backslash sequence.
       */

    case '\\': {
      int size;

      (void) Tcl_Backslash(p, &size);
      p += size - 1;
      break;
    }

      /*
       * Space: ignore if element is in braces or quotes;  otherwise
       * terminate element.
       */

    case ' ':
    case '\f':
    case '\n':
    case '\r':
    case '\t':
    case '\v':
      if ((openBraces == 0) && !inQuotes) {
        size = p - list;
        goto done;
      }
      break;

      /*
       * Double-quote:  if element is in quotes then terminate it.
       */

    case '"':
      if (inQuotes) {
        char *p2;

        size = p-list;
        p++;
        if ((isprint(*p) && isspace(*p)) || (*p == 0)) {
          goto done;
        }
        for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
             p2++) {
          /* null body */
        }
        Tcl_ResetResult(interp);
        sprintf(interp->result,
                "list element in quotes followed by \"%.*s\" %s",
                (int)(p2-p), p, "instead of space");
        return TCL_ERROR;
      }
      break;

      /*
       * End of list:  terminate element.
       */

    case 0:
      if (openBraces != 0) {
        Tcl_SetResult(interp, "unmatched open brace in list",
                      TCL_STATIC);
        return TCL_ERROR;
      } else if (inQuotes) {
        Tcl_SetResult(interp, "unmatched open quote in list",
                      TCL_STATIC);
        return TCL_ERROR;
      }
      size = p - list;
      goto done;

    }
    p++;
  }

 done:
  while (isprint(*p) && isspace(*p)) {
    p++;
  }
  *elementPtr = list;
  *nextPtr = p;
  if (sizePtr != 0) {
    *sizePtr = size;
  }
  return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCopyAndCollapse --
 *
 *	Copy a string and eliminate any backslashes that aren't in braces.
 *
 * Results:
 *	There is no return value.  Count chars. get copied from src
 *	to dst.  Along the way, if backslash sequences are found outside
 *	braces, the backslashes are eliminated in the copy.
 *	After scanning count chars. from source, a null character is
 *	placed at the end of dst.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

void TclCopyAndCollapse(int count, char *src, char *dst)
  //  int count;			/* Total number of characters to copy
  //				 * from src. */
  //register char *src;		/* Copy from here... */
  //register char *dst;		/* ... to here. */
{
  register char c;
  int numRead;

  for (c = *src; count > 0; src++, c = *src, count--) {
    if (c == '\\') {
      *dst = Tcl_Backslash(src, &numRead);
      if (*dst != 0) {
        dst++;
      }
      src += numRead-1;
      count -= numRead-1;
    } else {
      *dst = c;
      dst++;
    }
  }
  *dst = 0;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SplitList --
 *
 *	Splits a list up into its constituent fields.
 *
 * Results
 *	The return value is normally TCL_OK, which means that
 *	the list was successfully split up.  If TCL_ERROR is
 *	returned, it means that "list" didn't have proper list
 *	structure;  interp->result will contain a more detailed
 *	error message.
 *
 *	*argvPtr will be filled in with the address of an array
 *	whose elements point to the elements of list, in order.
 *	*argcPtr will get filled in with the number of valid elements
 *	in the array.  A single block of memory is dynamically allocated
 *	to hold both the argv array and a copy of the list (with
 *	backslashes and braces removed in the standard way).
 *	The caller must eventually free this memory by calling free()
 *	on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
 *	if the procedure returns normally.
 *
 * Side effects:
 *	Memory is allocated.
 *
 *----------------------------------------------------------------------
 */

int Tcl_SplitList(Tcl_Interp *interp, char *list, int *argcPtr, char ***argvPtr)
  //  Tcl_Interp *interp;		/* Interpreter to use for error reporting. */
  //char *list;			/* Pointer to string with list structure. */
  //int *argcPtr;		/* Pointer to location to fill in with
  //                         * the number of elements in the list. */
  //char ***argvPtr;		/* Pointer to place to store pointer to array
  //				 * of pointers to list elements. */
{
  char **argv;
  register char *p;
  int size, i, result, elSize, brace;
  char *element;

  /*
   * Figure out how much space to allocate.  There must be enough
   * space for both the array of pointers and also for a copy of
   * the list.  To estimate the number of pointers needed, count
   * the number of space characters in the list.
   */

  for (size = 1, p = list; *p != 0; p++) {
    if (isspace(*p)) {
      size++;
    }
  }
  size++;			/* Leave space for final NULL pointer. */
  argv = (char **) ckalloc((unsigned)
                           ((size * sizeof(char *)) + (p - list) + 1));
  for (i = 0, p = ((char *) argv) + size*sizeof(char *);
       *list != 0; i++) {
    result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
    if (result != TCL_OK) {
      ckfree((char *) argv);
      return result;
    }
    if (*element == 0) {
      break;
    }
    if (i >= size) {
      ckfree((char *) argv);
      Tcl_SetResult(interp, "internal error in Tcl_SplitList",
		    TCL_STATIC);
      return TCL_ERROR;
    }
    argv[i] = p;
    if (brace) {
      strncpy(p, element, elSize);
      p += elSize;
      *p = 0;
      p++;
    } else {
      TclCopyAndCollapse(elSize, element, p);
      p += elSize+1;
    }
  }

  argv[i] = NULL;
  *argvPtr = argv;
  *argcPtr = i;
  return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ScanElement --
 *
 *	This procedure is a companion procedure to Tcl_ConvertElement.
 *	It scans a string to see what needs to be done to it (e.g.
 *	add backslashes or enclosing braces) to make the string into
 *	a valid Tcl list element.
 *
 * Results:
 *	The return value is an overestimate of the number of characters
 *	that will be needed by Tcl_ConvertElement to produce a valid
 *	list element from string.  The word at *flagPtr is filled in
 *	with a value needed by Tcl_ConvertElement when doing the actual
 *	conversion.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int Tcl_ScanElement(char *string, int *flagPtr)
  //  char *string;		/* String to convert to Tcl list element. */
  //int *flagPtr;		/* Where to store information to guide
  //                         * Tcl_ConvertElement. */
{
  int flags, nestingLevel;
  register char *p;

  /*
   * This procedure and Tcl_ConvertElement together do two things:
   *
   * 1. They produce a proper list, one that will yield back the
   * argument strings when evaluated or when disassembled with
   * Tcl_SplitList.  This is the most important thing.
   * 
   * 2. They try to produce legible output, which means minimizing the
   * use of backslashes (using braces instead).  However, there are
   * some situations where backslashes must be used (e.g. an element
   * like "{abc": the leading brace will have to be backslashed.  For
   * each element, one of three things must be done:
   *
   * (a) Use the element as-is (it doesn't contain anything special
   * characters).  This is the most desirable option.
   *
   * (b) Enclose the element in braces, but leave the contents alone.
   * This happens if the element contains embedded space, or if it
   * contains characters with special interpretation ($, [, ;, or \),
   * or if it starts with a brace or double-quote, or if there are
   * no characters in the element.
   *
   * (c) Don't enclose the element in braces, but add backslashes to
   * prevent special interpretation of special characters.  This is a
   * last resort used when the argument would normally fall under case
   * (b) but contains unmatched braces.  It also occurs if the last
   * character of the argument is a backslash or if the element contains
   * a backslash followed by newline.
   *
   * The procedure figures out how many bytes will be needed to store
   * the result (actually, it overestimates).  It also collects information
   * about the element in the form of a flags word.

⌨️ 快捷键说明

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