diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2005-06-01 11:00:24 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2005-06-01 11:00:24 (GMT) |
commit | 854f85bb1700aa6f106cc6a443cb0eb2e917f2de (patch) | |
tree | d3bbe95a2b84f8455477e5d9e709e78633b6d7bd /generic/tclCmdIL.c | |
parent | 8f397c357860e5098e4eeea5140ed0d3c724075d (diff) | |
download | tcl-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.c | 62 |
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)); |