summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--generic/tkText.c298
2 files changed, 166 insertions, 138 deletions
diff --git a/ChangeLog b/ChangeLog
index da7eb59..ca115de 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2003-05-21 Donal K. Fellows <fellowsd@cs.man.ac.uk>
+
+ * generic/tkText.c (TextSearchCmd): Forwards and backwards aren't
+ the same. [Bug 740558] Also edited SearchCore to get it closer
+ to the Engineering Manual style guidelines.
+
2003-05-19 Donal K. Fellows <fellowsd@cs.man.ac.uk>
* tests/textImage.test: Fixed faults in option parsing and
diff --git a/generic/tkText.c b/generic/tkText.c
index b6fbcbe..0f43d34 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -14,7 +14,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkText.c,v 1.36 2003/05/19 21:19:51 dkf Exp $
+ * RCS: @(#) $Id: tkText.c,v 1.37 2003/05/21 09:21:57 dkf Exp $
*/
#include "default.h"
@@ -2189,7 +2189,7 @@ TextSearchCmd(textPtr, interp, objc, objv)
searchSpec.exact = 1;
break;
case SEARCH_FWD:
- searchSpec.backwards = 1;
+ searchSpec.backwards = 0;
break;
case SEARCH_NOCASE:
searchSpec.noCase = 1;
@@ -3398,7 +3398,8 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr)
* chars for regexp search, utf-8 bytes for exact search)
*/
if ((*searchSpecPtr->lineIndexProc)(interp, fromPtr, searchSpecPtr,
- &searchSpecPtr->startLine, &searchSpecPtr->startOffset) != TCL_OK) {
+ &searchSpecPtr->startLine,
+ &searchSpecPtr->startOffset) != TCL_OK) {
return TCL_ERROR;
}
@@ -3407,7 +3408,8 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr)
*/
if (toPtr != NULL) {
if ((*searchSpecPtr->lineIndexProc)(interp, toPtr, searchSpecPtr,
- &searchSpecPtr->stopLine, &searchSpecPtr->stopOffset) != TCL_OK) {
+ &searchSpecPtr->stopLine,
+ &searchSpecPtr->stopOffset) != TCL_OK) {
return TCL_ERROR;
}
} else {
@@ -3432,7 +3434,7 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr)
* The core of the search procedure. This procedure is actually
* completely independent of Tk, and could in the future be split
* off.
- *
+ *
* The function assumes regexp-based searches operate on Unicode
* strings, and exact searches on utf-8 strings. Therefore the
* 'foundMatchProc' and 'addLineProc' need to be aware of this
@@ -3442,9 +3444,9 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr)
* Standard Tcl result code.
*
* Side effects:
- * Only those of the 'searchSpecPtr->foundMatchProc' which is called
+ * Only those of the 'searchSpecPtr->foundMatchProc' which is called
* whenever a match is found.
- *
+ *
* Note that the way matching across multiple lines is implemented,
* we start afresh with each line we have available, even though we
* may already have examined the contents of that line (and further
@@ -3454,20 +3456,20 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr)
* Profiling should be done to see where the bottlenecks lie before
* attempting this, however. We would also need to be very careful
* such optimisation keep within the specified search bounds.
- *
+ *
*----------------------------------------------------------------------
*/
static int
SearchCore(interp, searchSpecPtr, patObj)
- Tcl_Interp *interp; /* For error messages */
- SearchSpec *searchSpecPtr; /* Search parameters */
- Tcl_Obj *patObj; /* Contains an exact string or a
- * regexp pattern. Must have a
- * refCount > 0 */
+ Tcl_Interp *interp; /* For error messages */
+ SearchSpec *searchSpecPtr; /* Search parameters */
+ Tcl_Obj *patObj; /* Contains an exact string or a
+ * regexp pattern. Must have a
+ * refCount > 0 */
{
int passes;
- /*
+ /*
* For exact searches these are utf-8 char* offsets, for regexp
* searches they are Unicode char offsets
*/
@@ -3475,13 +3477,11 @@ SearchCore(interp, searchSpecPtr, patObj)
int lineNum = searchSpecPtr->startLine;
int code = TCL_OK;
Tcl_Obj *theLine;
-
- /* For regexp searches only */
- Tcl_RegExp regexp = NULL;
- /* For exact searches only */
- CONST char *pattern = NULL;
- int firstNewLine;
-
+
+ Tcl_RegExp regexp = NULL; /* For regexp searches only */
+ CONST char *pattern = NULL; /* For exact searches only */
+ int firstNewLine = -1; /* For exact searches only */
+
if (searchSpecPtr->exact) {
/*
* Convert the pattern to lower-case if we're supposed to ignore
@@ -3489,27 +3489,27 @@ SearchCore(interp, searchSpecPtr, patObj)
*/
if (searchSpecPtr->noCase) {
patObj = Tcl_DuplicateObj(patObj);
- /*
+ /*
* This can change the length of the string behind the
* object's back, so ensure it is correctly synchronised.
*/
Tcl_SetObjLength(patObj, Tcl_UtfToLower(Tcl_GetString(patObj)));
}
} else {
- /*
+ /*
* Compile the regular expression. We want '^$' to match after and
* before \n respectively, so use the TCL_REG_NLANCH flag.
*/
regexp = Tcl_GetRegExpFromObj(interp, patObj,
- (searchSpecPtr->noCase ? TCL_REG_NOCASE : 0)
- | (searchSpecPtr->noLineStop ? 0 : TCL_REG_NLSTOP)
+ (searchSpecPtr->noCase ? TCL_REG_NOCASE : 0)
+ | (searchSpecPtr->noLineStop ? 0 : TCL_REG_NLSTOP)
| TCL_REG_ADVANCED | TCL_REG_CANMATCH | TCL_REG_NLANCH);
if (regexp == NULL) {
return TCL_ERROR;
}
}
- /*
+ /*
* For exact strings, we want to know where the first newline is,
* and we will also use this as a flag to test whether it is even
* possible to match the pattern on a single line. If not we
@@ -3517,46 +3517,47 @@ SearchCore(interp, searchSpecPtr, patObj)
*/
if (searchSpecPtr->exact) {
char *nl;
-
- /*
+
+ /*
* We only need to set the matchLength once for exact searches,
* and we do it here. It is also used below as the actual
* pattern length, so it has dual purpose.
*/
pattern = Tcl_GetStringFromObj(patObj, &matchLength);
nl = strchr(pattern, '\n');
- /*
+ /*
* If there is no newline, or it is the very end of the string,
* then we don't need any special treatment, since single-line
* matching will work fine.
*/
- if (nl == NULL || nl[1] == '\0') {
- firstNewLine = -1;
- } else {
+ if (nl != NULL && nl[1] != '\0') {
firstNewLine = (nl - pattern);
}
} else {
- firstNewLine = -1;
matchLength = 0; /* Only needed to prevent compiler warnings. */
}
-
- /*
+
+ /*
* Keep a reference here, so that we can be sure the object
* doesn't disappear behind our backs and invalidate its
* contents which we are using.
*/
Tcl_IncrRefCount(patObj);
- /* For building up the current line being checked */
+ /*
+ * For building up the current line being checked
+ */
theLine = Tcl_NewObj();
Tcl_IncrRefCount(theLine);
for (passes = 0; passes < 2; ) {
ClientData lineInfo;
int linesSearched = 1;
-
+
if (lineNum >= searchSpecPtr->numLines) {
- /* Don't search the dummy last line of the text. */
+ /*
+ * Don't search the dummy last line of the text.
+ */
goto nextLine;
}
@@ -3568,8 +3569,8 @@ SearchCore(interp, searchSpecPtr, patObj)
* what we 'lastOffset' represents.
*/
- lineInfo = (*searchSpecPtr->addLineProc)(lineNum, searchSpecPtr,
- theLine, &lastOffset);
+ lineInfo = (*searchSpecPtr->addLineProc)(lineNum,
+ searchSpecPtr, theLine, &lastOffset);
firstOffset = 0;
if (lineNum == searchSpecPtr->startLine) {
@@ -3581,14 +3582,14 @@ SearchCore(interp, searchSpecPtr, patObj)
passes++;
if ((passes == 1) ^ searchSpecPtr->backwards) {
/*
- * Forward search and first pass, or backward
+ * Forward search and first pass, or backward
* search and second pass.
- *
+ *
* Only use the last part of the line.
*/
- if ((searchSpecPtr->startOffset >= lastOffset)
- && ((lastOffset != 0) || searchSpecPtr->exact)) {
+ if ((searchSpecPtr->startOffset >= lastOffset)
+ && ((lastOffset != 0) || searchSpecPtr->exact)) {
goto nextLine;
}
@@ -3601,7 +3602,7 @@ SearchCore(interp, searchSpecPtr, patObj)
lastOffset = searchSpecPtr->startOffset;
}
}
-
+
/*
* Check for matches within the current line 'lineNum'. If so,
* and if we're searching backwards or for all matches, repeat
@@ -3611,7 +3612,7 @@ SearchCore(interp, searchSpecPtr, patObj)
*/
matchOffset = -1;
-
+
if (searchSpecPtr->exact) {
int maxExtraLines = 0;
CONST char *startOfLine = Tcl_GetString(theLine);
@@ -3619,18 +3620,20 @@ SearchCore(interp, searchSpecPtr, patObj)
do {
Tcl_UniChar ch;
CONST char *p;
-
- p = strstr(startOfLine + firstOffset, pattern);
+
+ p = strstr(startOfLine + firstOffset, pattern);
if (p == NULL) {
- if (firstNewLine == -1) break;
- if (firstNewLine >= (lastOffset - firstOffset)) break;
+ if (firstNewLine == -1 ||
+ firstNewLine >= (lastOffset - firstOffset)) {
+ break;
+ }
p = startOfLine + lastOffset - firstNewLine - 1;
- if (strncmp(p, pattern, ((unsigned)firstNewLine) + 1)) {
+ if (strncmp(p, pattern, (unsigned)(firstNewLine + 1))) {
break;
} else {
int extraLines = 1;
int skipFirst = lastOffset - firstNewLine -1;
- /*
+ /*
* We may be able to match if given more text.
* The following 'while' block handles multi-line
* exact searches.
@@ -3638,87 +3641,94 @@ SearchCore(interp, searchSpecPtr, patObj)
while (1) {
int len;
- if (lineNum + extraLines
- >= searchSpecPtr->numLines) {
+ if (lineNum+extraLines>=searchSpecPtr->numLines) {
p = NULL;
break;
}
-
- /*
+
+ /*
* Only add the line if we haven't already
* done so already.
*/
if (extraLines > maxExtraLines) {
- if ((*searchSpecPtr->addLineProc)(lineNum
- + extraLines, searchSpecPtr, theLine,
- &len) == NULL) {
+ if ((*searchSpecPtr->addLineProc)(lineNum
+ + extraLines, searchSpecPtr, theLine,
+ &len) == NULL) {
p = NULL;
break;
}
maxExtraLines = extraLines;
}
-
+
startOfLine = Tcl_GetString(theLine);
p = startOfLine + skipFirst;
- /*
- * Use the fact that 'matchLength = patLength'
+ /*
+ * Use the fact that 'matchLength = patLength'
* for exact searches
*/
if ((len - skipFirst) >= matchLength) {
- /*
+ /*
* We now have enough text to match, so
* we make a final test and break
* whatever the result
*/
- if (strncmp(p, pattern,
- (unsigned)matchLength)) {
+ if (strncmp(p, pattern, (unsigned)matchLength)) {
p = NULL;
}
break;
} else {
- /* Not enough text yet, but check the prefix */
+ /*
+ * Not enough text yet, but check the prefix
+ */
if (strncmp(p, pattern,
(unsigned)(len - skipFirst))) {
p = NULL;
break;
}
- /* The prefix matches, so keep looking */
+ /*
+ * The prefix matches, so keep looking
+ */
}
extraLines++;
}
- /*
- * If we reach here, with p != NULL, we've found a
+ /*
+ * If we reach here, with p != NULL, we've found a
* multi-line match, else we started a multi-match
* but didn't finish it off, so we go to the next line.
*/
- if (p == NULL) break;
+ if (p == NULL) {
+ break;
+ }
}
}
firstOffset = p - startOfLine;
if (firstOffset >= lastOffset) {
break;
}
-
- /* Remember the match */
+
+ /*
+ * Remember the match
+ */
matchOffset = firstOffset;
-
- /*
+
+ /*
* Move the starting point one character on from the
* previous match, in case we are doing repeated or
* backwards searches (for the latter, we actually do
* repeated forward searches).
*/
- firstOffset += Tcl_UtfToUniChar(startOfLine + matchOffset, &ch);
- if (searchSpecPtr->all) {
- if (!(*searchSpecPtr->foundMatchProc)(lineNum,
- searchSpecPtr, lineInfo, theLine,
- matchOffset, matchLength)) {
- /* We reached the end of the search */
- goto searchDone;
- }
+ firstOffset += Tcl_UtfToUniChar(startOfLine+matchOffset, &ch);
+ if (searchSpecPtr->all &&
+ !(*searchSpecPtr->foundMatchProc)(lineNum,
+ searchSpecPtr, lineInfo, theLine, matchOffset,
+ matchLength)) {
+ /*
+ * We reached the end of the search
+ */
+ goto searchDone;
}
} while (searchSpecPtr->backwards || searchSpecPtr->all);
-
+
} else {
int maxExtraLines = 0;
@@ -3727,9 +3737,8 @@ SearchCore(interp, searchSpecPtr, patObj)
Tcl_RegExpInfo info;
int match;
- match = Tcl_RegExpExecObj(interp, regexp, theLine,
- firstOffset, 1,
- ((firstOffset > 0) ? TCL_REG_NOTBOL : 0));
+ match = Tcl_RegExpExecObj(interp, regexp, theLine, firstOffset,
+ 1, ((firstOffset > 0) ? TCL_REG_NOTBOL : 0));
if (match < 0) {
code = TCL_ERROR;
goto searchDone;
@@ -3739,26 +3748,30 @@ SearchCore(interp, searchSpecPtr, patObj)
if (!match) {
int extraLines = 1;
int curLen = 0;
-
- if (info.extendStart < 0) { break; }
-
- /*
+
+ if (info.extendStart < 0) {
+ break;
+ }
+
+ /*
* We may be able to match if given more text.
* The following 'while' block handles multi-line
* exact searches.
*/
while (1) {
- /* Move firstOffset to first possible start */
+ /*
+ * Move firstOffset to first possible start
+ */
firstOffset += info.extendStart;
if (firstOffset >= lastOffset) {
- /*
+ /*
* We're being told that the only possible
* new match is starting after the end of
* the line. But, that is the next line which
* we will handle when we look at that line.
*/
- if (!searchSpecPtr->backwards
- && (firstOffset == curLen)) {
+ if (!searchSpecPtr->backwards
+ && (firstOffset == curLen)) {
linesSearched = extraLines + 1;
}
break;
@@ -3767,12 +3780,14 @@ SearchCore(interp, searchSpecPtr, patObj)
if (lineNum + extraLines >= searchSpecPtr->numLines) {
break;
}
- /* Add next line, provided we haven't already done so */
+ /*
+ * Add next line, provided we haven't already done so
+ */
if (extraLines > maxExtraLines) {
- if ((*searchSpecPtr->addLineProc)(lineNum
- + extraLines, searchSpecPtr, theLine,
- NULL) == NULL) {
- /*
+ if ((*searchSpecPtr->addLineProc)(lineNum
+ + extraLines, searchSpecPtr, theLine,
+ NULL) == NULL) {
+ /*
* There are no more acceptable lines, so
* we can say we have searched all of these
*/
@@ -3783,28 +3798,30 @@ SearchCore(interp, searchSpecPtr, patObj)
}
maxExtraLines = extraLines;
}
-
- match = Tcl_RegExpExecObj(interp, regexp, theLine,
- firstOffset, 1,
+
+ match = Tcl_RegExpExecObj(interp, regexp, theLine,
+ firstOffset, 1,
((firstOffset > 0) ? TCL_REG_NOTBOL : 0));
if (match < 0) {
code = TCL_ERROR;
goto searchDone;
}
Tcl_RegExpGetInfo(regexp, &info);
- if (match || (info.extendStart < 0)) {
+ if (match || info.extendStart < 0) {
break;
}
- /* The prefix matches, so keep looking */
+ /*
+ * The prefix matches, so keep looking
+ */
extraLines++;
}
- /*
+ /*
* If we reach here, with match == 1, we've found a
* multi-line match, which we will record in the code
* which follows directly else we started a
* multi-line match but didn't finish it off, so we
- * go to the next line.
- *
+ * go to the next line.
+ *
* Here is where we could perform an optimisation,
* since we have already retrieved the contents of
* the next line (and many more), so we shouldn't
@@ -3813,53 +3830,54 @@ SearchCore(interp, searchSpecPtr, patObj)
* searches.
*/
if (!match) {
- /*
- * This 'break' will take us to
- * just before the 'nextLine:' below.
+ /*
+ * This 'break' will take us to just before
+ * the 'nextLine:' below.
*/
break;
}
}
-
+
firstOffset += info.matches[0].start;
if (firstOffset >= lastOffset) {
break;
}
-
- /* Remember the match */
+
+ /*
+ * Remember the match
+ */
matchOffset = firstOffset;
matchLength = info.matches[0].end - info.matches[0].start;
-
- /*
+
+ /*
* Move the starting point one character on, in case
* we are doing repeated or backwards searches (for the
* latter, we actually do repeated forward searches).
*/
firstOffset++;
- if (searchSpecPtr->all) {
- if (!(*searchSpecPtr->foundMatchProc)(lineNum,
- searchSpecPtr, lineInfo, theLine,
- matchOffset, matchLength)) {
- /* We reached the end of the search */
- goto searchDone;
- }
+ if (searchSpecPtr->all &&
+ !(*searchSpecPtr->foundMatchProc)(lineNum,
+ searchSpecPtr, lineInfo, theLine, matchOffset,
+ matchLength)) {
+ /*
+ * We reached the end of the search
+ */
+ goto searchDone;
}
} while (searchSpecPtr->backwards || searchSpecPtr->all);
-
}
-
+
/*
* If the 'all' flag is set, we will already have stored all
* matches, so we just proceed to the next line.
- *
+ *
* If not, and there is a match we need to store that information
* and we are done.
*/
if ((matchOffset >= 0) && !searchSpecPtr->all) {
- (*searchSpecPtr->foundMatchProc)(lineNum, searchSpecPtr,
- lineInfo, theLine,
- matchOffset, matchLength);
+ (*searchSpecPtr->foundMatchProc)(lineNum, searchSpecPtr,
+ lineInfo, theLine, matchOffset, matchLength);
goto searchDone;
}
@@ -3867,14 +3885,16 @@ SearchCore(interp, searchSpecPtr, patObj)
* Go to the next (or previous) line;
*/
- nextLine:
+ nextLine:
- for (;linesSearched > 0;linesSearched--) {
- /* If we have just completed the 'stopLine', we are done */
+ for (; linesSearched>0 ; linesSearched--) {
+ /*
+ * If we have just completed the 'stopLine', we are done
+ */
if (lineNum == searchSpecPtr->stopLine) {
goto searchDone;
}
-
+
if (searchSpecPtr->backwards) {
lineNum--;
if (lineNum < 0) {
@@ -3887,14 +3907,16 @@ SearchCore(interp, searchSpecPtr, patObj)
}
}
}
-
- Tcl_SetObjLength(theLine,0);
+
+ Tcl_SetObjLength(theLine, 0);
}
- searchDone:
-
- /* Free up the cached line and pattern */
+ searchDone:
+
+ /*
+ * Free up the cached line and pattern
+ */
Tcl_DecrRefCount(theLine);
Tcl_DecrRefCount(patObj);
-
+
return code;
}