tclParse.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:55k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclParse.c --
  3.  *
  4.  * This file contains procedures that parse Tcl scripts.  They
  5.  * do so in a general-purpose fashion that can be used for many
  6.  * different purposes, including compilation, direct execution,
  7.  * code analysis, etc.  
  8.  *
  9.  * Copyright (c) 1997 Sun Microsystems, Inc.
  10.  * Copyright (c) 1998-2000 Ajuba Solutions.
  11.  * Contributions from Don Porter, NIST, 2002. (not subject to US copyright)
  12.  *
  13.  * See the file "license.terms" for information on usage and redistribution
  14.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  15.  *
  16.  * RCS: @(#) $Id: tclParse.c,v 1.25.2.3 2007/10/15 13:29:19 msofer Exp $
  17.  */
  18. #include "tclInt.h"
  19. #include "tclPort.h"
  20. /*
  21.  * The following table provides parsing information about each possible
  22.  * 8-bit character.  The table is designed to be referenced with either
  23.  * signed or unsigned characters, so it has 384 entries.  The first 128
  24.  * entries correspond to negative character values, the next 256 correspond
  25.  * to positive character values.  The last 128 entries are identical to the
  26.  * first 128.  The table is always indexed with a 128-byte offset (the 128th
  27.  * entry corresponds to a character value of 0).
  28.  *
  29.  * The macro CHAR_TYPE is used to index into the table and return
  30.  * information about its character argument.  The following return
  31.  * values are defined.
  32.  *
  33.  * TYPE_NORMAL -        All characters that don't have special significance
  34.  *                      to the Tcl parser.
  35.  * TYPE_SPACE -         The character is a whitespace character other
  36.  *                      than newline.
  37.  * TYPE_COMMAND_END -   Character is newline or semicolon.
  38.  * TYPE_SUBS -          Character begins a substitution or has other
  39.  *                      special meaning in ParseTokens: backslash, dollar
  40.  *                      sign, or open bracket.
  41.  * TYPE_QUOTE -         Character is a double quote.
  42.  * TYPE_CLOSE_PAREN -   Character is a right parenthesis.
  43.  * TYPE_CLOSE_BRACK -   Character is a right square bracket.
  44.  * TYPE_BRACE -         Character is a curly brace (either left or right).
  45.  */
  46. #define TYPE_NORMAL             0
  47. #define TYPE_SPACE              0x1
  48. #define TYPE_COMMAND_END        0x2
  49. #define TYPE_SUBS               0x4
  50. #define TYPE_QUOTE              0x8
  51. #define TYPE_CLOSE_PAREN        0x10
  52. #define TYPE_CLOSE_BRACK        0x20
  53. #define TYPE_BRACE              0x40
  54. #define CHAR_TYPE(c) (charTypeTable+128)[(int)(c)]
  55. static CONST char charTypeTable[] = {
  56.     /*
  57.      * Negative character values, from -128 to -1:
  58.      */
  59.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  60.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  61.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  62.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  63.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  64.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  65.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  66.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  67.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  68.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  69.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  70.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  71.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  72.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  73.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  74.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  75.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  76.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  77.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  78.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  79.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  80.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  81.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  82.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  83.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  84.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  85.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  86.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  87.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  88.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  89.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  90.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  91.     /*
  92.      * Positive character values, from 0-127:
  93.      */
  94.     TYPE_SUBS,        TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  95.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  96.     TYPE_NORMAL,      TYPE_SPACE,       TYPE_COMMAND_END, TYPE_SPACE,
  97.     TYPE_SPACE,       TYPE_SPACE,       TYPE_NORMAL,      TYPE_NORMAL,
  98.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  99.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  100.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  101.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  102.     TYPE_SPACE,       TYPE_NORMAL,      TYPE_QUOTE,       TYPE_NORMAL,
  103.     TYPE_SUBS,        TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  104.     TYPE_NORMAL,      TYPE_CLOSE_PAREN, TYPE_NORMAL,      TYPE_NORMAL,
  105.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  106.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  107.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  108.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_COMMAND_END,
  109.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  110.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  111.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  112.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  113.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  114.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  115.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  116.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_SUBS,
  117.     TYPE_SUBS,        TYPE_CLOSE_BRACK, TYPE_NORMAL,      TYPE_NORMAL,
  118.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  119.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  120.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  121.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  122.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  123.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  124.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_BRACE,
  125.     TYPE_NORMAL,      TYPE_BRACE,       TYPE_NORMAL,      TYPE_NORMAL,
  126.     /*
  127.      * Large unsigned character values, from 128-255:
  128.      */
  129.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  130.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  131.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  132.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  133.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  134.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  135.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  136.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  137.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  138.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  139.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  140.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  141.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  142.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  143.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  144.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  145.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  146.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  147.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  148.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  149.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  150.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  151.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  152.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  153.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  154.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  155.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  156.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  157.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  158.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  159.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  160.     TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,      TYPE_NORMAL,
  161. };
  162. /*
  163.  * Prototypes for local procedures defined in this file:
  164.  */
  165. static int CommandComplete _ANSI_ARGS_((CONST char *script,
  166.     int numBytes));
  167. static int ParseComment _ANSI_ARGS_((CONST char *src, int numBytes,
  168.     Tcl_Parse *parsePtr));
  169. static int ParseTokens _ANSI_ARGS_((CONST char *src, int numBytes,
  170.     int mask, Tcl_Parse *parsePtr));
  171. /*
  172.  *----------------------------------------------------------------------
  173.  *
  174.  * Tcl_ParseCommand --
  175.  *
  176.  * Given a string, this procedure parses the first Tcl command
  177.  * in the string and returns information about the structure of
  178.  * the command.
  179.  *
  180.  * Results:
  181.  * The return value is TCL_OK if the command was parsed
  182.  * successfully and TCL_ERROR otherwise.  If an error occurs
  183.  * and interp isn't NULL then an error message is left in
  184.  * its result.  On a successful return, parsePtr is filled in
  185.  * with information about the command that was parsed.
  186.  *
  187.  * Side effects:
  188.  * If there is insufficient space in parsePtr to hold all the
  189.  * information about the command, then additional space is
  190.  * malloc-ed.  If the procedure returns TCL_OK then the caller must
  191.  * eventually invoke Tcl_FreeParse to release any additional space
  192.  * that was allocated.
  193.  *
  194.  *----------------------------------------------------------------------
  195.  */
  196. int
  197. Tcl_ParseCommand(interp, string, numBytes, nested, parsePtr)
  198.     Tcl_Interp *interp; /* Interpreter to use for error reporting;
  199.  * if NULL, then no error message is
  200.  * provided. */
  201.     CONST char *string; /* First character of string containing
  202.  * one or more Tcl commands. */
  203.     register int numBytes; /* Total number of bytes in string.  If < 0,
  204.  * the script consists of all bytes up to 
  205.  * the first null character. */
  206.     int nested; /* Non-zero means this is a nested command:
  207.  * close bracket should be considered
  208.  * a command terminator. If zero, then close
  209.  * bracket has no special meaning. */
  210.     register Tcl_Parse *parsePtr;
  211.      /* Structure to fill in with information
  212.  * about the parsed command; any previous
  213.  * information in the structure is
  214.  * ignored. */
  215. {
  216.     register CONST char *src; /* Points to current character
  217.  * in the command. */
  218.     char type; /* Result returned by CHAR_TYPE(*src). */
  219.     Tcl_Token *tokenPtr; /* Pointer to token being filled in. */
  220.     int wordIndex; /* Index of word token for current word. */
  221.     int terminators; /* CHAR_TYPE bits that indicate the end
  222.  * of a command. */
  223.     CONST char *termPtr; /* Set by Tcl_ParseBraces/QuotedString to
  224.  * point to char after terminating one. */
  225.     int scanned;
  226.     
  227.     if ((string == NULL) && (numBytes!=0)) {
  228. if (interp != NULL) {
  229.     Tcl_SetResult(interp, "can't parse a NULL pointer", TCL_STATIC);
  230. }
  231. return TCL_ERROR;
  232.     }
  233.     if (numBytes < 0) {
  234. numBytes = strlen(string);
  235.     }
  236.     parsePtr->commentStart = NULL;
  237.     parsePtr->commentSize = 0;
  238.     parsePtr->commandStart = NULL;
  239.     parsePtr->commandSize = 0;
  240.     parsePtr->numWords = 0;
  241.     parsePtr->tokenPtr = parsePtr->staticTokens;
  242.     parsePtr->numTokens = 0;
  243.     parsePtr->tokensAvailable = NUM_STATIC_TOKENS;
  244.     parsePtr->string = string;
  245.     parsePtr->end = string + numBytes;
  246.     parsePtr->term = parsePtr->end;
  247.     parsePtr->interp = interp;
  248.     parsePtr->incomplete = 0;
  249.     parsePtr->errorType = TCL_PARSE_SUCCESS;
  250.     if (nested != 0) {
  251. terminators = TYPE_COMMAND_END | TYPE_CLOSE_BRACK;
  252.     } else {
  253. terminators = TYPE_COMMAND_END;
  254.     }
  255.     /*
  256.      * Parse any leading space and comments before the first word of the
  257.      * command.
  258.      */
  259.     scanned = ParseComment(string, numBytes, parsePtr);
  260.     src = (string + scanned); numBytes -= scanned;
  261.     if (numBytes == 0) {
  262. if (nested) {
  263.     parsePtr->incomplete = nested;
  264. }
  265.     }
  266.     /*
  267.      * The following loop parses the words of the command, one word
  268.      * in each iteration through the loop.
  269.      */
  270.     parsePtr->commandStart = src;
  271.     while (1) {
  272. /*
  273.  * Create the token for the word.
  274.  */
  275. if (parsePtr->numTokens == parsePtr->tokensAvailable) {
  276.     TclExpandTokenArray(parsePtr);
  277. }
  278. wordIndex = parsePtr->numTokens;
  279. tokenPtr = &parsePtr->tokenPtr[wordIndex];
  280. tokenPtr->type = TCL_TOKEN_WORD;
  281. /*
  282.  * Skip white space before the word. Also skip a backslash-newline
  283.  * sequence: it should be treated just like white space.
  284.  */
  285. scanned = TclParseWhiteSpace(src, numBytes, parsePtr, &type);
  286. src += scanned; numBytes -= scanned;
  287. if (numBytes == 0) {
  288.     parsePtr->term = src;
  289.     break;
  290. }
  291. if ((type & terminators) != 0) {
  292.     parsePtr->term = src;
  293.     src++;
  294.     break;
  295. }
  296. tokenPtr->start = src;
  297. parsePtr->numTokens++;
  298. parsePtr->numWords++;
  299. /*
  300.  * At this point the word can have one of three forms: something
  301.  * enclosed in quotes, something enclosed in braces, or an
  302.  * unquoted word (anything else).
  303.  */
  304. if (*src == '"') {
  305.     if (Tcl_ParseQuotedString(interp, src, numBytes,
  306.     parsePtr, 1, &termPtr) != TCL_OK) {
  307. goto error;
  308.     }
  309.     src = termPtr; numBytes = parsePtr->end - src;
  310. } else if (*src == '{') {
  311.     if (Tcl_ParseBraces(interp, src, numBytes,
  312.     parsePtr, 1, &termPtr) != TCL_OK) {
  313. goto error;
  314.     }
  315.     src = termPtr; numBytes = parsePtr->end - src;
  316. } else {
  317.     /*
  318.      * This is an unquoted word.  Call ParseTokens and let it do
  319.      * all of the work.
  320.      */
  321.     if (ParseTokens(src, numBytes, TYPE_SPACE|terminators,
  322.     parsePtr) != TCL_OK) {
  323. goto error;
  324.     }
  325.     src = parsePtr->term; numBytes = parsePtr->end - src;
  326. }
  327. /*
  328.  * Finish filling in the token for the word and check for the
  329.  * special case of a word consisting of a single range of
  330.  * literal text.
  331.  */
  332. tokenPtr = &parsePtr->tokenPtr[wordIndex];
  333. tokenPtr->size = src - tokenPtr->start;
  334. tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1);
  335. if ((tokenPtr->numComponents == 1)
  336. && (tokenPtr[1].type == TCL_TOKEN_TEXT)) {
  337.     tokenPtr->type = TCL_TOKEN_SIMPLE_WORD;
  338. }
  339. /*
  340.  * Do two additional checks: (a) make sure we're really at the
  341.  * end of a word (there might have been garbage left after a
  342.  * quoted or braced word), and (b) check for the end of the
  343.  * command.
  344.  */
  345. scanned = TclParseWhiteSpace(src, numBytes, parsePtr, &type);
  346. if (scanned) {
  347.     src += scanned; numBytes -= scanned;
  348.     continue;
  349. }
  350. if (numBytes == 0) {
  351.     parsePtr->term = src;
  352.     break;
  353. }
  354. if ((type & terminators) != 0) {
  355.     parsePtr->term = src;
  356.     src++; 
  357.     break;
  358. }
  359. if (src[-1] == '"') { 
  360.     if (interp != NULL) {
  361. Tcl_SetResult(interp, "extra characters after close-quote",
  362. TCL_STATIC);
  363.     }
  364.     parsePtr->errorType = TCL_PARSE_QUOTE_EXTRA;
  365. } else {
  366.     if (interp != NULL) {
  367. Tcl_SetResult(interp, "extra characters after close-brace",
  368. TCL_STATIC);
  369.     }
  370.     parsePtr->errorType = TCL_PARSE_BRACE_EXTRA;
  371. }
  372. parsePtr->term = src;
  373. goto error;
  374.     }
  375.     parsePtr->commandSize = src - parsePtr->commandStart;
  376.     return TCL_OK;
  377.     error:
  378.     Tcl_FreeParse(parsePtr);
  379.     if (parsePtr->commandStart == NULL) {
  380. parsePtr->commandStart = string;
  381.     }
  382.     parsePtr->commandSize = parsePtr->end - parsePtr->commandStart;
  383.     return TCL_ERROR;
  384. }
  385. /*
  386.  *----------------------------------------------------------------------
  387.  *
  388.  * TclParseWhiteSpace --
  389.  *
  390.  * Scans up to numBytes bytes starting at src, consuming white
  391.  * space as defined by Tcl's parsing rules.  
  392.  *
  393.  * Results:
  394.  * Returns the number of bytes recognized as white space.  Records
  395.  * at parsePtr, information about the parse.  Records at typePtr
  396.  * the character type of the non-whitespace character that terminated
  397.  * the scan.
  398.  *
  399.  * Side effects:
  400.  * None.
  401.  *
  402.  *----------------------------------------------------------------------
  403.  */
  404. int
  405. TclParseWhiteSpace(src, numBytes, parsePtr, typePtr)
  406.     CONST char *src; /* First character to parse. */
  407.     register int numBytes; /* Max number of bytes to scan. */
  408.     Tcl_Parse *parsePtr; /* Information about parse in progress.
  409.  * Updated if parsing indicates
  410.  * an incomplete command. */
  411.     char *typePtr; /* Points to location to store character
  412.  * type of character that ends run
  413.  * of whitespace */
  414. {
  415.     register char type = TYPE_NORMAL;
  416.     register CONST char *p = src;
  417.     while (1) {
  418. while (numBytes && ((type = CHAR_TYPE(*p)) & TYPE_SPACE)) {
  419.     numBytes--; p++;
  420. }
  421. if (numBytes && (type & TYPE_SUBS)) {
  422.     if (*p != '\') {
  423. break;
  424.     }
  425.     if (--numBytes == 0) {
  426. break;
  427.     }
  428.     if (p[1] != 'n') {
  429. break;
  430.     }
  431.     p+=2;
  432.     if (--numBytes == 0) {
  433. parsePtr->incomplete = 1;
  434. break;
  435.     }
  436.     continue;
  437. }
  438. break;
  439.     }
  440.     *typePtr = type;
  441.     return (p - src);
  442. }
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * TclParseHex --
  447.  *
  448.  * Scans a hexadecimal number as a Tcl_UniChar value.
  449.  * (e.g., for parsing x and u escape sequences).
  450.  * At most numBytes bytes are scanned.
  451.  *
  452.  * Results:
  453.  * The numeric value is stored in *resultPtr.
  454.  * Returns the number of bytes consumed.
  455.  *
  456.  * Notes:
  457.  * Relies on the following properties of the ASCII
  458.  * character set, with which UTF-8 is compatible:
  459.  *
  460.  * The digits '0' .. '9' and the letters 'A' .. 'Z' and 'a' .. 'z' 
  461.  * occupy consecutive code points, and '0' < 'A' < 'a'.
  462.  *
  463.  *----------------------------------------------------------------------
  464.  */
  465. int
  466. TclParseHex(src, numBytes, resultPtr)
  467.     CONST char *src; /* First character to parse. */
  468.     int numBytes; /* Max number of byes to scan */
  469.     Tcl_UniChar *resultPtr; /* Points to storage provided by
  470.  * caller where the Tcl_UniChar
  471.  * resulting from the conversion is
  472.  * to be written. */
  473. {
  474.     Tcl_UniChar result = 0;
  475.     register CONST char *p = src;
  476.     while (numBytes--) {
  477. unsigned char digit = UCHAR(*p);
  478. if (!isxdigit(digit))
  479.     break;
  480. ++p;
  481. result <<= 4;
  482. if (digit >= 'a') {
  483.     result |= (10 + digit - 'a');
  484. } else if (digit >= 'A') {
  485.     result |= (10 + digit - 'A');
  486. } else {
  487.     result |= (digit - '0');
  488. }
  489.     }
  490.     *resultPtr = result;
  491.     return (p - src);
  492. }
  493. /*
  494.  *----------------------------------------------------------------------
  495.  *
  496.  * TclParseBackslash --
  497.  *
  498.  * Scans up to numBytes bytes starting at src, consuming a
  499.  * backslash sequence as defined by Tcl's parsing rules.  
  500.  *
  501.  * Results:
  502.  *  Records at readPtr the number of bytes making up the backslash
  503.  *  sequence.  Records at dst the UTF-8 encoded equivalent of
  504.  *  that backslash sequence.  Returns the number of bytes written
  505.  *  to dst, at most TCL_UTF_MAX.  Either readPtr or dst may be
  506.  *  NULL, if the results are not needed, but the return value is
  507.  *  the same either way.
  508.  *
  509.  * Side effects:
  510.  *  None.
  511.  *
  512.  *----------------------------------------------------------------------
  513.  */
  514. int
  515. TclParseBackslash(src, numBytes, readPtr, dst)
  516.     CONST char * src; /* Points to the backslash character of a
  517.  * a backslash sequence */
  518.     int numBytes; /* Max number of bytes to scan */
  519.     int *readPtr; /* NULL, or points to storage where the
  520.  * number of bytes scanned should be written. */
  521.     char *dst; /* NULL, or points to buffer where the UTF-8
  522.  * encoding of the backslash sequence is to be
  523.  * written.  At most TCL_UTF_MAX bytes will be
  524.  * written there. */
  525. {
  526.     register CONST char *p = src+1;
  527.     Tcl_UniChar result;
  528.     int count;
  529.     char buf[TCL_UTF_MAX];
  530.     if (numBytes == 0) {
  531. if (readPtr != NULL) {
  532.     *readPtr = 0;
  533. }
  534. return 0;
  535.     }
  536.     if (dst == NULL) {
  537.         dst = buf;
  538.     }
  539.     if (numBytes == 1) {
  540. /* Can only scan the backslash.  Return it. */
  541. result = '\';
  542. count = 1;
  543. goto done;
  544.     }
  545.     count = 2;
  546.     switch (*p) {
  547.         /*
  548.          * Note: in the conversions below, use absolute values (e.g.,
  549.          * 0xa) rather than symbolic values (e.g. n) that get converted
  550.          * by the compiler.  It's possible that compilers on some
  551.          * platforms will do the symbolic conversions differently, which
  552.          * could result in non-portable Tcl scripts.
  553.          */
  554.         case 'a':
  555.             result = 0x7;
  556.             break;
  557.         case 'b':
  558.             result = 0x8;
  559.             break;
  560.         case 'f':
  561.             result = 0xc;
  562.             break;
  563.         case 'n':
  564.             result = 0xa;
  565.             break;
  566.         case 'r':
  567.             result = 0xd;
  568.             break;
  569.         case 't':
  570.             result = 0x9;
  571.             break;
  572.         case 'v':
  573.             result = 0xb;
  574.             break;
  575.         case 'x':
  576.     count += TclParseHex(p+1, numBytes-1, &result);
  577.     if (count == 2) {
  578. /* No hexadigits -> This is just "x". */
  579. result = 'x';
  580.     } else {
  581. /* Keep only the last byte (2 hex digits) */
  582. result = (unsigned char) result;
  583.     }
  584.             break;
  585.         case 'u':
  586.     count += TclParseHex(p+1, (numBytes > 5) ? 4 : numBytes-1, &result);
  587.     if (count == 2) {
  588. /* No hexadigits -> This is just "u". */
  589. result = 'u';
  590.     }
  591.             break;
  592.         case 'n':
  593.             count--;
  594.             do {
  595.                 p++; count++;
  596.             } while ((count < numBytes) && ((*p == ' ') || (*p == 't')));
  597.             result = ' ';
  598.             break;
  599.         case 0:
  600.             result = '\';
  601.             count = 1;
  602.             break;
  603.         default:
  604.             /*
  605.              * Check for an octal number oo?o?
  606.              */
  607.             if (isdigit(UCHAR(*p)) && (UCHAR(*p) < '8')) { /* INTL: digit */
  608.                 result = (unsigned char)(*p - '0');
  609.                 p++;
  610.                 if ((numBytes == 2) || !isdigit(UCHAR(*p)) /* INTL: digit */
  611. || (UCHAR(*p) >= '8')) { 
  612.                     break;
  613.                 }
  614.                 count = 3;
  615.                 result = (unsigned char)((result << 3) + (*p - '0'));
  616.                 p++;
  617.                 if ((numBytes == 3) || !isdigit(UCHAR(*p)) /* INTL: digit */
  618. || (UCHAR(*p) >= '8')) {
  619.                     break;
  620.                 }
  621.                 count = 4;
  622.                 result = (unsigned char)((result << 3) + (*p - '0'));
  623.                 break;
  624.             }
  625.             /*
  626.              * We have to convert here in case the user has put a
  627.              * backslash in front of a multi-byte utf-8 character.
  628.              * While this means nothing special, we shouldn't break up
  629.              * a correct utf-8 character. [Bug #217987] test subst-3.2
  630.              */
  631.     if (Tcl_UtfCharComplete(p, numBytes - 1)) {
  632.         count = Tcl_UtfToUniChar(p, &result) + 1; /* +1 for '' */
  633.     } else {
  634. char utfBytes[TCL_UTF_MAX];
  635. memcpy(utfBytes, p, (size_t) (numBytes - 1));
  636. utfBytes[numBytes - 1] = '';
  637.         count = Tcl_UtfToUniChar(utfBytes, &result) + 1;
  638.     }
  639.             break;
  640.     }
  641.     done:
  642.     if (readPtr != NULL) {
  643.         *readPtr = count;
  644.     }
  645.     return Tcl_UniCharToUtf((int) result, dst);
  646. }
  647. /*
  648.  *----------------------------------------------------------------------
  649.  *
  650.  * ParseComment --
  651.  *
  652.  * Scans up to numBytes bytes starting at src, consuming a
  653.  * Tcl comment as defined by Tcl's parsing rules.  
  654.  *
  655.  * Results:
  656.  *  Records in parsePtr information about the parse.  Returns the
  657.  *  number of bytes consumed.
  658.  *
  659.  * Side effects:
  660.  *  None.
  661.  *
  662.  *----------------------------------------------------------------------
  663.  */
  664. static int
  665. ParseComment(src, numBytes, parsePtr)
  666.     CONST char *src; /* First character to parse. */
  667.     register int numBytes; /* Max number of bytes to scan. */
  668.     Tcl_Parse *parsePtr; /* Information about parse in progress.
  669.  * Updated if parsing indicates
  670.  * an incomplete command. */
  671. {
  672.     register CONST char *p = src;
  673.     while (numBytes) {
  674. char type;
  675. int scanned;
  676. do {
  677.     scanned = TclParseWhiteSpace(p, numBytes, parsePtr, &type);
  678.     p += scanned; numBytes -= scanned;
  679. } while (numBytes && (*p == 'n') && (p++,numBytes--));
  680. if ((numBytes == 0) || (*p != '#')) {
  681.     break;
  682. }
  683. if (parsePtr->commentStart == NULL) {
  684.     parsePtr->commentStart = p;
  685. }
  686. while (numBytes) {
  687.     if (*p == '\') {
  688. scanned = TclParseWhiteSpace(p, numBytes, parsePtr, &type);
  689. if (scanned) {
  690.     p += scanned; numBytes -= scanned;
  691. } else {
  692.     /*
  693.      * General backslash substitution in comments isn't
  694.      * part of the formal spec, but test parse-15.47
  695.      * and history indicate that it has been the de facto
  696.      * rule.  Don't change it now.
  697.      */
  698.     TclParseBackslash(p, numBytes, &scanned, NULL);
  699.     p += scanned; numBytes -= scanned;
  700. }
  701.     } else {
  702. p++; numBytes--;
  703. if (p[-1] == 'n') {
  704.     break;
  705. }
  706.     }
  707. }
  708. parsePtr->commentSize = p - parsePtr->commentStart;
  709.     }
  710.     return (p - src);
  711. }
  712. /*
  713.  *----------------------------------------------------------------------
  714.  *
  715.  * ParseTokens --
  716.  *
  717.  * This procedure forms the heart of the Tcl parser.  It parses one
  718.  * or more tokens from a string, up to a termination point
  719.  * specified by the caller.  This procedure is used to parse
  720.  * unquoted command words (those not in quotes or braces), words in
  721.  * quotes, and array indices for variables.  No more than numBytes
  722.  * bytes will be scanned.
  723.  *
  724.  * Results:
  725.  * Tokens are added to parsePtr and parsePtr->term is filled in
  726.  * with the address of the character that terminated the parse (the
  727.  * first one whose CHAR_TYPE matched mask or the character at
  728.  * parsePtr->end).  The return value is TCL_OK if the parse
  729.  * completed successfully and TCL_ERROR otherwise.  If a parse
  730.  * error occurs and parsePtr->interp isn't NULL, then an error
  731.  * message is left in the interpreter's result.
  732.  *
  733.  * Side effects:
  734.  * None.
  735.  *
  736.  *----------------------------------------------------------------------
  737.  */
  738. static int
  739. ParseTokens(src, numBytes, mask, parsePtr)
  740.     register CONST char *src; /* First character to parse. */
  741.     register int numBytes; /* Max number of bytes to scan. */
  742.     int mask; /* Specifies when to stop parsing.  The
  743.  * parse stops at the first unquoted
  744.  * character whose CHAR_TYPE contains
  745.  * any of the bits in mask. */
  746.     Tcl_Parse *parsePtr; /* Information about parse in progress.
  747.  * Updated with additional tokens and
  748.  * termination information. */
  749. {
  750.     char type; 
  751.     int originalTokens, varToken;
  752.     Tcl_Token *tokenPtr;
  753.     Tcl_Parse nested;
  754.     /*
  755.      * Each iteration through the following loop adds one token of
  756.      * type TCL_TOKEN_TEXT, TCL_TOKEN_BS, TCL_TOKEN_COMMAND, or
  757.      * TCL_TOKEN_VARIABLE to parsePtr.  For TCL_TOKEN_VARIABLE tokens,
  758.      * additional tokens are added for the parsed variable name.
  759.      */
  760.     originalTokens = parsePtr->numTokens;
  761.     while (numBytes && !((type = CHAR_TYPE(*src)) & mask)) {
  762. if (parsePtr->numTokens == parsePtr->tokensAvailable) {
  763.     TclExpandTokenArray(parsePtr);
  764. }
  765. tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens];
  766. tokenPtr->start = src;
  767. tokenPtr->numComponents = 0;
  768. if ((type & TYPE_SUBS) == 0) {
  769.     /*
  770.      * This is a simple range of characters.  Scan to find the end
  771.      * of the range.
  772.      */
  773.     while ((++src, --numBytes) 
  774.     && !(CHAR_TYPE(*src) & (mask | TYPE_SUBS))) {
  775. /* empty loop */
  776.     }
  777.     tokenPtr->type = TCL_TOKEN_TEXT;
  778.     tokenPtr->size = src - tokenPtr->start;
  779.     parsePtr->numTokens++;
  780. } else if (*src == '$') {
  781.     /*
  782.      * This is a variable reference.  Call Tcl_ParseVarName to do
  783.      * all the dirty work of parsing the name.
  784.      */
  785.     varToken = parsePtr->numTokens;
  786.     if (Tcl_ParseVarName(parsePtr->interp, src, numBytes,
  787.     parsePtr, 1) != TCL_OK) {
  788. return TCL_ERROR;
  789.     }
  790.     src += parsePtr->tokenPtr[varToken].size;
  791.     numBytes -= parsePtr->tokenPtr[varToken].size;
  792. } else if (*src == '[') {
  793.     /*
  794.      * Command substitution.  Call Tcl_ParseCommand recursively
  795.      * (and repeatedly) to parse the nested command(s), then
  796.      * throw away the parse information.
  797.      */
  798.     src++; numBytes--;
  799.     while (1) {
  800. if (Tcl_ParseCommand(parsePtr->interp, src,
  801. numBytes, 1, &nested) != TCL_OK) {
  802.     parsePtr->errorType = nested.errorType;
  803.     parsePtr->term = nested.term;
  804.     parsePtr->incomplete = nested.incomplete;
  805.     return TCL_ERROR;
  806. }
  807. src = nested.commandStart + nested.commandSize;
  808. numBytes = parsePtr->end - src;
  809. /*
  810.  * This is equivalent to Tcl_FreeParse(&nested), but
  811.  * presumably inlined here for sake of runtime optimization
  812.  */
  813. if (nested.tokenPtr != nested.staticTokens) {
  814.     ckfree((char *) nested.tokenPtr);
  815. }
  816. /*
  817.  * Check for the closing ']' that ends the command
  818.  * substitution.  It must have been the last character of
  819.  * the parsed command.
  820.  */
  821. if ((nested.term < parsePtr->end) && (*nested.term == ']')
  822. && !nested.incomplete) {
  823.     break;
  824. }
  825. if (numBytes == 0) {
  826.     if (parsePtr->interp != NULL) {
  827. Tcl_SetResult(parsePtr->interp,
  828.     "missing close-bracket", TCL_STATIC);
  829.     }
  830.     parsePtr->errorType = TCL_PARSE_MISSING_BRACKET;
  831.     parsePtr->term = tokenPtr->start;
  832.     parsePtr->incomplete = 1;
  833.     return TCL_ERROR;
  834. }
  835.     }
  836.     tokenPtr->type = TCL_TOKEN_COMMAND;
  837.     tokenPtr->size = src - tokenPtr->start;
  838.     parsePtr->numTokens++;
  839. } else if (*src == '\') {
  840.     /*
  841.      * Backslash substitution.
  842.      */
  843.     TclParseBackslash(src, numBytes, &tokenPtr->size, NULL);
  844.     if (tokenPtr->size == 1) {
  845. /* Just a backslash, due to end of string */
  846. tokenPtr->type = TCL_TOKEN_TEXT;
  847. parsePtr->numTokens++;
  848. src++; numBytes--;
  849. continue;
  850.     }
  851.     if (src[1] == 'n') {
  852. if (numBytes == 2) {
  853.     parsePtr->incomplete = 1;
  854. }
  855. /*
  856.  * Note: backslash-newline is special in that it is
  857.  * treated the same as a space character would be.  This
  858.  * means that it could terminate the token.
  859.  */
  860. if (mask & TYPE_SPACE) {
  861.     if (parsePtr->numTokens == originalTokens) {
  862. goto finishToken;
  863.     }
  864.     break;
  865. }
  866.     }
  867.     tokenPtr->type = TCL_TOKEN_BS;
  868.     parsePtr->numTokens++;
  869.     src += tokenPtr->size;
  870.     numBytes -= tokenPtr->size;
  871. } else if (*src == 0) {
  872.     tokenPtr->type = TCL_TOKEN_TEXT;
  873.     tokenPtr->size = 1;
  874.     parsePtr->numTokens++;
  875.     src++; numBytes--;
  876. } else {
  877.     panic("ParseTokens encountered unknown character");
  878. }
  879.     }
  880.     if (parsePtr->numTokens == originalTokens) {
  881. /*
  882.  * There was nothing in this range of text.  Add an empty token
  883.  * for the empty range, so that there is always at least one
  884.  * token added.
  885.  */
  886. if (parsePtr->numTokens == parsePtr->tokensAvailable) {
  887.     TclExpandTokenArray(parsePtr);
  888. }
  889. tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens];
  890. tokenPtr->start = src;
  891. tokenPtr->numComponents = 0;
  892. finishToken:
  893. tokenPtr->type = TCL_TOKEN_TEXT;
  894. tokenPtr->size = 0;
  895. parsePtr->numTokens++;
  896.     }
  897.     parsePtr->term = src;
  898.     return TCL_OK;
  899. }
  900. /*
  901.  *----------------------------------------------------------------------
  902.  *
  903.  * Tcl_FreeParse --
  904.  *
  905.  * This procedure is invoked to free any dynamic storage that may
  906.  * have been allocated by a previous call to Tcl_ParseCommand.
  907.  *
  908.  * Results:
  909.  * None.
  910.  *
  911.  * Side effects:
  912.  * If there is any dynamically allocated memory in *parsePtr,
  913.  * it is freed.
  914.  *
  915.  *----------------------------------------------------------------------
  916.  */
  917. void
  918. Tcl_FreeParse(parsePtr)
  919.     Tcl_Parse *parsePtr; /* Structure that was filled in by a
  920.  * previous call to Tcl_ParseCommand. */
  921. {
  922.     if (parsePtr->tokenPtr != parsePtr->staticTokens) {
  923. ckfree((char *) parsePtr->tokenPtr);
  924. parsePtr->tokenPtr = parsePtr->staticTokens;
  925.     }
  926. }
  927. /*
  928.  *----------------------------------------------------------------------
  929.  *
  930.  * TclExpandTokenArray --
  931.  *
  932.  * This procedure is invoked when the current space for tokens in
  933.  * a Tcl_Parse structure fills up; it allocates memory to grow the
  934.  * token array
  935.  *
  936.  * Results:
  937.  * None.
  938.  *
  939.  * Side effects:
  940.  * Memory is allocated for a new larger token array; the memory
  941.  * for the old array is freed, if it had been dynamically allocated.
  942.  *
  943.  *----------------------------------------------------------------------
  944.  */
  945. void
  946. TclExpandTokenArray(parsePtr)
  947.     Tcl_Parse *parsePtr; /* Parse structure whose token space
  948.  * has overflowed. */
  949. {
  950.     int newCount;
  951.     Tcl_Token *newPtr;
  952.     newCount = parsePtr->tokensAvailable*2;
  953.     newPtr = (Tcl_Token *) ckalloc((unsigned) (newCount * sizeof(Tcl_Token)));
  954.     memcpy((VOID *) newPtr, (VOID *) parsePtr->tokenPtr,
  955.     (size_t) (parsePtr->tokensAvailable * sizeof(Tcl_Token)));
  956.     if (parsePtr->tokenPtr != parsePtr->staticTokens) {
  957. ckfree((char *) parsePtr->tokenPtr);
  958.     }
  959.     parsePtr->tokenPtr = newPtr;
  960.     parsePtr->tokensAvailable = newCount;
  961. }
  962. /*
  963.  *----------------------------------------------------------------------
  964.  *
  965.  * Tcl_ParseVarName --
  966.  *
  967.  * Given a string starting with a $ sign, parse off a variable
  968.  * name and return information about the parse.  No more than
  969.  * numBytes bytes will be scanned.
  970.  *
  971.  * Results:
  972.  * The return value is TCL_OK if the command was parsed
  973.  * successfully and TCL_ERROR otherwise.  If an error occurs and
  974.  * interp isn't NULL then an error message is left in its result. 
  975.  * On a successful return, tokenPtr and numTokens fields of
  976.  * parsePtr are filled in with information about the variable name
  977.  * that was parsed.  The "size" field of the first new token gives
  978.  * the total number of bytes in the variable name.  Other fields in
  979.  * parsePtr are undefined.
  980.  *
  981.  * Side effects:
  982.  * If there is insufficient space in parsePtr to hold all the
  983.  * information about the command, then additional space is
  984.  * malloc-ed.  If the procedure returns TCL_OK then the caller must
  985.  * eventually invoke Tcl_FreeParse to release any additional space
  986.  * that was allocated.
  987.  *
  988.  *----------------------------------------------------------------------
  989.  */
  990. int
  991. Tcl_ParseVarName(interp, string, numBytes, parsePtr, append)
  992.     Tcl_Interp *interp; /* Interpreter to use for error reporting;
  993.  * if NULL, then no error message is
  994.  * provided. */
  995.     CONST char *string; /* String containing variable name.  First
  996.  * character must be "$". */
  997.     register int numBytes; /* Total number of bytes in string.  If < 0,
  998.  * the string consists of all bytes up to the
  999.  * first null character. */
  1000.     Tcl_Parse *parsePtr; /* Structure to fill in with information
  1001.  * about the variable name. */
  1002.     int append; /* Non-zero means append tokens to existing
  1003.  * information in parsePtr; zero means ignore
  1004.  * existing tokens in parsePtr and reinitialize
  1005.  * it. */
  1006. {
  1007.     Tcl_Token *tokenPtr;
  1008.     register CONST char *src;
  1009.     unsigned char c;
  1010.     int varIndex, offset;
  1011.     Tcl_UniChar ch;
  1012.     unsigned array;
  1013.     if ((numBytes == 0) || (string == NULL)) {
  1014. return TCL_ERROR;
  1015.     }
  1016.     if (numBytes < 0) {
  1017. numBytes = strlen(string);
  1018.     }
  1019.     if (!append) {
  1020. parsePtr->numWords = 0;
  1021. parsePtr->tokenPtr = parsePtr->staticTokens;
  1022. parsePtr->numTokens = 0;
  1023. parsePtr->tokensAvailable = NUM_STATIC_TOKENS;
  1024. parsePtr->string = string;
  1025. parsePtr->end = (string + numBytes);
  1026. parsePtr->interp = interp;
  1027. parsePtr->errorType = TCL_PARSE_SUCCESS;
  1028. parsePtr->incomplete = 0;
  1029.     }
  1030.     /*
  1031.      * Generate one token for the variable, an additional token for the
  1032.      * name, plus any number of additional tokens for the index, if
  1033.      * there is one.
  1034.      */
  1035.     src = string;
  1036.     if ((parsePtr->numTokens + 2) > parsePtr->tokensAvailable) {
  1037. TclExpandTokenArray(parsePtr);
  1038.     }
  1039.     tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens];
  1040.     tokenPtr->type = TCL_TOKEN_VARIABLE;
  1041.     tokenPtr->start = src;
  1042.     varIndex = parsePtr->numTokens;
  1043.     parsePtr->numTokens++;
  1044.     tokenPtr++;
  1045.     src++; numBytes--;
  1046.     if (numBytes == 0) {
  1047. goto justADollarSign;
  1048.     }
  1049.     tokenPtr->type = TCL_TOKEN_TEXT;
  1050.     tokenPtr->start = src;
  1051.     tokenPtr->numComponents = 0;
  1052.     /*
  1053.      * The name of the variable can have three forms:
  1054.      * 1. The $ sign is followed by an open curly brace.  Then 
  1055.      *    the variable name is everything up to the next close
  1056.      *    curly brace, and the variable is a scalar variable.
  1057.      * 2. The $ sign is not followed by an open curly brace.  Then
  1058.      *    the variable name is everything up to the next
  1059.      *    character that isn't a letter, digit, or underscore.
  1060.      *    :: sequences are also considered part of the variable
  1061.      *    name, in order to support namespaces. If the following
  1062.      *    character is an open parenthesis, then the information
  1063.      *    between parentheses is the array element name.
  1064.      * 3. The $ sign is followed by something that isn't a letter,
  1065.      *    digit, or underscore:  in this case, there is no variable
  1066.      *    name and the token is just "$".
  1067.      */
  1068.     if (*src == '{') {
  1069. src++; numBytes--;
  1070. tokenPtr->type = TCL_TOKEN_TEXT;
  1071. tokenPtr->start = src;
  1072. tokenPtr->numComponents = 0;
  1073. while (numBytes && (*src != '}')) {
  1074.     numBytes--; src++;
  1075. }
  1076. if (numBytes == 0) {
  1077.     if (parsePtr->interp != NULL) {
  1078. Tcl_SetResult(parsePtr->interp,
  1079. "missing close-brace for variable name", TCL_STATIC);
  1080.     }
  1081.     parsePtr->errorType = TCL_PARSE_MISSING_VAR_BRACE;
  1082.     parsePtr->term = tokenPtr->start-1;
  1083.     parsePtr->incomplete = 1;
  1084.     goto error;
  1085. }
  1086. tokenPtr->size = src - tokenPtr->start;
  1087. tokenPtr[-1].size = src - tokenPtr[-1].start;
  1088. parsePtr->numTokens++;
  1089. src++;
  1090.     } else {
  1091. tokenPtr->type = TCL_TOKEN_TEXT;
  1092. tokenPtr->start = src;
  1093. tokenPtr->numComponents = 0;
  1094. while (numBytes) {
  1095.     if (Tcl_UtfCharComplete(src, numBytes)) {
  1096.         offset = Tcl_UtfToUniChar(src, &ch);
  1097.     } else {
  1098. char utfBytes[TCL_UTF_MAX];
  1099. memcpy(utfBytes, src, (size_t) numBytes);
  1100. utfBytes[numBytes] = '';
  1101.         offset = Tcl_UtfToUniChar(utfBytes, &ch);
  1102.     }
  1103.     c = UCHAR(ch);
  1104.     if (isalnum(c) || (c == '_')) { /* INTL: ISO only, UCHAR. */
  1105. src += offset;  numBytes -= offset;
  1106. continue;
  1107.     }
  1108.     if ((c == ':') && (numBytes != 1) && (src[1] == ':')) {
  1109. src += 2; numBytes -= 2;
  1110. while (numBytes && (*src == ':')) {
  1111.     src++; numBytes--; 
  1112. }
  1113. continue;
  1114.     }
  1115.     break;
  1116. }
  1117. /*
  1118.  * Support for empty array names here.
  1119.  */
  1120. array = (numBytes && (*src == '('));
  1121. tokenPtr->size = src - tokenPtr->start;
  1122. if ((tokenPtr->size == 0) && !array) {
  1123.     goto justADollarSign;
  1124. }
  1125. parsePtr->numTokens++;
  1126. if (array) {
  1127.     /*
  1128.      * This is a reference to an array element.  Call
  1129.      * ParseTokens recursively to parse the element name,
  1130.      * since it could contain any number of substitutions.
  1131.      */
  1132.     if (ParseTokens(src+1, numBytes-1, TYPE_CLOSE_PAREN, parsePtr)
  1133.     != TCL_OK) {
  1134. goto error;
  1135.     }
  1136.     if ((parsePtr->term == (src + numBytes)) 
  1137.     || (*parsePtr->term != ')')) { 
  1138. if (parsePtr->interp != NULL) {
  1139.     Tcl_SetResult(parsePtr->interp, "missing )",
  1140.     TCL_STATIC);
  1141. }
  1142. parsePtr->errorType = TCL_PARSE_MISSING_PAREN;
  1143. parsePtr->term = src;
  1144. parsePtr->incomplete = 1;
  1145. goto error;
  1146.     }
  1147.     src = parsePtr->term + 1;
  1148. }
  1149.     }
  1150.     tokenPtr = &parsePtr->tokenPtr[varIndex];
  1151.     tokenPtr->size = src - tokenPtr->start;
  1152.     tokenPtr->numComponents = parsePtr->numTokens - (varIndex + 1);
  1153.     return TCL_OK;
  1154.     /*
  1155.      * The dollar sign isn't followed by a variable name.
  1156.      * replace the TCL_TOKEN_VARIABLE token with a
  1157.      * TCL_TOKEN_TEXT token for the dollar sign.
  1158.      */
  1159.     justADollarSign:
  1160.     tokenPtr = &parsePtr->tokenPtr[varIndex];
  1161.     tokenPtr->type = TCL_TOKEN_TEXT;
  1162.     tokenPtr->size = 1;
  1163.     tokenPtr->numComponents = 0;
  1164.     return TCL_OK;
  1165.     error:
  1166.     Tcl_FreeParse(parsePtr);
  1167.     return TCL_ERROR;
  1168. }
  1169. /*
  1170.  *----------------------------------------------------------------------
  1171.  *
  1172.  * Tcl_ParseVar --
  1173.  *
  1174.  * Given a string starting with a $ sign, parse off a variable
  1175.  * name and return its value.
  1176.  *
  1177.  * Results:
  1178.  * The return value is the contents of the variable given by
  1179.  * the leading characters of string.  If termPtr isn't NULL,
  1180.  * *termPtr gets filled in with the address of the character
  1181.  * just after the last one in the variable specifier.  If the
  1182.  * variable doesn't exist, then the return value is NULL and
  1183.  * an error message will be left in interp's result.
  1184.  *
  1185.  * Side effects:
  1186.  * None.
  1187.  *
  1188.  *----------------------------------------------------------------------
  1189.  */
  1190. CONST char *
  1191. Tcl_ParseVar(interp, string, termPtr)
  1192.     Tcl_Interp *interp; /* Context for looking up variable. */
  1193.     register CONST char *string; /* String containing variable name.
  1194.  * First character must be "$". */
  1195.     CONST char **termPtr; /* If non-NULL, points to word to fill
  1196.  * in with character just after last
  1197.  * one in the variable specifier. */
  1198. {
  1199.     Tcl_Parse parse;
  1200.     register Tcl_Obj *objPtr;
  1201.     int code;
  1202.     if (Tcl_ParseVarName(interp, string, -1, &parse, 0) != TCL_OK) {
  1203. return NULL;
  1204.     }
  1205.     if (termPtr != NULL) {
  1206. *termPtr = string + parse.tokenPtr->size;
  1207.     }
  1208.     if (parse.numTokens == 1) {
  1209. /*
  1210.  * There isn't a variable name after all: the $ is just a $.
  1211.  */
  1212. return "$";
  1213.     }
  1214.     code = Tcl_EvalTokensStandard(interp, parse.tokenPtr, parse.numTokens);
  1215.     if (code != TCL_OK) {
  1216. return NULL;
  1217.     }
  1218.     objPtr = Tcl_GetObjResult(interp);
  1219.     /*
  1220.      * At this point we should have an object containing the value of
  1221.      * a variable.  Just return the string from that object.
  1222.      *
  1223.      * This should have returned the object for the user to manage, but
  1224.      * instead we have some weak reference to the string value in the
  1225.      * object, which is why we make sure the object exists after resetting
  1226.      * the result.  This isn't ideal, but it's the best we can do with the
  1227.      * current documented interface. -- hobbs
  1228.      */
  1229.     if (!Tcl_IsShared(objPtr)) {
  1230. Tcl_IncrRefCount(objPtr);
  1231.     }
  1232.     Tcl_ResetResult(interp);
  1233.     return TclGetString(objPtr);
  1234. }
  1235. /*
  1236.  *----------------------------------------------------------------------
  1237.  *
  1238.  * Tcl_ParseBraces --
  1239.  *
  1240.  * Given a string in braces such as a Tcl command argument or a string
  1241.  * value in a Tcl expression, this procedure parses the string and
  1242.  * returns information about the parse.  No more than numBytes bytes
  1243.  * will be scanned.
  1244.  *
  1245.  * Results:
  1246.  * The return value is TCL_OK if the string was parsed successfully and
  1247.  * TCL_ERROR otherwise. If an error occurs and interp isn't NULL then
  1248.  * an error message is left in its result. On a successful return,
  1249.  * tokenPtr and numTokens fields of parsePtr are filled in with
  1250.  * information about the string that was parsed. Other fields in
  1251.  * parsePtr are undefined. termPtr is set to point to the character
  1252.  * just after the last one in the braced string.
  1253.  *
  1254.  * Side effects:
  1255.  * If there is insufficient space in parsePtr to hold all the
  1256.  * information about the command, then additional space is
  1257.  * malloc-ed. If the procedure returns TCL_OK then the caller must
  1258.  * eventually invoke Tcl_FreeParse to release any additional space
  1259.  * that was allocated.
  1260.  *
  1261.  *----------------------------------------------------------------------
  1262.  */
  1263. int
  1264. Tcl_ParseBraces(interp, string, numBytes, parsePtr, append, termPtr)
  1265.     Tcl_Interp *interp; /* Interpreter to use for error reporting;
  1266.  * if NULL, then no error message is
  1267.  * provided. */
  1268.     CONST char *string; /* String containing the string in braces.
  1269.  * The first character must be '{'. */
  1270.     register int numBytes; /* Total number of bytes in string. If < 0,
  1271.  * the string consists of all bytes up to
  1272.  * the first null character. */
  1273.     register Tcl_Parse *parsePtr;
  1274.      /* Structure to fill in with information
  1275.  * about the string. */
  1276.     int append; /* Non-zero means append tokens to existing
  1277.  * information in parsePtr; zero means
  1278.  * ignore existing tokens in parsePtr and
  1279.  * reinitialize it. */
  1280.     CONST char **termPtr; /* If non-NULL, points to word in which to
  1281.  * store a pointer to the character just
  1282.  * after the terminating '}' if the parse
  1283.  * was successful. */
  1284. {
  1285.     Tcl_Token *tokenPtr;
  1286.     register CONST char *src;
  1287.     int startIndex, level, length;
  1288.     if ((numBytes == 0) || (string == NULL)) {
  1289. return TCL_ERROR;
  1290.     }
  1291.     if (numBytes < 0) {
  1292. numBytes = strlen(string);
  1293.     }
  1294.     if (!append) {
  1295. parsePtr->numWords = 0;
  1296. parsePtr->tokenPtr = parsePtr->staticTokens;
  1297. parsePtr->numTokens = 0;
  1298. parsePtr->tokensAvailable = NUM_STATIC_TOKENS;
  1299. parsePtr->string = string;
  1300. parsePtr->end = (string + numBytes);
  1301. parsePtr->interp = interp;
  1302. parsePtr->errorType = TCL_PARSE_SUCCESS;
  1303.     }
  1304.     src = string;
  1305.     startIndex = parsePtr->numTokens;
  1306.     if (parsePtr->numTokens == parsePtr->tokensAvailable) {
  1307. TclExpandTokenArray(parsePtr);
  1308.     }
  1309.     tokenPtr = &parsePtr->tokenPtr[startIndex];
  1310.     tokenPtr->type = TCL_TOKEN_TEXT;
  1311.     tokenPtr->start = src+1;
  1312.     tokenPtr->numComponents = 0;
  1313.     level = 1;
  1314.     while (1) {
  1315. while (++src, --numBytes) {
  1316.     if (CHAR_TYPE(*src) != TYPE_NORMAL) {
  1317. break;
  1318.     }
  1319. }
  1320. if (numBytes == 0) {
  1321.     register int openBrace = 0;
  1322.     parsePtr->errorType = TCL_PARSE_MISSING_BRACE;
  1323.     parsePtr->term = string;
  1324.     parsePtr->incomplete = 1;
  1325.     if (parsePtr->interp == NULL) {
  1326. /*
  1327.  * Skip straight to the exit code since we have no
  1328.  * interpreter to put error message in.
  1329.  */
  1330. goto error;
  1331.     }
  1332.     Tcl_SetResult(parsePtr->interp, "missing close-brace", TCL_STATIC);
  1333.     /*
  1334.      *  Guess if the problem is due to comments by searching
  1335.      *  the source string for a possible open brace within the
  1336.      *  context of a comment.  Since we aren't performing a
  1337.      *  full Tcl parse, just look for an open brace preceded
  1338.      *  by a '<whitespace>#' on the same line.
  1339.      */
  1340.     while (--src > string) {
  1341. switch (*src) {
  1342.     case '{':
  1343. openBrace = 1;
  1344. break;
  1345.     case 'n':
  1346. openBrace = 0;
  1347. break;
  1348.     case '#' :
  1349. if (openBrace && (isspace(UCHAR(src[-1])))) {
  1350.     Tcl_AppendResult(parsePtr->interp,
  1351.     ": possible unbalanced brace in comment",
  1352.     (char *) NULL);
  1353.     goto error;
  1354. }
  1355. break;
  1356. }
  1357.     }
  1358.     error:
  1359.     Tcl_FreeParse(parsePtr);
  1360.     return TCL_ERROR;
  1361. }
  1362. switch (*src) {
  1363.     case '{':
  1364. level++;
  1365. break;
  1366.     case '}':
  1367. if (--level == 0) {
  1368.     /*
  1369.      * Decide if we need to finish emitting a
  1370.      * partially-finished token.  There are 3 cases:
  1371.      *     {abc newline xyz} or {xyz}
  1372.      * - finish emitting "xyz" token
  1373.      *     {abc newline}
  1374.      * - don't emit token after newline
  1375.      *     {} - finish emitting zero-sized token
  1376.      *
  1377.      * The last case ensures that there is a token
  1378.      * (even if empty) that describes the braced string.
  1379.      */
  1380.     
  1381.     if ((src != tokenPtr->start)
  1382.     || (parsePtr->numTokens == startIndex)) {
  1383. tokenPtr->size = (src - tokenPtr->start);
  1384. parsePtr->numTokens++;
  1385.     }
  1386.     if (termPtr != NULL) {
  1387. *termPtr = src+1;
  1388.     }
  1389.     return TCL_OK;
  1390. }
  1391. break;
  1392.     case '\':
  1393. TclParseBackslash(src, numBytes, &length, NULL);
  1394. if ((length > 1) && (src[1] == 'n')) {
  1395.     /*
  1396.      * A backslash-newline sequence must be collapsed, even
  1397.      * inside braces, so we have to split the word into
  1398.      * multiple tokens so that the backslash-newline can be
  1399.      * represented explicitly.
  1400.      */
  1401.     if (numBytes == 2) {
  1402. parsePtr->incomplete = 1;
  1403.     }
  1404.     tokenPtr->size = (src - tokenPtr->start);
  1405.     if (tokenPtr->size != 0) {
  1406. parsePtr->numTokens++;
  1407.     }
  1408.     if ((parsePtr->numTokens+1) >= parsePtr->tokensAvailable) {
  1409. TclExpandTokenArray(parsePtr);
  1410.     }
  1411.     tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens];
  1412.     tokenPtr->type = TCL_TOKEN_BS;
  1413.     tokenPtr->start = src;
  1414.     tokenPtr->size = length;
  1415.     tokenPtr->numComponents = 0;
  1416.     parsePtr->numTokens++;
  1417.     src += length - 1;
  1418.     numBytes -= length - 1;
  1419.     tokenPtr++;
  1420.     tokenPtr->type = TCL_TOKEN_TEXT;
  1421.     tokenPtr->start = src + 1;
  1422.     tokenPtr->numComponents = 0;
  1423. } else {
  1424.     src += length - 1;
  1425.     numBytes -= length - 1;
  1426. }
  1427. break;
  1428. }
  1429.     }
  1430. }
  1431. /*
  1432.  *----------------------------------------------------------------------
  1433.  *
  1434.  * Tcl_ParseQuotedString --
  1435.  *
  1436.  * Given a double-quoted string such as a quoted Tcl command argument
  1437.  * or a quoted value in a Tcl expression, this procedure parses the
  1438.  * string and returns information about the parse.  No more than
  1439.  * numBytes bytes will be scanned.
  1440.  *
  1441.  * Results:
  1442.  * The return value is TCL_OK if the string was parsed successfully and
  1443.  * TCL_ERROR otherwise. If an error occurs and interp isn't NULL then
  1444.  * an error message is left in its result. On a successful return,
  1445.  * tokenPtr and numTokens fields of parsePtr are filled in with
  1446.  * information about the string that was parsed. Other fields in
  1447.  * parsePtr are undefined. termPtr is set to point to the character
  1448.  * just after the quoted string's terminating close-quote.
  1449.  *
  1450.  * Side effects:
  1451.  * If there is insufficient space in parsePtr to hold all the
  1452.  * information about the command, then additional space is
  1453.  * malloc-ed. If the procedure returns TCL_OK then the caller must
  1454.  * eventually invoke Tcl_FreeParse to release any additional space
  1455.  * that was allocated.
  1456.  *
  1457.  *----------------------------------------------------------------------
  1458.  */
  1459. int
  1460. Tcl_ParseQuotedString(interp, string, numBytes, parsePtr, append, termPtr)
  1461.     Tcl_Interp *interp; /* Interpreter to use for error reporting;
  1462.  * if NULL, then no error message is
  1463.  * provided. */
  1464.     CONST char *string; /* String containing the quoted string. 
  1465.  * The first character must be '"'. */
  1466.     register int numBytes; /* Total number of bytes in string. If < 0,
  1467.  * the string consists of all bytes up to
  1468.  * the first null character. */
  1469.     register Tcl_Parse *parsePtr;
  1470.      /* Structure to fill in with information
  1471.  * about the string. */
  1472.     int append; /* Non-zero means append tokens to existing
  1473.  * information in parsePtr; zero means
  1474.  * ignore existing tokens in parsePtr and
  1475.  * reinitialize it. */
  1476.     CONST char **termPtr; /* If non-NULL, points to word in which to
  1477.  * store a pointer to the character just
  1478.  * after the quoted string's terminating
  1479.  * close-quote if the parse succeeds. */
  1480. {
  1481.     if ((numBytes == 0) || (string == NULL)) {
  1482. return TCL_ERROR;
  1483.     }
  1484.     if (numBytes < 0) {
  1485. numBytes = strlen(string);
  1486.     }
  1487.     if (!append) {
  1488. parsePtr->numWords = 0;
  1489. parsePtr->tokenPtr = parsePtr->staticTokens;
  1490. parsePtr->numTokens = 0;
  1491. parsePtr->tokensAvailable = NUM_STATIC_TOKENS;
  1492. parsePtr->string = string;
  1493. parsePtr->end = (string + numBytes);
  1494. parsePtr->interp = interp;
  1495. parsePtr->errorType = TCL_PARSE_SUCCESS;
  1496.     }
  1497.     
  1498.     if (ParseTokens(string+1, numBytes-1, TYPE_QUOTE, parsePtr) != TCL_OK) {
  1499. goto error;
  1500.     }
  1501.     if (*parsePtr->term != '"') {
  1502. if (parsePtr->interp != NULL) {
  1503.     Tcl_SetResult(parsePtr->interp, "missing "", TCL_STATIC);
  1504. }
  1505. parsePtr->errorType = TCL_PARSE_MISSING_QUOTE;
  1506. parsePtr->term = string;
  1507. parsePtr->incomplete = 1;
  1508. goto error;
  1509.     }
  1510.     if (termPtr != NULL) {
  1511. *termPtr = (parsePtr->term + 1);
  1512.     }
  1513.     return TCL_OK;
  1514.     error:
  1515.     Tcl_FreeParse(parsePtr);
  1516.     return TCL_ERROR;
  1517. }
  1518. /*
  1519.  *----------------------------------------------------------------------
  1520.  *
  1521.  * CommandComplete --
  1522.  *
  1523.  * This procedure is shared by TclCommandComplete and
  1524.  * Tcl_ObjCommandcoComplete; it does all the real work of seeing
  1525.  * whether a script is complete
  1526.  *
  1527.  * Results:
  1528.  * 1 is returned if the script is complete, 0 if there are open
  1529.  * delimiters such as " or (. 1 is also returned if there is a
  1530.  * parse error in the script other than unmatched delimiters.
  1531.  *
  1532.  * Side effects:
  1533.  * None.
  1534.  *
  1535.  *----------------------------------------------------------------------
  1536.  */
  1537. static int
  1538. CommandComplete(script, numBytes)
  1539.     CONST char *script; /* Script to check. */
  1540.     int numBytes; /* Number of bytes in script. */
  1541. {
  1542.     Tcl_Parse parse;
  1543.     CONST char *p, *end;
  1544.     int result;
  1545.     p = script;
  1546.     end = p + numBytes;
  1547.     while (Tcl_ParseCommand((Tcl_Interp *) NULL, p, end - p, 0, &parse)
  1548.     == TCL_OK) {
  1549. p = parse.commandStart + parse.commandSize;
  1550. if (p >= end) {
  1551.     break;
  1552. }
  1553. Tcl_FreeParse(&parse);
  1554.     }
  1555.     if (parse.incomplete) {
  1556. result = 0;
  1557.     } else {
  1558. result = 1;
  1559.     }
  1560.     Tcl_FreeParse(&parse);
  1561.     return result;
  1562. }
  1563. /*
  1564.  *----------------------------------------------------------------------
  1565.  *
  1566.  * Tcl_CommandComplete --
  1567.  *
  1568.  * Given a partial or complete Tcl script, this procedure
  1569.  * determines whether the script is complete in the sense
  1570.  * of having matched braces and quotes and brackets.
  1571.  *
  1572.  * Results:
  1573.  * 1 is returned if the script is complete, 0 otherwise.
  1574.  * 1 is also returned if there is a parse error in the script
  1575.  * other than unmatched delimiters.
  1576.  *
  1577.  * Side effects:
  1578.  * None.
  1579.  *
  1580.  *----------------------------------------------------------------------
  1581.  */
  1582. int
  1583. Tcl_CommandComplete(script)
  1584.     CONST char *script; /* Script to check. */
  1585. {
  1586.     return CommandComplete(script, (int) strlen(script));
  1587. }
  1588. /*
  1589.  *----------------------------------------------------------------------
  1590.  *
  1591.  * TclObjCommandComplete --
  1592.  *
  1593.  * Given a partial or complete Tcl command in a Tcl object, this
  1594.  * procedure determines whether the command is complete in the sense of
  1595.  * having matched braces and quotes and brackets.
  1596.  *
  1597.  * Results:
  1598.  * 1 is returned if the command is complete, 0 otherwise.
  1599.  *
  1600.  * Side effects:
  1601.  * None.
  1602.  *
  1603.  *----------------------------------------------------------------------
  1604.  */
  1605. int
  1606. TclObjCommandComplete(objPtr)
  1607.     Tcl_Obj *objPtr; /* Points to object holding script
  1608.  * to check. */
  1609. {
  1610.     CONST char *script;
  1611.     int length;
  1612.     script = Tcl_GetStringFromObj(objPtr, &length);
  1613.     return CommandComplete(script, length);
  1614. }
  1615. /*
  1616.  *----------------------------------------------------------------------
  1617.  *
  1618.  * TclIsLocalScalar --
  1619.  *
  1620.  * Check to see if a given string is a legal scalar variable
  1621.  * name with no namespace qualifiers or substitutions.
  1622.  *
  1623.  * Results:
  1624.  * Returns 1 if the variable is a local scalar.
  1625.  *
  1626.  * Side effects:
  1627.  * None.
  1628.  *
  1629.  *----------------------------------------------------------------------
  1630.  */
  1631. int
  1632. TclIsLocalScalar(src, len)
  1633.     CONST char *src;
  1634.     int len;
  1635. {
  1636.     CONST char *p;
  1637.     CONST char *lastChar = src + (len - 1);
  1638.     for (p = src; p <= lastChar; p++) {
  1639. if ((CHAR_TYPE(*p) != TYPE_NORMAL) &&
  1640. (CHAR_TYPE(*p) != TYPE_COMMAND_END)) {
  1641.     /*
  1642.      * TCL_COMMAND_END is returned for the last character
  1643.      * of the string.  By this point we know it isn't
  1644.      * an array or namespace reference.
  1645.      */
  1646.     return 0;
  1647. }
  1648. if  (*p == '(') {
  1649.     if (*lastChar == ')') { /* we have an array element */
  1650. return 0;
  1651.     }
  1652. } else if (*p == ':') {
  1653.     if ((p != lastChar) && *(p+1) == ':') { /* qualified name */
  1654. return 0;
  1655.     }
  1656. }
  1657.     }
  1658.     return 1;
  1659. }