Tcl Source Code

Artifact [3b8279c7f8]
Login

Artifact 3b8279c7f8adac9d196e5b108932df983d675c35:

Attachment "bytearraymatch.diff" to ticket [1827996fff] added by hobbs 2007-11-08 07:48:06.
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.339
diff -u -r1.339 tclExecute.c
--- generic/tclExecute.c	20 Oct 2007 02:15:05 -0000	1.339
+++ generic/tclExecute.c	8 Nov 2007 00:45:30 -0000
@@ -4063,6 +4063,15 @@
 	    ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2);
 	    match = TclUniCharMatch(ustring1, length1, ustring2, length2,
 		    nocase);
+	} else if ((valuePtr->typePtr == &tclByteArrayType)
+		|| (value2Ptr->typePtr == &tclByteArrayType)) {
+	    unsigned char *string1, *string2;
+	    int length1, length2;
+
+	    string1 = Tcl_GetByteArrayFromObj(valuePtr, &length1);
+	    string2 = Tcl_GetByteArrayFromObj(value2Ptr, &length2);
+	    match = TclByteArrayMatch(string1, length1, string2, length2,
+		    nocase);
 	} else {
 	    match = Tcl_StringCaseMatch(TclGetString(valuePtr),
 		    TclGetString(value2Ptr), nocase);
Index: generic/tclInt.decls
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.decls,v
retrieving revision 1.114
diff -u -r1.114 tclInt.decls
--- generic/tclInt.decls	6 Sep 2007 18:13:20 -0000	1.114
+++ generic/tclInt.decls	8 Nov 2007 00:45:30 -0000
@@ -942,6 +942,11 @@
     void TclBackgroundException(Tcl_Interp *interp, int code)
 }
 
+# Added for 8.5b3 to improve binary glob match case
+declare 237 generic {
+    int TclByteArrayMatch(CONST char *string, int strLen,
+	    CONST char *pattern, int ptnLen, int nocase)
+}
 
 ##############################################################################
 
Index: generic/tclIntDecls.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIntDecls.h,v
retrieving revision 1.105
diff -u -r1.105 tclIntDecls.h
--- generic/tclIntDecls.h	6 Sep 2007 18:13:20 -0000	1.105
+++ generic/tclIntDecls.h	8 Nov 2007 00:45:30 -0000
@@ -1057,6 +1057,12 @@
 EXTERN void		TclBackgroundException (Tcl_Interp * interp, 
 				int code);
 #endif
+#ifndef TclByteArrayMatch_TCL_DECLARED
+#define TclByteArrayMatch_TCL_DECLARED
+/* 237 */
+EXTERN int		TclByteArrayMatch (CONST char * string, int strLen, 
+				CONST char * pattern, int ptnLen, int nocase);
+#endif
 
 typedef struct TclIntStubs {
     int magic;
@@ -1314,6 +1320,7 @@
     Var * (*tclVarHashCreateVar) (TclVarHashTable * tablePtr, const char * key, int * newPtr); /* 234 */
     void (*tclInitVarHashTable) (TclVarHashTable * tablePtr, Namespace * nsPtr); /* 235 */
     void (*tclBackgroundException) (Tcl_Interp * interp, int code); /* 236 */
+    int (*tclByteArrayMatch) (CONST char * string, int strLen, CONST char * pattern, int ptnLen, int nocase); /* 237 */
 } TclIntStubs;
 
 #ifdef __cplusplus
@@ -2047,6 +2054,10 @@
 #define TclBackgroundException \
 	(tclIntStubsPtr->tclBackgroundException) /* 236 */
 #endif
+#ifndef TclByteArrayMatch
+#define TclByteArrayMatch \
+	(tclIntStubsPtr->tclByteArrayMatch) /* 237 */
+#endif
 
 #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */
 
Index: generic/tclStubInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStubInit.c,v
retrieving revision 1.144
diff -u -r1.144 tclStubInit.c
--- generic/tclStubInit.c	6 Sep 2007 18:13:23 -0000	1.144
+++ generic/tclStubInit.c	8 Nov 2007 00:45:30 -0000
@@ -326,6 +326,7 @@
     TclVarHashCreateVar, /* 234 */
     TclInitVarHashTable, /* 235 */
     TclBackgroundException, /* 236 */
+    TclByteArrayMatch, /* 237 */
 };
 
 TclIntPlatStubs tclIntPlatStubs = {
Index: generic/tclUtil.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclUtil.c,v
retrieving revision 1.84
diff -u -r1.84 tclUtil.c
--- generic/tclUtil.c	28 Oct 2007 03:17:00 -0000	1.84
+++ generic/tclUtil.c	8 Nov 2007 00:45:30 -0000
@@ -1553,6 +1553,195 @@
 /*
  *----------------------------------------------------------------------
  *
+ * TclByteArrayMatch --
+ *
+ *	See if a particular string matches a particular pattern. Allows case
+ *	insensitivity.
+ *	Parallels tclUtf.c:TclUniCharMatch, adjusted for char*.
+ *
+ * Results:
+ *	The return value is 1 if string matches pattern, and 0 otherwise. The
+ *	matching operation permits the following special characters in the
+ *	pattern: *?\[] (see the manual entry for details on what these mean).
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclByteArrayMatch(
+    CONST char *string,		/* String. */
+    int strLen,			/* Length of String */
+    CONST char *pattern,	/* Pattern, which may contain special
+				 * characters. */
+    int ptnLen,			/* Length of Pattern */
+    int nocase)			/* 0 for case sensitive, 1 for insensitive */
+{
+    CONST char *stringEnd, *patternEnd;
+    char p;
+
+    stringEnd = string + strLen;
+    patternEnd = pattern + ptnLen;
+
+    while (1) {
+	/*
+	 * See if we're at the end of both the pattern and the string. If so,
+	 * we succeeded. If we're at the end of the pattern but not at the end
+	 * of the string, we failed.
+	 */
+
+	if (pattern == patternEnd) {
+	    return (string == stringEnd);
+	}
+	p = *pattern;
+	if ((string == stringEnd) && (p != '*')) {
+	    return 0;
+	}
+
+	/*
+	 * Check for a "*" as the next pattern character. It matches any
+	 * substring. We handle this by skipping all the characters up to the
+	 * next matching one in the pattern, and then calling ourselves
+	 * recursively for each postfix of string, until either we match or we
+	 * reach the end of the string.
+	 */
+
+	if (p == '*') {
+	    /*
+	     * Skip all successive *'s in the pattern.
+	     */
+
+	    while (*(++pattern) == '*') {
+		/* empty body */
+	    }
+	    if (pattern == patternEnd) {
+		return 1;
+	    }
+	    p = *pattern;
+	    if (nocase) {
+		p = tolower(p);
+	    }
+	    while (1) {
+		/*
+		 * Optimization for matching - cruise through the string
+		 * quickly if the next char in the pattern isn't a special
+		 * character.
+		 */
+
+		if ((p != '[') && (p != '?') && (p != '\\')) {
+		    if (nocase) {
+			while ((string < stringEnd) && (p != *string)
+				&& (p != tolower(*string))) {
+			    string++;
+			}
+		    } else {
+			while ((string < stringEnd) && (p != *string)) {
+			    string++;
+			}
+		    }
+		}
+		if (TclByteArrayMatch(string, stringEnd - string,
+			pattern, patternEnd - pattern, nocase)) {
+		    return 1;
+		}
+		if (string == stringEnd) {
+		    return 0;
+		}
+		string++;
+	    }
+	}
+
+	/*
+	 * Check for a "?" as the next pattern character. It matches any
+	 * single character.
+	 */
+
+	if (p == '?') {
+	    pattern++;
+	    string++;
+	    continue;
+	}
+
+	/*
+	 * Check for a "[" as the next pattern character. It is followed by a
+	 * list of characters that are acceptable, or by a range (two
+	 * characters separated by "-").
+	 */
+
+	if (p == '[') {
+	    char ch1, startChar, endChar;
+
+	    pattern++;
+	    ch1 = (nocase ? tolower(*string) : *string);
+	    string++;
+	    while (1) {
+		if ((*pattern == ']') || (pattern == patternEnd)) {
+		    return 0;
+		}
+		startChar = (nocase ? tolower(*pattern) : *pattern);
+		pattern++;
+		if (*pattern == '-') {
+		    pattern++;
+		    if (pattern == patternEnd) {
+			return 0;
+		    }
+		    endChar = (nocase ? tolower(*pattern) : *pattern);
+		    pattern++;
+		    if (((startChar <= ch1) && (ch1 <= endChar))
+			    || ((endChar <= ch1) && (ch1 <= startChar))) {
+			/*
+			 * Matches ranges of form [a-z] or [z-a].
+			 */
+			break;
+		    }
+		} else if (startChar == ch1) {
+		    break;
+		}
+	    }
+	    while (*pattern != ']') {
+		if (pattern == patternEnd) {
+		    pattern--;
+		    break;
+		}
+		pattern++;
+	    }
+	    pattern++;
+	    continue;
+	}
+
+	/*
+	 * If the next pattern character is '\', just strip off the '\' so we
+	 * do exact matching on the character that follows.
+	 */
+
+	if (p == '\\') {
+	    if (++pattern == patternEnd) {
+		return 0;
+	    }
+	}
+
+	/*
+	 * There's no special character. Just make sure that the next bytes of
+	 * each string match.
+	 */
+
+	if (nocase) {
+	    if (tolower(*string) != tolower(*pattern)) {
+		return 0;
+	    }
+	} else if (*string != *pattern) {
+	    return 0;
+	}
+	string++;
+	pattern++;
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * Tcl_DStringInit --
  *
  *	Initializes a dynamic string, discarding any previous contents of the