Code patching

BlitzMax Forums/BlitzMax Programming/Code patching

Hi,

Does anyone know if there is a standard code patcher around? One that works with any language and just requires some tags to work, like:
[OPEN]myfile.bmx[/]
[FIND]"hello world[/]
[INSERT AFTER] and worldets[/]
[FIND]"Funky!"[/]
[REPLACE WITH]"Groovy!"[/]
Or something similar.

I want to make my max module tweaks, so that they can be easily applied after a sync mods... Otherwise I'll have to make a simple system myself.

I don't know but there is a " missing after world and after worldets...

Hi,

Well, I made my own really simple one since I couldn't find one. The syntax is ugly and it's not very versatile, but it does the job.

Here it is:
'
' Ultra simple code patcher for module tweaks
'
SuperStrict

Global bmaxpath:String = "C:/BlitzMax/"
Rem
Try
	bmaxpath = BlitzMaxPath()
Catch err$
	Notify "Couldn't find BlitzMax :("
	End
EndTry
EndRem

Local url:String = RequestFile("Select Patch file","Text Files:txt;")
If url = "" Then End
PatchParse(url)

Function PatchParse(url:Object)
	
	Local patch:String = LoadText(url)
	Local token:String
	Local content:String
	
	Local file:String
	Local code:String
	Local find:String
		
	Local i:Int
	While patch
		Local ret:String[] = PatchGetToken(patch)
		patch	= ret[0]
		token	= ret[1]
		content	= ret[2]
		
		Select token
			Case "OPEN"
				file = content.Replace("BMAXPATH",bmaxpath)
				If FileType(file) = 0 Then RuntimeError "Couldn't load: ~q"+file+"~q"
				code = LoadText(file)
				Print "Modifying... ~q"+file+"~q"
								
			Case "FIND"
				find = content
				If code.find(find)<0
					Print code
					RuntimeError "Couldn't find: "+find
				EndIf
				
			Case "INSERT AFTER"
				If code.find(content) < 0
					Local b:Int = code.find(find)+find.length
					code = code[..b] + content + code[b+1..]
				Else
					Print "Already Modified!"
				EndIf
				
			Case "INSERT BEFORE"
				If code.find(content) < 0
					Local b:Int = code.find(find)
					code = code[..b] + content + code[b+1..]
				Else
					Print "Already Modified!"
				EndIf
												
			Case "REPLACE WITH"
				If code.find(content) < 0
					code = code.Replace(find,content)
				Else
					Print "Already Modified!"
				EndIf
				
			Case "CLOSE"
				SaveText(code,file)
				Print "Saving... ~q"+file+"~q"
				code = ""
				file = ""
								
		EndSelect 
	Wend
	
EndFunction

Function PatchGetToken:String[](s:String)

	Local a:Int = s.Find("[")
	If a<0 Then Return ["","",""]
	Local b:Int = s.Find("]")
	If b<a Then Return ["","",""]
	Local c:Int = s.Find("[/]")
	If c<b Then Return ["","",""]
	
	Local ret:String[3]
	ret[0] = s[c+3..]
	ret[1] = s[a+1..b]
	ret[2] = s[b+1..c]
	
	Return ret
	
EndFunction


And here is a script to apply the SetMaxWindowSize for Windows:

SetMaxWindowSize MaxGui Tweak

**************************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/gui/window.h[/]

[FIND]	virtual void setMinSize( int w,int h )=0;[/]

[INSERT AFTER]
	virtual void setMaxSize( int w,int h )=0;[/]

[FIND]void		bbSetMinWindowSize( BBWindow *window,int w,int h );[/]

[INSERT AFTER]
void		bbSetMaxWindowSize( BBWindow *window,int w,int h );[/]

[CLOSE][/]

**************************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/gui/window.cpp[/]

[FIND]void BBWindow::setMinSize( int w,int h ){
}[/]

[INSERT AFTER]
void BBWindow::setMaxSize( int w,int h ){
}
[/]

[FIND]	window->setMinSize( w>=0 ? w : window->width(),h>=0 ? h : window->height() );
}[/]

[INSERT AFTER]
void		bbSetMaxWindowSize( BBWindow *window,int w,int h ){
	window->debug();
	window->setMaxSize( w>=0 ? w : window->width(),h>=0 ? h : window->height() );
}
[/]

[CLOSE][/]

***************************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/win32gui/win32window.h[/]

[FIND]	int _minw,_minh;[/]

[INSERT AFTER]
	int _maxw,_maxh;[/]

[FIND]	void setMinSize( int w,int h );[/]

[INSERT AFTER]
	void setMaxSize( int w,int h );[/]

[CLOSE][/]

***************************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/win32gui/win32window.cpp[/]

[FIND]	HWND parent=0;[/]
[INSERT AFTER]
	_maxw = 0;
	_maxh = 0;[/]

[FIND]	_minw=w;
	_minh=h;
}[/]
[INSERT AFTER]
void Win32Window::setMaxSize( int w,int h ){
	_maxw=w;
	_maxh=h;
}
[/]

[FIND]			p->ptMinTrackSize.y=_minh;[/]
[INSERT AFTER]
			if (_maxw>0) p->ptMaxTrackSize.x=_maxw;
			if (_maxh>0) p->ptMaxTrackSize.y=_maxh;[/]


[CLOSE][/]

***************************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/win32gui.bmx[/]

[FIND]Function bbSetMinWindowSize( window,w,h )[/]
[INSERT AFTER]
Function bbSetMaxWindowSize( window,w,h )[/]


[FIND]		bbSetMinWindowSize handle,w,h
	End Method[/]

[INSERT AFTER]
	Method SetMaximumSize(w,h)
		bbSetMaxWindowSize handle,w,h
	End Method
[/]
[CLOSE][/]

***************************


[OPEN]BMAXPATH/mod/brl.mod/maxgui.mod/maxgui.bmx[/]

[FIND]	window.SetMinimumSize( w,h )
End Function[/]

[INSERT AFTER]
Rem
bbdoc: Set a window gadget's maximum size.
EndRem
Function SetMaxWindowSize( window:TGadget,w,h )
	window.SetMaximumSize( w,h )
End Function
[/]
[CLOSE][/]

***************************

[OPEN]BMAXPATH/mod/brl.mod/maxgui.mod/gadget.bmx[/]

[FIND]	Method SetMinimumSize(w,h)
	End Method[/]

[INSERT AFTER]
	Method SetMaximumSize(w,h)
	End Method
[/]
[CLOSE][/]

***************************


And the Textfield Return tweak:
Textfield fetch Return Tweak

***************************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/win32gui/win32hwnd.cpp[/]

[FIND]static LRESULT CALLBACK KeyboardProc( int code,WPARAM wparam,LPARAM lparam ){
	if( code<0 ) return CallNextHookEx( KBMESSAGEHOOK,code,wparam,lparam );[/]

[INSERT AFTER]
	//
	// Fredborg was here!
	if (wparam == VK_RETURN){
		HWND current = GetFocus();
		if (current!=NULL){
			char classname[16];
			if (GetClassName(current,classname,sizeof(classname))!=0){
				if (strnicmp(classname,"edit",4)==0){
					HWND par = GetAncestor(current,GA_PARENT);
					SetFocus(par);
				}
			}
		}
	}
[/]

[CLOSE][/]


And a tweak to block hotkeys from being triggered in textfields and textareas:
Block Hotkeys

Use style=4 on creation to block hotkeys/menu keys from being trigerred while typing in a textfield or textarea


********************************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/win32gui/win32hwnd.cpp[/]

[FIND]	BBObject *ev=brl_maxgui_HotKeyEvent( wparam,keymods(),(int)GetForegroundWindow() );
	if( ev!=&bbNullObject ){
		if ((lparam&0x80000000)==0) brl_event_EmitEvent( ev );				
		return 1;
	}[/]

[REPLACE WITH]	BBObject *ev=brl_maxgui_HotKeyEvent( wparam,keymods(),(int)GetForegroundWindow() );
	if( ev!=&bbNullObject ){

		// Check if the currently focused gadget is a TextField or TextArea that blocks hotkeys
		HWND current = GetFocus();
		int checkhotkey = 1;
		if (current!=NULL){
			char classname[16];
			if (GetClassName(current,classname,sizeof(classname))!=0){
				
				if (GetWindowLong(current,GWL_USERDATA) == 1){
					if (strnicmp(classname,"edit",4)==0){
						checkhotkey = 0;
						// printf("hotkey blocked!");fflush(stdout); 
					}else if (strnicmp(classname,"richedit",8)==0){
						checkhotkey = 0;
						// printf("hotkey blocked!");fflush(stdout);
					}
				}
				
			}
		}
	
		if (checkhotkey == 1){

			if ((lparam&0x80000000)==0) brl_event_EmitEvent( ev );				
			return 1;
		}
	
	}[/]

[CLOSE][/]

***********************

[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/win32gui/win32textarea2.cpp[/]

[FIND]	else {
		hwnd=CreateWindowEx( xstyle,"RichEdit20A","",wstyle,0,0,0,0,parent,0,GetModuleHandle(0),0 );
	}[/]

[INSERT AFTER]
	// Block shortcuts
	if (style&4){
		SetWindowLong(hwnd,GWL_USERDATA,1);
	}
[/]

[CLOSE][/]

************************


[OPEN]BMAXPATH/mod/brl.mod/win32maxgui.mod/win32gui/win32textfield.cpp[/]

[FIND]	HWND hwnd=CreateWindowEx( xstyle,"EDIT","",wstyle,0,0,0,0,parent,0,GetModuleHandle(0),0 );[/]

[INSERT AFTER]
	// Block shortcuts
	if (style&4){
		SetWindowLong(hwnd,GWL_USERDATA,1);
	}
[/]

[CLOSE][/]


This would be an ideal AutoHotKey job I suspect.

why not just use patch?

patch --help
Usage: patch [OPTION]... [ORIGFILE [PATCHFILE]]

(should be part of mingw if not *easily* installable)

There are even GUI's for it :o

I did something similar to search for Function or Method and stuck debuglog messages in each BRL.mod module to say when a function/method was entered. Worked pretty well and helped find out how images/pixmaps worked.

Yeah, patch uses the unified diff format (which is pretty much a standard) and is used by the likes of Subversion for its diff/merge/patching.

"diff" is also a nice tool for comparing differences between two files - also outputs unified diff format.