361 lines
9.3 KiB
C
361 lines
9.3 KiB
C
|
/*
|
||
|
* misc functions
|
||
|
* Copyright (C) 1984-2000 Microsoft Inc.
|
||
|
*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
BOOL fCase = FALSE; /* Flag specifying case sensitive search */
|
||
|
BOOL fReverse = FALSE; /* Flag for direction of search */
|
||
|
|
||
|
extern HWND hDlgFind; /* handle to modeless FindText window */
|
||
|
|
||
|
LPTSTR ReverseScan(
|
||
|
LPTSTR lpSource,
|
||
|
LPTSTR lpLast,
|
||
|
LPTSTR lpSearch,
|
||
|
BOOL fCaseSensitive )
|
||
|
{
|
||
|
TCHAR cLastCharU;
|
||
|
TCHAR cLastCharL;
|
||
|
INT iLen;
|
||
|
|
||
|
cLastCharU= (TCHAR) (INT_PTR) CharUpper( (LPTSTR)(INT_PTR)(*lpSearch) );
|
||
|
cLastCharL= (TCHAR) (INT_PTR) CharLower( (LPTSTR)(INT_PTR)(*lpSearch) );
|
||
|
|
||
|
iLen = lstrlen(lpSearch);
|
||
|
|
||
|
if (!lpLast)
|
||
|
lpLast = lpSource + lstrlen(lpSource);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (lpLast == lpSource)
|
||
|
return NULL;
|
||
|
|
||
|
--lpLast;
|
||
|
|
||
|
if (fCaseSensitive)
|
||
|
{
|
||
|
if (*lpLast != *lpSearch)
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( !( *lpLast == cLastCharU || *lpLast == cLastCharL ) )
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (fCaseSensitive)
|
||
|
{
|
||
|
if (!_tcsncmp( lpLast, lpSearch, iLen))
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// compare whole string using locale specific comparison.
|
||
|
// do not use C runtime version since it may be wrong.
|
||
|
//
|
||
|
|
||
|
if( 2 == CompareString( LOCALE_USER_DEFAULT,
|
||
|
NORM_IGNORECASE | SORT_STRINGSORT | NORM_STOP_ON_NULL,
|
||
|
lpLast, iLen,
|
||
|
lpSearch, iLen) )
|
||
|
break;
|
||
|
}
|
||
|
} while (TRUE);
|
||
|
|
||
|
return lpLast;
|
||
|
}
|
||
|
|
||
|
LPTSTR ForwardScan(LPTSTR lpSource, LPTSTR lpSearch, BOOL fCaseSensitive )
|
||
|
{
|
||
|
TCHAR cFirstCharU;
|
||
|
TCHAR cFirstCharL;
|
||
|
int iLen = lstrlen(lpSearch);
|
||
|
|
||
|
cFirstCharU= (TCHAR) (INT_PTR) CharUpper( (LPTSTR)(INT_PTR)(*lpSearch) );
|
||
|
cFirstCharL= (TCHAR) (INT_PTR) CharLower( (LPTSTR)(INT_PTR)(*lpSearch) );
|
||
|
|
||
|
while (*lpSource)
|
||
|
{
|
||
|
if (fCaseSensitive)
|
||
|
{
|
||
|
if (*lpSource != *lpSearch)
|
||
|
{
|
||
|
lpSource++;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( !( *lpSource == cFirstCharU || *lpSource == cFirstCharL ) )
|
||
|
{
|
||
|
lpSource++;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fCaseSensitive)
|
||
|
{
|
||
|
if (!_tcsncmp( lpSource, lpSearch, iLen))
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( 2 == CompareString( LOCALE_USER_DEFAULT,
|
||
|
NORM_IGNORECASE | SORT_STRINGSORT | NORM_STOP_ON_NULL,
|
||
|
lpSource, iLen,
|
||
|
lpSearch, iLen) )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
lpSource++;
|
||
|
}
|
||
|
|
||
|
return *lpSource ? lpSource : NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* search forward or backward in the edit control text for the given pattern */
|
||
|
/* It is the responsibility of the caller to set the cursor */
|
||
|
|
||
|
BOOL Search (TCHAR * szKey)
|
||
|
{
|
||
|
BOOL bStatus= FALSE;
|
||
|
TCHAR * pStart, *pMatch;
|
||
|
DWORD StartIndex, LineNum, EndIndex;
|
||
|
DWORD SelStart, SelEnd, i;
|
||
|
HANDLE hEText; // handle to edit text
|
||
|
UINT uSelState;
|
||
|
HMENU hMenu;
|
||
|
BOOL bSelectAll = FALSE;
|
||
|
|
||
|
|
||
|
if (!*szKey)
|
||
|
return( bStatus );
|
||
|
|
||
|
SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&SelStart, (LPARAM)&SelEnd);
|
||
|
|
||
|
|
||
|
/*
|
||
|
when we finish the search, we highlight the text found, and continue
|
||
|
the search after the end of the highlighted position (in forward
|
||
|
case) or from the begining of the highlighted position in the reverse
|
||
|
direction (in reverse case). this would break if the user has
|
||
|
selected all text. this hack would take care of it. (this is consistent
|
||
|
with VC editors' search too.*/
|
||
|
|
||
|
hMenu = GetMenu(hwndSP);
|
||
|
uSelState = GetMenuState(GetSubMenu(hMenu, 1), M_SELECTALL, MF_BYCOMMAND);
|
||
|
if (uSelState == MF_GRAYED)
|
||
|
{
|
||
|
bSelectAll = TRUE;
|
||
|
SelStart = SelEnd =0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* get pointer to edit control text to search
|
||
|
*/
|
||
|
|
||
|
hEText= (HANDLE) SendMessage( hwndEdit, EM_GETHANDLE, 0, 0 );
|
||
|
if( !hEText ) // silently return if we can't get it
|
||
|
{
|
||
|
return( bStatus );
|
||
|
}
|
||
|
pStart= LocalLock( hEText );
|
||
|
if( !pStart )
|
||
|
{
|
||
|
return( bStatus );
|
||
|
}
|
||
|
|
||
|
if (fReverse)
|
||
|
{
|
||
|
/* Get current line number */
|
||
|
LineNum= (DWORD)SendMessage(hwndEdit, EM_LINEFROMCHAR, SelStart, 0);
|
||
|
/* Get index to start of the line */
|
||
|
StartIndex= (DWORD)SendMessage(hwndEdit, EM_LINEINDEX, LineNum, 0);
|
||
|
/* Set upper limit for search text */
|
||
|
EndIndex= SelStart;
|
||
|
pMatch= NULL;
|
||
|
|
||
|
/* Search line by line, from LineNum to 0 */
|
||
|
i = LineNum;
|
||
|
while (TRUE)
|
||
|
{
|
||
|
pMatch= ReverseScan(pStart+StartIndex,pStart+EndIndex,szKey,fCase);
|
||
|
if (pMatch)
|
||
|
break;
|
||
|
/* current StartIndex is the upper limit for the next search */
|
||
|
EndIndex= StartIndex;
|
||
|
|
||
|
if (i)
|
||
|
{
|
||
|
/* Get start of the next line */
|
||
|
i-- ;
|
||
|
StartIndex = (DWORD)SendMessage(hwndEdit, EM_LINEINDEX, i, 0);
|
||
|
}
|
||
|
else
|
||
|
break ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pMatch= ForwardScan(pStart+SelEnd, szKey, fCase);
|
||
|
}
|
||
|
|
||
|
LocalUnlock(hEText);
|
||
|
|
||
|
if (pMatch == NULL)
|
||
|
{
|
||
|
//
|
||
|
// alert user on not finding any text unless it is replace all
|
||
|
//
|
||
|
if( !(FR.Flags & FR_REPLACEALL) )
|
||
|
{
|
||
|
HANDLE hPrevCursor= SetCursor( hStdCursor );
|
||
|
AlertBox( hDlgFind ? hDlgFind : hwndSP,
|
||
|
szNN,
|
||
|
szCFS,
|
||
|
szSearch,
|
||
|
MB_APPLMODAL | MB_OK | MB_ICONASTERISK);
|
||
|
SetCursor( hPrevCursor );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SelStart = (DWORD)(pMatch - pStart);
|
||
|
SendMessage( hwndEdit, EM_SETSEL, SelStart, SelStart+lstrlen(szKey));
|
||
|
|
||
|
// since we are selecting the found text, enable SelectAll again.
|
||
|
if (bSelectAll)
|
||
|
{
|
||
|
EnableMenuItem(GetSubMenu(hMenu, 1), M_SELECTALL, MF_ENABLED);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// show the selected text unless it is replace all
|
||
|
//
|
||
|
|
||
|
if( !(FR.Flags & FR_REPLACEALL) )
|
||
|
{
|
||
|
SendMessage(hwndEdit, EM_SCROLLCARET, 0, 0);
|
||
|
}
|
||
|
bStatus= TRUE; // found
|
||
|
}
|
||
|
|
||
|
return( bStatus );
|
||
|
}
|
||
|
|
||
|
/* ** Recreate sxspad edit window, get text from old window and put in
|
||
|
new window. Called when user changes style from wrap on/off */
|
||
|
BOOL FAR NpReCreate( long style )
|
||
|
{
|
||
|
RECT rcT1;
|
||
|
HWND hwndT1;
|
||
|
HANDLE hT1;
|
||
|
int cchTextNew;
|
||
|
TCHAR* pchText;
|
||
|
BOOL fWrap = ((style & WS_HSCROLL) == 0);
|
||
|
HCURSOR hPrevCursor;
|
||
|
BOOL bModified; // modify flag from old edit buffer
|
||
|
|
||
|
/* if wordwrap, remove soft carriage returns */
|
||
|
hPrevCursor= SetCursor( hWaitCursor ); // this may take some time...
|
||
|
if (!fWrap)
|
||
|
SendMessage(hwndEdit, EM_FMTLINES, FALSE, 0L);
|
||
|
|
||
|
bModified= (SendMessage( hwndEdit, EM_GETMODIFY, 0,0 ) != 0);
|
||
|
|
||
|
cchTextNew= (int)SendMessage( hwndEdit, WM_GETTEXTLENGTH, 0, 0L );
|
||
|
hT1= LocalAlloc( LMEM_MOVEABLE, ByteCountOf(cchTextNew + 1) );
|
||
|
if( !hT1 )
|
||
|
{
|
||
|
/* failed, was wordwrap; insert soft carriage returns */
|
||
|
if (!fWrap)
|
||
|
SendMessage(hwndEdit, EM_FMTLINES, TRUE, 0L);
|
||
|
SetCursor( hPrevCursor );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
GetClientRect( hwndSP, (LPRECT)&rcT1 );
|
||
|
|
||
|
/*
|
||
|
* save the current edit control text.
|
||
|
*/
|
||
|
pchText= LocalLock (hT1);
|
||
|
SendMessage( hwndEdit, WM_GETTEXT, cchTextNew+1, (LPARAM)pchText );
|
||
|
hwndT1= CreateWindowEx( WS_EX_CLIENTEDGE,
|
||
|
TEXT("Edit"),
|
||
|
TEXT(""), // pchText
|
||
|
style,
|
||
|
0,
|
||
|
0,
|
||
|
rcT1.right,
|
||
|
rcT1.bottom,
|
||
|
hwndSP,
|
||
|
(HMENU)ID_EDIT,
|
||
|
hInstanceSP, NULL );
|
||
|
if( !hwndT1 )
|
||
|
{
|
||
|
SetCursor( hPrevCursor );
|
||
|
if (!fWrap)
|
||
|
SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
|
||
|
LocalUnlock(hT1);
|
||
|
LocalFree(hT1);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The user can "add" styles to the edit window after it is
|
||
|
// created (like WS_EX_RTLREADING) when language packs are installed.
|
||
|
// Preserve these styles when changing the word wrap.
|
||
|
//
|
||
|
|
||
|
SetWindowLong( hwndT1 ,
|
||
|
GWL_EXSTYLE ,
|
||
|
GetWindowLong( hwndEdit , GWL_EXSTYLE )|WS_EX_CLIENTEDGE ) ;
|
||
|
|
||
|
// Set font before set text to save time calculating
|
||
|
SendMessage( hwndT1, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0) );
|
||
|
|
||
|
if (!SendMessage (hwndT1, WM_SETTEXT, 0, (LPARAM) pchText))
|
||
|
{
|
||
|
SetCursor( hPrevCursor );
|
||
|
if (!fWrap)
|
||
|
SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
|
||
|
DestroyWindow( hwndT1 );
|
||
|
LocalUnlock( hT1 );
|
||
|
LocalFree( hT1 );
|
||
|
return FALSE;
|
||
|
}
|
||
|
LocalUnlock(hT1);
|
||
|
|
||
|
|
||
|
DestroyWindow( hwndEdit ); // out with the old
|
||
|
hwndEdit = hwndT1; // in with the new
|
||
|
/*
|
||
|
* Win32s does not support the EM_SETHANDLE message, so just do
|
||
|
* the assignment. hT1 already contains the edit control text.
|
||
|
*/
|
||
|
/* free the earlier allocated memory in hEdit */
|
||
|
if (hEdit)
|
||
|
LocalFree(hEdit);
|
||
|
|
||
|
hEdit = hT1;
|
||
|
|
||
|
/* limit text for safety's sake. */
|
||
|
PostMessage( hwndEdit, EM_LIMITTEXT, (WPARAM)CCHSPMAX, 0L );
|
||
|
|
||
|
ShowWindow(hwndSP, SW_SHOW);
|
||
|
SetTitle( fUntitled ? szUntitled : szFileName );
|
||
|
SendMessage( hwndEdit, EM_SETMODIFY, bModified, 0L );
|
||
|
SetFocus(hwndEdit);
|
||
|
|
||
|
SetCursor( hPrevCursor ); // restore cursor
|
||
|
return TRUE;
|
||
|
}
|
||
|
|