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

📄 tclparse.c

📁 CMX990 demonstration board (DE9901)
💻 C
📖 第 1 页 / 共 3 页
字号:
  if (result != TCL_OK) {
    /*
     * The increment below results in slightly cleaner message in
     * the errorInfo variable (the close-bracket will appear).
     */

    if (**termPtr == ']') {
      *termPtr += 1;
    }
    return result;
  }
  (*termPtr) += 1;
  length = strlen(iPtr->result);
  shortfall = length + 1 - (pvPtr->end - pvPtr->next);
  if (shortfall > 0) {
    (*pvPtr->expandProc)(pvPtr, shortfall);
  }
  strcpy(pvPtr->next, iPtr->result);
  pvPtr->next += length;
  Tcl_FreeResult(iPtr);
  iPtr->result = iPtr->resultSpace;
  iPtr->resultSpace[0] = '\0';
  return TCL_OK;
}

/*
 *--------------------------------------------------------------
 *
 * TclParseBraces --
 *
 *	This procedure scans the information between matching
 *	curly braces.
 *
 * Results:
 *	The return value is a standard Tcl result, which is
 *	TCL_OK unless there was an error while parsing string.
 *	If an error occurs then interp->result contains a
 *	standard error message.  *TermPtr is filled
 *	in with the address of the character just after the
 *	last one successfully processed;  this is usually the
 *	character just after the matching close-brace.  The
 *	information between curly braces is stored in standard
 *	fashion in *pvPtr, null-terminated with pvPtr->next
 *	pointing to the terminating null character.
 *
 * Side effects:
 *	The storage space at *pvPtr may be expanded.
 *
 *--------------------------------------------------------------
 */
int TclParseBraces(Tcl_Interp *interp, char *string, char **termPtr, ParseValue *pvPtr)
  //  Tcl_Interp *interp;	/* Interpreter to use for nested command
  //				 * evaluations and error messages. */
  //char *string;		/* Character just after opening bracket. */
  //char **termPtr;		/* Store address of terminating character
  //                             * here. */
  //register ParseValue *pvPtr;	/* Information about where to place
  //				 * result of command. */
{
  int level;
  register char *src, *dst, *end;
  register char c;

  src = string;
  dst = pvPtr->next;
  end = pvPtr->end;
  level = 1;

  /*
   * Copy the characters one at a time to the result area, stopping
   * when the matching close-brace is found.
   */

  while (1) {
    c = *src;
    src++;
    if (dst == end) {
      pvPtr->next = dst;
      (*pvPtr->expandProc)(pvPtr, 20);
      dst = pvPtr->next;
      end = pvPtr->end;
    }
    *dst = c;
    dst++;
    if (CHAR_TYPE(c) == TCL_NORMAL) {
      continue;
    } else if (c == '{') {
      level++;
    } else if (c == '}') {
      level--;
      if (level == 0) {
        dst--;			/* Don't copy the last close brace. */
        break;
      }
    } else if (c == '\\') {
      int count;

      /*
       * Must always squish out backslash-newlines, even when in
       * braces.  This is needed so that this sequence can appear
       * anywhere in a command, such as the middle of an expression.
       */

      if (*src == '\n') {
        dst--;
        src++;
      } else {
        (void) Tcl_Backslash(src-1, &count);
        while (count > 1) {
          if (dst == end) {
            pvPtr->next = dst;
            (*pvPtr->expandProc)(pvPtr, 20);
            dst = pvPtr->next;
            end = pvPtr->end;
          }
          *dst = *src;
          dst++;
          src++;
          count--;
        }
      }
    } else if (c == '\0') {
      Tcl_SetResult(interp, "missing close-brace", TCL_STATIC);
      *termPtr = string-1;
      return TCL_ERROR;
    }
  }

  *dst = '\0';
  pvPtr->next = dst;
  *termPtr = src;
  return TCL_OK;
}

/*
 *--------------------------------------------------------------
 *
 * TclParseWords --
 *
 *	This procedure parses one or more words from a command
 *	string and creates argv-style pointers to fully-substituted
 *	copies of those words.
 *
 * Results:
 *	The return value is a standard Tcl result.
 *	
 *	*argcPtr is modified to hold a count of the number of words
 *	successfully parsed, which may be 0.  At most maxWords words
 *	will be parsed.  If 0 <= *argcPtr < maxWords then it
 *	means that a command separator was seen.  If *argcPtr
 *	is maxWords then it means that a command separator was
 *	not seen yet.
 *
 *	*TermPtr is filled in with the address of the character
 *	just after the last one successfully processed in the
 *	last word.  This is either the command terminator (if
 *	*argcPtr < maxWords), the character just after the last
 *	one in a word (if *argcPtr is maxWords), or the vicinity
 *	of an error (if the result is not TCL_OK).
 *	
 *	The pointers at *argv are filled in with pointers to the
 *	fully-substituted words, and the actual contents of the
 *	words are copied to the buffer at pvPtr.
 *
 *	If an error occurrs then an error message is left in
 *	interp->result and the information at *argv, *argcPtr,
 *	and *pvPtr may be incomplete.
 *
 * Side effects:
 *	The buffer space in pvPtr may be enlarged by calling its
 *	expandProc.
 *
 *--------------------------------------------------------------
 */
int TclParseWords(Tcl_Interp *interp, char *string, int flags, int maxWords,
                  char **termPtr, int *argcPtr, char **argv, ParseValue *pvPtr)
  //  Tcl_Interp *interp;	/* Interpreter to use for nested command
  //				 * evaluations and error messages. */
  //char *string;		/* First character of word. */
  //int flags;			/* Flags to control parsing (same values as
  //				 * passed to Tcl_Eval). */
  //int maxWords;		/* Maximum number of words to parse. */
  //char **termPtr;		/* Store address of terminating character
  //                             * here. */
  //int *argcPtr;		/* Filled in with actual number of words
  //                             * parsed. */
  //char **argv;		/* Store addresses of individual words here. */
  //register ParseValue *pvPtr;	/* Information about where to place
  //				 * fully-substituted word. */
{
  register char *src, *dst;
  register char c;
  int type, result, argc;
  char *oldBuffer;		/* Used to detect when pvPtr's buffer gets
				 * reallocated, so we can adjust all of the
				 * argv pointers. */

  src = string;
  oldBuffer = pvPtr->buffer;
  dst = pvPtr->next;
  for (argc = 0; argc < maxWords; argc++) {
    argv[argc] = dst;

    /*
     * Skip leading space.
     */
    
  skipSpace:
    c = *src;
    type = CHAR_TYPE(c);
    while (type == TCL_SPACE) {
      src++;
      c = *src;
      type = CHAR_TYPE(c);
    }
    
    /*
     * Handle the normal case (i.e. no leading double-quote or brace).
     */

    if (type == TCL_NORMAL) {
    normalArg:
      while (1) {
        if (dst == pvPtr->end) {
          /*
           * Target buffer space is about to run out.  Make
           * more space.
           */
	
          pvPtr->next = dst;
          (*pvPtr->expandProc)(pvPtr, 1);
          dst = pvPtr->next;
        }
	
        if (type == TCL_NORMAL) {
        copy:
          *dst = c;
          dst++;
          src++;
        } else if (type == TCL_SPACE) {
          goto wordEnd;
        } else if (type == TCL_DOLLAR) {
          int length;
          char *value;
	
          value = Tcl_ParseVar(interp, src, termPtr);
          if (value == NULL) {
            return TCL_ERROR;
          }
          src = *termPtr;
          length = strlen(value);
          if ((pvPtr->end - dst) <= length) {
            pvPtr->next = dst;
            (*pvPtr->expandProc)(pvPtr, length);
            dst = pvPtr->next;
          }
          strcpy(dst, value);
          dst += length;
        } else if (type == TCL_COMMAND_END) {
          if ((c == ']') && !(flags & TCL_BRACKET_TERM)) {
            goto copy;
          }

          /*
           * End of command;  simulate a word-end first, so
           * that the end-of-command can be processed as the
           * first thing in a new word.
           */

          goto wordEnd;
        } else if (type == TCL_OPEN_BRACKET) {
          pvPtr->next = dst;
          result = TclParseNestedCmd(interp, src+1, flags, termPtr,
                                     pvPtr);
          if (result != TCL_OK) {
            return result;
          }
          src = *termPtr;
          dst = pvPtr->next;
        } else if (type == TCL_BACKSLASH) {
          int numRead;
    
          *dst = Tcl_Backslash(src, &numRead);
          if (*dst != 0) {
            dst++;
          }
          src += numRead;
        } else {
          goto copy;
        }
        c = *src;
        type = CHAR_TYPE(c);
      }
    } else {
    
      /*
       * Check for the end of the command.
       */
	
      if (type == TCL_COMMAND_END) {
        if (flags & TCL_BRACKET_TERM) {
          if (c == '\0') {
            Tcl_SetResult(interp, "missing close-bracket",
                          TCL_STATIC);
            return TCL_ERROR;
          }
        } else {
          if (c == ']') {
            goto normalArg;
          }
        }
        goto done;
      }
	
      /*
       * Now handle the special cases: open braces, double-quotes,
       * and backslash-newline.
       */

      pvPtr->next = dst;
      if (type == TCL_QUOTE) {
        result = TclParseQuotes(interp, src+1, '"', flags,
                                termPtr, pvPtr);
      } else if (type == TCL_OPEN_BRACE) {
        result = TclParseBraces(interp, src+1, termPtr, pvPtr);
      } else if ((type == TCL_BACKSLASH) && (src[1] == '\n')) {
        src += 2;
        goto skipSpace;
      } else {
        goto normalArg;
      }
      if (result != TCL_OK) {
        return result;
      }
	
      /*
       * Back from quotes or braces;  make sure that the terminating
       * character was the end of the word.  Have to be careful here
       * to handle continuation lines (i.e. lines ending in backslash).
       */
	
      c = **termPtr;
      if ((c == '\\') && ((*termPtr)[1] == '\n')) {
        c = (*termPtr)[2];
      }
      type = CHAR_TYPE(c);
      if ((type != TCL_SPACE) && (type != TCL_COMMAND_END)) {
        if (*src == '"') {
          Tcl_SetResult(interp, "extra characters after close-quote",
                        TCL_STATIC);
        } else {
          Tcl_SetResult(interp, "extra characters after close-brace",
                        TCL_STATIC);
        }
        return TCL_ERROR;
      }
      src = *termPtr;
      dst = pvPtr->next;

    }

    /*
     * We're at the end of a word, so add a null terminator.  Then
     * see if the buffer was re-allocated during this word.  If so,
     * update all of the argv pointers.
     */

  wordEnd:
    *dst = '\0';
    dst++;
    if (oldBuffer != pvPtr->buffer) {
      int i;

      for (i = 0; i <= argc; i++) {
        argv[i] = pvPtr->buffer + (argv[i] - oldBuffer);
      }
      oldBuffer = pvPtr->buffer;
    }
  }

 done:
  pvPtr->next = dst;
  *termPtr = src;
  *argcPtr = argc;
  return TCL_OK;
}

/*
 *--------------------------------------------------------------
 *
 * TclExpandParseValue --
 *
 *	This procedure is commonly used as the value of the
 *	expandProc in a ParseValue.  It uses malloc to allocate
 *	more space for the result of a parse.

⌨️ 快捷键说明

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