windows-nt/Source/XPSP1/NT/shell/osshell/accesory/newpad/npmisc.c
2020-09-26 16:20:57 +08:00

384 lines
9.6 KiB
C

/*
* misc notepad functions
* Copyright (C) 1984-2000 Microsoft Corporation
*/
#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(hwndNP);
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 : hwndNP,
szNN,
szCFS,
szSearch,
MB_APPLMODAL | MB_OK | MB_ICONINFORMATION);
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 notepad edit window, get text from old window and put in new window.
// Called when user changes style from wrap on/off
//
// Called with the style of the new window
//
BOOL NpReCreate( long style )
{
RECT rcT1;
HWND hwndT1;
HANDLE hT1;
int cchTextNew;
TCHAR* pchText;
BOOL fWrapIsOn = ((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( fWrapIsOn )
{
GotoAndScrollInView(1); // get around MLE bug
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, restore wordwrap; insert soft carriage returns
if( fWrapIsOn )
{
SendMessage(hwndEdit, EM_FMTLINES, TRUE, 0L);
}
SetCursor( hPrevCursor );
return FALSE;
}
GetClientRect( hwndNP, (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,
hwndNP,
(HMENU)ID_EDIT,
hInstanceNP, NULL );
if( !hwndT1 )
{
SetCursor( hPrevCursor );
if( fWrapIsOn ) // restore wordwrap
{
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( fWrapIsOn ) // restore wordwrap
{
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
// free the earlier allocated memory in hEdit
if (hEdit)
LocalFree(hEdit);
hEdit = hT1;
// limit text for safety's sake.
PostMessage( hwndEdit, EM_LIMITTEXT, (WPARAM)CCHNPMAX, 0L );
ShowWindow(hwndNP, SW_SHOW);
SendMessage( hwndEdit, EM_SETMODIFY, bModified, 0L );
SetFocus(hwndEdit);
SetCursor( hPrevCursor ); // restore cursor
// redraw the status bar
if( fStatus )
{
RECT rcClient;
GetClientRect(hwndNP, &rcClient);
NPSize(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
ShowWindow( hwndStatus, SW_SHOW );
}
return TRUE;
}