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