Page 1 of 1

scan DLL source files to make wrapper

Posted: Wed Jan 30, 2008 4:15 am
by eddy
Here is a little code I used to scan Chipmunk DLL source.( .H .C files)
You need :
- DLL sources (coded in C )
- compiled DLL

Code: Select all

Global SourceDir.s = GetPathPart(ProgramFilename())
Global DllFile.s="chipmunk-4.0.2.dll"
Debug "Search in directory = "+SourceDir
Debug "DLL = "+DllFile

; =======================
; get .H and .C source files 
; =======================
Global NewList SourceFiles.s()
Procedure.s GetSourceTexts(file.s)
	If ReadFile(0,file)		
		;read file to string
		Protected lof = Lof(0)
		Protected text.s=Space(lof+1)
		ReadData(0,@text,lof)		
		CloseFile(0)
		
		;remove 'C' comments
		CreateRegularExpression(1, "[/]{2,}[^\r^\n]*")
		If MatchRegularExpression(1,text)
			text=ReplaceRegularExpression(1,text,"")		
		EndIf 
		
		ProcedureReturn text 
	EndIf 		
	
	ProcedureReturn ""
EndProcedure
Procedure GetSourceFiles()	
	If ExamineDirectory(0,SourceDir,"*.h")
		While NextDirectoryEntry(0)
			If DirectoryEntryType(0) = #PB_DirectoryEntry_File
				AddElement(SourceFiles())
				SourceFiles()= DirectoryEntryName(0)
			EndIf       
		Wend
		FinishDirectory(0)  
	EndIf
	
	
	If ExamineDirectory(0,SourceDir,"*.c")
		While NextDirectoryEntry(0)
			If DirectoryEntryType(0) = #PB_DirectoryEntry_File
				AddElement(SourceFiles())
				SourceFiles()= DirectoryEntryName(0)
			EndIf       
		Wend
		FinishDirectory(0)  
	EndIf
EndProcedure  
GetSourceFiles()

; =======================
; get functions from text
; =======================
Global NewList DllFunc.s()
Global NewList DllFuncDECL.s()
Procedure GetDLLFunctions()
	;{ REGEX HELP FILE
	; CreateRegularExpression(#RegularExpression, Pattern$) - Create a new regular expression.
	; ExtractRegularExpression(#RegularExpression, String$, Array$()) - Extract strings according To the regular expression into an array.
	; IsRegularExpression(#RegularExpression) - Tests If the given '#RegularExpression' is an initialized regular expression object.
	; 	MatchRegularExpression(#RegularExpression, String$) - Tests If a string match the regular expression.
	; 		ReplaceRegularExpression(#RegularExpression, String$, ReplaceString$) - Replace some strings according To the regular expression.		
	; 		RegularExpressionError() - Return the last regular expression error.
	;}
	
	Debug "[ Dll Functions ]"
	
	; =======================
	; get DLL functions
	; =======================		
	If  OpenLibrary(0,DllFile)
		If ExamineLibraryFunctions(0)	
			While NextLibraryFunction()			
				AddElement(DllFunc())
				AddElement(DllFuncDECL())
				DllFunc()= LibraryFunctionName()
			Wend 
		EndIf 
	EndIf
	
	; =======================
	; scan each sourcefile 
	; =======================		
	Protected Dim Found.s(0)
	ForEach SourceFiles()	 
		Debug "-"+SourceFiles()
		Protected text.s = GetSourceTexts(SourceFiles())		
		If text.s<>""								
			ResetList(DllFuncDECL())
			ResetList(DllFunc())
			While NextElement(DllFunc()) And NextElement(DllFuncDECL())
				If DllFuncDECL()<>""
					Continue
				EndIf 			
				
				; =======================
				; parse text	
				; =======================		
				CreateRegularExpression(1, "[\w]{3,}[ \t*]+"+DllFunc()+"[ \t]*[(][^)]*[)]")			
				If Not MatchRegularExpression(1, text)				
					CreateRegularExpression(1, "[\w]*[ \t]*[\w]+[ \t]+"+DllFunc()+"[^;]*")	
					If Not MatchRegularExpression(1, text)					
						Continue 
					EndIf 
				EndIf 
				; =======================
				; find function
				; =======================				
				ReDim Found.s(0)
				Protected count = ExtractRegularExpression(1, text, Found.s()) 
				DllFuncDECL()=Found(0)					
				If count>1
					For i=0 To count-1 
						Debug "   >("+Str(i+1)+") "+Found(i)															
					Next  				
					Debug ""
				Else 
					Debug	"   >"+ DllFuncDECL()
				EndIf 				
			Wend 				
		EndIf  
	Next 		 
	
	ResetList(DllFuncDECL())
	ResetList(DllFunc())
	While NextElement(DllFunc()) And NextElement(DllFuncDECL())
		If DllFuncDECL()=""
			MessageRequester("ERROR","missing functions :"+DllFunc())
			End 	
		EndIf		
	Wend 
	Debug ""	
EndProcedure
GetDLLFunctions()

; =======================
; convert functions 
; ( and register all needed types )
; =======================
Global NewList DllType.s()
Global NewList DllTypeDECL.s()
Procedure RegisterDllType(NewType.s)	
	NewType=Trim(RemoveString(NewType,#TAB$))
	Select NewType
		Case "f","l","c","void"
			ProcedureReturn 
	EndSelect
	
	ForEach DllType()	
		If DllType()=NewType
			ProcedureReturn
		EndIf 
	Next
	
	AddElement(DllType())
	AddElement(DllTypeDECL())
	DllType()=NewType
	Debug "---------------->"+ DllType();+" "+Str(Len(NewType))
EndProcedure
Procedure.s GetDllType(SourceCode.s,ReturnType.b=0)
	;TEST : extern const usigned int **sfsdfs
	SourceCode=ReplaceString(SourceCode,"*"," *")
	CreateRegularExpression(1,"[*][ \t]+")
	SourceCode=ReplaceRegularExpression(1,SourceCode,"*")
	SourceCode=Trim(SourceCode)		
	CreateRegularExpression(1,"[ \t]+")
	SourceCode=ReplaceRegularExpression(1,SourceCode," ")		
	
	;TEST : EXCUInt **sfsdfs		
	Protected ConvertedType.s=SourceCode
	Protected varSuffix.s
	If FindString(ConvertedType,"extern ",1)
		ConvertedType=RemoveString(ConvertedType,"const ")
		varSuffix+"EX"
	EndIf 
	If FindString(ConvertedType,"const ",1)
		ConvertedType=RemoveString(ConvertedType,"const ")
		varSuffix+"CS"
	EndIf 
	If FindString(ConvertedType,"unsigned ",1)
		ConvertedType=RemoveString(ConvertedType,"unsigned ")
		varSuffix+"U"
	EndIf 
	
	Protected count = CountString(ConvertedType," ")				
	Protected varName.s = StringField(	ConvertedType,count+1," ")			
	If ReturnType
		CreateRegularExpression(1,"[\w]+")
		varName=ReplaceRegularExpression(1,varName,"result")
	EndIf 				
	
	;TEST : **sfsdfs.EXCUInt	
	ConvertedType=StringField(ConvertedType,count," ")										
	If LCase(ConvertedType)="float"
		ConvertedType="f"
	ElseIf LCase(ConvertedType)="int"
		ConvertedType="l"
	ElseIf LCase(ConvertedType)="char"
		ConvertedType="c"
	EndIf		
	RegisterDllType(ConvertedType)
	
	ProcedureReturn varName+varSuffix+"."+ConvertedType
EndProcedure
Procedure.s GetPBParams(SourceCode.s)
	SourceCode=StringField(SourceCode,2,"(")
	SourceCode=StringField(SourceCode,1,")")
	SourceCode=Trim(SourceCode)
	If SourceCode=""
		ProcedureReturn ""
	EndIf 
	If SourceCode="void"
		ProcedureReturn "()"
	EndIf 
	
	Protected params.s = ""
	Protected count = CountString(SourceCode,",")+1
	For i=1 To count 
		If params<>""
			params+","	
		EndIf 
		params+GetDllType(StringField(SourceCode,i,","))
	Next 
	
	ProcedureReturn "("+params+")"
EndProcedure
Procedure GetPBFunctions()
	
	Debug "[ PB Functions ]"
	
	ResetList(DllFunc())
	ResetList(DllFuncDECL())
	While NextElement(DllFunc()) And NextElement(DllFuncDECL())
	   CreateRegularExpression(1,"[ \t\w*]+"+DllFunc())   
	   If MatchRegularExpression(1, DllFuncDECL())	
			Dim Found.s(0)
			ExtractRegularExpression(1, DllFuncDECL(), Found.s()) 		
			Protected FuncReturn.s = GetDllType(Trim(Found(0)),1)
			Protected FuncParams.s = GetPBParams(DllFuncDECL())
			
			If FuncReturn="result.void"
				DllFuncDECL()="   "+DllFunc()+FuncParams
			Else
				DllFuncDECL()=".l "+DllFunc()+FuncParams+" ; "+FuncReturn
			EndIf 
			
			Debug DllFuncDECL()
		Else 
			MessageRequester("ERROR","RETURNED TYPE NOT FOUND!")
		EndIf  
	Wend 
	Debug ""
EndProcedure
GetPBFunctions()

; =======================
; get types from text
; =======================
Procedure GetDLLTypes()
	Debug "[ PB Types ]"
	
	; =======================
	; scan each sourcefile 
	; =======================		
	Dim Found.s(0)
	ForEach SourceFiles()
		Debug "-"+SourceFiles()
		Protected text.s = GetSourceTexts(SourceFiles())		
		If text.s<>""	
			ResetList(DllTypeDECL())
			ResetList(DllType())
			While NextElement(DllType()) And NextElement(DllTypeDECL())
				If DllTypeDECL()<>""
					Continue
				EndIf 
				
				; =======================
				; parse text	
				; =======================					
				CreateRegularExpression(1,"typedef[ \t]+[se][\w]+[ \t]+"+DllType()+"[ \t\w]*[{][^}]+[}]")	
				If Not MatchRegularExpression(1,text)
					CreateRegularExpression(1,"typedef[ \t]+[\w]+[ \t]+"+DllType()+"[^;]*")	
					If Not MatchRegularExpression(1,text)
						CreateRegularExpression(1,"typedef[ \t]+[\w]+[ \t*]+[(][*]"+DllType()+"[)][^;]*")	
						If Not MatchRegularExpression(1,text)
							Continue
						EndIf 
					EndIf 				
				EndIf 
				; =======================
				; find type
				; =======================					
				ReDim Found.s(0)
				Protected count=ExtractRegularExpression(1,text,Found())
				DllTypeDECL()= Found(0)
				Debug	"   >"+ DllTypeDECL()
			Wend 
		EndIf 	
	Next 
	
	ResetList(DllTypeDECL())
	ResetList(DllType())
	While NextElement(DllType()) And NextElement(DllTypeDECL())
		If DllTypeDECL()=""
			MessageRequester("ERROR","missing functions :"+DllType())
			End 	
		EndIf		
	Wend 	
	Debug ""	
EndProcedure
GetDLLTypes()


; i=1 
; ForEach TypeReturn()
; 	Debug "typereturn = "+RemoveString(TypeReturn(),"result.")
; Next 
; Debug typeReturnList

;{
If OpenWindow(0, 0, 0, 600, 600, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	
   If CreateGadgetList(WindowID(0))
		EditorGadget(1, 10, 10, 580, 580)
   EndIf
   AddGadgetItem(1,-1,"#ChipmunkDLL=0") 
   AddGadgetItem(1,-1,"DllFilename$="+#DOUBLEQUOTE$+"chipmunk-4.0.2.dll"+#DOUBLEQUOTE$) 
   AddGadgetItem(1,-1,"") 
   
   AddGadgetItem(1,-1,";OPEN library") 
   AddGadgetItem(1,-1,"If Not OpenLibrary(#ChipmunkDLL, DllFilename$) : End : EndIf")
	AddGadgetItem(1,-1,"If Not IsLibrary(#ChipmunkDLL) : End : EndIf") 
   AddGadgetItem(1,-1,"") 
   
	AddGadgetItem(1,-1,";CLOSE library function") 
	AddGadgetItem(1,-1,"Procedure FreeChipmunk()") 
	AddGadgetItem(1,-1,"	 If IsLibrary(#ChipmunkDLL)") 
	AddGadgetItem(1,-1,"	 	 CloseLibrary(#ChipmunkDLL)") 
	AddGadgetItem(1,-1,"	 EndIf") 
	AddGadgetItem(1,-1,"EndProcedure") 
	AddGadgetItem(1,-1,"")    
   
   ;AddGadgetItem(1,-1,";return types")
   ;ForEach TypeReturn()
	;AddGadgetItem(1,-1,"Define.l "+TypeReturn())
	;Next 
   ;AddGadgetItem(1,-1,"") 
   
	AddGadgetItem(1,-1,";hidden declarations for editor code autocompletion")
	AddGadgetItem(1,-1,"CompilerIf 0")
	ForEach DllFuncDECL()
	AddGadgetItem(1,-1,"ProcedureC"+DllFuncDECL());+"(*x.RECT,y)")
	Next 
	AddGadgetItem(1,-1,"CompilerEndIf") 
	AddGadgetItem(1,-1,"") 
	
	AddGadgetItem(1,-1,";Function prototypes")
	ForEach DllFuncDECL()
	AddGadgetItem(1,-1,"PrototypeC"+DllFuncDECL());+"(*x.RECT,y)")
	Next 	
	AddGadgetItem(1,-1,"") 
	
	AddGadgetItem(1,-1,";Function macro")
	AddGadgetItem(1,-1,"Macro Quote")
   AddGadgetItem(1,-1,#DOUBLEQUOTE$)
   AddGadgetItem(1,-1,"EndMacro") 
   AddGadgetItem(1,-1,"Macro DefineProc(name)")
	AddGadgetItem(1,-1,"Global name#.name = GetFunction(#ChipmunkDLL,Quote#name#Quote)")
	AddGadgetItem(1,-1,"EndMacro") 
	AddGadgetItem(1,-1,"") 
	   
	AddGadgetItem(1,-1,";Function declarations")	   
	ResetList(DllFuncDECL())
	ResetList(DllFunc())
	While NextElement(DllFuncDECL()) And NextElement(DllFunc())
		AddGadgetItem(1,-1,"DefineProc("+DllFunc()+")") ;+","+#DOUBLEQUOTE$+DllFunc()+#DOUBLEQUOTE$
	Wend  	 
	AddGadgetItem(1,-1,"") 
		
   Repeat
		Event = WaitWindowEvent()		
   Until Event = #PB_Event_CloseWindow
EndIf
;}


Posted: Wed Jan 30, 2008 7:00 pm
by SFSxOI
Hi eddy,

Been trying to play around with this a little, now the dumb question, how do you get it to work? Is this for PB 4.10?

Posted: Wed Jan 30, 2008 10:28 pm
by eddy
Its the code I used to scan Chipmunk source codes.
It could be improved...

Posted: Wed Jan 30, 2008 11:34 pm
by SFSxOI
always room for improvement, heck, I could stand a little improvement also :)

was just wondering how you use it tho. I can't seem to get it to do anything.

Posted: Sun Feb 03, 2008 6:17 pm
by eddy
Updated

- improved regex
- Add : DLL types
- Add : PB function decls
- Add : DLL filename
- Add : the source directory.

TODO :
- convert DLL types to PB types
- scan sub directory source files

Posted: Tue Mar 11, 2008 1:12 am
by Rook Zimbabwe
I can't get this to work in PB4.2b2 either, and PB4.1 keeps dropping commands...

If I have just a DLL will this work? :D

Posted: Tue Apr 01, 2008 5:50 pm
by Philippe-felixer76-2
Rook Zimbabwe wrote:I can't get this to work in PB4.2b2 either, and PB4.1 keeps dropping commands...

If I have just a DLL will this work? :D
Same here..

Looks handy ..