Need help organizing your code? Then this is your lucky day!
This handy program reads your DBP project and gives you a nice code report. It tells you how many lines of code you have - physical and logical. It also tells you how many of them are remarks and blank spaces. It also shows how many functions and source files you have. It even finds the number of lines of code in each individual function and recommends the biggest and most obfuscated ones for refactoring. If that isn't enough, it even detects how obfuscated a project is in terms of spagetti points.
To use it just drag and drop your dbpro file on the exe of this program:
Rem Project: Line Counter
Rem Created: 2/12/2007 6:04:57 PM
Rem ***** Main Source File *****
type userfunction
name as string
code as dword
endtype
local project as string
local source as string
global code as dword
global blank as dword
global remark as dword
global logical as dword
global num as integer
global slop as double integer
global files as dword
global dim userfunctions(0) as userfunction
project = project_name$()
source = get_source$(project)
count(source)
sort()
if file exist("Line Counter.txt") then delete file "Line Counter.txt"
open to write 1, "Line Counter.txt"
write string 1, "***** Line Counter v1.02 *****"
write string 1, ""
write string 1, "Project " + left$(project, len(project)-6)
write string 1, ""
write string 1, "Physical: " + cstr$(code)
write string 1, "Logical: " + cstr$(logical)
write string 1, ""
write string 1, "Remarks: " + cstr$(remark)
write string 1, "Blanks: " + cstr$(blank)
write string 1, ""
write string 1, "Recommended refactoring"
write string 1, ""
for num = array count(userfunctions(0)) to 0 step -1
write string 1, userfunctions(num).name + space$(29-len(userfunctions(num).name)+1) + cstr$(userfunctions(num).code)
inc slop, userfunctions(num).code^2
next num
slop = slop / files
write string 1, ""
write string 1, "Total functions: " + cstr$(array count(userfunctions(0)))
write string 1, "Total source files: " + cstr$(files)
write string 1, "Overall obfuscation: " + cstr$(slop) + " spagetti points"
close file 1
execute file "Line Counter.txt", "", ""
end
`sort functions by size
function sort()
quicksort(0, array count(userfunctions(0)))
endfunction
function quicksort(left as integer, right as integer)
local i as integer
local j as integer
local x as dword
local y as dword
local z as string
i = left
j = right
x = userfunctions((left + right)/2).code
repeat
while userfunctions(i).code < x && i<right
inc i
endwhile
while x < userfunctions(j).code && j>left
dec j
endwhile
if i<=j
y = userfunctions(i).code
userfunctions(i).code = userfunctions(j).code
userfunctions(j).code = y
z = userfunctions(i).name
userfunctions(i).name = userfunctions(j).name
userfunctions(j).name = z
inc i
dec j
endif
until i > j
if left < j then quicksort(left, j)
if i < right then quicksort(i, right)
endfunction
`count lines of code
function count(source as string)
local str as string
local infunction as boolean
local functioncode as dword
local mainsource as boolean
local inmain as dword
`open source file to count
open to read 1, source
`main source file code
userfunctions(0).name = "Main Source File"
inmain = 1
while file end(1) = 0
`read source line
read string 1, str
str = lower$(trim$(str))
if str = "remstart"
remcount()
else
if left$(str, 9) = "function "
`new function is starting
infunction = 1
if inmain
inmain = 0
userfunctions(0).code = maincode
endif
array insert at bottom userfunctions(0)
userfunctions().name = function_name$(str) + "()"
endif
`increment number of lines of code
inc code
if str = "" then inc blank
if left$(str, 1) = "`" or left$(str, 3) = "rem" then inc remark
if infunction then inc functioncode
if inmain then inc maincode
poop = poop
if str = "endfunction" or left$(str, 12) = "endfunction "
`function is ending
infunction = 0
userfunctions().code = functioncode
functioncode = 0
endif
endif
endwhile
if inmain = 1
inmain = 0
userfunctions(0).code = maincode
endif
inc logical, code - remark - blank
close file 1
endfunction
function remcount()
local str as string
while file end(1) = 0
inc code
inc remark
`read source line
read string 1, str
str = lower$(trim$(str))
if str = "remend" then exit
endwhile
endfunction
`get the name of a function
function function_name$(str as string)
local name as string
local char as dword
`take "function " part off
str = right$(str, len(str) - 9)
for char = 1 to len(str)
if mid$(str, char) = "("
`found parameters
name = left$(str, char-1)
exit
endif
next char
endfunction name
`get into the project folder and return the DBPRO file name
function project_name$()
local path as string
local DBPRO as string
local char as dword
path = left$(right$(cl$(), len(cl$())-1), len(cl$())-2)
for char = len(path) to 1 step -1
if mid$(path, char) = ""
`backslash marks ending of path and beginning of file name
set dir left$(path, char)
DBPRO = right$(path, len(path) - char)
exit
endif
next char
endfunction DBPRO
`find the final source file
function get_source$(DBPRO as string)
local str as string
local source as string
`search DBPRO file for "final source="
open to read 1, DBPRO
files = 1
while file end(1) = 0
read string 1, str
if lower$(left$(str, 13)) = "final source="
`final source file sound
source = right$(str, len(str) - 13)
exit
endif
if lower$(left$(str, 7)) = "include" then inc files
endwhile
close file 1
endfunction source
`find multi logic
function multi_logic(str as string)
local char as dword
local length as dword
str = parse_string$(str)
length = len(str)
for char = 1 to length
if newMid$(str, char, 4) = "then"
inc logical
endif
next char
endfunction
`removes "" strings from a string
function parse_string$(str as string)
local char as dword
local length as dword
local old_length as dword
local instring as boolean
length = len(str)
old_length = length
for char = 1 to length
if mid$(str, char) = chr$(34)
if instring
`found end of "" string
str = left$(str, normal_end) + right$(str, length - char)
length = len(str)
dec char, old_length - length
old_length = length
instring = 0
else
`found beginning of "" string
normal_end = char - 1
instring = 1
endif
endif
next char
if instring then str = left$(str, normal_end)
endfunction str
`removes leading and trailing spaces
function trim$(str as string)
local pos as dword
local length as dword
length = len(str)
pos = length
while pos
if mid$(str, pos) <> " "
str = left$(str, pos)
`this is where the exitfunction would be, but instead the ltrim$()
` the length must be resized because the string was just chopped
length = pos
pos = 1
while pos <= length
if mid$(str, pos) <> " "
dec pos
str = right$(str, length - pos)
exitfunction str
endif
inc pos
endwhile
endif
dec pos
endwhile
endfunction ""
` Converts a number into a string with commas separating the thousands
function cstr$(num as dword)
local str as string
local length as dword
local pos as integer
str = str$(num)
length = len(str)
for pos = length - 3 to 1 step - 3
str = left$(str, pos) + "," + right$(str, length - pos)
inc length
next pos
endfunction str
function newMid$(a$,b,c)
if len(a$)<c then c=len(a$)-b+1
ReturnValue$=right$(left$(a$,b+c-1),c)
endfunction ReturnValue$
I highly recommend making a new DBP project just for this because you'll need the exe after its compiled. Please compile this in hidden mode. This is most compatible with CodeSurge, but I'm working on making it work with any IDE though. If it doesn't run when you drag and drop you may need to recompile your project - it needs the _Temp.dbsource file.
With simply dragging and dropping the dbpro file onto the exe, the program gave itself a code report:
***** Line Counter v1.02 *****
Project Line Counter
Physical: 344
Logical: 240
Remarks: 29
Blanks: 75
Recommended refactoring
count() 65
Main Source File 58
quicksort() 35
parse_string$() 31
trim$() 27
get_source$() 22
remcount() 18
project_name$() 18
function_name$() 17
multi_logic() 16
cstr$() 11
newmid$() 4
sort() 3
Total functions: 12
Total source files: 1
Overall obfuscation: 12,327 spagetti points
Tips for refactoring functions
Here's some tips on getting less spagetti points.
Sequental Operations
If you have a function with lots of independent operations, put each operation in a seperate function and call them from the original.
This code
(Where a b c and d are several lines of code)
function bigfunction()
a
b
c
d
endfunction
can be turned into this:
function bigfunction()
a()
b()
c()
d()
endfunction
function a()
endfunction
function b()
endfunction
function c()
endfunction
function d()
endfunction
Pipelines
If you have a function where one operation is the input to the next, put them all in separate functions and use parameters and return values.
This code
(Where a b c and d are several lines of code)
function bigfunction()
a
b
c
d
endfunction
can be turned into this:
function bigfunction()
d(c(b(a())))
endfunction
function a()
endfunction
function b()
endfunction
function c()
endfunction
function d()
endfunction
Big nests (not the bird kind)
If you have a function that has control logic nesting so deeply you can't even count the number of indentations, take the inner loops and pull them out in a separate function.
This code
(Where a b c are loops and d is several lines of code)
function bigfunction()
for a
for b
for c
d
next c
next b
next a
endfunction
can be turned into this:
function bigfunction()
for a
for b
c()
next b
next a
endfunction
function c()
for c
d
next c
endfunction
Please post how many spagetti points your project earns, we need to know how many points the average project is so we have something to compare the points with. Good luck de-obfuscating!