stylecheck.pl 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use File::Basename;
  5. # Desired indentation.
  6. my $indentation = 2;
  7. if ($#ARGV != 0) {
  8. print "\nUsage: stylecheck.pl source\n";
  9. exit;
  10. }
  11. my $source = $ARGV[0];
  12. open(my $in, "<", $source) or die "Can't open source: $!";
  13. my $lineno = 0;
  14. my @c_source = <$in>;
  15. my $filename = $source;
  16. $filename =~ y/\\/\//;
  17. $filename = basename($filename);
  18. my $i_level = 0;
  19. my $c_comment = "";
  20. my $state = "start";
  21. my $cr = "\r";
  22. my $lf = "\n";
  23. my $tab = "\t";
  24. my $f_lineno = 0;
  25. my $f_params = "";
  26. my $t_lineno = 0;
  27. my $t_type = "";
  28. my $e_lineno = 0;
  29. my $e_name = "";
  30. my $d_lineno = 0;
  31. my $d_name = "";
  32. my $d_name2 = "";
  33. my $d_name_app = "";
  34. my $scope = "";
  35. sub style {
  36. my $desc = shift;
  37. print("style: $desc at line $lineno in \"$filename\"\n");
  38. }
  39. sub error {
  40. my $desc = shift;
  41. print("error: $desc at line $lineno in \"$filename\"\n");
  42. }
  43. # Indentation check.
  44. sub check_indentation {
  45. shift =~ /^(\s*)/;
  46. if (length($1) != $i_level) {
  47. style "indentation violation";
  48. }
  49. }
  50. my $emptycnt = 0;
  51. foreach my $line (@c_source) {
  52. $lineno += 1;
  53. #****************************************************************************
  54. # Check on EOL.
  55. if (not ($line =~ /$cr$lf$/)) {
  56. error "detected malformed EOL";
  57. }
  58. $line =~ s/$cr//;
  59. $line =~ s/$lf//;
  60. #****************************************************************************
  61. # Check on trailing spaces.
  62. if ($line =~ /\s$/) {
  63. style "detected trailing spaces";
  64. }
  65. #****************************************************************************
  66. # Check on TABs.
  67. if ($line =~ /$tab/) {
  68. style "detected TAB";
  69. $line =~ s/$tab/ /;
  70. }
  71. #****************************************************************************
  72. # Check on empty lines.
  73. my $tmp = $line;
  74. $tmp =~ s/\s//;
  75. if (length($tmp) == 0) {
  76. $emptycnt = $emptycnt + 1;
  77. if ($emptycnt == 2) {
  78. style "detected multiple empty lines"
  79. }
  80. next;
  81. }
  82. else {
  83. $emptycnt = 0;
  84. }
  85. #****************************************************************************
  86. # Stripping strings content for ease of parsing, all strings become _string_.
  87. $line =~ s/\\\"//;
  88. if ($line =~ s/(\"[^"]*\")/_string_/) {
  89. # print "string: $1 replaced by _string_\n";
  90. }
  91. #******************************************************************************
  92. # State machine handling.
  93. if ($state eq "start") {
  94. # Searching for a global code element or a comment start.
  95. # Indentation check.
  96. check_indentation $line;
  97. #******************************************************************************
  98. # Functions matching, triggered by the "(".
  99. if ($line =~ /^(static|)\s*(struct|union|)\s*([a-zA-Z_][a-zA-Z0-9_]*\s*[*]*)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/) {
  100. # $1=scope $2$3=return type $4=name
  101. $line =~ s/^(static|)\s*(struct|union|)\s*([a-zA-Z_][a-zA-Z0-9_]*\s*[*]*)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\(//;
  102. # print "function: " . $1 . " " . $2 . " " . $3 . " " . $4 . "(";
  103. # Size of the match up to parameters.
  104. my $size = $+[0] - $-[0];
  105. # Function line number.
  106. $f_lineno = $lineno;
  107. # Checking if all parameters are on the same line.
  108. if ($line =~ /.*\)\s*{\s*$/) {
  109. $line =~ s/\)\s*{\s*$//;
  110. # print $line . "\n";
  111. $f_params = $line;
  112. $i_level = $indentation;
  113. $state = "infunc";
  114. }
  115. else {
  116. # print $line;
  117. $f_params = $line;
  118. $i_level = $size;
  119. $state = "inparams";
  120. }
  121. }
  122. #******************************************************************************
  123. # Structures matching.
  124. elsif ($line =~ /^\s*struct\s+([a-zA-Z_][a-zA-Z0-9_]*)/) {
  125. }
  126. #******************************************************************************
  127. # Single line "typedef" matching.
  128. elsif ($line =~ /^\s*typedef\s+([\sa-zA-Z0-9_]*\*+)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*;\s*$/ or
  129. $line =~ /^\s*typedef\s+([\sa-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*;\s*$/) {
  130. }
  131. #******************************************************************************
  132. # Single line "typedef function" matching.
  133. elsif ($line =~ /^\s*typedef\s+.*\(\s*\*\s*([a-zA-Z0-9_]*)\s*\)\(/) {
  134. }
  135. #******************************************************************************
  136. # Multi line "typedef struct" matching.
  137. elsif ($line =~ /^\s*typedef\s*struct\s*([a-zA-Z_][a-zA-Z0-9_]*|\s?)?/) {
  138. $t_lineno = $lineno;
  139. $t_type = "struct " . $1;
  140. $state = "intypedef";
  141. }
  142. #******************************************************************************
  143. # Multi line "typedef enum" matching.
  144. elsif ($line =~ /^\s*typedef\s*enum\s*([a-zA-Z_][a-zA-Z0-9_]*|\s?)?/) {
  145. $t_lineno = $lineno;
  146. $t_type = "enum " . $1;
  147. if ($line =~ /([a-zA-Z_][a-zA-Z0-9_]*)\s*;\s*$/) {
  148. # Special case of a single-line typedef enum.
  149. }
  150. else {
  151. $state = "intypedef";
  152. }
  153. }
  154. #******************************************************************************
  155. # Multi line "enum" matching.
  156. elsif ($line =~ /^\s*enum\s*([a-zA-Z_][a-zA-Z0-9_]*)/) {
  157. $e_name = $1;
  158. $e_lineno = $lineno;
  159. if ($line =~ /;\s*$/) {
  160. # Special case of a single-line enum.
  161. }
  162. else {
  163. $state = "inenum";
  164. }
  165. }
  166. #******************************************************************************
  167. # Struct variable matching.
  168. elsif ($line =~ /^\s*(static|)\s+([\sa-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*\[.*\]|[a-zA-Z_][a-zA-Z0-9_]*)\s*(;\s*$|=)/ or
  169. $line =~ /^\s*(static|)\s+([\sa-zA-Z0-9_]*\*+)\s*([a-zA-Z_][a-zA-Z0-9_]*\[.*\]|[a-zA-Z_][a-zA-Z0-9_]*)\s*(;\s*$|=)/) {
  170. }
  171. #******************************************************************************
  172. # Variable matching.
  173. elsif ($line =~ /^\s*(static|).*\s+([a-zA-Z_][a-zA-Z0-9_]*\s*\*+|[a-zA-Z_][a-zA-Z0-9_]*)\s*([a-zA-Z_][a-zA-Z0-9_]*\[.*\]|[a-zA-Z_][a-zA-Z0-9_]*)\s*(;\s*$|=)/) {
  174. # variable declaration.
  175. }
  176. #******************************************************************************
  177. # #nclude matching.
  178. elsif ($line =~ /^\s*#include\s+"([^"]+)"/) {
  179. }
  180. #******************************************************************************
  181. # #if matching.
  182. elsif ($line =~ /^\s*#if\s+(.+)/) {
  183. }
  184. #******************************************************************************
  185. # #ifdef matching.
  186. elsif ($line =~ /^\s*#ifdef\s+([\w_]+)/) {
  187. }
  188. #******************************************************************************
  189. # #define matching.
  190. elsif ($line =~ /^\s*#define\s+([\w_]+)\s*(.*)/) {
  191. $d_lineno = $lineno;
  192. $d_name = $1;
  193. $d_name2 = $2;
  194. # enum typedef declaration.
  195. if ($line =~ /[^\\]$/) {
  196. # Special case of a single-line typedef enum.
  197. }
  198. else {
  199. $state = "indefine";
  200. }
  201. }
  202. #******************************************************************************
  203. # Comment start matching.
  204. elsif ("$line" =~ /^\s*\/\*/) {
  205. if ("$line" =~ /\*\//) {
  206. # Special case of single line comments.
  207. $line =~ /^\s*(\/\*.*\*\/)/;
  208. }
  209. else {
  210. # Start of multi-line comment.
  211. $line =~ /(\/\*.*)/;
  212. $c_comment = $1 . " ";
  213. $state = "incomment";
  214. }
  215. }
  216. }
  217. #******************************************************************************
  218. # Scanning for function parameters end and function body begin.
  219. elsif ($state eq "inparams") {
  220. # Indentation check.
  221. check_indentation $line;
  222. if ($line =~ /.*\)\s*{\s*$/) {
  223. # print $line . "\n";
  224. $line =~ s/\)\s*{\s*$//;
  225. $f_params = $f_params . $line;
  226. $i_level = $indentation;
  227. $state = "infunc";
  228. print "$f_params\n";
  229. }
  230. else {
  231. $f_params = $f_params . $line;
  232. # print $line;
  233. }
  234. }
  235. #******************************************************************************
  236. # Scanning for function end.
  237. elsif ($state eq "infunc") {
  238. # Checking for function end, the final "}".
  239. if ($line =~ /^\}/) {
  240. $i_level = 0;
  241. $state = "start";
  242. next;
  243. }
  244. # Indentation check.
  245. check_indentation $line;
  246. if ($line =~ /(\/\*.*\*\/)/) {
  247. # Single line comments inside functions.
  248. }
  249. elsif ("$line" =~ /(\/\*.*)/) {
  250. # Start of multi-line comment inside a function.
  251. $c_comment = $1 . " ";
  252. $state = "infunccomment";
  253. }
  254. }
  255. #******************************************************************************
  256. # Scanning for comment end within a function body.
  257. elsif ($state eq "infunccomment") {
  258. if ("$line" =~ /\*\/\s*$/) {
  259. # End of mult-line comment.
  260. $line =~ /(.*\*\/)/;
  261. $c_comment .= $1;
  262. $state = "infunc";
  263. }
  264. else {
  265. # Add the whole line.
  266. $c_comment .= $line . " ";
  267. }
  268. }
  269. #******************************************************************************
  270. # Scanning for comment end.
  271. elsif ($state eq "incomment") {
  272. if ("$line" =~ /\*\/\s*$/) {
  273. # End of mult-line comment.
  274. $line =~ /(.*\*\/)/;
  275. $c_comment .= $1;
  276. $state = "start";
  277. }
  278. else {
  279. # Add the whole line.
  280. $c_comment .= $line . " ";
  281. }
  282. }
  283. #******************************************************************************
  284. # Scanning for typedef end.
  285. elsif ($state eq "intypedef") {
  286. if ($line =~ /^\s*}\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*;\s*$/) {
  287. # typedef end because the final '} <name>;'.
  288. $state = "start";
  289. }
  290. }
  291. #******************************************************************************
  292. # Scanning for enum end.
  293. elsif ($state eq "inenum") {
  294. if ($line =~ /^\s*}\s*;\s*$/) {
  295. # enum end because the final '};'.
  296. $state = "start";
  297. }
  298. }
  299. #******************************************************************************
  300. # Scanning for define end.
  301. elsif ($state eq "indefine") {
  302. if ($line =~ /[^\\]$/) {
  303. # define end because the final 'not \'.
  304. # remove blank from starting of the line
  305. $line =~ s/^\s+|\s+$//g;
  306. # Add the whole line.
  307. $d_name2 .= $line;
  308. $state = "start";
  309. }
  310. else {
  311. # Add the whole line.
  312. # $line =~ s/^\s+|\s+$//g;
  313. $line =~ s/^\s*(.*?)\s*$/$1/;
  314. $d_name2 .= $line;
  315. }
  316. }
  317. }
  318. close $in or die "$in: $!";