]>
git.zerfleddert.de Git - micropolis/blob - src/tcl/tclparse.c
4 * This file contains a collection of procedures that are used
5 * to parse Tcl commands or parts of commands (like quoted
6 * strings or nested sub-commands).
8 * Copyright 1991 Regents of the University of California.
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
19 static char rcsid
[] = "$Header: /user6/ouster/tcl/RCS/tclParse.c,v 1.21 92/06/08 09:32:37 ouster Exp $ SPRITE (Berkeley)";
25 * The following table assigns a type to each character. Only types
26 * meaningful to Tcl parsing are represented here. The table indexes
27 * all 256 characters, with the negative ones first, then the positive
31 char tclTypeTable
[] = {
32 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
33 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
34 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
35 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
36 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
37 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
38 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
39 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
40 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
41 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
42 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
43 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
44 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
45 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
46 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
47 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
48 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
49 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
50 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
51 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
52 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
53 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
54 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
55 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
56 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
57 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
58 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
59 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
60 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
61 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
62 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
63 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
64 TCL_COMMAND_END
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
65 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
66 TCL_NORMAL
, TCL_SPACE
, TCL_COMMAND_END
, TCL_SPACE
,
67 TCL_SPACE
, TCL_SPACE
, TCL_NORMAL
, TCL_NORMAL
,
68 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
69 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
70 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
71 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
72 TCL_SPACE
, TCL_NORMAL
, TCL_QUOTE
, TCL_NORMAL
,
73 TCL_DOLLAR
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
74 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
75 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
76 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
77 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
78 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_COMMAND_END
,
79 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
80 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
81 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
82 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
83 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
84 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
85 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
86 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_OPEN_BRACKET
,
87 TCL_BACKSLASH
, TCL_COMMAND_END
, TCL_NORMAL
, TCL_NORMAL
,
88 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
89 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
90 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
91 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
92 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
93 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
,
94 TCL_NORMAL
, TCL_NORMAL
, TCL_NORMAL
, TCL_OPEN_BRACE
,
95 TCL_NORMAL
, TCL_CLOSE_BRACE
, TCL_NORMAL
, TCL_NORMAL
,
99 * Function prototypes for procedures local to this file:
102 static char * QuoteEnd
_ANSI_ARGS_((char *string
, int term
));
103 static char * VarNameEnd
_ANSI_ARGS_((char *string
));
106 *----------------------------------------------------------------------
110 * Figure out how to handle a backslash sequence.
113 * The return value is the character that should be substituted
114 * in place of the backslash sequence that starts at src, or 0
115 * if the backslash sequence should be replace by nothing (e.g.
116 * backslash followed by newline). If readPtr isn't NULL then
117 * it is filled in with a count of the number of characters in
118 * the backslash sequence. Note: if the backslash isn't followed
119 * by characters that are understood here, then the backslash
120 * sequence is only considered to be one character long, and it
121 * is replaced by a backslash char.
126 *----------------------------------------------------------------------
130 Tcl_Backslash(src
, readPtr
)
131 char *src
; /* Points to the backslash character of
132 * a backslash sequence. */
133 int *readPtr
; /* Fill in with number of characters read
134 * from src, unless NULL. */
136 register char *p
= src
+1;
166 if (isspace(*p
) || (*p
== 0)) {
174 if (isspace(*p
) || (*p
== 0)) {
179 result
= (*p
& 037) | 0200;
187 if (isspace(*p
) || (*p
== 0)) {
217 result
= (result
<< 3) + (*p
- '0');
223 result
= (result
<< 3) + (*p
- '0');
231 if (readPtr
!= NULL
) {
238 *--------------------------------------------------------------
242 * This procedure parses a double-quoted string such as a
243 * quoted Tcl command argument or a quoted value in a Tcl
244 * expression. This procedure is also used to parse array
245 * element names within parentheses, or anything else that
246 * needs all the substitutions that happen in quotes.
249 * The return value is a standard Tcl result, which is
250 * TCL_OK unless there was an error while parsing the
251 * quoted string. If an error occurs then interp->result
252 * contains a standard error message. *TermPtr is filled
253 * in with the address of the character just after the
254 * last one successfully processed; this is usually the
255 * character just after the matching close-quote. The
256 * fully-substituted contents of the quotes are stored in
257 * standard fashion in *pvPtr, null-terminated with
258 * pvPtr->next pointing to the terminating null character.
261 * The buffer space in pvPtr may be enlarged by calling its
264 *--------------------------------------------------------------
268 TclParseQuotes(interp
, string
, termChar
, flags
, termPtr
, pvPtr
)
269 Tcl_Interp
*interp
; /* Interpreter to use for nested command
270 * evaluations and error messages. */
271 char *string
; /* Character just after opening double-
273 int termChar
; /* Character that terminates "quoted" string
274 * (usually double-quote, but sometimes
275 * right-paren or something else). */
276 int flags
; /* Flags to pass to nested Tcl_Eval calls. */
277 char **termPtr
; /* Store address of terminating character
279 ParseValue
*pvPtr
; /* Information about where to place
280 * fully-substituted result of parse. */
282 register char *src
, *dst
, c
;
288 if (dst
== pvPtr
->end
) {
290 * Target buffer space is about to run out. Make more space.
294 (*pvPtr
->expandProc
)(pvPtr
, 1);
305 } else if (CHAR_TYPE(c
) == TCL_NORMAL
) {
310 } else if (c
== '$') {
314 value
= Tcl_ParseVar(interp
, src
-1, termPtr
);
319 length
= strlen(value
);
320 if ((pvPtr
->end
- dst
) <= length
) {
322 (*pvPtr
->expandProc
)(pvPtr
, length
);
328 } else if (c
== '[') {
332 result
= TclParseNestedCmd(interp
, src
, flags
, termPtr
, pvPtr
);
333 if (result
!= TCL_OK
) {
339 } else if (c
== '\\') {
343 *dst
= Tcl_Backslash(src
, &numRead
);
349 } else if (c
== '\0') {
350 Tcl_ResetResult(interp
);
351 sprintf(interp
->result
, "missing %c", termChar
);
361 *--------------------------------------------------------------
363 * TclParseNestedCmd --
365 * This procedure parses a nested Tcl command between
366 * brackets, returning the result of the command.
369 * The return value is a standard Tcl result, which is
370 * TCL_OK unless there was an error while executing the
371 * nested command. If an error occurs then interp->result
372 * contains a standard error message. *TermPtr is filled
373 * in with the address of the character just after the
374 * last one processed; this is usually the character just
375 * after the matching close-bracket, or the null character
376 * at the end of the string if the close-bracket was missing
377 * (a missing close bracket is an error). The result returned
378 * by the command is stored in standard fashion in *pvPtr,
379 * null-terminated, with pvPtr->next pointing to the null
383 * The storage space at *pvPtr may be expanded.
385 *--------------------------------------------------------------
389 TclParseNestedCmd(interp
, string
, flags
, termPtr
, pvPtr
)
390 Tcl_Interp
*interp
; /* Interpreter to use for nested command
391 * evaluations and error messages. */
392 char *string
; /* Character just after opening bracket. */
393 int flags
; /* Flags to pass to nested Tcl_Eval. */
394 char **termPtr
; /* Store address of terminating character
396 register ParseValue
*pvPtr
; /* Information about where to place
397 * result of command. */
399 int result
, length
, shortfall
;
400 Interp
*iPtr
= (Interp
*) interp
;
402 result
= Tcl_Eval(interp
, string
, flags
| TCL_BRACKET_TERM
, termPtr
);
403 if (result
!= TCL_OK
) {
405 * The increment below results in slightly cleaner message in
406 * the errorInfo variable (the close-bracket will appear).
409 if (**termPtr
== ']') {
415 length
= strlen(iPtr
->result
);
416 shortfall
= length
+ 1 - (pvPtr
->end
- pvPtr
->next
);
418 (*pvPtr
->expandProc
)(pvPtr
, shortfall
);
420 strcpy(pvPtr
->next
, iPtr
->result
);
421 pvPtr
->next
+= length
;
422 Tcl_FreeResult(iPtr
);
423 iPtr
->result
= iPtr
->resultSpace
;
424 iPtr
->resultSpace
[0] = '\0';
429 *--------------------------------------------------------------
433 * This procedure scans the information between matching
437 * The return value is a standard Tcl result, which is
438 * TCL_OK unless there was an error while parsing string.
439 * If an error occurs then interp->result contains a
440 * standard error message. *TermPtr is filled
441 * in with the address of the character just after the
442 * last one successfully processed; this is usually the
443 * character just after the matching close-brace. The
444 * information between curly braces is stored in standard
445 * fashion in *pvPtr, null-terminated with pvPtr->next
446 * pointing to the terminating null character.
449 * The storage space at *pvPtr may be expanded.
451 *--------------------------------------------------------------
455 TclParseBraces(interp
, string
, termPtr
, pvPtr
)
456 Tcl_Interp
*interp
; /* Interpreter to use for nested command
457 * evaluations and error messages. */
458 char *string
; /* Character just after opening bracket. */
459 char **termPtr
; /* Store address of terminating character
461 register ParseValue
*pvPtr
; /* Information about where to place
462 * result of command. */
465 register char *src
, *dst
, *end
;
474 * Copy the characters one at a time to the result area, stopping
475 * when the matching close-brace is found.
483 (*pvPtr
->expandProc
)(pvPtr
, 20);
489 if (CHAR_TYPE(c
) == TCL_NORMAL
) {
491 } else if (c
== '{') {
493 } else if (c
== '}') {
496 dst
--; /* Don't copy the last close brace. */
499 } else if (c
== '\\') {
503 * Must always squish out backslash-newlines, even when in
504 * braces. This is needed so that this sequence can appear
505 * anywhere in a command, such as the middle of an expression.
512 (void) Tcl_Backslash(src
-1, &count
);
516 (*pvPtr
->expandProc
)(pvPtr
, 20);
526 } else if (c
== '\0') {
527 Tcl_SetResult(interp
, "missing close-brace", TCL_STATIC
);
540 *--------------------------------------------------------------
544 * This procedure parses one or more words from a command
545 * string and creates argv-style pointers to fully-substituted
546 * copies of those words.
549 * The return value is a standard Tcl result.
551 * *argcPtr is modified to hold a count of the number of words
552 * successfully parsed, which may be 0. At most maxWords words
553 * will be parsed. If 0 <= *argcPtr < maxWords then it
554 * means that a command separator was seen. If *argcPtr
555 * is maxWords then it means that a command separator was
558 * *TermPtr is filled in with the address of the character
559 * just after the last one successfully processed in the
560 * last word. This is either the command terminator (if
561 * *argcPtr < maxWords), the character just after the last
562 * one in a word (if *argcPtr is maxWords), or the vicinity
563 * of an error (if the result is not TCL_OK).
565 * The pointers at *argv are filled in with pointers to the
566 * fully-substituted words, and the actual contents of the
567 * words are copied to the buffer at pvPtr.
569 * If an error occurrs then an error message is left in
570 * interp->result and the information at *argv, *argcPtr,
571 * and *pvPtr may be incomplete.
574 * The buffer space in pvPtr may be enlarged by calling its
577 *--------------------------------------------------------------
581 TclParseWords(interp
, string
, flags
, maxWords
, termPtr
, argcPtr
, argv
, pvPtr
)
582 Tcl_Interp
*interp
; /* Interpreter to use for nested command
583 * evaluations and error messages. */
584 char *string
; /* First character of word. */
585 int flags
; /* Flags to control parsing (same values as
586 * passed to Tcl_Eval). */
587 int maxWords
; /* Maximum number of words to parse. */
588 char **termPtr
; /* Store address of terminating character
590 int *argcPtr
; /* Filled in with actual number of words
592 char **argv
; /* Store addresses of individual words here. */
593 register ParseValue
*pvPtr
; /* Information about where to place
594 * fully-substituted word. */
596 register char *src
, *dst
;
598 int type
, result
, argc
;
599 char *oldBuffer
; /* Used to detect when pvPtr's buffer gets
600 * reallocated, so we can adjust all of the
604 oldBuffer
= pvPtr
->buffer
;
606 for (argc
= 0; argc
< maxWords
; argc
++) {
610 * Skip leading space.
616 while (type
== TCL_SPACE
) {
623 * Handle the normal case (i.e. no leading double-quote or brace).
626 if (type
== TCL_NORMAL
) {
629 if (dst
== pvPtr
->end
) {
631 * Target buffer space is about to run out. Make
636 (*pvPtr
->expandProc
)(pvPtr
, 1);
640 if (type
== TCL_NORMAL
) {
645 } else if (type
== TCL_SPACE
) {
647 } else if (type
== TCL_DOLLAR
) {
651 value
= Tcl_ParseVar(interp
, src
, termPtr
);
656 length
= strlen(value
);
657 if ((pvPtr
->end
- dst
) <= length
) {
659 (*pvPtr
->expandProc
)(pvPtr
, length
);
664 } else if (type
== TCL_COMMAND_END
) {
665 if ((c
== ']') && !(flags
& TCL_BRACKET_TERM
)) {
670 * End of command; simulate a word-end first, so
671 * that the end-of-command can be processed as the
672 * first thing in a new word.
676 } else if (type
== TCL_OPEN_BRACKET
) {
678 result
= TclParseNestedCmd(interp
, src
+1, flags
, termPtr
,
680 if (result
!= TCL_OK
) {
685 } else if (type
== TCL_BACKSLASH
) {
688 *dst
= Tcl_Backslash(src
, &numRead
);
702 * Check for the end of the command.
705 if (type
== TCL_COMMAND_END
) {
706 if (flags
& TCL_BRACKET_TERM
) {
708 Tcl_SetResult(interp
, "missing close-bracket",
721 * Now handle the special cases: open braces, double-quotes,
722 * and backslash-newline.
726 if (type
== TCL_QUOTE
) {
727 result
= TclParseQuotes(interp
, src
+1, '"', flags
,
729 } else if (type
== TCL_OPEN_BRACE
) {
730 result
= TclParseBraces(interp
, src
+1, termPtr
, pvPtr
);
731 } else if ((type
== TCL_BACKSLASH
) && (src
[1] == '\n')) {
737 if (result
!= TCL_OK
) {
742 * Back from quotes or braces; make sure that the terminating
743 * character was the end of the word. Have to be careful here
744 * to handle continuation lines (i.e. lines ending in backslash).
748 if ((c
== '\\') && ((*termPtr
)[1] == '\n')) {
752 if ((type
!= TCL_SPACE
) && (type
!= TCL_COMMAND_END
)) {
754 Tcl_SetResult(interp
, "extra characters after close-quote",
757 Tcl_SetResult(interp
, "extra characters after close-brace",
768 * We're at the end of a word, so add a null terminator. Then
769 * see if the buffer was re-allocated during this word. If so,
770 * update all of the argv pointers.
776 if (oldBuffer
!= pvPtr
->buffer
) {
779 for (i
= 0; i
<= argc
; i
++) {
780 argv
[i
] = pvPtr
->buffer
+ (argv
[i
] - oldBuffer
);
782 oldBuffer
= pvPtr
->buffer
;
794 *--------------------------------------------------------------
796 * TclExpandParseValue --
798 * This procedure is commonly used as the value of the
799 * expandProc in a ParseValue. It uses malloc to allocate
800 * more space for the result of a parse.
803 * The buffer space in *pvPtr is reallocated to something
804 * larger, and if pvPtr->clientData is non-zero the old
805 * buffer is freed. Information is copied from the old
806 * buffer to the new one.
811 *--------------------------------------------------------------
815 TclExpandParseValue(pvPtr
, needed
)
816 register ParseValue
*pvPtr
; /* Information about buffer that
817 * must be expanded. If the clientData
818 * in the structure is non-zero, it
819 * means that the current buffer is
820 * dynamically allocated. */
821 int needed
; /* Minimum amount of additional space
828 * Either double the size of the buffer or add enough new space
829 * to meet the demand, whichever produces a larger new buffer.
832 newSpace
= (pvPtr
->end
- pvPtr
->buffer
) + 1;
833 if (newSpace
< needed
) {
836 newSpace
+= newSpace
;
838 new = (char *) ckalloc((unsigned) newSpace
);
841 * Copy from old buffer to new, free old buffer if needed, and
842 * mark new buffer as malloc-ed.
845 memcpy((VOID
*) new, (VOID
*) pvPtr
->buffer
, pvPtr
->next
- pvPtr
->buffer
);
846 pvPtr
->next
= new + (pvPtr
->next
- pvPtr
->buffer
);
847 if (pvPtr
->clientData
!= 0) {
848 ckfree(pvPtr
->buffer
);
851 pvPtr
->end
= new + newSpace
- 1;
852 pvPtr
->clientData
= (ClientData
) 1;
856 *----------------------------------------------------------------------
860 * Given a pointer into a Tcl command, find the end of the next
861 * word of the command.
864 * The return value is a pointer to the character just after the
865 * last one that's part of the word pointed to by "start". This
866 * may be the address of the NULL character at the end of the
872 *----------------------------------------------------------------------
876 TclWordEnd(start
, nested
)
877 char *start
; /* Beginning of a word of a Tcl command. */
878 int nested
; /* Zero means this is a top-level command.
879 * One means this is a nested command (close
880 * brace is a word terminator). */
886 while (isspace(*p
)) {
891 * Handle words beginning with a double-quote or a brace.
895 p
= QuoteEnd(p
+1, '"');
896 } else if (*p
== '{') {
898 while (braces
!= 0) {
901 (void) Tcl_Backslash(p
, &count
);
906 } else if (*p
== '{') {
908 } else if (*p
== 0) {
915 * Handle words that don't start with a brace or double-quote.
916 * This code is also invoked if the word starts with a brace or
917 * double-quote and there is garbage after the closing brace or
918 * quote. This is an error as far as Tcl_Eval is concerned, but
919 * for here the garbage is treated as part of the word.
925 while ((*p
!= ']') && (*p
!= 0)) {
926 p
= TclWordEnd(p
, 1);
931 } else if (*p
== '\\') {
932 (void) Tcl_Backslash(p
, &count
);
934 } else if (*p
== '$') {
936 } else if (*p
== ';') {
938 * Note: semi-colon terminates a word
939 * and also counts as a word by itself.
946 } else if (isspace(*p
)) {
948 } else if ((*p
== ']') && nested
) {
958 *----------------------------------------------------------------------
962 * Given a pointer to a string that obeys the parsing conventions
963 * for quoted things in Tcl, find the end of that quoted thing.
964 * The actual thing may be a quoted argument or a parenthesized
968 * The return value is a pointer to the character just after the
969 * last one that is part of the quoted string.
974 *----------------------------------------------------------------------
978 QuoteEnd(string
, term
)
979 char *string
; /* Pointer to character just after opening
981 int term
; /* This character will terminate the
982 * quoted string (e.g. '"' or ')'). */
984 register char *p
= string
;
987 while ((*p
!= 0) && (*p
!= term
)) {
989 (void) Tcl_Backslash(p
, &count
);
991 } else if (*p
== '[') {
993 while ((*p
!= ']') && (*p
!= 0)) {
994 p
= TclWordEnd(p
, 1);
999 } else if (*p
== '$') {
1009 *----------------------------------------------------------------------
1013 * Given a pointer to a variable reference using $-notation, find
1014 * the end of the variable name spec.
1017 * The return value is a pointer to the character just after the
1018 * last one that is part of the variable name.
1023 *----------------------------------------------------------------------
1028 char *string
; /* Pointer to dollar-sign character. */
1030 register char *p
= string
+1;
1035 } while ((*p
!= '}') && (*p
!= 0));
1037 while (isalnum(*p
) || (*p
== '_')) {
1040 if ((*p
== '(') && (p
!= string
+1)) {
1041 p
= QuoteEnd(p
+1, ')');
1048 *----------------------------------------------------------------------
1052 * Given a string starting with a $ sign, parse off a variable
1053 * name and return its value.
1056 * The return value is the contents of the variable given by
1057 * the leading characters of string. If termPtr isn't NULL,
1058 * *termPtr gets filled in with the address of the character
1059 * just after the last one in the variable specifier. If the
1060 * variable doesn't exist, then the return value is NULL and
1061 * an error message will be left in interp->result.
1066 *----------------------------------------------------------------------
1070 Tcl_ParseVar(interp
, string
, termPtr
)
1071 Tcl_Interp
*interp
; /* Context for looking up variable. */
1072 register char *string
; /* String containing variable name.
1073 * First character must be "$". */
1074 char **termPtr
; /* If non-NULL, points to word to fill
1075 * in with character just after last
1076 * one in the variable specifier. */
1079 char *name1
, *name1End
, c
, *result
;
1080 register char *name2
;
1081 #define NUM_CHARS 200
1082 char copyStorage
[NUM_CHARS
];
1086 * There are three cases:
1087 * 1. The $ sign is followed by an open curly brace. Then the variable
1088 * name is everything up to the next close curly brace, and the
1089 * variable is a scalar variable.
1090 * 2. The $ sign is not followed by an open curly brace. Then the
1091 * variable name is everything up to the next character that isn't
1092 * a letter, digit, or underscore. If the following character is an
1093 * open parenthesis, then the information between parentheses is
1094 * the array element name, which can include any of the substitutions
1095 * permissible between quotes.
1096 * 3. The $ sign is followed by something that isn't a letter, digit,
1097 * or underscore: in this case, there is no variable name, and "$"
1103 if (*string
== '{') {
1106 while (*string
!= '}') {
1108 Tcl_SetResult(interp
, "missing close-brace for variable name",
1121 while (isalnum(*string
) || (*string
== '_')) {
1124 if (string
== name1
) {
1131 if (*string
== '(') {
1135 * Perform substitutions on the array element name, just as
1136 * is done for quotes.
1139 pv
.buffer
= pv
.next
= copyStorage
;
1140 pv
.end
= copyStorage
+ NUM_CHARS
- 1;
1141 pv
.expandProc
= TclExpandParseValue
;
1142 pv
.clientData
= (ClientData
) NULL
;
1143 if (TclParseQuotes(interp
, string
+1, ')', 0, &end
, &pv
)
1146 sprintf(msg
, "\n (parsing index for array \"%.*s\")",
1147 string
-name1
, name1
);
1148 Tcl_AddErrorInfo(interp
, msg
);
1166 result
= Tcl_GetVar2(interp
, name1
, name2
, TCL_LEAVE_ERR_MSG
);
1170 if ((name2
!= NULL
) && (pv
.buffer
!= copyStorage
)) {