summaryrefslogtreecommitdiffstats
path: root/generic/tclUtil.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclUtil.c')
-rw-r--r--generic/tclUtil.c147
1 files changed, 117 insertions, 30 deletions
diff --git a/generic/tclUtil.c b/generic/tclUtil.c
index d5a3b94..265651b 100644
--- a/generic/tclUtil.c
+++ b/generic/tclUtil.c
@@ -446,7 +446,7 @@ TclMaxListLength(
* If TCL_OK is returned, then *elementPtr will be set to point to the
* first element of list, and *nextPtr will be set to point to the
* character just after any white space following the last character
- * that's part of the element. If this is the last argument in the list,
+ * that's part of the element. If this is the last element in the list,
* then *nextPtr will point just after the last character in the list
* (i.e., at the character at list+listLength). If sizePtr is non-NULL,
* *sizePtr is filled in with the number of bytes in the element. If
@@ -496,6 +496,11 @@ TclFindElement(
const char *limit; /* Points just after list's last byte. */
int openBraces = 0; /* Brace nesting level during parse. */
int inQuotes = 0;
+ enum TFECommentState { /* TIP#??? */
+ ELEMENT_WORD, /* Not in a comment word (that we know). */
+ BEFORE_COMMENT, /* In a comment before the element. */
+ AFTER_COMMENT /* In a comment after the element. */
+ } inComment = ELEMENT_WORD;
int size = 0; /* lint. */
int numChars;
int literal = 1;
@@ -526,13 +531,15 @@ TclFindElement(
elemStart = p;
/*
- * Find element's end (a space, close brace, or the end of the string).
+ * Find end of word (a space, close brace, or the end of the string).
*/
+ mainLoop: /* Comment words may cause jumping back
+ * to this point in the function. */
while (p < limit) {
switch (*p) {
/*
- * Open brace: don't treat specially unless the element is in
+ * Open brace: don't treat specially unless the word is in
* braces. In this case, keep a nesting count.
*/
@@ -543,7 +550,7 @@ TclFindElement(
break;
/*
- * Close brace: if element is in braces, keep nesting count and
+ * Close brace: if word is in braces, keep nesting count and
* quit when the last close brace is seen.
*/
@@ -558,22 +565,47 @@ TclFindElement(
}
/*
- * Garbage after the closing brace; return an error.
+ * There is something after the closing brace. Could that
+ * be because it is the closing brace of a comment prefix?
*/
-
- if (interp != NULL) {
- p2 = p;
- while ((p2 < limit) && (!TclIsSpaceProc(*p2))
- && (p2 < p+20)) {
- p2++;
- }
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "list element in braces followed by \"%.*s\" "
- "instead of space", (int) (p2-p), p));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "JUNK",
- NULL);
- }
- return TCL_ERROR;
+
+ if ((size != 1) || (inComment != ELEMENT_WORD) ||
+ (*elemStart != '#')) {
+
+ /*
+ * No, that was no comment prefix, so *p is simply
+ * garbage after the closing brace; return an error.
+ */
+
+ if (interp != NULL) {
+ p2 = p;
+ while ((p2 < limit) && (!TclIsSpaceProc(*p2))
+ && (p2 < p+20)) {
+ p2++;
+ }
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "list element in braces followed by \"%.*s\" "
+ "instead of space", (int) (p2-p), p));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "JUNK",
+ NULL);
+ }
+ return TCL_ERROR;
+ }
+
+ /*
+ * Yes, that was a comment prefix. Check if the comment
+ * is brace- or quote-delimited.
+ */
+
+ inComment = BEFORE_COMMENT;
+ openBraces = 0;
+ if (*p == '{') {
+ openBraces = 1;
+ p++;
+ } else if (*p == '"') {
+ inQuotes = 1;
+ p++;
+ }
}
break;
@@ -585,7 +617,7 @@ TclFindElement(
case '\\':
if (openBraces == 0) {
/*
- * A backslash sequence not within a brace quoted element
+ * A backslash sequence not within a brace quoted word
* means the value of the element is different from the
* substring we are parsing. A call to TclCopyAndCollapse()
* is needed to produce the element value. Inform the caller.
@@ -597,8 +629,8 @@ TclFindElement(
break;
/*
- * Space: ignore if element is in braces or quotes; otherwise
- * terminate element.
+ * Space: ignore if word is in braces or quotes; otherwise
+ * terminate word.
*/
case ' ':
@@ -614,7 +646,7 @@ TclFindElement(
break;
/*
- * Double-quote: if element is in quotes then terminate it.
+ * Double-quote: if word is in quotes then terminate it.
*/
case '"':
@@ -649,7 +681,7 @@ TclFindElement(
}
/*
- * End of list: terminate element.
+ * End of list: terminate word.
*/
if (p == limit) {
@@ -677,14 +709,69 @@ TclFindElement(
while ((p < limit) && (TclIsSpaceProc(*p))) {
p++;
}
- *elementPtr = elemStart;
- *nextPtr = p;
- if (sizePtr != 0) {
- *sizePtr = size;
+ if (inComment == BEFORE_COMMENT) {
+
+ /*
+ * The word which has just been read was a comment rather than
+ * a list element, so we'll have to do it all again.
+ */
+
+ inComment = ELEMENT_WORD;
+ literal = 1;
+ openBraces = 0;
+ inQuotes = 0;
+ if (*p == '{') {
+ openBraces = 1;
+ p++;
+ } else if (*p == '"') {
+ inQuotes = 1;
+ p++;
+ }
+ elemStart = p;
+ goto mainLoop;
+ }
+ if (inComment == ELEMENT_WORD) {
+
+ /*
+ * The word which has just been read was the sought list element.
+ */
+
+ *elementPtr = elemStart;
+ if (sizePtr != 0) {
+ *sizePtr = size;
+ }
+ if (literalPtr != 0) {
+ *literalPtr = literal;
+ }
}
- if (literalPtr != 0) {
- *literalPtr = literal;
+ *nextPtr = p;
+
+ /*
+ * Could there be a comment word after what has been read so far?
+ */
+
+ if ((limit - p > 3) && (p[0] == '{') && (p[1] == '#') &&
+ (p[2] == '}') && !(TclIsSpaceProc(p[3]))) {
+ /*
+ * It appears there is, so go back and scan past it.
+ * This is needed because callers use (*nextPtr == limit) as
+ * a test for whether this was the last list element.
+ */
+
+ p += 3;
+ inComment = AFTER_COMMENT;
+ openBraces = 0;
+ inQuotes = 0;
+ if (*p == '{') {
+ openBraces = 1;
+ p++;
+ } else if (*p == '"') {
+ inQuotes = 1;
+ p++;
+ }
+ goto mainLoop;
}
+
return TCL_OK;
}