checksrc.pl 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #!/usr/bin/perl
  2. #***************************************************************************
  3. # _ _ ____ _
  4. # Project ___| | | | _ \| |
  5. # / __| | | | |_) | |
  6. # | (__| |_| | _ <| |___
  7. # \___|\___/|_| \_\_____|
  8. #
  9. # Copyright (C) 2011 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  10. #
  11. # This software is licensed as described in the file COPYING, which
  12. # you should have received as part of this distribution. The terms
  13. # are also available at http://curl.haxx.se/docs/copyright.html.
  14. #
  15. # You may opt to use, copy, modify, merge, publish, distribute and/or sell
  16. # copies of the Software, and permit persons to whom the Software is
  17. # furnished to do so, under the terms of the COPYING file.
  18. #
  19. # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  20. # KIND, either express or implied.
  21. #
  22. ###########################################################################
  23. my $max_column = 79;
  24. my $indent = 2;
  25. my $warnings;
  26. my $errors;
  27. my $file;
  28. my $dir=".";
  29. my $wlist;
  30. sub checkwarn {
  31. my ($num, $col, $file, $line, $msg, $error) = @_;
  32. my $w=$error?"error":"warning";
  33. if($w) {
  34. $warnings++;
  35. }
  36. else {
  37. $errors++;
  38. }
  39. $col++;
  40. print "$file:$num:$col: $w: $msg\n";
  41. print " $line\n";
  42. if($col < 80) {
  43. my $pref = (' ' x $col);
  44. print "${pref}^\n";
  45. }
  46. }
  47. $file = shift @ARGV;
  48. while(1) {
  49. if($file =~ /-D(.*)/) {
  50. $dir = $1;
  51. $file = shift @ARGV;
  52. next;
  53. }
  54. elsif($file =~ /-W(.*)/) {
  55. $wlist .= " $1 ";
  56. $file = shift @ARGV;
  57. next;
  58. }
  59. last;
  60. }
  61. if(!$file) {
  62. print "checksrc.pl [option] <file1> [file2] ...\n";
  63. print " Options:\n";
  64. print " -D[DIR] Directory to prepend file names\n";
  65. print " -W[file] Whitelist the given file - ignore all its flaws\n";
  66. exit;
  67. }
  68. do {
  69. if("$wlist" !~ / $file /) {
  70. my $fullname = $file;
  71. $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/');
  72. scanfile($fullname);
  73. }
  74. $file = shift @ARGV;
  75. } while($file);
  76. sub scanfile {
  77. my ($file) = @_;
  78. my $line = 1;
  79. my $prevl;
  80. my $l;
  81. open(R, "<$file") || die "failed to open $file";
  82. my $copyright=0;
  83. while(<R>) {
  84. chomp;
  85. my $l = $_;
  86. my $column = 0;
  87. # check for a copyright statement
  88. if(!$copyright && ($l =~ /copyright .* \d\d\d\d/i)) {
  89. $copyright=1;
  90. }
  91. # detect long lines
  92. if(length($l) > $max_column) {
  93. checkwarn($line, length($l), $file, $l, "Longer than $max_column columns");
  94. }
  95. # detect TAB characters
  96. if($l =~ /^(.*)\t/) {
  97. checkwarn($line, length($1), $file, $l, "Contains TAB character", 1);
  98. }
  99. # detect trailing white space
  100. if($l =~ /^(.*)[ \t]+\z/) {
  101. checkwarn($line, length($1), $file, $l, "Trailing whitespace");
  102. }
  103. # check spaces after for/if/while
  104. if($l =~ /^(.*)(for|if|while) \(/) {
  105. if($1 =~ / *\#/) {
  106. # this is a #if, treat it differently
  107. }
  108. else {
  109. checkwarn($line, length($1)+length($2), $file, $l,
  110. "$2 with space");
  111. }
  112. }
  113. # check spaces after open paren after for/if/while
  114. if($l =~ /^(.*)(for|if|while)\( /) {
  115. if($1 =~ / *\#/) {
  116. # this is a #if, treat it differently
  117. }
  118. else {
  119. checkwarn($line, length($1)+length($2)+1, $file, $l,
  120. "$2 with space first in condition");
  121. }
  122. }
  123. # check for "} else"
  124. if($l =~ /^(.*)\} *else/) {
  125. checkwarn($line, length($1), $file, $l, "else after closing brace on same line");
  126. }
  127. # check for "){"
  128. if($l =~ /^(.*)\)\{/) {
  129. checkwarn($line, length($1)+1, $file, $l, "missing space after close paren");
  130. }
  131. # scan for use of banned functions
  132. if($l =~ /^(.*\W)(sprintf|vsprintf|strcat|strncat|gets)\s*\(/) {
  133. checkwarn($line, length($1), $file, $l,
  134. "use of $2 is banned");
  135. }
  136. # check for open brace first on line but not first column
  137. # only alert if previous line ended with a close paren and wasn't a cpp
  138. # line
  139. if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) {
  140. checkwarn($line, length($1), $file, $l, "badly placed open brace");
  141. }
  142. # if the previous line starts with if/while/for AND ends with an open
  143. # brace, check that this line is indented $indent more steps, if not
  144. # a cpp line
  145. if($prevl =~ /^( *)(if|while|for)\(.*\{\z/) {
  146. my $first = length($1);
  147. # this line has some character besides spaces
  148. if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) {
  149. my $second = length($1);
  150. my $expect = $first+$indent;
  151. if($expect != $second) {
  152. my $diff = $second - $first;
  153. checkwarn($line, length($1), $file, $l,
  154. "not indented $indent steps, uses $diff)");
  155. }
  156. }
  157. }
  158. $line++;
  159. $prevl = $l;
  160. }
  161. if(!$copyright) {
  162. checkwarn(1, 0, $file, "", "Missing copyright statement", 1);
  163. }
  164. close(R);
  165. }
  166. if($errors || $warnings) {
  167. printf "checksrc: %d errors and %d warnings\n", $errors, $warnings;
  168. exit 5; # return failure
  169. }