Advertisement
Guest User

Untitled

a guest
Jun 26th, 2017
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.82 KB | None | 0 0
  1. #!/usr/bin/python3
  2. #
  3. # Made by duponc_j, modified by sourio_b while supervised by sbriss_a in case he fucked things up (and he did)
  4. # Version: 1.4.1
  5. #
  6.  
  7. '''
  8. An Epitech norme checker
  9.  
  10. Usage: python norme.py <dir to scan> [-nocheat] [-verbose] [-score] [-libc]
  11.  
  12. -verbose: affiche les messages impossible d\'ouvrir
  13. -nocheat: desactive la detection de la triche
  14. -score: affiche le nombre de faute de norme
  15. -libc: active la verification des fonctions de la libc
  16. -malloc: desactive le controle du malloc
  17. -printline: affiche la ligne provoquant une erreur
  18. -return: active verifier le retour des fonctions (return ;)
  19. -comment: ne pas verifier les commentaire
  20.  
  21. Non geree:
  22. - Indentation
  23. - +<escape>
  24. - verification de la presence de gl_
  25.  
  26. Bug:
  27. Il est arrivee que le checker ne trouve aucune faute alors qu\'il en existe, si
  28. ce bug vous arrive maillez moi.
  29. '''
  30.  
  31. import sys,re,os,pwd
  32.  
  33. blind_logins = [ "vial_k" ]
  34.  
  35. def static_var(varname, value):
  36. def decorate(func):
  37. setattr(func, varname, value)
  38. return func
  39. return decorate
  40.  
  41. class norme:
  42. def __init__(self):
  43. self.user = []
  44. self.verbose = 0
  45. self.cheat = 1
  46. self.comment = 1
  47. self.score = 0
  48. self.note = 0
  49. self.libc = 1
  50. # self.malloc = 1
  51. self.malloc = 0
  52. self.printline = 0
  53. self.creturn = 1
  54. self.the_dir = ""
  55.  
  56. def new_file(self):
  57. self.nb_line = 1
  58. self.nb_return = 0
  59. self.nb_funcline = 0
  60. self.nb_func = 0
  61. self.sys_include = 0
  62. self.double_inclusion = 0
  63. self.is_func = 0
  64. self.in_comment = 0
  65. self.out_comment = 0
  66. self.typedef = 0
  67. if self.verbose == 1:
  68. print("Scan: %s" % self.file)
  69.  
  70. @static_var("passed", 0)
  71. def check_header(self):
  72. norme = -1
  73. if self.check_header.passed:
  74. norme = 0
  75. for blind in blind_logins:
  76. if (blind in self.user):
  77. return
  78. if (self.nb_line == 1):
  79. if (self.line[:2] != '/*'):
  80. self.print_error('header incorrect', norme)
  81. self.check_header.__func__.passed = 1
  82. elif (self.nb_line == 9):
  83. if (self.line[:2] != '*/'):
  84. self.print_error('header incorrect', norme)
  85. self.check_header.__func__.passed = 1
  86. elif self.nb_line == 4 or self.nb_line == 7 or self.nb_line == 8:
  87. if self.cheat:
  88. p = re.compile('([\w-]* [\w-]*)$')
  89. test = re.search(p, self.line)
  90. if test:
  91. if not test.group(1) in self.user:
  92. self.print_error('login '+ test.group(1) +' incorrect', norme)
  93. self.check_header.__func__.passed = 1
  94. elif (self.nb_line == 5):
  95. if self.cheat:
  96. p = re.compile('<(.*)@')
  97. test = re.search(p, self.line)
  98. if test:
  99. if not test.group(1) in self.user:
  100. self.print_error('login '+ test.group(1) +' incorrect', norme)
  101. self.check_header.__func__.passed = 1
  102. else:
  103. if (self.line[:2] != '**'):
  104. self.print_error('header incorrect', norme)
  105. self.check_header.__func__.passed = 1
  106.  
  107. @static_var("passed", 0)
  108. def check_virgule(self):
  109. norme = -1
  110. if self.check_virgule.passed:
  111. norme = 0
  112. n = 0
  113. quote = 0
  114. while n < len(self.line) and self.line[n] != '\n' :
  115. if self.line[n] == '\'' or self.line[n] == '"':
  116. if quote:
  117. quote = 0
  118. else:
  119. quote = 1
  120. if (self.line[n] == ',') and quote == 0:
  121. if self.line[n + 1] != ' ' and self.line[n + 1] != '\n' and self.line[n + 1] != '\t':
  122. if self.line[-2:-1] == '\\':
  123. pass
  124. self.print_error('point-virgule ou virgule mal place', norme)
  125. self.check_virgule.__func__.passed = 1
  126. break
  127. n = n + 1
  128.  
  129. @static_var("passed", 0)
  130. def check_space_par(self):
  131. norme = -1
  132. if self.check_space_par.passed:
  133. norme = 0
  134. n = 0
  135. quote = 0
  136. while n < len(self.line) and self.line[n] != '\n' :
  137. if self.line[n] == '\'' or self.line[n] == '"':
  138. if quote:
  139. quote = 0
  140. else:
  141. quote = 1
  142. if (self.line[n] == '(') and quote == 0:
  143. if self.line[n + 1] == ' ':
  144. self.print_error('espace parenthese ouvrante', norme)
  145. self.check_space_par.__func__.passed = 1
  146. break
  147. if (self.line[n] == ')') and quote == 0:
  148. if self.line[n - 1] == ' ':
  149. self.print_error('espace parenthese fermante', norme)
  150. self.check_space_par.__func__.passed = 1
  151. break
  152. n = n + 1
  153.  
  154. @static_var("passed", 0)
  155. def check_nbchar(self):
  156. norme = -5
  157. if self.check_nbchar.passed:
  158. norme = 0
  159. line = self.line.replace('\t', " ")
  160. if len(line) > 78:
  161. note = len(line) - 78
  162. self.print_error('chaine de plus de 80 caracteres', norme)
  163. self.check_nbchar.__func__.passed = 1
  164.  
  165. @static_var("passed", 0)
  166. def check_return(self):
  167. norme = -1
  168. if self.check_return.passed:
  169. norme = 0
  170. if (self.line[:1] == '\n'):# and self.line != "*/\n"):
  171. if (self.nb_return == 1):
  172. self.print_error('double retour a la ligne', norme)
  173. self.check_return.__func__.passed = 1
  174. else:
  175. self.nb_return = 1
  176. else:
  177. self.nb_return = 0
  178.  
  179. @static_var("passed", 0)
  180. def check_nbline(self):
  181. norme = -5
  182. if self.check_nbline.passed:
  183. norme = 0
  184. if self.file[-2:] == ".c":
  185. if self.line[:1] == '}':
  186. self.is_func = 0
  187. self.nb_funcline = 0
  188. if self.line[:2] == '};':
  189. self.is_func = 0
  190. self.nb_funcline = 0
  191. self.nb_func = self.nb_func -1
  192. if self.line[:1] == '{' and self.typedef == 0:
  193. self.is_func = 1
  194. self.nb_funcline = 0
  195. self.nb_func = self.nb_func + 1
  196. if self.nb_func == 6:
  197. self.print_error('plus de 5 fonctions dans le fichier', norme)
  198. self.check_nbline.__func__.passed = 1
  199. else:
  200. if self.nb_func >= 1 and self.is_func:
  201. self.nb_funcline = self.nb_funcline + 1
  202. if self.nb_funcline >= 26:
  203. self.print_error('fonction de plus de 25 lignes', norme)
  204. self.check_nbline.__func__.passed = 1
  205.  
  206. @static_var("passed", 0)
  207. def check_cfunc(self):
  208. norme = -1
  209. if self.check_cfunc.passed:
  210. norme = 0
  211. p = re.compile('[ \t](if|else|return|while|for|break)(\()')
  212. test = re.search(p, self.line)
  213. if test:
  214. self.print_error('pas d\'espace apres mot clef', norme)
  215. self.check_cfunc.__func__.passed = 1
  216.  
  217. @static_var("passed", 0)
  218. def check_arg(self):
  219. norme = -1
  220. if self.check_arg.passed:
  221. norme = 0
  222. if self.line[-2:] == ")\n" and self.line[:1] != '\t' and self.line[:1] != ' ':
  223. p = re.compile('(.*),(.*),(.*),(.*),(.*)\)$')
  224. test = re.search(p, self.line)
  225. if test and self.line.find(')') == self.line.rfind(')'):
  226. note = 1
  227. if len(test.groups()) > 0:
  228. note = len(test.groups()) - 4
  229. #self.note += len(test.groups()) - 1 - 4
  230. self.print_error('plus de 4 arguments passes en parametre', norme)
  231. self.check_arg.__func__.passed = 1
  232.  
  233. @static_var("passed", 0)
  234. def check_sys_include(self):
  235. return
  236. if self.check_sys_include.passed:
  237. return
  238. if self.line[:1] == "#" and self.line[-2:] == "\"\n":
  239. self.sys_include = 1
  240. else:
  241. if self.line[:1] == "#" and self.line[-2:] == ">\n" and self.sys_include == 1:
  242. self.print_error('Header systeme mal placee')
  243. self.check_sys_include.__func__.passed = 1
  244.  
  245. @static_var("passed", 0)
  246. def check_comment(self):
  247. norme = -5
  248. if self.check_comment.passed:
  249. norme = 0
  250. if self.is_func and self.comment:
  251. p = re.compile('(//|/\*)')
  252. test = re.search(p, self.line)
  253. if test:
  254. note = 1
  255. if len(test.groups()) > 0:
  256. # self.note += len(test.groups()) - 1
  257. note = len(test.groups())
  258. self.print_error('Commentaires dans le code', norme)
  259. self.check_comment.__func__.passed = 1
  260.  
  261. @static_var("passed", 0)
  262. def check_malloc(self):
  263. if self.check_malloc.passed:
  264. return
  265. p = re.compile('[^x](malloc)(\()')
  266. test = re.search(p, self.line)
  267. if test and (self.file != "xmalloc.c"):
  268. self.print_error('Malloc non verifiee')
  269. self.check_malloc.__func__.passed = 1
  270.  
  271. @static_var("passed", 0)
  272. def check_double(self):
  273. return
  274. norme = -1
  275. if self.check_double.passed:
  276. norme = 0
  277. if self.file[-2:] == ".h":
  278. if self.line[:1] != '\n':
  279. if self.double_inclusion != 1:
  280. self.double_inclusion = 1
  281. if self.line[-4:] != "_H_\n":
  282. self.print_error('Header non protegee', norme)
  283. self.check_double.__func__.passed = 1
  284. else:
  285. self.double_inclusion = 1
  286.  
  287. @static_var("passed", 0)
  288. def check_operateur(self, op):
  289. norme = -1
  290. if self.check_operateur.passed:
  291. norme = 0
  292. n = 0
  293. quote = 0
  294. while n < len(self.line) and self.line[n] != '\n' :
  295. if self.line[n] == '\'' or self.line[n] == '"':
  296. if quote:
  297. quote = 0
  298. else:
  299. quote = 1
  300. if (self.line[n] == op) and quote == 0:
  301. if (self.line[n + 1] != ' ' or self.line[n - 1] != ' ') and self.line[n + 1] != ';' and self.line[n + 1] != '=' and self.line[n + 1] != '\n':
  302. if self.line[n - 1] != op and self.line[n + 1] != op and not self.line[:n].isspace():
  303. msg = 'Operateur %c mal place' % op
  304. self.print_error(msg, norme)
  305. self.check_operateur.__func__.passed = 1
  306. n = n + 1
  307.  
  308. def check_typedef(self):
  309. if self.line[:7] == "typedef":
  310. self.typedef = 1
  311. else:
  312. self.typedef = 0
  313.  
  314. @static_var("passed", 0)
  315. def check_regex(self, regex, msg):
  316. norme = -42
  317. if self.check_regex.passed:
  318. norme = 0
  319. p = re.compile(regex)
  320. test = re.search(p, self.line)
  321. if test:
  322. note = 1
  323. if len(test.groups()) > 0:
  324. note = len(test.groups())
  325. # self.note += len(test.groups()) - 1
  326. self.print_error(msg, norme)
  327. self.check_regex.__func__.passed = 1
  328.  
  329. # def check_endlinespaces(self):
  330. # # dot = self.line.rfind(';')
  331. # end = self.line.find('\n')
  332. # # tab = self.line.rfind('\t', 0, end)
  333. # res = end - dot - 1
  334. # if dot > 0 and res > 0:
  335. # self.print_error("Espace(s) en fin de ligne", res)
  336. # if tab > 0 and self.line[tab:].isspace():
  337. # self.print_error("Tab(s) en fin de ligne", len(self.line[tab:]))
  338.  
  339. @static_var("passed", 0)
  340. def check_returns(self):
  341. norme = -1
  342. if self.check_returns.__func__.passed:
  343. norme = 0
  344. dot = self.line.rfind(';')
  345. if dot == -1:
  346. return
  347. pos = dot - 1
  348. left = self.line[:dot]
  349. while pos >= 0 and (left[pos] == ' ' or left[pos] == '\t'):
  350. pos = pos - 1
  351. pos = pos + 1
  352. ret = self.line.find("return")
  353. if ret == -1:
  354. ret = self.line.find("break")
  355. par = self.line.find("(")
  356. if (ret != -1 and par == -1):
  357. pos = pos + 1
  358. if pos < dot:
  359. self.print_error("Espaces avant le ';'", norme)
  360. self.check_returns.__func__.passed = 1
  361.  
  362. @static_var("passed", 0)
  363. def check_endlinespaces(self):
  364. norme = -1
  365. if self.check_endlinespaces.passed:
  366. norme = 0
  367. dot = self.line.find('\n')
  368. if dot == -1:
  369. return
  370. pos = dot - 1
  371. left = self.line[:dot]
  372. while pos >= 0 and (left[pos] == ' ' or left[pos] == '\t'):
  373. pos = pos - 1
  374. pos = pos + 1
  375. if pos < dot:
  376. self.print_error("Espace(s) en fin de ligne", norme)
  377. self.check_endlinespaces.__func__.passed = 1
  378.  
  379. @static_var("passed", 0)
  380. def check_line(self):
  381. norme = -5
  382. # self.check_comment()
  383. if self.is_func != 1 and self.line.find("/*") != -1:
  384. self.out_comment = 1
  385. if self.out_comment:
  386. if self.is_func != 1 and self.line.find("*/") != -1:
  387. self.nb_return = 0
  388. self.out_comment = 0
  389. return
  390. if self.is_func == 1 and self.line.find("/*") != -1 and self.line.find('\"') == -1:
  391. self.in_comment = 1
  392. # if self.is_func == 1 and self.in_comment and self.line.find("*/") != -1:
  393. if self.check_line.passed:
  394. norme = 0
  395. self.print_error("Commentaires dans le code", norme)
  396. self.check_line.__func__.passed = 1
  397. if self.line.find("*/") != -1:
  398. self.nb_return = 0
  399. self.in_comment = 0
  400. return
  401. # if (self.in_comment == 1):
  402. # if not self.check_line.passed:
  403. # self.print_error("Commentaires dans le code", norme)
  404. # self.check_line.__func__.passed = 1
  405. self.check_nbline() # DOIT TOUJORS ETRE EN PREMIER
  406. self.check_sys_include()
  407. self.check_virgule()
  408. self.check_space_par()
  409. self.check_endlinespaces()
  410. # self.check_regex('[ \t]$', 'Espace en fin de ligne')
  411. # if self.creturn == 0:
  412. self.check_returns()
  413. # self.check_regex('return( \(\)| ;|;)', 'Mauvais format de return')
  414. if self.libc == 0:
  415. self.check_regex('[^_](printf|atof|atoi|atol|strcmp|strlen|strcat|strncat|strncmp|strcpy|strncpy|fprintf|strstr|strtoc|sprintf|asprintf|perror|strtod|strtol|strtoul)(\()', \
  416. 'Fonction de la lib C')
  417. self.check_nbchar()
  418. self.check_cfunc()
  419. self.check_arg()
  420. self.check_return()
  421. self.check_double()
  422. self.check_operateur('+')
  423. self.check_operateur('|')
  424. self.check_typedef() #DOIT TOUJOURS ETRE EN DERNIER
  425. if self.malloc:
  426. self.check_malloc()
  427.  
  428. def print_error(self, msg, val = -1):
  429. if val != 0:
  430. if val == -42 or self.note == -42:
  431. self.note = -42
  432. return
  433. if self.note == -10 or self.note > 0:
  434. self.note = 1
  435. elif self.note <= -10:
  436. self.note = 1
  437. elif self.note == -5 or (self.note + val < -5):
  438. self.note = -10
  439. else:
  440. self.note = self.note + val
  441. print("Erreur dans %s a la ligne %s:%s => %s"% (self.the_dir + self.file, self.nb_line, msg, val))
  442. if self.printline:
  443. print(self.line)
  444.  
  445. def cant_open(self, file):
  446. if (self.verbose or file == sys.argv[1]):
  447. print("Impossible d'ouvrir %s", file)
  448.  
  449. def scandir(self, thedir):
  450. self.the_dir = thedir
  451. try:
  452. dir = os.listdir(thedir)
  453. except:
  454. self.cant_open(thedir)
  455. else:
  456. # check_makefile(thedir)
  457. for file in dir:
  458. try:
  459. if os.path.islink(thedir + file):
  460. continue
  461. if (os.path.isdir(thedir + file)):
  462. self.scandir(thedir + "/" + file + "/")
  463. if file[-2:] == '.c' or file[-2:] == '.h':
  464. self.file = file
  465. self.new_file()
  466. file = thedir + file
  467. try:
  468. fd = open(file, 'r')
  469. except IOError:
  470. self.cant_open(file)
  471. else:
  472. for self.line in fd.readlines():
  473. if self.nb_line <= 9:
  474. self.check_header()
  475. else:
  476. self.check_line()
  477. self.nb_line = self.nb_line + 1
  478. fd.close()
  479. except:
  480. print("Issue on %s: Please do the norm manually"% file)
  481.  
  482. def get_user(self):
  483. try:
  484. fd = open(sys.argv[1] + 'auteur')
  485. except IOError:
  486. user = os.getenv('USER')
  487. self.user.append(user)
  488. try:
  489. self.user.append(pwd.getpwnam(user)[4]) #Recuperation du nom complet de l'utilisateur
  490. except:
  491. pass
  492. else:
  493. buffer = fd.read()
  494. fd.close()
  495. p = re.compile('([\w]*)')
  496. test = re.findall(p, buffer)
  497. for user in test:
  498. if user:
  499. self.user.append(user)
  500. self.user.append(pwd.getpwnam(user)[4])
  501.  
  502.  
  503. def check_makefile(thedir):
  504. file = thedir + "Makefile"
  505. if os.path.isfile(file):
  506. try:
  507. fd = open(file, 'r')
  508. except IOError:
  509. print("Impossible d'ouvrir le Makefile")
  510. else:
  511. buffer = fd.read()
  512. p = re.compile('(-g|-pg|-lefence)')
  513. test = re.search(p, buffer)
  514. if test:
  515. print("Options de debug dans le Makefile")
  516. p = re.compile('(-Wall)')
  517. test = re.search(p, buffer)
  518. if not test:
  519. print("-Wall n'est pas dans le Makefile")
  520. # p = re.compile('(-pedantic)')
  521. # test = re.search(p, buffer)
  522. # if not test:
  523. # print "-pedantic n'est pas dans le Makefile"
  524. if buffer[:2] != "##":
  525. print("Header du Makefile invalide")
  526. fd.close()
  527.  
  528. def help():
  529. print("Aide")
  530. print("Usage: norme.py <dir_to_scan>")
  531. print("-verbose: affiche les messages impossible d'ouvrir")
  532. print("-nocheat: desactive la detection de la triche")
  533. print("-score: affiche le nombre de faute de norme")
  534. print("-libc: active la verification des fonctions de la libc")
  535. print("-malloc: desactive le controle du malloc")
  536. print("-printline: affiche la ligne provoquant une erreur")
  537. print("-return: active verifier le retour des fonctions (return ;)")
  538. print("-comment: ne pas verifier les commentaire")
  539. sys.exit()
  540.  
  541. def main():
  542. if len(sys.argv) == 1:
  543. print("Usage: norme.py <dir_to_scan>")
  544. sys.exit()
  545. moulin = norme()
  546. if '-verbose' in sys.argv[1:]:
  547. moulin.verbose = 1
  548. if '-comment' in sys.argv[1:]:
  549. moulin.comment = 0
  550. if '-nocheat' in sys.argv[1:]:
  551. moulin.cheat = 0
  552. if '-score' in sys.argv[1:]:
  553. moulin.score = 1
  554. if '-libc' in sys.argv[1:]:
  555. moulin.libc = 0
  556. if '-malloc' in sys.argv[1:]:
  557. moulin.malloc = 0
  558. if '-printline' in sys.argv[1:]:
  559. moulin.printline = 1
  560. if '-return' in sys.argv[1:]:
  561. moulin.creturn = 0
  562. if '--user' in sys.argv[1:]:
  563. try:
  564. moulin.user.append(sys.argv[sys.argv.index("--user") + 1])
  565. except:
  566. pass
  567. if '-help' in sys.argv[1:]:
  568. help()
  569. if sys.argv[1][-1:] != '/':
  570. sys.argv[1] = sys.argv[1] + '/'
  571. if moulin.cheat == 1:
  572. moulin.get_user()
  573. try:
  574. moulin.scandir(sys.argv[1])
  575. except NameError:
  576. print("Usage: norme.py <dir_to_scan>")
  577. if moulin.score:
  578. print(moulin.note, file=sys.stderr)
  579.  
  580. if __name__ == "__main__":
  581. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement