2 /* Expect depends on these Tcl functions, which have been removed
3 in the latest version of Tcl/Tk 8.3. */
8 * This file contains a collection of procedures that are used
9 * to parse Tcl commands or parts of commands (like quoted
10 * strings or nested sub-commands).
12 * Copyright (c) 1987-1993 The Regents of the University of California.
13 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
15 * See the file "license.terms" for information on usage and redistribution
16 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 /* Only do this for Tcl8.3 and above. */
23 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 2
27 static char *QuoteEnd(char *string, char *lastChar, int term);
28 static char *VarNameEnd(char *string, char *lastChar);
29 static char *ScriptEnd(char *p, char *lastChar, int nested);
31 *----------------------------------------------------------------------
35 * Given a pointer into a Tcl command, find the end of the next
36 * word of the command.
39 * The return value is a pointer to the last character that's part
40 * of the word pointed to by "start". If the word doesn't end
41 * properly within the string then the return value is the address
42 * of the null character at the end of the string.
47 *----------------------------------------------------------------------
51 TclWordEnd(start, lastChar, nested, semiPtr)
52 char *start; /* Beginning of a word of a Tcl command. */
53 char *lastChar; /* Terminating character in string. */
54 int nested; /* Zero means this is a top-level command.
55 * One means this is a nested command (close
56 * bracket is a word terminator). */
57 int *semiPtr; /* Set to 1 if word ends with a command-
58 * terminating semi-colon, zero otherwise.
59 * If NULL then ignored. */
64 if (semiPtr != NULL) {
69 * Skip leading white space (backslash-newline must be treated like
70 * white-space, except that it better not be the last thing in the
74 for (p = start; ; p++) {
75 if (isspace(UCHAR(*p))) {
78 if ((p[0] == '\\') && (p[1] == '\n')) {
79 if (p+2 == lastChar) {
88 * Handle words beginning with a double-quote or a brace.
92 p = QuoteEnd(p+1, lastChar, '"');
97 } else if (*p == '{') {
102 (void) Tcl_Backslash(p, &count);
107 } else if (*p == '{') {
109 } else if (p == lastChar) {
117 * Handle words that don't start with a brace or double-quote.
118 * This code is also invoked if the word starts with a brace or
119 * double-quote and there is garbage after the closing brace or
120 * quote. This is an error as far as Tcl_Eval is concerned, but
121 * for here the garbage is treated as part of the word.
126 p = ScriptEnd(p+1, lastChar, 1);
131 } else if (*p == '\\') {
134 * Backslash-newline: it maps to a space character
135 * that is a word separator, so the word ends just before
141 (void) Tcl_Backslash(p, &count);
143 } else if (*p == '$') {
144 p = VarNameEnd(p, lastChar);
149 } else if (*p == ';') {
151 * Include the semi-colon in the word that is returned.
154 if (semiPtr != NULL) {
158 } else if (isspace(UCHAR(*p))) {
160 } else if ((*p == ']') && nested) {
162 } else if (p == lastChar) {
165 * Nested commands can't end because of the end of the
178 *----------------------------------------------------------------------
182 * Given a pointer to a string that obeys the parsing conventions
183 * for quoted things in Tcl, find the end of that quoted thing.
184 * The actual thing may be a quoted argument or a parenthesized
188 * The return value is a pointer to the last character that is
189 * part of the quoted string (i.e the character that's equal to
190 * term). If the quoted string doesn't terminate properly then
191 * the return value is a pointer to the null character at the
197 *----------------------------------------------------------------------
201 QuoteEnd(string, lastChar, term)
202 char *string; /* Pointer to character just after opening
204 char *lastChar; /* Terminating character in string. */
205 int term; /* This character will terminate the
206 * quoted string (e.g. '"' or ')'). */
208 register char *p = string;
213 (void) Tcl_Backslash(p, &count);
215 } else if (*p == '[') {
216 for (p++; *p != ']'; p++) {
217 p = TclWordEnd(p, lastChar, 1, (int *) NULL);
223 } else if (*p == '$') {
224 p = VarNameEnd(p, lastChar);
229 } else if (p == lastChar) {
239 *----------------------------------------------------------------------
243 * Given a pointer to a variable reference using $-notation, find
244 * the end of the variable name spec.
247 * The return value is a pointer to the last character that
248 * is part of the variable name. If the variable name doesn't
249 * terminate properly then the return value is a pointer to the
250 * null character at the end of the string.
255 *----------------------------------------------------------------------
259 VarNameEnd(string, lastChar)
260 char *string; /* Pointer to dollar-sign character. */
261 char *lastChar; /* Terminating character in string. */
263 register char *p = string+1;
266 for (p++; (*p != '}') && (p != lastChar); p++) {
267 /* Empty loop body. */
271 while (isalnum(UCHAR(*p)) || (*p == '_')) {
274 if ((*p == '(') && (p != string+1)) {
275 return QuoteEnd(p+1, lastChar, ')');
282 *----------------------------------------------------------------------
286 * Given a pointer to the beginning of a Tcl script, find the end of
290 * The return value is a pointer to the last character that's part
291 * of the script pointed to by "p". If the command doesn't end
292 * properly within the string then the return value is the address
293 * of the null character at the end of the string.
298 *----------------------------------------------------------------------
302 ScriptEnd(p, lastChar, nested)
303 char *p; /* Script to check. */
304 char *lastChar; /* Terminating character in string. */
305 int nested; /* Zero means this is a top-level command.
306 * One means this is a nested command (the
307 * last character of the script must be
314 while (isspace(UCHAR(*p))) {
320 if ((*p == '#') && commentOK) {
324 * If the script ends with backslash-newline, then
325 * this command isn't complete.
328 if ((p[1] == '\n') && (p+2 == lastChar)) {
331 Tcl_Backslash(p, &length);
336 } while ((p != lastChar) && (*p != '\n'));
339 p = TclWordEnd(p, lastChar, nested, &commentOK);
356 #endif /* Tcl8.3 and above. */