mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
480 lines
12 KiB
480 lines
12 KiB
/*
|
|
* misc functions
|
|
* Copyright (C) 1984-1995 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) CharUpper( (LPTSTR)(*lpSearch) );
|
|
cLastCharL= (TCHAR) CharLower( (LPTSTR)(*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
|
|
{
|
|
if (!_tcsnicmp (lpLast, 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) CharUpper( (LPTSTR)(*lpSearch) );
|
|
cFirstCharL= (TCHAR) CharLower( (LPTSTR)(*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 (!_tcsnicmp( lpSource, 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
|
|
|
|
if (!*szKey)
|
|
return( bStatus );
|
|
|
|
SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&SelStart, (LPARAM)&SelEnd);
|
|
|
|
/*
|
|
* 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= SendMessage(hwndEdit, EM_LINEFROMCHAR, SelStart, 0);
|
|
/* Get index to start of the line */
|
|
StartIndex= 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= 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_ICONASTERISK);
|
|
SetCursor( hPrevCursor );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelStart = pMatch - pStart;
|
|
SendMessage( hwndEdit, EM_SETSEL, SelStart, SelStart+lstrlen(szKey));
|
|
|
|
//
|
|
// 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 */
|
|
BOOL FAR NpReCreate( long style )
|
|
{
|
|
RECT rcT1;
|
|
HWND hwndT1;
|
|
int iScrollMax = (style & WS_HSCROLL ? 100 : 0);
|
|
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 );
|
|
|
|
cchTextNew= SendMessage( hwndEdit, WM_GETTEXTLENGTH, 0, 0L );
|
|
hT1= LocalAlloc( LHND, 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( 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 (!fWrap)
|
|
SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
|
|
LocalUnlock(hT1);
|
|
LocalFree(hT1);
|
|
return FALSE;
|
|
}
|
|
|
|
// 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.
|
|
*/
|
|
hEdit = hT1;
|
|
|
|
/* limit text for safety's sake. */
|
|
PostMessage( hwndEdit, EM_LIMITTEXT, (WPARAM)CCHNPMAX, 0L );
|
|
|
|
ShowWindow(hwndNP, SW_SHOW);
|
|
SetTitle( fUntitled ? szUntitled : szFileName );
|
|
SendMessage( hwndEdit, EM_SETMODIFY, bModified, 0L );
|
|
SetFocus(hwndEdit);
|
|
|
|
#if !defined(UNICODE) && defined(JAPAN)
|
|
{
|
|
extern FARPROC lpEditSubClassProc;
|
|
extern FARPROC lpEditClassProc;
|
|
|
|
/* Sub Classing again */
|
|
lpEditClassProc = (FARPROC) GetWindowLong (hwndEdit, GWL_WNDPROC);
|
|
SetWindowLong (hwndEdit, GWL_WNDPROC, (LONG) lpEditSubClassProc);
|
|
}
|
|
#endif
|
|
SetCursor( hPrevCursor ); // restore cursor
|
|
return TRUE;
|
|
}
|
|
|
|
#if !defined(UNICODE) && defined(JAPAN)
|
|
|
|
/* Edit Control tune up routine */
|
|
|
|
WORD NEAR PASCAL EatOneCharacter(HWND);
|
|
|
|
FARPROC lpEditClassProc;
|
|
FARPROC lpEditSubClassProc;
|
|
|
|
/* routine to retrieve WM_CHAR from the message queue associated with hwnd.
|
|
* this is called by EatString.
|
|
*/
|
|
WORD NEAR PASCAL EatOneCharacter(hwnd)
|
|
register HWND hwnd;
|
|
{
|
|
MSG msg;
|
|
register int i = 10;
|
|
|
|
while (!PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE))
|
|
{
|
|
if (--i == 0)
|
|
return -1;
|
|
Yield();
|
|
}
|
|
return (msg.wParam & 0x00FF);
|
|
}
|
|
|
|
BOOL FAR PASCAL EatString(HWND,LPSTR,WORD);
|
|
/* This routine is called when the Edit Control receives WM_IME_REPORT
|
|
* with IR_STRINGSTART message. The purpose of this function is to eat
|
|
* all WM_CHARs between IR_STRINGSTART and IR_STRINGEND and to build a
|
|
* string block.
|
|
*/
|
|
BOOL FAR PASCAL EatString(hwnd, lpSp, cchLen)
|
|
register HWND hwnd;
|
|
LPSTR lpSp;
|
|
WORD cchLen;
|
|
{
|
|
MSG msg;
|
|
int i = 10; // loop counter for avoid infinite loop
|
|
int w;
|
|
|
|
*lpSp = '\0';
|
|
if (cchLen < 4)
|
|
return FALSE; // not enough
|
|
cchLen -= 2;
|
|
|
|
while (i--)
|
|
{
|
|
while (PeekMessage (&msg, hwnd, 0, 0, PM_REMOVE))
|
|
{
|
|
i = 10;
|
|
switch (msg.message)
|
|
{
|
|
case WM_CHAR:
|
|
*lpSp++ = (BYTE)msg.wParam;
|
|
cchLen--;
|
|
if (IsDBCSLeadByte ((BYTE)msg.wParam))
|
|
{
|
|
if ((w = EatOneCharacter(hwnd)) == -1)
|
|
{
|
|
/* Bad DBCS sequence - abort */
|
|
lpSp--;
|
|
goto WillBeDone;
|
|
}
|
|
*lpSp++ = (BYTE)w;
|
|
cchLen--;
|
|
}
|
|
if (cchLen <= 0)
|
|
goto WillBeDone; // buffer exhausted
|
|
break;
|
|
|
|
case WM_IME_REPORT:
|
|
if (msg.wParam == IR_STRINGEND)
|
|
{
|
|
if (cchLen <= 0)
|
|
goto WillBeDone; // no more room to stuff
|
|
if ((w = EatOneCharacter(hwnd)) == -1)
|
|
goto WillBeDone;
|
|
*lpSp++ = (BYTE)w;
|
|
if (IsDBCSLeadByte((BYTE)w))
|
|
{
|
|
if ((w = EatOneCharacter(hwnd)) == -1)
|
|
{
|
|
/* Bad DBCS sequence - abort */
|
|
lpSp--;
|
|
goto WillBeDone;
|
|
}
|
|
*lpSp++ = (BYTE)w;
|
|
}
|
|
goto WillBeDone;
|
|
}
|
|
|
|
/* Fall through */
|
|
|
|
default:
|
|
TranslateMessage (&msg);
|
|
DispatchMessage (&msg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* We don't get WM_IME_REPORT + IR_STRINGEND
|
|
* But received string will be OK
|
|
*/
|
|
|
|
WillBeDone:
|
|
|
|
*lpSp = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LONG FAR PASCAL EditSubClassProc(
|
|
HWND hWnd,
|
|
UINT wMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam )
|
|
{
|
|
LPSTR lpP;
|
|
HANDLE hMem;
|
|
HANDLE hClipSave;
|
|
|
|
if (wMessage == WM_IME_REPORT)
|
|
{
|
|
if (wParam == IR_STRING)
|
|
{
|
|
if (lpP = GlobalLock((HANDLE)lParam))
|
|
{
|
|
CallWindowProc(lpEditClassProc, hWnd,
|
|
EM_REPLACESEL, 0, (LPARAM)lpP);
|
|
GlobalUnlock( (HANDLE)lParam );
|
|
return 1L; // processed
|
|
}
|
|
return 0L;
|
|
}
|
|
if (wParam == IR_STRINGSTART)
|
|
{
|
|
if( (hMem= GlobalAlloc (GHND, 512L)) == NULL )
|
|
{
|
|
goto DoProc;
|
|
}
|
|
if( (lpP = GlobalLock(hMem)) == NULL )
|
|
{
|
|
GlobalFree(hMem);
|
|
goto DoProc;
|
|
}
|
|
if (EatString(hWnd, lpP, 512))
|
|
{
|
|
CallWindowProc(lpEditClassProc,hWnd,EM_REPLACESEL,0,(DWORD)lpP);
|
|
GlobalUnlock (hMem);
|
|
GlobalFree (hMem);
|
|
return 0L;
|
|
}
|
|
GlobalUnlock (hMem);
|
|
GlobalFree (hMem);
|
|
}
|
|
}
|
|
DoProc:
|
|
return CallWindowProc(lpEditClassProc,hWnd,wMessage,wParam,lParam);
|
|
}
|
|
#endif
|