PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/scripts/refactor_count.py

https://github.com/Pilen/teeworlds-dikumod
Python | 351 lines | 299 code | 41 blank | 11 comment | 42 complexity | 16abec3488b02c4327ff7a4784641849 MD5 | raw file
  1. import os, re, sys
  2. alphanum = "0123456789abcdefghijklmnopqrstuvwzyxABCDEFGHIJKLMNOPQRSTUVWXYZ_"
  3. cpp_keywords = ["auto", "const", "double", "float", "int", "short", "struct", "unsigned", # C
  4. "break", "continue", "else", "for", "long", "signed", "switch", "void",
  5. "case", "default", "enum", "goto", "register", "sizeof", "typedef", "volatile",
  6. "char", "do", "extern", "if", "return", "static", "union", "while",
  7. "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try", # C++
  8. "bool", "explicit", "new", "static_cast", "typeid",
  9. "catch", "false", "operator", "template", "typename",
  10. "class", "friend", "private", "this", "using",
  11. "const_cast", "inline", "public", "throw", "virtual",
  12. "delete", "mutable", "protected", "true", "wchar_t"]
  13. allowed_words = []
  14. #allowed_words += ["bitmap_left", "advance", "glyph"] # ft2
  15. allowed_words += ["qsort"] # stdio / stdlib
  16. allowed_words += ["size_t", "cosf", "sinf", "asinf", "acosf", "atanf", "powf", "fabs", "rand", "powf", "fmod", "sqrtf"] # math.h
  17. allowed_words += ["time_t", "time", "strftime", "localtime"] # time.h
  18. allowed_words += [ # system.h
  19. "int64",
  20. "dbg_assert", "dbg_msg", "dbg_break", "dbg_logger_stdout", "dbg_logger_debugger", "dbg_logger_file",
  21. "mem_alloc", "mem_zero", "mem_free", "mem_copy", "mem_move", "mem_comp", "mem_stats", "total_allocations", "allocated",
  22. "thread_create", "thread_sleep", "lock_wait", "lock_create", "lock_release", "lock_destroy", "swap_endian",
  23. "io_open", "io_read", "io_read", "io_write", "io_flush", "io_close", "io_seek", "io_skip", "io_tell", "io_length",
  24. "str_comp", "str_length", "str_quickhash", "str_format", "str_copy", "str_comp_nocase", "str_sanitize", "str_append",
  25. "str_comp_num", "str_find_nocase", "str_sanitize_strong", "str_uppercase", "str_toint", "str_tofloat",
  26. "str_utf8_encode", "str_utf8_rewind", "str_utf8_forward", "str_utf8_decode", "str_sanitize_cc", "str_skip_whitespaces",
  27. "fs_makedir", "fs_listdir", "fs_storage_path", "fs_is_dir",
  28. "net_init", "net_addr_comp", "net_host_lookup", "net_addr_str", "type", "port", "net_addr_from_str",
  29. "net_udp_create", "net_udp_send", "net_udp_recv", "net_udp_close", "net_socket_read_wait",
  30. "net_stats", "sent_bytes", "recv_bytes", "recv_packets", "sent_packets",
  31. "time_get", "time_freq", "time_timestamp"]
  32. allowed_words += ["vec2", "vec3", "vec4", "round", "clamp", "length", "dot", "normalize", "frandom", "mix", "distance", "min",
  33. "closest_point_on_line", "max", "absolute"] # math.hpp
  34. allowed_words += [ # tl
  35. "array", "sorted_array", "string",
  36. "all", "sort", "add", "remove_index", "remove", "delete_all", "set_size",
  37. "base_ptr", "size", "swap", "empty", "front", "pop_front", "find_binary", "find_linear", "clear", "range", "end", "cstr",
  38. "partition_linear", "partition_binary"]
  39. allowed_words += ["fx2f", "f2fx"] # fixed point math
  40. def CheckIdentifier(ident):
  41. return False
  42. class Checker:
  43. def CheckStart(self, checker, filename):
  44. pass
  45. def CheckLine(self, checker, line):
  46. pass
  47. def CheckEnd(self, checker):
  48. pass
  49. class FilenameExtentionChecker(Checker):
  50. def __init__(self):
  51. self.allowed = [".cpp", ".h"]
  52. def CheckStart(self, checker, filename):
  53. ext = os.path.splitext(filename)[1]
  54. if not ext in self.allowed:
  55. checker.Error("file extention '%s' is not allowed" % ext)
  56. class IncludeChecker(Checker):
  57. def __init__(self):
  58. self.disallowed_headers = ["stdio.h", "stdlib.h", "string.h", "memory.h"]
  59. def CheckLine(self, checker, line):
  60. if "#include" in line:
  61. include_file = ""
  62. if '<' in line:
  63. include_file = line.split('<')[1].split(">")[0]
  64. #if not "/" in include_file:
  65. # checker.Error("%s is not allowed" % include_file)
  66. elif '"' in line:
  67. include_file = line.split('"')[1]
  68. #print include_file
  69. if include_file in self.disallowed_headers:
  70. checker.Error("%s is not allowed" % include_file)
  71. class HeaderGuardChecker(Checker):
  72. def CheckStart(self, checker, filename):
  73. self.check = ".h" in filename
  74. self.guard = "#ifndef " + filename[4:].replace("/", "_").replace(".hpp", "").replace(".h", "").upper() + "_H"
  75. def CheckLine(self, checker, line):
  76. if self.check:
  77. #if "#" in line:
  78. self.check = False
  79. #if not self.check:
  80. if line.strip() == self.guard:
  81. pass
  82. else:
  83. checker.Error("malformed or missing header guard. Should be '%s'" % self.guard)
  84. class CommentChecker(Checker):
  85. def CheckLine(self, checker, line):
  86. if line.strip()[-2:] == "*/" and "/*" in line:
  87. checker.Error("single line multiline comment")
  88. class FileChecker:
  89. def __init__(self):
  90. self.checkers = []
  91. self.checkers += [FilenameExtentionChecker()]
  92. self.checkers += [HeaderGuardChecker()]
  93. self.checkers += [IncludeChecker()]
  94. self.checkers += [CommentChecker()]
  95. def Error(self, errormessage):
  96. self.current_errors += [(self.current_line, errormessage)]
  97. def CheckLine(self, line):
  98. for c in self.checkers:
  99. c.CheckLine(self, line)
  100. return True
  101. def CheckFile(self, filename):
  102. self.current_file = filename
  103. self.current_line = 0
  104. self.current_errors = []
  105. for c in self.checkers:
  106. c.CheckStart(self, filename)
  107. for line in file(filename).readlines():
  108. self.current_line += 1
  109. if "ignore_check" in line:
  110. continue
  111. self.CheckLine(line)
  112. for c in self.checkers:
  113. c.CheckEnd(self)
  114. def GetErrors(self):
  115. return self.current_errors
  116. def cstrip(lines):
  117. d = ""
  118. for l in lines:
  119. if "ignore_convention" in l:
  120. continue
  121. l = re.sub("^[\t ]*#.*", "", l)
  122. l = re.sub("//.*", "", l)
  123. l = re.sub('\".*?\"', '"String"', l) # remove strings
  124. d += l.strip() + " "
  125. d = re.sub('\/\*.*?\*\/', "", d) # remove /* */ comments
  126. d = d.replace("\t", " ") # tab to space
  127. d = re.sub(" *", " ", d) # remove double spaces
  128. #d = re.sub("", "", d) # remove /* */ comments
  129. d = d.strip()
  130. # this eats up cases like 'n {'
  131. i = 1
  132. while i < len(d)-2:
  133. if d[i] == ' ':
  134. if not (d[i-1] in alphanum and d[i+1] in alphanum):
  135. d = d[:i] + d[i+1:]
  136. i += 1
  137. return d
  138. #def stripstrings(data):
  139. # return re.sub('\".*?\"', 'STRING', data)
  140. def get_identifiers(data):
  141. idents = {}
  142. data = " "+data+" "
  143. regexp = re.compile("[^a-zA-Z0-9_][a-zA-Z_][a-zA-Z0-9_]+[^a-zA-Z0-9_]")
  144. start = 0
  145. while 1:
  146. m = regexp.search(data, start)
  147. if m == None:
  148. break
  149. start = m.end()-1
  150. name = data[m.start()+1:m.end()-1]
  151. if name in idents:
  152. idents[name] += 1
  153. else:
  154. idents[name] = 1
  155. return idents
  156. grand_total = 0
  157. grand_offenders = 0
  158. gen_html = 1
  159. if gen_html:
  160. print "<head>"
  161. print '<link href="/style.css" rel="stylesheet" type="text/css" />'
  162. print "</head>"
  163. print "<body>"
  164. print '<div id="outer">'
  165. print '<div id="top_left"><div id="top_right"><div id="top_mid">'
  166. print '<a href="/"><img src="/images/twlogo.png" alt="teeworlds logo" /></a>'
  167. print '</div></div></div>'
  168. print '<div id="menu_left"><div id="menu_right"><div id="menu_mid">'
  169. print '</div></div></div>'
  170. print '<div id="tlc"><div id="trc"><div id="tb">&nbsp;</div></div></div>'
  171. print '<div id="lb"><div id="rb"><div id="mid">'
  172. print '<div id="container">'
  173. print '<p class="topic_text">'
  174. print '<h1>Code Refactoring Progress</h1>'
  175. print '''This is generated by a script that find identifiers in the code
  176. that doesn't conform to the code standard. Right now it only shows headers
  177. because they need to be fixed before we can do the rest of the source.
  178. This is a ROUGH estimate of the progress'''
  179. print '</p>'
  180. print '<p class="topic_text">'
  181. print '<table>'
  182. #print "<tr><td><b>%</b></td><td><b>#</b></td><td><b>File</b></td><td><b>Offenders</b></td></tr>"
  183. line_order = 1
  184. total_files = 0
  185. complete_files = 0
  186. total_errors = 0
  187. for (root,dirs,files) in os.walk("src"):
  188. for filename in files:
  189. filename = os.path.join(root, filename)
  190. if "/." in filename or "/external/" in filename or "/base/" in filename or "/generated/" in filename:
  191. continue
  192. if "src/osxlaunch/client.h" in filename: # ignore this file, ObjC file
  193. continue
  194. if "e_config_variables.h" in filename: # ignore config files
  195. continue
  196. if "src/game/variables.hpp" in filename: # ignore config files
  197. continue
  198. if not (".hpp" in filename or ".h" in filename or ".cpp" in filename):
  199. continue
  200. #total_files += 1
  201. #if not "src/engine/client/ec_client.cpp" in filename:
  202. # continue
  203. f = FileChecker()
  204. f.CheckFile(filename)
  205. num_errors = len(f.GetErrors())
  206. total_errors += num_errors
  207. if num_errors:
  208. print '<tr style="background: #e0e0e0"><td colspan="2">%s, %d errors</td></tr>' % (filename, num_errors),
  209. for line, msg in f.GetErrors():
  210. print '<tr"><td>%d</td><td>%s</td></tr>' % (line, msg)
  211. #print '<table>'
  212. #GetErrors()
  213. if 0:
  214. text = cstrip(file(filename).readlines()) # remove all preprocessor stuff and comments
  215. #text = stripstrings(text) # remove strings (does not solve all cases however)
  216. #print text
  217. idents = get_identifiers(text)
  218. offenders = 0
  219. total = 0
  220. offender_list = {}
  221. for name in idents:
  222. #print name
  223. if len(name) <= 2: # skip things that are too small
  224. continue
  225. if name in cpp_keywords: # skip keywords
  226. continue
  227. if name in allowed_words: # skip allowed keywords
  228. continue
  229. total += idents[name]
  230. if name != name.lower(): # strip names that are not only lower case
  231. continue
  232. offender_list[name] = idents[name]
  233. if not gen_html:
  234. print "[%d] %s"%(idents[name], name)
  235. offenders += idents[name]
  236. grand_total += total
  237. grand_offenders += offenders
  238. if total == 0:
  239. total = 1
  240. line_order = -line_order
  241. done = int((1-(offenders / float(total))) * 100)
  242. if done == 100:
  243. complete_files += 1
  244. if done != 100 and gen_html:
  245. color = "#ffa0a0"
  246. if done > 20:
  247. color = "#ffd080"
  248. if done > 50:
  249. color = "#ffff80"
  250. if done > 75:
  251. color = "#e0ff80"
  252. if done == 100:
  253. color = "#80ff80"
  254. line_color = "#f0efd5"
  255. if line_order > 0:
  256. line_color = "#ffffff"
  257. offender_string = ""
  258. count = 0
  259. for name in offender_list:
  260. count += 1
  261. offender_string += "[%d]%s " % (offender_list[name], name)
  262. if count%5 == 0:
  263. offender_string += "<br/>"
  264. print '<tr style="background: %s">' % line_color,
  265. print '<td style="text-align: right; background: %s"><b>%d%%</b></td><td style="text-align: center">%d</td><td>%s</td>' % (color, done, offenders, filename),
  266. print '<td style="text-align: right">%s</td>' % offender_string
  267. print "</tr>"
  268. count = 0
  269. if gen_html:
  270. print "</table>"
  271. print "<h1>%d errors</h1>" % total_errors
  272. if 0:
  273. print "<h1>%.1f%% Identifiers done</h1>" % ((1-(grand_offenders / float(grand_total))) * 100)
  274. print "%d left of %d" % (grand_offenders, grand_total)
  275. print "<h1>%.1f%% Files done</h1>" % ((complete_files / float(total_files)) * 100)
  276. print "%d left of %d" % (total_files-complete_files, total_files)
  277. print "</p>"
  278. print "<div style='clear:both;'></div>"
  279. print '</div>'
  280. print '</div></div></div>'
  281. print '<div id="blc"><div id="brc"><div id="bb">&nbsp;</div></div></div>'
  282. print '</div>'
  283. print "</body>"