Das kleine Tool ( 11KB ) erstellt eine neue komplette Projektdatei.
Alle Includes werden hinzugeladen, ungenutzte Proceduren entfernt
und auch sämtliche Kommentare.
Dieses Tool ist entstanden, weil der derzeitige PBCompiler 4.02
ungenutzte Proceduren mitcompiliert.
Download pbanalyzer.zippbAnalyzer.exe Main.pb [Outfile.pb]
-EDIT-
* Enumerationen und Konstanten werden mit berücksichtigt.
* UTF-8 kompatibel
-EDIT-
* Quellcode hinzugefügt
Code: Alles auswählen
;{Zunächst Quelltext ausserhalb der Procs scannen
; und Proceduren auf 1 setzen die verwendet werden. \inuse = 1
; Anschließend die verwendendeten Proceduren nach enthaltenen
; Aufrufen rekursiv durchsuchen \inuse = 2
; Zum Schluß sollten dann alle Procs auflistbar sein die
; nicht genutzt werden.
; Diese dann rauslöschen und den Quellcode neu speichern
;}
Structure INCLS
File.s ; Dateiname
CrC.l ; Checksumme
Typ.b ; Typ: Xincl./ Incl.
EndStructure
Structure PROCS
Name.s ; Name
Param.s ; Aufrufparameter
CrC.l ; Ckecksumme für schnelle Vergleiche
Typ.b ; Typ Long, String etc.
Decl.b ; Typ DLL, CDLL Std.
LineS.l ; Beginn der Procedure im Code
LineE.l ; Ende der Procedure im Code
LineS_L.l ; Beginn der Proc im Original Code
LineE_L.l; Beginn der Proc im Original Code
InUse.l ; Verwendet ja/nein ( Level )
Counts.l; Aufrufe
EndStructure
;- Window Constants
;
Enumeration
#pbaWnd
EndEnumeration
;- Gadget Constants
;
Enumeration
#pbA_P_Panel
#pbA_TV_Procs
#pbA_LI_Unsed
#pbA_F_Format
#pbA_CX_Comment
#pbA_CX_Blank
#pba_CX_Procs
#pbA_LV_Log
#pbA_B_OK
#pbA_B_Exit
EndEnumeration
;- StatusBar Constants
;
Enumeration
#pbA_Statusbar
EndEnumeration
Global NewList Code.s() ; Gekürzter Sourcecode
Global NewList Code_L.s() ; Original Sourcecode
Global NewList Proc.PROCS() ; HashMap Proceduren
Global NewList Incl.INCLS() ; HashMap Includes
Global NewList List.INCLS() ; Linked Listen
Global NewList Strc.s()
Global NewList Cons.s()
Global NewList PBCm.l(), G_iProcCount.l, G_iPBCount.l
Global Path.s ; IncludePath
Global FileMode.l = #PB_UTF8
#VERSION = "pbAnalyzer v1.3 by DiGe"
;{ Declarations
Declare DoProcValidation ()
Declare ScanQuellCode ( FromLn.l, ToLn.l, Level.l )
Declare.s GetProcCmds ( txt.s, *pos.Long, flag.b )
Declare CopyFileSettings ( FromFile.s, ToFile.s )
Declare ReadLineOfCodes ( File.s )
Declare.s AddIncludeFile ( File.s ); Result = Filename if not exists
Declare WriteLineOfCodes ( File.s, flag.b )
Declare.b ReadPBCommandList ()
;}
Procedure.b Open_pbaWnd()
If OpenWindow(#pbaWnd, 419, 289, 600, 430, "pbAnalyzer", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_Invisible )
If CreateStatusBar(#pbA_Statusbar, WindowID(#pbaWnd))
EndIf
If CreateGadgetList(WindowID(#pbaWnd))
Frame3DGadget(#pbA_F_Format, 5, 360, 350, 40, "Remove Settings")
CheckBoxGadget(#pbA_CX_Comment, 10, 375, 70, 20, "Comments")
CheckBoxGadget(#pbA_CX_Blank, 90, 375, 55, 20, "Blanks")
CheckBoxGadget(#pba_CX_Procs, 160, 375, 90, 20, "Unused Procs")
ButtonGadget(#pbA_B_OK, 380, 370, 105, 30, "Continue")
ButtonGadget(#pbA_B_Exit, 490, 370, 105, 30, "Exit")
;-
PanelGadget(#pbA_P_Panel, 5, 5, 590, 355)
AddGadgetItem(#pbA_P_Panel, -1, "Unused Procedures")
;-
ListIconGadget(#pbA_LI_Unsed, 3, 3, 580, 325, "Nr", 60, #PB_ListIcon_CheckBoxes | #PB_ListIcon_GridLines)
AddGadgetColumn(#pbA_LI_Unsed, 1, "Name", 200)
AddGadgetColumn(#pbA_LI_Unsed, 2, "Parameter", 275)
AddGadgetColumn(#pbA_LI_Unsed, 3, "Type", 40)
AddGadgetItem(#pbA_P_Panel, -1, "CallStack")
TreeGadget(#pbA_TV_Procs, 3, 3, 580, 325)
AddGadgetItem(#pbA_P_Panel, -1, "Info-Log")
ListViewGadget(#pbA_LV_Log, 3, 3, 580, 325)
CloseGadgetList()
ProcedureReturn #True
EndIf
EndIf
EndProcedure
Procedure LogText ( Text.s )
AddGadgetItem( #pbA_LV_Log, -1, Text )
StatusBarText( #pbA_Statusbar, 0, Text )
EndProcedure
Procedure.b ReadPBCommandList ()
File.s = #PB_Compiler_Home + "\Compilers\PBFunctionListing.txt"
FileNr = ReadFile( #PB_Any, File )
If FileNr
FileMode = ReadStringFormat(FileNr)
Count = Val(ReadString( FileNr, FileMode ))
While Not Eof(FileNr)
dummy.s = ReadString( FileNr, FileMode )
dummy = UCase(StringField( dummy, 1, " " ))
If AddElement( PBCm())
PBCm() = CRC32Fingerprint( @dummy, Len(dummy))
EndIf
Wend
CloseFile( FileNr )
EndIf
G_iPBCount = CountList(PBCm())
If Count = G_iPBCount
ProcedureReturn #True
EndIf
ProcedureReturn #Null
EndProcedure
Procedure.l FindStringEx( txt.s, Search.s, pos.l ) ; Search Strings Outside " " & ' '
Repeat
n = FindString( txt, Search, pos )
If n
i = CountString( Left(txt, n), Chr(34))
j = CountString( Left(txt, n), Chr(39))
; Anzahl ungerade??
If (i And i%2) Or (j And j%2): pos = n + 1 : Else : pos = 0 : EndIf
Else
pos = 0
n = 0
EndIf
Until pos = 0
ProcedureReturn n
EndProcedure
Procedure WriteLineOfCodes ( file.s, flag.b )
FileNr = CreateFile( #PB_Any, File + ".log" )
If FileNr
WriteStringN( FileNr, ";{ Removed Functions", FileMode )
ForEach Proc()
If Not Proc()\InUse
Count + 1
dummy.s = "; " + RSet(Str(Count), 3, "0") + " : " + Proc()\Name + " [ " + Proc()\Param + " ] "
WriteStringN( FileNr, dummy, FileMode )
EndIf
Next
WriteStringN( FileNr, ";}", FileMode )
LogText ( "Removed: " + Str(Count) + " unused Procedures")
WriteStringN( FileNr, ";{ Statistics ( Level | Calls | Name | Parameter )", FileMode )
Count = 0
ForEach Proc()
If Proc()\InUse
Count + 1
dummy.s = "; " + RSet(Str(Count), 3, "0") + " : "
dummy + RSet(Str(Proc()\InUse), 2, "0") + " | "
dummy + RSet(Str(Proc()\Counts), 3, "0") + " | "
dummy + Proc()\Name + " [ " + Proc()\Param + " ] "
WriteStringN( FileNr, dummy, FileMode )
EndIf
Next
WriteStringN( FileNr, ";}", FileMode )
CloseFile( FileNr )
EndIf
FileNr.l = CreateFile( #PB_Any, File )
If FileNr
WriteStringN( FileNr, ";- Created with " + #VERSION, FileMode )
If CountList(Cons())
; Enumerationen und Konstanten
WriteStringN( FileNr, ";{ Constants", FileMode )
ForEach Cons()
WriteStringN( FileNr, Cons(), FileMode )
Next
WriteStringN( FileNr, ";}", FileMode )
EndIf
If CountList(Strc())
; Structuren schreiben
WriteStringN( FileNr, ";{ Structures", FileMode )
ForEach Strc()
WriteStringN( FileNr, Strc(), FileMode )
Next
WriteStringN( FileNr, ";}", FileMode )
EndIf
If CountList(Proc())
; Declarationen erstellen
WriteStringN( FileNr, ";{ Declares", FileMode )
ForEach Proc()
If Proc()\InUse
dummy.s = "Declare"
If Proc()\Decl = 2 : dummy + "DLL" : ElseIf Proc()\Decl = 3 : dummy + "CDLL" : EndIf
If Proc()\Typ : dummy + "." + Chr(Proc()\Typ&$FF) : EndIf
dummy + " " + Proc()\Name + " ( " + Proc()\Param + " ) "
WriteStringN( FileNr, dummy, FileMode )
EndIf
Next
WriteStringN( FileNr, ";}", FileMode )
EndIf
WriteStringN( FileNr, ";{ Functions", FileMode )
ForEach Code()
WriteStringN( FileNr, Code(), FileMode )
Next
WriteStringN( FileNr, ";}", FileMode )
CloseFile( FileNr )
EndIf
EndProcedure
Procedure.s AddIncludeFile ( file.s ); Result = Filename if not exists
Protected flag.b, Typ.b
If UCase(Left(File, 1)) = "X"
Typ = 1
Else
Typ = 0
EndIf
File = Mid(File, FindString(File, Chr(34), 0) + 1, #MAX_PATH)
File = Mid(File, 1, Len(File) - 1)
If Mid(File, 2, 1) <> ":"
File = Path + File
EndIf
If File
CrC.l = CRC32Fingerprint( @File, Len(File))
EndIf
If Not CrC : ProcedureReturn "" : EndIf
If Typ
ForEach Incl()
If CrC = Incl()\CrC
flag = #True
Break
EndIf
Next
EndIf
If Not flag
If AddElement( Incl() )
Incl()\File = File
Incl()\CrC = CrC
Incl()\Typ = Typ
EndIf
Else
File = ""
EndIf
ProcedureReturn File
EndProcedure
Procedure.b AddProcedure ( txt.s )
Protected flag, n.l, Typ.b, Decl.b, success.b, dummy.s
dummy.s = UCase(Left(txt, 10))
If Left(dummy, 9) = "PROCEDURE" And dummy <> "PROCEDURER"
n = FindString( txt, " ", 9 )
If n
dummy = UCase(Left(txt, n - 1 ))
Else
ProcedureReturn #Null
EndIf
n = Len(dummy)
If Mid(txt, n - 1, 1) = "."
Typ = Asc(LCase(Mid(txt, n, 1)))
dummy = Left(dummy, n - 2 )
EndIf
Select Right(dummy, 4)
Case "DURE" : Decl = 1
Case "UREC" : Decl = 1
Case "EDLL" : Decl = 2
Case "CDLL" : Decl = 3
Default : ProcedureReturn #Null
EndSelect
;Das 'Procedure' Wort entfernen
txt = Trim(Mid ( txt, n+1, #MAX_PATH ))
n = FindString(txt, "(", 1)
If n And AddElement( Proc() )
Proc()\Typ = Typ
Proc()\Decl = Decl
dummy = Trim(Mid( txt, 1, n - 1))
Proc()\Name = dummy : dummy = UCase(dummy)
Proc()\CrC = CRC32Fingerprint( @dummy, Len(dummy))
Proc()\Param = Trim(Mid( txt, n + 1, #MAX_PATH ))
Proc()\Param = Trim(Left(Proc()\Param, Len(Proc()\Param) - 1))
If Proc()\Param
Proc()\Param = ReplaceString(Proc()\Param, " ", "" )
Proc()\Param = ReplaceString(Proc()\Param, " ", "" )
Proc()\Param = ReplaceString(Proc()\Param, ",", ", " )
EndIf
Proc()\LineS = ListIndex(Code())
Proc()\LineS_L = ListIndex(Code_L())
success = #True
EndIf
EndIf
ProcedureReturn success
EndProcedure
Procedure ReadLineOfCodes ( file.s )
Protected pos.Long, zeile.s, dummy.s
If FileSize( file ) < 1
ProcedureReturn
EndIf
FileNr.l = ReadFile( #PB_Any, file )
If FileNr
FileMode = ReadStringFormat(FileNr)
While Eof(FileNr) <> #True
zeile.s = Trim(ReadString( FileNr, FileMode ))
If AddElement(Code_L())
Code_L() = zeile
EndIf
; Kommentare entfernen
i = FindStringEx ( zeile, ";", 1 )
If i
zeile = Left(zeile, i - 1 )
EndIf
; Mehrzeilige Anweisungen aufsplitten
Repeat
i = FindStringEx ( zeile, ":", 1 )
If i And Not F_DS
; Checken ob Label
If i < Len(zeile)
dummy = Trim(Left(zeile, i - 1 ))
zeile = Trim(Mid ( zeile, i + 1, #MAX_PATH ))
Else
dummy = zeile
i = 0
EndIf
Else
dummy = zeile
i = 0
EndIf
vgl.s = Trim(UCase(Left(dummy, 14)))
; Cut Comment Lines
If Not vgl Or Left(vgl, 1) = ";" Or Left(vgl, 7) = "DECLARE"
ElseIf Left(vgl, 12) = "ENUMERATION " Or vgl = "ENUMERATION"
F_Enum = #True
If AddElement( Cons() ) : Cons() = dummy : EndIf
ElseIf vgl = "ENDENUMERATION"
F_Enum = #Null
If AddElement( Cons() ) : Cons() = dummy : EndIf
ElseIf F_Enum Or ( Left(vgl, 1) = "#" And Not F_Enum )
If AddElement( Cons() ) : Cons() = dummy : EndIf
; Strukturen
ElseIf Left(vgl, 10) = "STRUCTURE "
F_Struct = #True
If AddElement( Strc() ) : Strc() = dummy : EndIf
ElseIf Left(vgl, 12) = "ENDSTRUCTURE"
F_Struct = #Null
If AddElement( Strc() ) : Strc() = dummy : EndIf
ElseIf F_Struct
If AddElement( Strc() ) : Strc() = dummy : EndIf
; Include Tag prüfen
ElseIf Left(vgl, 12) = "XINCLUDEFILE" Or Left(vgl, 11) = "INCLUDEFILE"
vgl = AddIncludeFile( dummy )
If vgl : ReadLineOfCodes( vgl ) : EndIf
; CodeZeile hinzufügen
ElseIf AddElement( Code() )
Code() = dummy
If Left(vgl, 11) = "INCLUDEPATH"
vgl = Mid( dummy, 12, #MAX_PATH )
vgl = Trim( ReplaceString( vgl, Chr(34), "" ))
Path = Path + vgl
If Right(Path, 1) <> "\" : Path + "\" : EndIf
ElseIf vgl = "DATASECTION"
F_DS = #True
ElseIf vgl = "ENDDATASECTION"
F_DS = #Null
; Proceduren Tag prüfen
ElseIf AddProcedure( dummy )
ElseIf Left(vgl, 12) = "ENDPROCEDURE"
Proc()\LineE = ListIndex(Code())
Proc()\LineE_L = ListIndex(Code_L())
EndIf
EndIf
Until i = 0
Wend
CloseFile( FileNr )
EndIf
EndProcedure
Procedure CopyFileSettings ( FromFile.s, ToFile.s )
If FileSize( FromFile ) < 1 : ProcedureReturn : EndIf
FileIDTo.l = OpenFile( #PB_Any, ToFile )
If FileIDTo
FileIdFrom.l = ReadFile( #PB_Any, FromFile )
If FileIdFrom
n = Lof(FileIdFrom) - 1
For i = n To 0 Step -1
FileSeek( FileIdFrom, i )
If ReadByte( FileIdFrom ) = 0
Size = n - i
*mem = AllocateMemory( Size )
ReadData( FileIdFrom, *mem, Size )
FileSeek( FileIDTo, Lof(FileIDTo))
WriteData( FileIDTo, *mem, Size )
FreeMemory( *mem )
Break
EndIf
Next
CloseFile( FileIdFrom )
EndIf
CloseFile( FileIDTo )
EndIf
EndProcedure
Procedure.s GetProcCmds ( txt.s, *pos.Long, flag.b ); 0-Every Command, 1-Functions()only
Protected Result.s = ""
If *pos\l = 0 : *pos\l = 1 : EndIf
Repeat
If flag = 0
n = FindStringEx ( txt, " ", *pos\l )
If Not n : Result = txt : EndIf
Else
n = FindStringEx ( txt, "(", *pos\l )
EndIf
If n
txt = Trim(Mid( txt, *pos\l, n - *pos\l))
l = Len(txt)
For i = l To 1 Step -1
c = Asc(Mid(txt, i, 1))
; Solange Rückwärts gehen, bis nach gültigen Zeichen
; ein ungültiges Zeichen kommt
If c < 48 Or ( c > 57 And c < 65 ) Or c > 122
If found
Result = Mid ( txt, i + 1, #MAX_PATH )
found = #Null
Break
EndIf
Else
found = #True
EndIf
Next
If found
Result = txt
EndIf
*pos\l = n + 1
If Result : n = 0 : EndIf
EndIf
Until Not n
ProcedureReturn UCase(Result)
EndProcedure
Procedure.l ScanQuellCode ( FromLn.l, ToLn.l, Level.l )
Protected pos.Long, dummy.s, txt.s
; Überprüfen, welche Proceduren verwendet werden
; Einsprünge aus dem Hauptprogramm suchen
If FromLn > ToLn Or G_iProcCount < 1 : ProcedureReturn : EndIf
; Debug ""
; Debug "Scan from:" + Str(FromLn) + ".." + Str(ToLn)
For i = FromLn To ToLn
If Not SelectElement( Code(), i )
Break
EndIf
pos\l = 1
txt.s = Code()
;AddGadgetItem( #pbA_TV_Procs, -1, txt, 0, 0 )
Repeat
dummy = GetProcCmds( txt, @pos, #True )
If dummy
CrC = CRC32Fingerprint( @dummy, Len(dummy))
If CrC
ForEach Proc()
If Proc()\CrC = CrC
Proc()\Counts + 1
If Not Proc()\InUse
Proc()\InUse = Level
EndIf
Count + 1
;AddGadgetItem( #pbA_TV_Procs, -1, Proc()\Name, 0, 1 )
Break
EndIf
Next
EndIf
EndIf
Until dummy = ""
Next
ProcedureReturn Count
EndProcedure
Procedure DoProcValidation ()
G_iProcCount = CountList(Proc())
If G_iProcCount < 1 : ProcedureReturn : EndIf
n = G_iProcCount - 1
a = 0
b = 0
LogText ( "Do PreScan.." )
; Zunächst Globalen Code prüfen, Ausserhalb von Proceduren
Count = 0
For i = 0 To n
SelectElement( Proc(), i )
b = Proc()\LineS - 1
If b > a
Count + ScanQuellCode( a, b, 1 )
SelectElement( Proc(), i )
EndIf
a = Proc()\LineE + 1
Next
b = CountList( Code() ) - 1
If a <= b
Count + ScanQuellCode( a, b, 1 )
EndIf
LogText ( "done." )
LogText ( "Do DeepScan.." )
; Jetzt innerhalb von genutzten Proceduren suchen
For e = 2 To 20
Count = 0
LogText ( " - Level : " + Str(e))
For i = 0 To n
SelectElement( Proc(), i )
If Proc()\InUse = e - 1
a = Proc()\LineS + 1
b = Proc()\LineE - 1
Count + ScanQuellCode( a, b, e )
EndIf
Next
If Not Count : Break : EndIf
Next
LogText ( "done." )
EndProcedure
Procedure RemoveUnsedProcs ()
n = G_iProcCount - 1
For i = n To 0 Step - 1
SelectElement( Proc(), i )
If Not Proc()\InUse
For d = Proc()\LineE To Proc()\LineS Step -1
SelectElement( Code(), d )
DeleteElement( Code() )
Next
EndIf
Next
EndProcedure
Procedure pbAnalyzer ( file.s )
If file = "" : file = OpenFileRequester( "PB Quellcode öffnen", "", "Text (*.txt)|*.txt;*.bat|PureBasic (*.pb)|*.pb;*.pbi|Alle Dateien (*.*)|*.*", 1 ) : EndIf
LogText ( "* " + #VERSION + "*" )
LogText ( "" )
If file = ""
LogText ( "Usage pbAnalyzer.exe sourcefile.pb [outfile.pb]" )
ProcedureReturn
EndIf
Path = GetPathPart( file )
;ReadPBCommandList()
LogText ( "Path: " + GetPathPart(file) )
LogText ( "Reading: " + GetFilePart(file) + ".." )
ReadLineOfCodes( file )
LogText ( "done" )
G_iProcCount = CountList(Proc())
LogText ( "Found " + Str(G_iProcCount) + " Procedures" )
DoProcValidation()
ForEach Proc()
If Not Proc()\InUse
AddGadgetItem(#pbA_LI_Unsed, Count, Str(Count) + Chr(10) + Proc()\Name + Chr(10) + Proc()\Param )
SetGadgetItemState(#pbA_LI_Unsed, Count, #PB_ListIcon_Checked )
Count + 1
EndIf
Next
EndProcedure
file.s = ProgramParameter()
NewFile.s = ProgramParameter()
If Open_pbaWnd()
SetGadgetState(#pbA_P_Panel, 2)
HideWindow(#pbaWnd, #Null)
pbAnalyzer( file )
LogText ( "All done.")
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_CloseWindow : Ende = #True
ElseIf Event = #PB_Event_Gadget
Select EventGadget()
Case #pbA_B_Exit : Ende = #True
Case #pbA_B_OK
If GetGadgetState(#pba_CX_Procs)
RemoveUnsedProcs ()
EndIf
If Not NewFile
NewFile = GetPathPart(file) + "pbA_" + GetFilePart(file)
EndIf
LogText ( "Writing File: " + GetFilePart(NewFile) )
WriteLineOfCodes( NewFile, #Null )
LogText ( "Copy File Settings...")
CopyFileSettings( file, NewFile )
LogText ( "done")
EndSelect
EndIf
Until Ende
EndIf
End
