checkfiles.pl 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #!/usr/bin/perl
  2. # You may redistribute this program and/or modify it under the terms of
  3. # the GNU General Public License as published by the Free Software Foundation,
  4. # either version 3 of the License, or (at your option) any later version.
  5. #
  6. # This program is distributed in the hope that it will be useful,
  7. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. # GNU General Public License for more details.
  10. #
  11. # You should have received a copy of the GNU General Public License
  12. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. use strict;
  14. use warnings;
  15. my $lineInfo;
  16. my $ignore;
  17. my $header = <<EOF;
  18. /* vim: set expandtab ts=4 sw=4: */
  19. /*
  20. * You may redistribute this program and/or modify it under the terms of
  21. * the GNU General Public License as published by the Free Software Foundation,
  22. * either version 3 of the License, or (at your option) any later version.
  23. *
  24. * This program is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. * GNU General Public License for more details.
  28. *
  29. * You should have received a copy of the GNU General Public License
  30. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  31. */
  32. EOF
  33. my @headerArray = split("\n", $header);
  34. sub error {
  35. if (!$ignore) {
  36. print $lineInfo . ' ' . $_[0] . "\n";
  37. }
  38. };
  39. my $now = time;
  40. sub parse_file {
  41. my $fileName = shift;
  42. # Anything older than 24 hours gets a pass.
  43. if ((stat($fileName))[10] < $now - (3600 * 24)) { return; }
  44. #print "$fileName\n";
  45. $fileName =~ /^.*\/(.*)\..*$/ or die;
  46. my $name = $1;
  47. open my $file, "$fileName" or die $!;
  48. my $parenthCount = 0;
  49. my $functionParenthCount = 0;
  50. my $expectBracket = 0;
  51. while (my $line = <$file>) {
  52. chomp($line);
  53. my $lineNum = $.;
  54. $lineInfo = "$fileName:" . ($lineNum);
  55. #print "$line\n";
  56. if ($lineNum < scalar(@headerArray) + 1) {
  57. my $expectedLine = $headerArray[$lineNum - 1];
  58. if (index($line, $expectedLine) == -1) {
  59. error("missing header\n$expectedLine\n$line");
  60. }
  61. } elsif ($fileName =~ /\.h$/ && $lineNum < scalar(@headerArray) + 2) {
  62. if ($line !~ /^#ifndef ${name}_H$/) {
  63. error("expected #ifndef ${name}_H found ${line}");
  64. }
  65. } elsif ($fileName =~ /\.h$/ && $lineNum < scalar(@headerArray) + 3) {
  66. if ($line !~ /^#define ${name}_H$/) {
  67. error("expected #define ${name}_H found ${line}");
  68. }
  69. }
  70. $ignore = ($line =~ /CHECKFILES_IGNORE/);
  71. if ($expectBracket == 1) {
  72. $expectBracket = 0;
  73. if ($line !~ /^[\s]*{/) {
  74. error("expecting a { bracket " . $line);
  75. }
  76. }
  77. if (!($fileName =~ /_test/)) {
  78. my $n = $name;
  79. if ($name =~ /^W32(.*)$/) {
  80. $n = $1;
  81. }
  82. # implementations.. TUNConfigurator_Linux contains TUNConfigurator_doStuff...
  83. if ($name =~ /^([^_]*)_.*$/) {
  84. $n = $1;
  85. }
  86. if ($line =~ /^\w+\s.*\(/) {
  87. if (!($line =~ /^int main\(/
  88. || $line =~ / ${n}/
  89. || $line =~ /^[ ]?static /))
  90. {
  91. error("all globally visible functions must begin with the name of the file.");
  92. }
  93. }
  94. }
  95. if ($functionParenthCount > 0 || $line =~ /^\w+\s.*(\(.*)$/) {
  96. my $txt = ($functionParenthCount > 0) ? $line : $1;
  97. $functionParenthCount += (($txt =~ tr/(//) - ($txt =~ tr/)//));
  98. if ($functionParenthCount == 0) {
  99. $txt = substr($txt, rindex($txt, ')') + 1);
  100. if ($txt =~ /{/) {
  101. error("please put the opening bracket on the next line.");
  102. }
  103. }
  104. }
  105. if ($line =~ /[\w]*int[\w]*\s+\*+\w/ || $line =~ /[\w]*struct\s+[\w]+\s+\*+\w/) {
  106. error("int* blah; means int pointer named blah, int *blah; means int names splatblah");
  107. }
  108. if (length($line) > 100) {
  109. error("cjd's editor window is only 100 characters wide");
  110. }
  111. if ($fileName =~ /\.h$/ && !($fileName =~ /util\/platform\/libc\//)) {
  112. my $n = $name;
  113. # If the name is CryptoAuth_pvt.h, it's ok to make a structure called CryptoAuth
  114. if ($name =~ /^(.*)_pvt$/) { $n = $1; }
  115. if ($name =~ /^(.*)_impl$/) { $n = $1; }
  116. if ($line =~ /^struct / && !($line =~ /^struct ${n}/) && !($line =~ /\(/)) {
  117. error("all structures must begin with the name of the file.");
  118. }
  119. if ($line =~ /#define / && $line !~ /#define $n/) {
  120. error("all defines must begin with the name of the file.");
  121. }
  122. }
  123. if ($line =~ /\t/) {
  124. error("tabs are not allowed, use 4 spaces.");
  125. }
  126. if ($line =~ /\s$/) {
  127. error("trailing whitespace.");
  128. }
  129. if ($line =~ /(if|for|while)\(/) {
  130. error("If/for/while statements must be followed by whitespace.");
  131. }
  132. if ($parenthCount > 0 || $line =~ /[^\w#](if|for|while) (\(.*$)/) {
  133. my $txt = ($parenthCount > 0) ? $line : $2;
  134. $parenthCount += (($txt =~ tr/(//) - ($txt =~ tr/)//));
  135. if ($parenthCount == 0) {
  136. $txt = substr($txt, rindex($txt, ')') + 1);
  137. # for (x; y; z) ;
  138. # is not an unbracketed block.
  139. if ($txt !~ /^[\s]*;$/ && $txt !~ /^[\s]+{$/ && $txt !~ /^[\s]+{[\s]*\\$/) {
  140. if ($txt =~ /[\s]*$/) {
  141. $expectBracket = 1;
  142. } else {
  143. error($parenthCount . ' ' . $line);
  144. }
  145. }
  146. }
  147. }
  148. }
  149. close($file);
  150. }
  151. sub add_dir {
  152. my $dir = shift;
  153. opendir(DIR, $dir) or die $!;
  154. my @f = grep { !/^\.{1,2}$/ } readdir (DIR);
  155. closedir(DIR);
  156. @f = grep {!/^build/} @f;
  157. @f = grep {!/^.git/} @f;
  158. @f = map { $dir . '/' . $_ } @f;
  159. for my $file (@f) {
  160. if (-d $file) {
  161. add_dir($file);
  162. } elsif ($file =~ /\.[ch]$/) {
  163. #print "$file\n";
  164. parse_file($file);
  165. }
  166. }
  167. }
  168. add_dir('.');