📄 text.cpp
字号:
{
ptb = Elem(itb);
AssertSz(cch < ptb->_cch, "last block too small");
ptb->MoveGap(0);
ptb->_cch -= cch;
#ifdef DEBUG
((CTxtArray *)_prgRun)->Invariant();
#endif // DEBUG
}
((CTxtArray *)_prgRun)->CombineBlocks(_iRun);
if(_iRun >= Count() || !Elem(_iRun)->_cch)
BindToCp(_cp); // Empty block: force tp rebind
AssertSz (GetTextLength() ==
((CTxtArray *)_prgRun)->GetCch(),
"CTxtPtr::DeleteRange(): _prgRun->_cchText messed up !");
}
/*
* CTxtPtr::FindText (cpMost, dwFlags, pch, cchToFind)
*
* @mfunc
* Find the text string <p pch> of length <p cchToFind> starting at this
* text pointer. If found, move this text pointer to the end of the
* matched string and return the cp of the first character of the matched
* string. If not found, return -1 and don't change this text ptr.
*
* @rdesc
* character position of first match
* <lt> 0 if no match
*/
LONG CTxtPtr::FindText (
LONG cpLimit, //@parm limit of search or <lt> 0 for end of text
DWORD dwFlags, //@parm FR_MATCHCASE case must match <nl>
// FR_WHOLEWORD match must be a whole word
TCHAR const *pch, //@parm text to search for
const DWORD cchToFind) //@parm length of text to search for
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::FindText");
_TEST_INVARIANT_
BOOL bTemp; // Used in find-first-char loops
LONG cch;
const DWORD cchAdjText = _ped->GetAdjustedTextLength();
LONG cchChunk, cchChunkForward = 0;
LONG cchLeft;
LONG cchLimitFirst;
const DWORD cchText = GetTextLength();
LONG cchUnmatched;
LONG cchValid;
TCHAR chFirst;
LONG cpMatch;
BOOL fIgnoreCase = !(FR_MATCHCASE & dwFlags);
BOOL fSearchForward = FR_DOWN & dwFlags;
BOOL fWholeWord;
const int Direction = fSearchForward ? 1 : -1; // Which dir to step?
const TCHAR *pchCurrent;
const TCHAR *pchSave;
const TCHAR *pchStart; // ptr to start of new block search
CTxtPtr tp(*this); // tp used to walk CTxtBlk chunks
EDITWORDBREAKPROC pfnWB = _ped->_pfnWB;
if( !cchToFind )
{
return -1;
}
if ( fSearchForward )
{
if((DWORD)cpLimit > cchText) // NB: catches cpLimit < 0 too
cpLimit = cchText;
cch = cpLimit - _cp;
}
else
{
if((DWORD)cpLimit > _cp) // NB: catches cpLimit < 0 too
cpLimit = 0;
cch = _cp - cpLimit;
}
if((LONG)cchToFind > cch)
return -1;
chFirst = pch[0];
if(fIgnoreCase)
{
// Read Win32 spec to understand the following strange casts
chFirst = TCHAR (CharLower ((LPTSTR) chFirst));
}
cchLimitFirst = cch - (LONG)cchToFind + 1;
if (! fSearchForward )
{
tp.AdvanceCp(-(LONG)cchToFind + 1);
}
while(cchLimitFirst > 0)
{
// Fetch how many characters are remaining for this pchCurrent. If
// searching in reverse, fetch how many characters there are to the
// start of pchCurrent.
// NOTE: strings pointed to by pchCurrent are delineated by blocks
// or block gaps.
if ( fSearchForward )
{
pchCurrent = tp.GetPch(cchChunk);
cchChunk = min(cchLimitFirst, cchChunk);
tp.AdvanceCp(cchChunk);
cchChunkForward = cchChunk; // cch to tp.GetCp()
}
else
{
pchCurrent = tp.GetPchReverse(cchChunk, &cchChunkForward);
pchCurrent--;
cchChunkForward++;
cchChunk = min(cchLimitFirst, cchChunk);
tp.AdvanceCp(-cchChunk);
}
if( !pchCurrent )
{
return -1;
}
pchSave = pchStart = pchCurrent; // Save starting ptr
cchLimitFirst -= cchChunk;
while(cchChunk > 0)
{
// Match first char
if ( fIgnoreCase )
do {
bTemp = ( 2 == CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE | NORM_IGNOREWIDTH,
pchCurrent, 1, &chFirst, 1) );
pchCurrent += Direction;
} while(!bTemp && --cchChunk > 0);
else
do {
bTemp = TCHAR( *pchCurrent ) == chFirst;
pchCurrent += Direction;
} while(!bTemp && --cchChunk > 0);
cchChunkForward += pchSave - pchCurrent; // cch still valid
// for pchCurrent
pchSave = pchCurrent;
if(!fSearchForward) // Setup is for
{ // forward match
pchCurrent += 2;
cchChunkForward -= 2;
}
// Found first character; now find rest of string. Common routine
// for forward and backward: in both cases, we match the rest of
// the string going forward.
if(cchChunk > 0)
{
cchChunk--;
cchLeft = min((LONG)cchToFind - 1, cchChunkForward);
if( fIgnoreCase )
{
if ( !cchLeft )
{
// nothing to compare, we find a match
cchUnmatched = FALSE;
}
else
{
// Note: CompareString returns 2 if the two strings matched.
cchUnmatched = !( 2 == CompareString( LOCALE_USER_DEFAULT,
NORM_IGNORECASE | NORM_IGNOREWIDTH,
&pch[1], cchLeft, pchCurrent, cchLeft) ) ;
}
}
else
{
cchUnmatched = wcsncmp( &pch[1], pchCurrent, cchLeft);
}
if(!cchUnmatched)
{
// Matched whole (or partial) string. Calculate potential
// match cpFirst
cpMatch = tp.GetCp() + (fSearchForward ?
( -cchChunk - 1) : cchChunk );
fWholeWord = (dwFlags & FR_WHOLEWORD) &&
((DWORD)cpMatch + cchToFind <= cchAdjText);
// Check for word delimiter before the match
if((dwFlags & FR_WHOLEWORD) && cpMatch > 0)
{
CTxtPtr tpT(_ped, cpMatch - 1);
if((pfnWB((LPTSTR)tpT.GetPch(cchValid), 0,
sizeof(TCHAR), WB_CLASSIFY) & WBF_CLASS) == 0)
{ goto no_match; }
}
// doesn't attempt to check next char if there isn't one
if((LONG)cchToFind - 1 < cchChunkForward)
{
// pchCurrent is valid for one or more chars, so are
// either done or can check for word delimeter
// CTxtPtr tpT(_ped, cpMatch + cchToFind);
// TCHAR* temptemp=tpT.GetPch();
if (!fWholeWord ||
(pfnWB((LPTSTR)(pchCurrent + cchLeft), 0,
sizeof(TCHAR),WB_CLASSIFY) & WBF_CLASS) != 0)
{ goto done; }
}
else // Need to compare across chunks
if(tp.MatchAcrossChunks(dwFlags, cchChunkForward,
pch + 1, cchToFind - 1, fWholeWord, pfnWB))
{ goto done; }
}
no_match:
pchCurrent = pchSave;
}
}
}
return -1; // No match
done:
if (cpMatch >= 0)
SetCp(cpMatch + cchToFind); // Match: set this tp just past
// match. When we have wildcard
return cpMatch; // chars, we may need something
} // more general than cchToFind
/*
* CTxtPtr::MatchAcrossChunks (dwFlags, cchChunkForward, pch, cchToMatch,
* fWholeWord, pfnWB)
*
* @mfunc helper function for FindText
*
* @rdesc TRUE if match found
*
* @comm "*this" points to char to check against pch[cchMatched]
*/
#define __OPT_PLAT_FLAG (defined (ARMV4T))
#define __OPT_VER_OFF
#define __OPT_BUGNUMSTRING "26316"
#include <optimizer.h>
INLINE BOOL CTxtPtr::MatchAcrossChunks (
DWORD dwFlags, //@parm Search flags
DWORD cchMatched, //@parm Amount already matched
const TCHAR *pch, //@parm String to match against
DWORD cchToMatch, //@parm Total cch to match
BOOL fWholeWord, //@parm Match against whole word
EDITWORDBREAKPROC pfnWB) const //@parm Word break proc
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::MatchAcrossChunks");
_TEST_INVARIANT_
LONG cchChunk;
LONG cchValid;
const TCHAR *pchCurrent;
CTxtPtr tp(*this); // tp already points to next
// chunk if searching forward.
BOOL fSearchForward = (FR_DOWN & dwFlags) != 0;
BOOL fIgnoreCase = (FR_MATCHCASE & dwFlags) == 0;
if ( !fSearchForward )
{
// even though the overall search is in reverse, the compare is done
// forward.
tp.GetPch(cchValid); // searching in reverse leaves _cp at previous chunk
tp.AdvanceCp(cchValid); // line it back up with searching forward.
}
pch += cchMatched; // Bypass chars already matched
cchToMatch -= cchMatched;
if(!cchToMatch)
pchCurrent = tp.GetPch(cchValid);
while(cchToMatch > 0)
{
pchCurrent = tp.GetPch(cchChunk);
if(cchChunk <= 0)
return FALSE;
cchChunk = min(cchChunk, (LONG)cchToMatch);
tp.AdvanceCp(cchChunk);
cchToMatch -= cchChunk;
if ( fIgnoreCase )
{
#ifdef PWD_JUPITER
// GuyBark Jupiter 50123: fIgnoreCase means ignore width too.
// So take the same action as elsewhere when comparing strings.
// Both pch and pchCurrent point to strings that are at least
// cchChunk long.
// Note: CompareString returns 2 if the two strings matched.
if(CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREWIDTH,
pchCurrent, cchChunk, pch, cchChunk) == 2)
{
// Strings are close enough! Set things up as they would be set
// up using the ifdef'd out comparison test. Don't actually
// need to set up pchCurrent here, but can't do any harm.
pch += cchChunk;
pchCurrent += cchChunk;
cchChunk = 0;
}
// If the comparison failed, we don't need to mess with the pointers here,
// as we're going to leave anyway below because cchChunk is still non-zero.
#else
do {
if ( TCHAR (CharLower ( (LPTSTR) *pchCurrent++ )) != TCHAR (CharLower ( (LPTSTR) *pch++ )) )
break;
} while( --cchChunk > 0);
#endif // PWD_JUPITER
}
else
{
do {
if ( *pchCurrent++ != *pch++ )
break;
} while( --cchChunk > 0);
}
if(cchChunk > 0)
return FALSE;
}
return !fWholeWord || (pfnWB((LPTSTR)tp.GetPch(cchValid), 0,
sizeof(TCHAR), WB_CLASSIFY) & WBF_CLASS);
}
#define __OPT_PLAT_FLAG (defined (ARMV4T))
#define __OPT_VER_RESTORE
#define __OPT_BUGNUMSTRING "26316"
#include <optimizer.h>
/*
* CTxtPtr::FindEOP(cchMax)
*
* @mfunc
* Find EOP mark in a range within cchMax chars from this text pointer
* and position *this after it. If no EOP is found and cchMax is not
* enough to reach the start or end of the story, leave this text ptr
* alone and return 0. If no EOP is found and cchMax is sufficient to
* reach the start or end of the story, position this text ptr at the
* beginning/end of document (BOD/EOD) for cchMax <lt>/<gt> 0,
* respectively, that is, BOD and EOD are treated as a BOP and an EOP,
* respectively.
*
* @rdesc
* Return cch this text ptr is moved
*
* @devnote
* This function assumes that this text ptr isn't in middle of a CRLF
* or CRCRLF (found only in RichEdit 1.0 compatibility mode). Changing
* the for loop could speed up ITextRange MoveUntil/While substantially.
*/
LONG CTxtPtr::FindEOP (
LONG cchMax, //@parm Max signed count of chars to search
LONG *pResults) //@parm Flags saying if EOP and CELL are found
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::FindEOP");
LONG cch = 0, cchStart; // cch's for scans
unsigned ch; // Current char
DWORD cpSave = _cp; // Save _cp for returning delta
LONG iDir = 1; // Default forward motion
const TCHAR*pch; // Used to walk text chunks
LONG Results = 0; // Nothing found yet
CTxtPtr tp(*this); // tp to search text with
if(cchMax < 0) // Backward search
{
iDir = -1; // Backward motion
cchMax = -cchMax; // Make max count positive
cch = tp.AdjustCpCRLF(); // If in middle of CRLF or
if(!cch && IsAfterEOP()) // CRCRLF, or follow any EOP,
cch = tp.BackupCpCRLF(); // backup before EOP
cchMax += cch;
}
while(cchMax > 0) // Scan until get out of search
{ // range or match an EOP
pch = iDir > 0 // Point pch at contiguous text
? tp.GetPch(cch) // chunk going forward or
: tp.GetPchReverse(cch); // going backward
if(!pch) // No more text to search
break;
if(iDir < 0) // Going backward, point at
pch--; // previous char
cch = min(cch, cchMax); // Limit scan to cchMax chars
for(cchStart = cch; cch; cch--) // Scan chunk for EOP
{
if (!pch)
break;
ch = *pch;
if(ch == CELL)
Results |= FEOP_CELL; // Note that CELL was found
if(IsEOP(ch)) // Note that EOP was found
{ // Going forward, cch may = 0
Results |= FEOP_EOP;
break;
}
pch += iDir;
}
cchStart -= cch; // Get cch of chars passed by
cchMax -= cchStart; // Update cchMax
tp.AdvanceCp(iDir*cchStart); // Update tp
if((Results & FEOP_EOP) || !(pch)) // Found an EOP
break;
} // Continue with next chunk
if(pResults) // Report whether EOP and CELL
*pResults = Results; // were found
if(Results & FEOP_EOP || !tp.GetCp()) // Found EOP or cp is at beginning
{ // of story:
SetCp(tp.GetCp()); // set _cp = cp
if(GetChar() == LF) // In case there's a LF there,
AdvanceCp(1); // bypass it
else if(iDir > 0) // Position this ptr just after
AdvanceCpCRLF(); // EOP
}
return _cp - cpSave; // Return cch this tp moved
}
/*
* CTxtPtr::FindBOSentence(cch)
*
* @mfunc
* Find beginning of sentence in a range within cch chars from this text
* pointer and position *this at it. If no sentence beginning is found,
* position *this at beginning of document (BOD) for cch <lt> 0 and
* leave *this unchanged for cch >= 0.
*
* @rdesc
* Count of chars moved *this moves
*
* @comm
* This routine defines a sentence as a character string that ends with
* period followed by at least one whitespace character or the EOD. This
* should be replacable so that other kinds of sentence endings can be
* used. This routine also matches initials like "M. " as sentences.
* We could eliminate those by requiring that sentences don't end with
* a word consisting of a single capital character. Similarly, common
* abbreviations like "Mr." could be bypassed. To allow a sentence to
* end with these "words", two blanks following a period could be used
* to mean an unconditi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -