summaryrefslogtreecommitdiffstats
path: root/generic/tclCmdIL.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2005-06-01 11:00:24 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2005-06-01 11:00:24 (GMT)
commit854f85bb1700aa6f106cc6a443cb0eb2e917f2de (patch)
treed3bbe95a2b84f8455477e5d9e709e78633b6d7bd /generic/tclCmdIL.c
parent8f397c357860e5098e4eeea5140ed0d3c724075d (diff)
downloadtcl-854f85bb1700aa6f106cc6a443cb0eb2e917f2de.zip
tcl-854f85bb1700aa6f106cc6a443cb0eb2e917f2de.tar.gz
tcl-854f85bb1700aa6f106cc6a443cb0eb2e917f2de.tar.bz2
Implementation of TIP#241 from Joe Mistachkin
Also compilation of [switch -glob -nocase] from Donal Fellows
Diffstat (limited to 'generic/tclCmdIL.c')
-rw-r--r--generic/tclCmdIL.c62
1 files changed, 48 insertions, 14 deletions
diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c
index b68f7ba..883ed45 100644
--- a/generic/tclCmdIL.c
+++ b/generic/tclCmdIL.c
@@ -16,7 +16,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclCmdIL.c,v 1.75 2005/05/30 00:04:46 dkf Exp $
+ * RCS: @(#) $Id: tclCmdIL.c,v 1.76 2005/06/01 11:00:34 dkf Exp $
*/
#include "tclInt.h"
@@ -36,6 +36,15 @@ typedef struct SortElement {
} SortElement;
/*
+ * These function pointer types are used with the "lsearch" and "lsort"
+ * commands to facilitate the "-nocase" option.
+ */
+
+typedef int (*SortStrCmpFn_t) _ANSI_ARGS_((const char *, const char *));
+typedef int (*SortMemCmpFn_t) _ANSI_ARGS_((const void *, const void *,
+ size_t));
+
+/*
* The "lsort" command needs to pass certain information down to the
* function that compares two list elements, and the comparison function
* needs to pass success or failure information back up to the top-level
@@ -47,6 +56,8 @@ typedef struct SortInfo {
int isIncreasing; /* Nonzero means sort in increasing order. */
int sortMode; /* The sort mode. One of SORTMODE_*
* values defined below */
+ SortStrCmpFn_t strCmpFn; /* Basic string compare command (used with
+ * ASCII mode). */
Tcl_Obj *compareCmdPtr; /* The Tcl comparison command when sortMode
* is SORTMODE_COMMAND. Pre-initialized to
* hold base of command.*/
@@ -3201,7 +3212,7 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
char *bytes, *patternBytes;
int i, match, mode, index, result, listc, length, elemLen;
int dataType, isIncreasing, lower, upper, patInt, objInt;
- int offset, allMatches, inlineReturn, negatedMatch, returnSubindices;
+ int offset, allMatches, inlineReturn, negatedMatch, returnSubindices, noCase;
double patDouble, objDouble;
SortInfo sortInfo;
Tcl_Obj *patObj, **listv, *listPtr, *startPtr, *itemPtr;
@@ -3209,15 +3220,17 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
static CONST char *options[] = {
"-all", "-ascii", "-decreasing", "-dictionary",
"-exact", "-glob", "-increasing", "-index",
- "-inline", "-integer", "-not", "-real",
- "-regexp", "-sorted", "-start", "-subindices",
+ "-inline", "-integer", "-nocase", "-not",
+ "-real", "-regexp", "-sorted", "-start",
+ "-subindices",
NULL
};
enum options {
LSEARCH_ALL, LSEARCH_ASCII, LSEARCH_DECREASING, LSEARCH_DICTIONARY,
LSEARCH_EXACT, LSEARCH_GLOB, LSEARCH_INCREASING, LSEARCH_INDEX,
- LSEARCH_INLINE, LSEARCH_INTEGER, LSEARCH_NOT, LSEARCH_REAL,
- LSEARCH_REGEXP, LSEARCH_SORTED, LSEARCH_START, LSEARCH_SUBINDICES
+ LSEARCH_INLINE, LSEARCH_INTEGER, LSEARCH_NOCASE, LSEARCH_NOT,
+ LSEARCH_REAL, LSEARCH_REGEXP, LSEARCH_SORTED, LSEARCH_START,
+ LSEARCH_SUBINDICES
};
enum datatypes {
ASCII, DICTIONARY, INTEGER, REAL
@@ -3225,6 +3238,7 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
enum modes {
EXACT, GLOB, REGEXP, SORTED
};
+ SortStrCmpFn_t strCmpFn = strcmp;
mode = GLOB;
dataType = ASCII;
@@ -3236,6 +3250,7 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
listPtr = NULL;
startPtr = NULL;
offset = 0;
+ noCase = 0;
sortInfo.compareCmdPtr = NULL;
sortInfo.isIncreasing = 0;
sortInfo.sortMode = 0;
@@ -3288,6 +3303,10 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
case LSEARCH_INTEGER: /* -integer */
dataType = INTEGER;
break;
+ case LSEARCH_NOCASE: /* -nocase */
+ strCmpFn = strcasecmp;
+ noCase = 1;
+ break;
case LSEARCH_NOT: /* -not */
negatedMatch = 1;
break;
@@ -3422,7 +3441,8 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
* regexp rep before the list rep.
*/
regexp = Tcl_GetRegExpFromObj(interp, objv[objc - 1],
- TCL_REG_ADVANCED | TCL_REG_NOSUB);
+ TCL_REG_ADVANCED | TCL_REG_NOSUB |
+ (noCase ? TCL_REG_NOCASE : 0));
if (regexp == NULL) {
if (startPtr != NULL) {
Tcl_DecrRefCount(startPtr);
@@ -3531,7 +3551,7 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
switch ((enum datatypes) dataType) {
case ASCII:
bytes = TclGetString(itemPtr);
- match = strcmp(patternBytes, bytes);
+ match = strCmpFn(patternBytes, bytes);
break;
case DICTIONARY:
bytes = TclGetString(itemPtr);
@@ -3629,8 +3649,16 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
case ASCII:
bytes = Tcl_GetStringFromObj(itemPtr, &elemLen);
if (length == elemLen) {
- match = (memcmp(bytes, patternBytes,
- (size_t) length) == 0);
+ /*
+ * This split allows for more optimal
+ * compilation of memcmp
+ */
+ if (noCase) {
+ match = (strcasecmp(bytes, patternBytes) == 0);
+ } else {
+ match = (memcmp(bytes, patternBytes,
+ (size_t) length) == 0);
+ }
}
break;
case DICTIONARY:
@@ -3669,7 +3697,8 @@ Tcl_LsearchObjCmd(clientData, interp, objc, objv)
break;
case GLOB:
- match = Tcl_StringMatch(TclGetString(itemPtr), patternBytes);
+ match = Tcl_StringCaseMatch(TclGetString(itemPtr),
+ patternBytes, noCase);
break;
case REGEXP:
match = Tcl_RegExpExecObj(interp, regexp, itemPtr, 0, 0, 0);
@@ -3871,12 +3900,13 @@ Tcl_LsortObjCmd(clientData, interp, objc, objv)
* comparison function */
static CONST char *switches[] = {
"-ascii", "-command", "-decreasing", "-dictionary", "-increasing",
- "-index", "-indices", "-integer", "-real", "-unique", (char *) NULL
+ "-index", "-indices", "-integer", "-nocase", "-real", "-unique",
+ (char *) NULL
};
enum Lsort_Switches {
LSORT_ASCII, LSORT_COMMAND, LSORT_DECREASING, LSORT_DICTIONARY,
LSORT_INCREASING, LSORT_INDEX, LSORT_INDICES, LSORT_INTEGER,
- LSORT_REAL, LSORT_UNIQUE
+ LSORT_NOCASE, LSORT_REAL, LSORT_UNIQUE
};
if (objc < 2) {
@@ -3890,6 +3920,7 @@ Tcl_LsortObjCmd(clientData, interp, objc, objv)
sortInfo.isIncreasing = 1;
sortInfo.sortMode = SORTMODE_ASCII;
+ sortInfo.strCmpFn = strcmp;
sortInfo.indexv = NULL;
sortInfo.indexc = 0;
sortInfo.interp = interp;
@@ -3988,6 +4019,9 @@ Tcl_LsortObjCmd(clientData, interp, objc, objv)
case LSORT_INTEGER:
sortInfo.sortMode = SORTMODE_INTEGER;
break;
+ case LSORT_NOCASE:
+ sortInfo.strCmpFn = strcasecmp;
+ break;
case LSORT_REAL:
sortInfo.sortMode = SORTMODE_REAL;
break;
@@ -4262,7 +4296,7 @@ SortCompare(objPtr1, objPtr2, infoPtr)
}
if (infoPtr->sortMode == SORTMODE_ASCII) {
- order = strcmp(TclGetString(objPtr1), TclGetString(objPtr2));
+ order = infoPtr->strCmpFn(TclGetString(objPtr1), TclGetString(objPtr2));
} else if (infoPtr->sortMode == SORTMODE_DICTIONARY) {
order = DictionaryCompare(
TclGetString(objPtr1), TclGetString(objPtr2));