//
// findreplace.cpp - Implementation of
// Find and Replace functionality
// NoteXpad 2.0, Ryan Lederman, ryan@winprog.org
//
#include "findreplace.h"
#include "macros.h"
#include "options.h"
#include "util.h"
#include "stdlib.h"
HWND CreateFindReplaceDialog( HWND hWndParent )
{
HWND hWnd = 0;
if( !IsWindow( hWndParent ) )
return NULL;
hWnd = CreateDialog( GetModuleHandle( NULL ),
(LPCTSTR)IDD_FINDREPLACE,
hWndParent,
FRDialogProc );
CenterWindow( hWndParent, hWnd );
ShowWindow( hWnd, SW_SHOW );
return hWnd;
}
BOOL CALLBACK FRDialogProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_INITDIALOG: return OnInitDialog( hWnd, wParam, lParam );
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDCANCEL:
EndDialog( hWnd, 0 );
break;
case IDC_FINDNEXT: return FindReplace_OnFind( hWnd, wParam, lParam );
case IDC_REPLACE: return FindReplace_OnReplace( hWnd, wParam, lParam );
case IDC_REPLACEALL: return FindReplace_OnReplaceAll( hWnd, wParam, lParam );
case IDC_CASESENSITIVE:
switch( IsDlgButtonChecked( hWnd, IDC_CASESENSITIVE ) )
{
case BST_CHECKED:
SetOptionDWORD( T("CaseSensitive"), 1 );
break;
case BST_UNCHECKED:
SetOptionDWORD( T("CaseSensitive"), 0 );
break;
}
break;
}
break;
case WM_CLOSE:
EndDialog( hWnd, 0 );
break;
}
return FALSE;
}
BOOL OnInitDialog( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
//
// OnInitDialog
// Called when find/replace dialog is created
//
TCHAR szToFind[1024] = {0};
HWND hWndView = 0;
DWORD dwSelStart = 0;
DWORD dwSelEnd = 0;
HLOCAL hEditHandle = 0;
PVOID pEditVoid = 0;
DWORD dwCaseSensitive= 0;
SendMessage( GetDlgItem( hWnd, IDC_FINDFIELD ), EM_LIMITTEXT, 0, 0 );
SendMessage( GetDlgItem( hWnd, IDC_REPLACEFIELD ), EM_LIMITTEXT, 0, 0 );
//
// If there is a current selection in the view, make that what to find
//
hWndView = GetDlgItem( GetParent( hWnd ), ID_VIEW );
SendMessage( hWndView, EM_GETSEL, (WPARAM)&dwSelStart, (LPARAM)&dwSelEnd );
if( dwSelEnd != 0 )
{
hEditHandle = (HLOCAL)SendMessage( hWndView, EM_GETHANDLE, 0, 0 );
if( !hEditHandle )
return FALSE;
pEditVoid = LocalLock( hEditHandle );
if( !pEditVoid )
return FALSE;
memcpy( szToFind, (TCHAR*)((TCHAR*)pEditVoid+dwSelStart), (dwSelEnd-dwSelStart) );
SetWindowText( GetDlgItem( hWnd, IDC_FINDFIELD ), szToFind );
LocalUnlock( hEditHandle );
}
SetFocus( GetDlgItem( hWnd, IDC_FINDFIELD ) );
//
// Check case sensitive option
//
GetOptionDWORD( T("CaseSensitive"), &dwCaseSensitive );
if( dwCaseSensitive )
CheckDlgButton( hWnd, IDC_CASESENSITIVE, BST_CHECKED );
return FALSE;
}
BOOL FindReplace_OnFind( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
//
// FindReplace_OnFind
// Called when user presses find button on find/replace dialog
//
HLOCAL hEditHandle = 0;
PVOID pEditVoid = 0;
PVOID pLast = 0;
DWORD dwSelStart = 0;
DWORD dwSelEnd = 0;
DWORD dwIndex = 0;
HWND hWndView = 0;
TCHAR szToFind[1024] = {0};
//
// First, let's see if there is even something to search in the view.
//
hWndView = GetDlgItem( GetParent( hWnd ), ID_VIEW );
hEditHandle = (HLOCAL)SendMessage( hWndView, EM_GETHANDLE, 0, 0 );
if( !hEditHandle )
return FALSE;
pEditVoid = LocalLock( hEditHandle );
if( !pEditVoid )
return FALSE;
if( !*((TCHAR*)pEditVoid) ) {
LocalUnlock( hEditHandle );
return FALSE;
}
//
// Ok, so there's something in the view
//
GetDlgItemText( hWnd, IDC_FINDFIELD, szToFind, 1024 );
if( _tcslen( szToFind ) <= 0 )
{
// Nothing to search for
SetFocus( GetDlgItem( hWnd, IDC_FINDFIELD ) );
SendMessage( GetDlgItem( hWnd, IDC_FINDFIELD ), EM_SETSEL, 0, GetWindowTextLength( GetDlgItem( hWnd, IDC_FINDFIELD ) ) );
LocalUnlock( hEditHandle );
MessageBeep( MB_OK );
}
// We have something to find, let's get crackin
// First things first, discover address of first instance of search query
SendMessage( hWndView, EM_GETSEL, (WPARAM)&dwSelStart, (LPARAM)&dwSelEnd );
if( IsDlgButtonChecked( hWnd, IDC_CASESENSITIVE ) == BST_CHECKED )
pLast = (PVOID)_tcsstr( (TCHAR*)pEditVoid+dwSelEnd, szToFind );
else
pLast = (PVOID)StrStrI( (TCHAR*)pEditVoid+dwSelEnd, szToFind );
if( !pLast )
{
// Shiiiit, that query doesn't even exist in the document.
SetFocus( GetDlgItem( hWnd, IDC_FINDFIELD ) );
SendMessage( GetDlgItem( hWnd, IDC_FINDFIELD ), EM_SETSEL, 0, GetWindowTextLength( GetDlgItem( hWnd, IDC_FINDFIELD ) ) );
LocalUnlock( hEditHandle );
MessageBeep( MB_OK );
return FALSE;
}
dwIndex = ((TCHAR*)pLast - (TCHAR*)pEditVoid);
SendMessage( hWndView, EM_SETSEL, (WPARAM)dwIndex, (LPARAM)dwIndex+_tcslen( szToFind ) );
LocalUnlock( hEditHandle );
return FALSE;
}
BOOL FindReplace_OnReplace( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
//
// FindReplace_OnReplace
// Called when user presses replace button
//
TCHAR szToReplace[1024] = {0};
DWORD dwSelStart = 0;
DWORD dwSelEnd = 0;
HWND hWndView = 0;
hWndView = GetDlgItem( GetParent( hWnd ), ID_VIEW );
SendMessage( hWndView, EM_GETSEL, (WPARAM)&dwSelStart, (LPARAM)&dwSelEnd );
if( !dwSelEnd )
{
// There is no selection to replace
SetFocus( GetDlgItem( hWnd, IDC_REPLACEFIELD ) );
SendMessage( GetDlgItem( hWnd, IDC_REPLACEFIELD ), EM_SETSEL, 0, GetWindowTextLength( GetDlgItem( hWnd, IDC_FINDFIELD ) ) );
MessageBeep( MB_OK );
return FALSE;
}
GetDlgItemText( hWnd, IDC_REPLACEFIELD, szToReplace, 1024 );
SendMessage( hWndView, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)szToReplace );
return FALSE;
}
BOOL FindReplace_OnReplaceAll( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
//
// FindReplace_OnReplaceAll
// Called when user presses replace all button
//
TCHAR szToFind[1204] = {0};
TCHAR szToReplace[1024] = {0};
HLOCAL hEditHandle = 0;
HLOCAL hNewHandle = 0;
HLOCAL pNewVoid = 0;
PVOID pEditVoid = 0;
HWND hWndView = 0;
TCHAR *szTempBuffer = 0;
TCHAR *szTemp = 0;
DWORD dwNewBufLen = 0;
REPLACESTRUCT rs = {0};
GetDlgItemText( hWnd, IDC_FINDFIELD, szToFind, 1024 );
GetDlgItemText( hWnd, IDC_REPLACEFIELD, szToReplace, 1024 );
hWndView = GetDlgItem( GetParent( hWnd ), ID_VIEW );
if( _tcslen( szToFind ) <= 0 ) return FALSE;
//
// Allocate new buffer
//
hNewHandle = LocalAlloc( LMEM_MOVEABLE, 10 );
if( !hNewHandle ) return FALSE;
//
// Ok, let's get this show on the road
//
PostMessage( hWndView, EM_LIMITTEXT, 0, 0 );
SendMessage( hWndView, WM_SETREDRAW, FALSE, 0 );
hEditHandle = (HLOCAL)SendMessage( hWndView, EM_GETHANDLE, 0, 0 );
//
// Got access to the internal buffer of the edit box
//
pEditVoid = LocalLock( hEditHandle );
if( !pEditVoid ) return FALSE;
//
// Do replacment
//(TCHAR*)pEditVoid, &szTempBuffer, &dwNewBufLen, szToFind, szToReplace
if( IsDlgButtonChecked( hWnd, IDC_CASESENSITIVE ) == BST_CHECKED )
rs.bCaseSensitive = TRUE;
else
rs.bCaseSensitive = FALSE;
rs.iDestLen = &dwNewBufLen;
rs.szData = (TCHAR*)pEditVoid;
rs.szDest = &szTempBuffer;
rs.szFind = szToFind;
rs.szReplace = szToReplace;
if( Replace( &rs ) > 0 )
{
LocalUnlock( hEditHandle );
LocalFree( hEditHandle );
PostMessage( hWndView, EM_SETHANDLE, (WPARAM)hNewHandle, 0 );
LocalReAlloc( hNewHandle, (dwNewBufLen*sizeof(TCHAR))+sizeof(TCHAR), LMEM_MOVEABLE );
pNewVoid = LocalLock( hNewHandle );
memcpy( pNewVoid, szTempBuffer, dwNewBufLen*sizeof(TCHAR) );
free( szTempBuffer );
szTemp = (TCHAR*)pNewVoid;
szTemp[dwNewBufLen] = '\0';
LocalUnlock( hNewHandle );
}
PostMessage( hWndView, WM_SETREDRAW, TRUE, 0 );
return FALSE;
}
int Replace( PREPLACESTRUCT prs )
{
//
// Replaces all occurences of szFind with szReplace
// Assigns *szDest to the address of the newly created buffer
// and *iDestLen to the number of bytes copied to the new buffer
//
TCHAR *szBuffer = 0;
TCHAR *szFound = 0;
DWORD dwCopied = 0;
DWORD dwLength = 0;
DWORD dwNewLen = 0;
DWORD dwBufLen = 0;
DWORD dwNum = 0;
const TCHAR *szEnd = 0;
const TCHAR *szFloater= 0;
if( !prs ) return -1;
if( !prs->szData || !*prs->szData || !prs->szFind || !*prs->szFind || !prs->szReplace )
return -1;
if( !_tcslen( prs->szFind ) || !_tcslen( prs->szData ) )
return -1;
szEnd = prs->szData + _tcslen( prs->szData );
szFloater = prs->szData;
if( !szEnd || !szFloater )
return -1;
dwLength = _tcslen( prs->szData );
while( szFloater < szEnd )
{
szFloater = _tcsstr( szFloater, prs->szFind );
if( !szFloater )
break;
szFloater += _tcslen( prs->szFind );
if( _tcslen( prs->szReplace ) > _tcslen( prs->szFind ) )
dwLength += (_tcslen( prs->szReplace ) - _tcslen( prs->szFind ));
else
dwLength -= (_tcslen( prs->szReplace ) - _tcslen( prs->szFind ));
dwNum++;
}
if( !dwNum )
return 0;
szBuffer = (TCHAR*)calloc( dwLength+1, sizeof(TCHAR) );
if( !szBuffer )
return -1;
szFloater = prs->szData;
while( *szFloater ) {
if( prs->bCaseSensitive ) {
szFound = _tcsstr( szFloater, prs->szFind ); }
else {
szFound = StrStrI( szFloater, prs->szFind ); }
if( szFound ) {
// String is found, copy up to the beginning of the string
// to the buffer, and then szReplace, and begin loop again
// offset at last occurance of szFind+len(szFind)
// Copy to buffer at current offset from current read point
// to found string -1
memcpy( (void*)(szBuffer+dwBufLen), (void*)szFloater, (szFound - szFloater)*sizeof(TCHAR) );
dwBufLen += (szFound - szFloater); // Increment offset by how much we just copied
szFloater += (szFound - szFloater)+ _tcslen( prs->szFind ); // Increment read offset by how much we read + length of szFind
memcpy( (void*)(szBuffer+dwBufLen), prs->szReplace, _tcslen( prs->szReplace )*sizeof(TCHAR) ); // Copy 'replaced' word
dwBufLen += _tcslen( prs->szReplace );
// Do it all over again
}
else
{
// Word not found, copy rest of data to buffer
if( dwBufLen < dwLength )
memcpy( (void*)(szBuffer+dwBufLen), (void*)szFloater, (dwLength-dwBufLen)*sizeof(TCHAR) );
break;
}
}
// Done, return new buffer
szBuffer[dwLength] = '\0';
*prs->iDestLen = dwLength;
*prs->szDest = szBuffer;
return dwNum;
}