diff options
Diffstat (limited to 'win32/droplet')
-rw-r--r-- | win32/droplet/Makefile.am | 2 | ||||
-rw-r--r-- | win32/droplet/droplet.dsp | 223 | ||||
-rw-r--r-- | win32/droplet/droplet.rc | 197 | ||||
-rw-r--r-- | win32/droplet/dropletmain.cpp | 76 | ||||
-rw-r--r-- | win32/droplet/progressdlg.cpp | 211 | ||||
-rw-r--r-- | win32/droplet/progressdlg.h | 92 | ||||
-rw-r--r-- | win32/droplet/replace.cpp | 438 | ||||
-rw-r--r-- | win32/droplet/replace.h | 73 | ||||
-rw-r--r-- | win32/droplet/resource.h | 22 | ||||
-rw-r--r-- | win32/droplet/rliberr.h | 136 | ||||
-rw-r--r-- | win32/droplet/rliberr.rc | 2 | ||||
-rw-r--r-- | win32/droplet/stdafx.cpp | 31 | ||||
-rw-r--r-- | win32/droplet/stdafx.h | 39 | ||||
-rw-r--r-- | win32/droplet/temp.cmp | bin | 0 -> 186 bytes | |||
-rw-r--r-- | win32/droplet/temp.rep | 24 |
15 files changed, 1566 insertions, 0 deletions
diff --git a/win32/droplet/Makefile.am b/win32/droplet/Makefile.am new file mode 100644 index 0000000..5a5ca0a --- /dev/null +++ b/win32/droplet/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = droplet.dsp droplet.rc dropletmain.cpp progressdlg.h progressdlg.cpp replace.cpp replace.h resource.h stdafx.h stdafx.cpp temp.rep + diff --git a/win32/droplet/droplet.dsp b/win32/droplet/droplet.dsp new file mode 100644 index 0000000..579b546 --- /dev/null +++ b/win32/droplet/droplet.dsp @@ -0,0 +1,223 @@ +# Microsoft Developer Studio Project File - Name="droplet" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=droplet - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "droplet.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "droplet.mak" CFG="droplet - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "droplet - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "droplet - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "droplet - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "debug" +# PROP Intermediate_Dir "debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../.." /I ".." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libpcre.a kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x500000" /subsystem:windows /debug /machine:I386 /out:"../debug/droplet.exe" /pdbtype:sept /libpath:"..\win32\pcre\lib\\" /libpath:"..\pcre\lib\\" + +!ELSEIF "$(CFG)" == "droplet - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "release" +# PROP Intermediate_Dir "release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O1 /I "../.." /I ".." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 libpcre.a kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x500000" /subsystem:windows /machine:I386 /out:"../release/droplet.exe" /libpath:"..\pcre\lib\\" /opt:nowin98 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "droplet - Win32 Debug" +# Name "droplet - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\common\droplet.cpp +# End Source File +# Begin Source File + +SOURCE=.\droplet.rc +# End Source File +# Begin Source File + +SOURCE=.\dropletmain.cpp +# End Source File +# Begin Source File + +SOURCE=..\common\errutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\ProgressDlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\Replace.cpp +# End Source File +# Begin Source File + +SOURCE=..\common\rliberr.mc + +!IF "$(CFG)" == "droplet - Win32 Debug" + +# Begin Custom Build +InputPath=..\common\rliberr.mc +InputName=rliberr + +"$(InputName).rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + mc $(InputPath) + copy $(InputName).h ..\Common + +# End Custom Build + +!ELSEIF "$(CFG)" == "droplet - Win32 Release" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build +InputPath=..\common\rliberr.mc +InputName=rliberr + +"$(InputName).rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + mc $(InputPath) + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\temp.rep + +!IF "$(CFG)" == "droplet - Win32 Debug" + +# Begin Custom Build +InputPath=.\temp.rep + +"temp.cmp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ..\debug\repc.exe temp.rep temp.cmp + +# End Custom Build + +!ELSEIF "$(CFG)" == "droplet - Win32 Release" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build +InputPath=.\temp.rep + +"temp.cmp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ..\release\repc.exe temp.rep temp.cmp + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\common\droplet.h +# End Source File +# Begin Source File + +SOURCE=.\ProgressDlg.h +# End Source File +# Begin Source File + +SOURCE=.\Replace.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\MSG00001.bin +# End Source File +# Begin Source File + +SOURCE=..\common\rep.ico +# End Source File +# Begin Source File + +SOURCE=.\temp.cmp +# End Source File +# End Group +# End Target +# End Project +# Section droplet : {00000000-0000-0000-0000-800000800000} +# 1:15:IDD_PROGRESSDLG:101 +# End Section diff --git a/win32/droplet/droplet.rc b/win32/droplet/droplet.rc new file mode 100644 index 0000000..f0254d7 --- /dev/null +++ b/win32/droplet/droplet.rc @@ -0,0 +1,197 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// REP +// + +SCRIPT REP DISCARDABLE "temp.cmp" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,3,0,1 + PRODUCTVERSION 2,3,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Nate Nielsen\0" + VALUE "FileDescription", "rep droplet\0" + VALUE "FileVersion", "2, 3, 0, 1\0" + VALUE "InternalName", "droplet\0" + VALUE "LegalCopyright", "Copyright 2002, Nate Nielsen \0" + VALUE "LegalTrademarks", "\0" + VALUE "OLESelfRegister", "\0" + VALUE "OriginalFilename", "droplet.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "rep\0" + VALUE "ProductVersion", "2, 3, 0, 1\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PROGRESSDLG DIALOG DISCARDABLE 0, 0, 219, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Rep processing files..." +FONT 8, "Tahoma" +BEGIN + PUSHBUTTON "Cancel",2,162,74,50,14 + LTEXT "Preparing...",IDC_FILENAME,7,51,205,8 + LTEXT "",IDC_STATUS,7,62,205,8 + CONTROL "",IDC_FLIP,"Static",SS_GRAYRECT,7,75,148,10 + CONTROL "",IDC_STATIC,"Static",SS_GRAYFRAME,7,75,148,10 + ICON IDI_REP,IDC_STATIC,14,14,20,20 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_PROGRESSDLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 212 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// 11 +// + +1 11 DISCARDABLE "MSG00001.bin" + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_REP ICON DISCARDABLE "..\\common\\rep.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "droplet" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/win32/droplet/dropletmain.cpp b/win32/droplet/dropletmain.cpp new file mode 100644 index 0000000..9610ce2 --- /dev/null +++ b/win32/droplet/dropletmain.cpp @@ -0,0 +1,76 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +#include "stdafx.h" +#include "resource.h" +#include <initguid.h> +#include "replace.h" + +// ATL Support +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +END_OBJECT_MAP() + + +// _tWinMain: ------------------------------------------------------------- +// Our starting point. Silly name + +extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, + HINSTANCE /*hPrevInstance*/, LPTSTR /* lpCmdLine */, int /*nShowCmd*/) +{ + // ATL support + HRESULT hRes = CoInitialize(NULL); + _ASSERTE(SUCCEEDED(hRes)); + _Module.Init(ObjectMap, hInstance, NULL); + HRESULT hr = S_OK; + + // Make sure we have something to process + if(__argc <= 1) + { + MessageBox(NULL, _T("Drag and drop files onto this droplet to process them."), _T("Rep Droplet"), MB_OK | MB_ICONINFORMATION); + hr = E_FAIL; + } + + else + { + Replace replace; + if(SUCCEEDED(replace.initialize())) + { + for(int i = 1; i < __argc; i++) + { + // Process arguments appropriately + DWORD attrs = GetFileAttributes(__argv[i]); + if(attrs != 0xFFFFFFFF && attrs & FILE_ATTRIBUTE_DIRECTORY) + hr = replace.replaceFolder(__argv[i]); + else + hr = replace.replaceSingleFile(__argv[i]); + + if(FAILED(hr)) + break; + } + + replace.terminate(); + } + } + + _Module.Term(); + CoUninitialize(); + return SUCCEEDED(hr) ? 0 : 1; +} diff --git a/win32/droplet/progressdlg.cpp b/win32/droplet/progressdlg.cpp new file mode 100644 index 0000000..53f5e14 --- /dev/null +++ b/win32/droplet/progressdlg.cpp @@ -0,0 +1,211 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +// ProgressDlg.cpp : Implementation of CProgressDlg +#include "stdafx.h" +#include "ProgressDlg.h" + +// (Con|De)struction: ----------------------------------------------- + +ProgressDlg::ProgressDlg() +{ + m_numFiles = 0; + m_numReplaces = 0; + m_flip = false; + m_hThread = NULL; + m_hEvent = NULL; + InitializeCriticalSection(&m_sec); +} + +ProgressDlg::~ProgressDlg() +{ + DeleteCriticalSection(&m_sec); + if(m_hEvent) + CloseHandle(m_hEvent); +} + + +// threadProc: --------------------------------------------------------- +// Runs the dialog in another thread +static DWORD WINAPI threadProc(void* pv) +{ + ProgressDlg* dlg = (ProgressDlg*)pv; + return dlg->DoModal(NULL, NULL); +} + + +// startDialog: -------------------------------------------------------- +// Starts the dialog thread +HRESULT ProgressDlg::startDialog() +{ + ASSERT(m_hThread == NULL); + HRESULT ret = S_OK; + + if(m_hEvent) + CloseHandle(m_hEvent); + + m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + DWORD threadID; + m_hThread = CreateThread(NULL, 0, threadProc, this, CREATE_SUSPENDED, &threadID); + if(!m_hThread) + ret = HRESULT_FROM_WIN32(::GetLastError()); + else + ResumeThread(m_hThread); + + // Wait for dialog to start up. + ::WaitForSingleObject(m_hEvent, 10000); + CloseHandle(m_hEvent); + m_hEvent = NULL; + + return S_OK; +} + +// stopDialog: ---------------------------------------------------------- +// Stops the dialog thread and closes the dialog +int ProgressDlg::stopDialog() +{ + int ret = 0; + + if(m_hThread && m_hWnd) + { + ::PostMessage(m_hWnd, WM_CLOSE, 0, 0); + WaitForSingleObject(m_hThread, INFINITE); + } + else if(m_hThread) + { + EnterCriticalSection(&m_sec); + TerminateThread(m_hThread, -1); + } + + if(m_hThread) + { + DWORD code = 0; + GetExitCodeThread(m_hThread, &code); + CloseHandle(m_hThread); + m_hThread = NULL; + ret = (int)code; + } + + return 0; +} + +// isCancelled: ----------------------------------------------------------- +// Checks if user pressed cancel button +bool ProgressDlg::isCancelled() +{ + bool ret = false; + + EnterCriticalSection(&m_sec); + ret = m_isCancelled; + LeaveCriticalSection(&m_sec); + + return ret; +} + +// updateControls: -------------------------------------------------------- +// Update dialog status +void ProgressDlg::updateControls() +{ + if(IsWindow()) + { + string status; + status.format(_T("%d replaces in %d files"), m_numReplaces, m_numFiles); + SetDlgItemText(IDC_STATUS, status); + } +} + +// onReplaced: ------------------------------------------------------------- +// Called when a new replacement was made +void ProgressDlg::onReplaced() +{ + m_flip = !m_flip; + m_numReplaces++; + + // Do flicker thing + if(IsWindow()) + ::ShowWindow(GetDlgItem(IDC_FLIP), m_flip ? SW_SHOW : SW_HIDE); + + updateControls(); +} + +// onNewFile: -------------------------------------------------------------- +// Called when a new file starts processing +void ProgressDlg::onNewFile(LPCTSTR fileName) +{ + if(IsWindow()) + SetDlgItemText(IDC_FILENAME, fileName); + + m_numFiles++; + + updateControls(); +} + +// setTitle: --------------------------------------------------------------- +// Set the title. If no window then just store it +void ProgressDlg::setTitle(const string& title) +{ + m_title = title; + + if(IsWindow()) + SetWindowText(title); +} + + +// onInitDialog: ------------------------------------------------------------ +// Dialog initialization. We clear the event that says we've +// started up. +LRESULT ProgressDlg::onInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + EnterCriticalSection(&m_sec); + + if(!m_title.empty()) + SetWindowText(m_title.c_str()); + + if(m_hEvent) + SetEvent(m_hEvent); + + CenterWindow(NULL); + + LeaveCriticalSection(&m_sec); + + return 1; +} + +// onClose: ------------------------------------------------------------------ +// Dialog was closed +LRESULT ProgressDlg::onClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + // TODO: will this get called by NC area? + EndDialog(IDOK); + return 0; +} + +// onCancel: ------------------------------------------------------------------ +// User clicked cancel, set flag +LRESULT ProgressDlg::onCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) +{ + EnterCriticalSection(&m_sec); + m_isCancelled = true; + LeaveCriticalSection(&m_sec); + + EndDialog(IDCANCEL); + return 0; +} + diff --git a/win32/droplet/progressdlg.h b/win32/droplet/progressdlg.h new file mode 100644 index 0000000..1e416a1 --- /dev/null +++ b/win32/droplet/progressdlg.h @@ -0,0 +1,92 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +#ifndef __PROGRESSDLG_H_ +#define __PROGRESSDLG_H_ + +#include "resource.h" // main symbols +#include <atlhost.h> + +// ProgressDlg: -------------------------------------------------------- +// The status dialog which is run in another thread + +class ProgressDlg : + public CDialogImpl<ProgressDlg> +{ +public: + ProgressDlg(); + ~ProgressDlg(); + + enum { IDD = IDD_PROGRESSDLG }; + +BEGIN_MSG_MAP(ProgressDlg) + MESSAGE_HANDLER(WM_INITDIALOG, onInitDialog) + MESSAGE_HANDLER(WM_CLOSE, onClose) + COMMAND_ID_HANDLER(IDCANCEL, onCancel) +END_MSG_MAP() + +public: + // Start dialog in another thread + HRESULT startDialog(); + + // Stop the dialog thread + int stopDialog(); + + // Called when a replacement is noted + void onReplaced(); + + // Called (by Replace::replaceSingleFile) when starting + // to process new file + void onNewFile(LPCTSTR fileName); + + // Polled (by Replace::matchStatus) to check if user cancelled + bool isCancelled(); + + // Set the dialog title + void setTitle(const string& title); + +protected: + // Update status etc... + void updateControls(); + +// The message handlers +protected: + LRESULT onInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT onClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT onCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); + + // Handler prototypes: + // LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + // LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); + // LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); + +protected: + HANDLE m_hThread; // The dialog thread + string m_title; // The dialog title + + HANDLE m_hEvent; // dialog initialization event + CRITICAL_SECTION m_sec; // Used for syncing access to date below + + bool m_isCancelled; // Set when user clicks cancel + uint m_numFiles; // Number of files processed + uint m_numReplaces; // Number of replaces seen + bool m_flip; // Used for flicker display +}; + +#endif //__PROGRESSDLG_H_ diff --git a/win32/droplet/replace.cpp b/win32/droplet/replace.cpp new file mode 100644 index 0000000..8a7b51b --- /dev/null +++ b/win32/droplet/replace.cpp @@ -0,0 +1,438 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +#include "stdafx.h" +#include "Replace.h" +#include "common/errutil.h" +#include "common/rliberr.h" +#include "common/mystring.h" + + +// Error Macros: ------------------------------------------------- +// Display error messages and all that +// Only valid in this context +// Each of these jumps to the 'cleanup' label for wrapping +// up any open objects. + +#define RETURN(v) \ + { ret = (v); goto cleanup; } +#define WINERR(f) \ + { HRESULT hr = HRESULT_FROM_WIN32(::GetLastError()); RETURN(errorMessage(m_dlg.m_hWnd, hr, f)); } +#define WINERR_1(f, a) \ + { HRESULT hr = HRESULT_FROM_WIN32(::GetLastError()); RETURN(errorMessage(m_dlg.m_hWnd, hr, f, a)); } +#define WINERR_E(e, f) \ + { RETURN(errorMessage(m_dlg.m_hWnd, e, f)); } +#define REPERR(c, s) \ + { RETURN(rlibError(m_dlg.m_hWnd, c, s)); } + + +// The extension appended to backup or temp files +LPCTSTR kBackupExt = _T(".x_r"); + +// (Con|De)struction: ------------------------------------------- + +Replace::Replace() +{ + m_outFile = NULL; +} + +Replace::~Replace() +{ + ASSERT(m_outFile == NULL); +} + + +// initialize: --------------------------------------------------- +// Loads the script from resources and sets up dialog +// in another thread + +HRESULT Replace::initialize() +{ + HRESULT ret = S_OK; + + { + if(!m_droplet.load(GetModuleHandle(NULL))) + { + errorMessage(NULL, 0, _T("Couldn't access droplet rep script. The droplet is probably corrupted.")); + RETURN(E_FAIL); + } + + m_dlg.setTitle(m_droplet.getTitle()); + + r_context& ctx = m_droplet.getContext(); + + int r = repInit(&ctx); + if(r < 0) + REPERR(r, &(ctx.script)); + + // This starts the dialog in another thread + // in order to keep it responsive + m_dlg.startDialog(); + } + +cleanup: + return ret; +} + + +// terminate: ---------------------------------------------------- +// Undoes above + +HRESULT Replace::terminate() +{ + m_dlg.stopDialog(); + r_context& ctx = m_droplet.getContext(); + repFree(&ctx); + return S_OK; +} + + +// writeFile: ---------------------------------------------------- +// The callback called from within rlib when data output +// is required. The argument passed through the r_stream +// is a pointer to the Replace object. + +int Replace::writeFile(r_stream* stream, byte* data, size_t len) +{ + Replace* replace = (Replace*)stream->arg; + + // The m_outFile member should be set (and only set) + // whenever we're inside rlibRun + ASSERT(replace->m_outFile != NULL); + DWORD written = 0; + + // Double check that everything was written + return WriteFile(replace->m_outFile, data, len, &written, NULL) && len == written; +} + +// matchStatus: -------------------------------------------------- +// Callback whenever something is replaced in rlib +// Updates the dialog. + +int Replace::matchStatus(r_stream* stream, r_replace* repl) +{ + Replace* replace = (Replace*)stream->arg; + ASSERT_PTR(replace); + + replace->m_dlg.onReplaced(); + return replace->m_dlg.isCancelled() ? 1 : 0; +} + + +// replaceFolder: ------------------------------------------------ +// Recursively processes a folder using replaceSingleFile + +HRESULT Replace::replaceFolder(LPCTSTR folder) +{ + HANDLE hFindFile = NULL; + WIN32_FIND_DATA findData; + TCHAR old[260]; // Save the current folder (as we'll change it) + HRESULT ret = S_FALSE; + + { + // Backup the current directory + if(!GetCurrentDirectory(260, old)) + WINERR("Couldn't get the current directory."); + + if(!SetCurrentDirectory(folder)) + WINERR_1("Couldn't change the current directory to %s", folder); + + if(hFindFile = FindFirstFile(_T("*.*"), &findData)) + { + // And for every file + do + { + HRESULT r = S_FALSE; + if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if(findData.cFileName[0] == '.' && + (findData.cFileName[1] == '.' || findData.cFileName[1] == '\0')) + continue; + + r = replaceFolder(findData.cFileName); + } + else + { + r = replaceSingleFile(findData.cFileName); + } + + if(FAILED(r)) + RETURN(r); + if(r == S_OK) + ret = r; + } + while(FindNextFile(hFindFile, &findData)); + } + + // Make sure we didn't miss anything + if(::GetLastError() != 0 && ::GetLastError() != ERROR_NO_MORE_FILES) + WINERR_1("Couldn't list the directory %s", folder); + + // Change directory back + SetCurrentDirectory(old); + } + +cleanup: + if(hFindFile) + FindClose(hFindFile); + + return ret; +} + + +// replaceSingleFile: ---------------------------------------------- +// Process a file into a temp file or backup etc... +// Calls replaceFilename for actual processing + +HRESULT Replace::replaceSingleFile(LPCTSTR fileName) +{ + HRESULT ret = S_FALSE; + string temp; + USES_CONVERSION; + + r_context& ctx = m_droplet.getContext(); + + { + // Update the dialog display + m_dlg.onNewFile(fileName); + + // This lets us use the filename from within the script + ret = rlibSetVar(&(ctx.stream), "FILENAME", T2CA(fileName)); + if(ret < 0) + REPERR(ret, &(ctx.script)); + + // Make a temp/backup name + temp.assign(fileName); + temp.append(kBackupExt); + + // Now we do this 2 ways, if we're keeping backups then... + if(m_droplet.keepBackups()) + { + DeleteFile(temp); + + // Rename the original file to the backup + if(!MoveFile(fileName, temp)) + WINERR_1("There was an error while creating the backup file: %s", temp.c_str()); + + // Do a replacement operation back to the original + // from the backup + ret = replaceFilename(temp, fileName); + + // If there were no replacements + if(ret != S_OK) + { + DeleteFile(fileName); + + // And rename the backup file back + if(!MoveFile(temp, fileName)) + WINERR_1("There was an error while renaming the file: %s", fileName); + } + } + + // No backups, much faster (when there's no replacements)! + else + { + // Do a replacement operation to a temp file + ret = replaceFilename(fileName, temp); + + // If there were replacements + if(ret == S_OK) + { + DeleteFile(fileName); + + // Rename temp to original + if(!MoveFile(temp, fileName)) + WINERR_1("There was an error while renaming the file: %s", fileName); + } + + // If no replacements + else + { + // Remove temp file + DeleteFile(temp); + } + } + } + +cleanup: + + return ret; +} + +// replaceFilename: ------------------------------------------------- +// Process one file into another +// Open the files and passes them to replaceFile + +HRESULT Replace::replaceFilename(LPCTSTR fileIn, LPCTSTR fileOut) +{ + HANDLE in = INVALID_HANDLE_VALUE; + HANDLE out = INVALID_HANDLE_VALUE; + HRESULT ret = S_FALSE; + + { + // Basic readonly open + in = CreateFile(fileIn, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); + if(in == INVALID_HANDLE_VALUE) + WINERR_1("There was an error opening the file: %s", fileIn); + + // We need to know whether we're NT or not below + OSVERSIONINFO os; + os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&os); + + // This creates a new file for writing + // If we're running on NT, then use exactly the same + // attributes and permissions as original file + out = CreateFile(fileOut, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, + os.dwPlatformId & VER_PLATFORM_WIN32_NT ? in : NULL); + if(out == INVALID_HANDLE_VALUE) + WINERR_1("There was an error opening the file: %s", fileIn); + + + // Do replacements! + ret = replaceFile(in, out); + + } + +cleanup: + + if(in != INVALID_HANDLE_VALUE) + CloseHandle(in); + if(out != INVALID_HANDLE_VALUE) + CloseHandle(out); + + return ret; +} + + +// replaceFile: -------------------------------------------------------- +// Process one open file handle into another +// This memory maps the input file and passes it to replaceBuffer + +HRESULT Replace::replaceFile(HANDLE in, HANDLE out) +{ + HANDLE mapping = NULL; + void* data = NULL; + HRESULT ret = S_FALSE; + + { + // Memory map the input file + mapping = CreateFileMapping(in, NULL, PAGE_READONLY, 0, 0, NULL); + if(!mapping) + WINERR("There was an error reading the input file."); + + data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); + if(!data) + WINERR("There was an error reading the input file."); + + size_t size = GetFileSize(in, NULL); + if(size == INVALID_FILE_SIZE) + WINERR("There was an error reading the input file."); + + // And pass it on + ret = replaceBuffer((byte*)data, size, out); + } + +cleanup: + + if(data) + UnmapViewOfFile(data); + if(mapping) + CloseHandle(mapping); + + return ret; +} + + +// replaceBuffer: ---------------------------------------------------- +// Process a memory buffer into a file for output +// Uses the rlib functions directly + +HRESULT Replace::replaceBuffer(byte* data, size_t size, HANDLE out) +{ + ASSERT(m_outFile == NULL); + + size_t blockSize = m_droplet.getBuffSize() * 2; // Block size + size_t batchSize; // Current batch size + int r = R_IN; + bool dirty = false; + HRESULT ret = S_OK; + + { + // If there's no blocksize then we process the + // entire file at once + if(blockSize == 0) + blockSize = size; + + batchSize = blockSize; + + // Setup the rlib stream + r_context& ctx = m_droplet.getContext(); + + ctx.stream.nextIn = data; + ctx.stream.availIn = blockSize; + ctx.stream.fWrite = writeFile; + ctx.stream.arg = this; + ctx.stream.fMatch = matchStatus; + + // This is used by writeFile + m_outFile = out; + + // While we have more data to put in ... + while(size > 0 || r == R_IN) + { + // If rlib wants data then give it + if(r == R_IN) + { + batchSize = (blockSize > size) ? size : blockSize; + + ctx.stream.nextIn = data; + ctx.stream.availIn = batchSize; + + } + + // call rlib + r = rlibRun(&(ctx.stream), &(ctx.script), (size - batchSize) <= 0); + + // Oops! + if(r < 0) + REPERR(r, &(ctx.script)); + + if(ctx.stream.total > 0) + dirty = true; + + // Increment last batch + data += (batchSize - ctx.stream.availIn); + size -= (batchSize - ctx.stream.availIn); + } + + // Clears and prepares for next file + rlibClear(&ctx.stream); + } + +cleanup: + + m_outFile = NULL; + + if(FAILED(ret)) + return ret; + + return dirty ? S_OK : S_FALSE; +} diff --git a/win32/droplet/replace.h b/win32/droplet/replace.h new file mode 100644 index 0000000..b3c72c3 --- /dev/null +++ b/win32/droplet/replace.h @@ -0,0 +1,73 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +#ifndef __REPLACE_H__ +#define __REPLACE_H__ + +#include "ProgressDlg.h" +#include "common/Droplet.h" +#include "lib/rlib.h" + +// Replace: -------------------------------------------------------- +// Main processing class. Calls rlib for replacements + +class Replace +{ +public: + Replace(); + virtual ~Replace(); + + // Initialize processing (dialog, droplet etc...) + HRESULT initialize(); + + // Undo initialization + HRESULT terminate(); + + // Recursively process files in a folder + HRESULT replaceFolder(LPCTSTR folder); + + // Process a single file into itself (maybe using backups) + HRESULT replaceSingleFile(LPCTSTR fileName); + + // Process one file into another + HRESULT replaceFilename(LPCTSTR fileIn, LPCTSTR fileOut); + + // Process one open file into another + HRESULT replaceFile(HANDLE in, HANDLE out); + + // Process a memory buffer into an open file + HRESULT replaceBuffer(byte* data, size_t size, HANDLE out); + + +private: + // Callback for rlib when data output is needed + static int writeFile(r_stream* stream, byte* data, size_t len); + + // Callback for rlib status updates + static int matchStatus(r_stream* stream, r_replace* repl); + +protected: + Droplet m_droplet; // The droplet + ProgressDlg m_dlg; // The progress dialog + +private: + HANDLE m_outFile; // Open output file handle used by writeFile +}; + +#endif // __REPLACE_H__ diff --git a/win32/droplet/resource.h b/win32/droplet/resource.h new file mode 100644 index 0000000..91516ec --- /dev/null +++ b/win32/droplet/resource.h @@ -0,0 +1,22 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by droplet.rc +// +#define IDS_PROJNAME 100 +#define IDR_Droplet 100 +#define IDD_PROGRESSDLG 101 +#define IDC_FLIP 202 +#define IDC_STATUS 203 +#define IDI_REP 203 +#define IDC_FILENAME 204 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 204 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 205 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/win32/droplet/rliberr.h b/win32/droplet/rliberr.h new file mode 100644 index 0000000..8fe3a80 --- /dev/null +++ b/win32/droplet/rliberr.h @@ -0,0 +1,136 @@ +/* + * AUTHOR + * N. Nielsen + * + * VERSION + * 2.2.0b + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +#ifndef _RLIBERR_H_ +#define _RLIBERR_H_ + +#ifndef _WINERROR_ + #error Include winerror.h first. +#endif + +#define HRESULT_FROM_RLIB(code) \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_RLIB, abs(code)) + +/* ------------------------------------------------------------------------ *\ + Rlib Errors +\* ------------------------------------------------------------------------ */ +// +// Values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// +#define FACILITY_RLIB 0x196 + + +// +// Define the severity codes +// + + +// +// MessageId: RLIB_E_NOMEM +// +// MessageText: +// +// Out of Memory. +// +#define RLIB_E_NOMEM ((HRESULT)0x81960001L) + +// +// MessageId: RLIB_E_SYNTAX +// +// MessageText: +// +// Rep script syntax error. +// +#define RLIB_E_SYNTAX ((HRESULT)0x81960002L) + +// +// MessageId: RLIB_E_REGEXP +// +// MessageText: +// +// Regular expression syntax error. +// +#define RLIB_E_REGEXP ((HRESULT)0x81960003L) + +// +// MessageId: RLIB_E_LOOP +// +// MessageText: +// +// Rep encountered an endless loop. +// +#define RLIB_E_LOOP ((HRESULT)0x81960004L) + +// +// MessageId: RLIB_E_USER +// +// MessageText: +// +// User defined error. +// +#define RLIB_E_USER ((HRESULT)0x81960005L) + +// +// MessageId: RLIB_E_IOERR +// +// MessageText: +// +// There was an error reading or writing the data. +// +#define RLIB_E_IOERR ((HRESULT)0x81960006L) + +// +// MessageId: RLIB_E_INVARG +// +// MessageText: +// +// Programmer Error: Invalid argument. +// +#define RLIB_E_INVARG ((HRESULT)0x8196000AL) + +#endif // _RLIBERR_H_
\ No newline at end of file diff --git a/win32/droplet/rliberr.rc b/win32/droplet/rliberr.rc new file mode 100644 index 0000000..0885a89 --- /dev/null +++ b/win32/droplet/rliberr.rc @@ -0,0 +1,2 @@ +LANGUAGE 0x9,0x1 +1 11 MSG00001.bin diff --git a/win32/droplet/stdafx.cpp b/win32/droplet/stdafx.cpp new file mode 100644 index 0000000..7ab5779 --- /dev/null +++ b/win32/droplet/stdafx.cpp @@ -0,0 +1,31 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +// stdafx.cpp : source file that includes just the standard includes +// stdafx.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +#ifdef _ATL_STATIC_REGISTRY +#include <statreg.h> +#include <statreg.cpp> +#endif + +#include <atlimpl.cpp> diff --git a/win32/droplet/stdafx.h b/win32/droplet/stdafx.h new file mode 100644 index 0000000..16885d5 --- /dev/null +++ b/win32/droplet/stdafx.h @@ -0,0 +1,39 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +#if !defined(AFX_STDAFX_H__3607160A_967A_4E9D_A154_BC3CF029F2C2__INCLUDED_) +#define AFX_STDAFX_H__3607160A_967A_4E9D_A154_BC3CF029F2C2__INCLUDED_ + +#define STRICT +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#define _ATL_APARTMENT_THREADED + +#include <atlbase.h> +extern CComModule _Module; +#include <atlcom.h> +#include <atlwin.h> + +#include "config.win32.h" +#include "common/compat.h" +#include "common/usuals.h" +#include <mystring.h> + +#endif // !defined(AFX_STDAFX_H__3607160A_967A_4E9D_A154_BC3CF029F2C2__INCLUDED) diff --git a/win32/droplet/temp.cmp b/win32/droplet/temp.cmp Binary files differnew file mode 100644 index 0000000..137c82e --- /dev/null +++ b/win32/droplet/temp.cmp diff --git a/win32/droplet/temp.rep b/win32/droplet/temp.rep new file mode 100644 index 0000000..a2aaee4 --- /dev/null +++ b/win32/droplet/temp.rep @@ -0,0 +1,24 @@ +# +# AUTHOR +# N. Nielsen +# +# LICENSE +# This software is in the public domain. +# +# The software is provided "as is", without warranty of any kind, +# express or implied, including but not limited to the warranties +# of merchantability, fitness for a particular purpose, and +# noninfringement. In no event shall the author(s) be liable for any +# claim, damages, or other liability, whether in an action of +# contract, tort, or otherwise, arising from, out of, or in connection +# with the software or the use or other dealings in the software. +# +# SUPPORT +# Send bug reports to: <nielsen@memberwebs.com> +# + +# This is a placeholder script for the one written +# into the droplet + +match "yada" + replace "blah"
\ No newline at end of file |