checkSpace.pl (8689B)
1 #!/usr/bin/perl 2 3 use strict; 4 use warnings; 5 6 my $found = 0; 7 my $COLON_POS = 10; 8 9 sub msg { 10 $found = 1; 11 my $v = shift; 12 $v =~ /^\s*([^:]+):(.*)$/; 13 chomp(my $errtype = $1); 14 my $rest = $2; 15 my $padding = ' ' x ($COLON_POS - length $errtype); 16 print "$padding$errtype:$rest\n"; 17 } 18 19 my $C = 0; 20 21 if ($ARGV[0] =~ /^-/) { 22 my $lang = shift @ARGV; 23 $C = ($lang eq '-C'); 24 } 25 26 # hashmap of things where we allow spaces between them and (. 27 our %allow_space_after= map {$_, 1} qw{ 28 if while for switch return int unsigned elsif WINAPI 29 void __attribute__ op size_t double uint64_t 30 bool ssize_t 31 workqueue_reply_t hs_desc_decode_status_t 32 PRStatus 33 SMARTLIST_FOREACH_BEGIN SMARTLIST_FOREACH_END 34 HT_FOREACH 35 DIGESTMAP_FOREACH_MODIFY DIGESTMAP_FOREACH 36 DIGEST256MAP_FOREACH_MODIFY DIGEST256MAP_FOREACH 37 STRMAP_FOREACH_MODIFY STRMAP_FOREACH 38 SDMAP_FOREACH EIMAP_FOREACH RIMAP_FOREACH 39 MAP_FOREACH_MODIFY MAP_FOREACH 40 TOR_SIMPLEQ_FOREACH TOR_SIMPLEQ_FOREACH_SAFE 41 TOR_LIST_FOREACH TOR_LIST_FOREACH_SAFE 42 TOR_SLIST_FOREACH TOR_SLIST_FOREACH_SAFE 43 }; 44 45 our %basenames = (); 46 47 our %guardnames = (); 48 49 for my $fn (@ARGV) { 50 open(F, "$fn"); 51 my $lastnil = 0; 52 my $lastline = ""; 53 my $incomment = 0; 54 my $in_func_head = 0; 55 my $basename = $fn; 56 $basename =~ s#.*/##; 57 if ($basenames{$basename}) { 58 msg "dup fname:$fn (same as $basenames{$basename}).\n"; 59 } else { 60 $basenames{$basename} = $fn; 61 } 62 my $isheader = ($fn =~ /\.h/); 63 my $seenguard = 0; 64 my $guardname = "<none>"; 65 66 while (<F>) { 67 ## Warn about windows-style newlines. 68 # (We insist on lines that end with a single LF character, not 69 # CR LF.) 70 if (/\r/) { 71 msg "CR:$fn:$.\n"; 72 } 73 ## Warn about tabs. 74 # (We only use spaces) 75 if (/\t/) { 76 msg "TAB:$fn:$.\n"; 77 } 78 ## Warn about labels that don't have a space in front of them 79 # (We indent every label at least one space) 80 #if (/^[a-zA-Z_][a-zA-Z_0-9]*:/) { 81 # msg "nosplabel:$fn:$.\n"; 82 #} 83 ## Warn about trailing whitespace. 84 # (We don't allow whitespace at the end of the line; make your 85 # editor highlight it for you so you can stop adding it in.) 86 if (/ +$/) { 87 msg "Space\@EOL:$fn:$.\n"; 88 } 89 ## Warn about control keywords without following space. 90 # (We put a space after every 'if', 'while', 'for', 'switch', etc) 91 if ($C && /\s(?:if|while|for|switch)\(/) { 92 msg "KW(:$fn:$.\n"; 93 } 94 ## Warn about #else #if instead of #elif. 95 # (We only allow #elif) 96 if (($lastline =~ /^\# *else/) and ($_ =~ /^\# *if/)) { 97 msg "#else#if:$fn:$.\n"; 98 } 99 ## Warn about some K&R violations 100 # (We use K&R-style C, where open braces go on the same line as 101 # the statement that introduces them. In other words: 102 # if (a) { 103 # stuff; 104 # } else { 105 # other stuff; 106 # } 107 if (/^\s+\{/ and $lastline =~ /^\s*(if|while|for|else if)/ and 108 $lastline !~ /\{$/) { 109 msg "non-K&R {:$fn:$.\n"; 110 } 111 if (/^\s*else/ and $lastline =~ /\}$/) { 112 msg "}\\nelse:$fn:$.\n"; 113 } 114 $lastline = $_; 115 ## Warn about unnecessary empty lines. 116 # (Don't put an empty line before a line that contains nothing 117 # but a closing brace.) 118 if ($lastnil && /^\s*}\n/) { 119 msg "UnnecNL:$fn:$.\n"; 120 } 121 ## Warn about multiple empty lines. 122 # (At most one blank line in a row.) 123 if ($lastnil && /^$/) { 124 msg "DoubleNL:$fn:$.\n"; 125 } elsif (/^$/) { 126 $lastnil = 1; 127 } else { 128 $lastnil = 0; 129 } 130 ## Terminals are still 80 columns wide in my world. I refuse to 131 ## accept double-line lines. 132 # (Don't make lines wider than 80 characters, including newline.) 133 if (/^.{80}/ and not /LCOV_EXCL/) { 134 msg "Wide:$fn:$.\n"; 135 } 136 ### Juju to skip over comments and strings, since the tests 137 ### we're about to do are okay there. 138 if ($C) { 139 if ($incomment) { 140 if (m!\*/!) { 141 s!.*?\*/!!; 142 $incomment = 0; 143 } else { 144 next; 145 } 146 } 147 148 if ($isheader) { 149 if ($seenguard == 0) { 150 if (/^\s*\#\s*ifndef\s+(\S+)/) { 151 ++$seenguard; 152 $guardname = $1; 153 } 154 } elsif ($seenguard == 1) { 155 if (/^\s*\#\s*define (\S+)/) { 156 ++$seenguard; 157 if ($1 ne $guardname) { 158 msg "GUARD:$fn:$.: Header guard macro mismatch.\n"; 159 } 160 } 161 } 162 } 163 164 if (m!/\*.*?\*/!) { 165 s!\s*/\*.*?\*/!!; 166 } elsif (m!/\*!) { 167 s!\s*/\*!!; 168 $incomment = 1; 169 next; 170 } 171 s!"(?:[^\"]+|\\.)*"!"X"!g; 172 next if /^\#/; 173 ## Skip C++-style comments. 174 if (m!//!) { 175 # msg "//:$fn:$.\n"; 176 s!//.*!!; 177 } 178 ## Warn about unquoted braces preceded by unexpected character. 179 if (/([^\s'\)\(\{])\{/) { 180 msg "$1\{:$fn:$.\n"; 181 } 182 ## Warn about double semi-colons at the end of a line. 183 if (/;;$/) { 184 msg ";;:$fn:$.\n" 185 } 186 ## Warn about multiple internal spaces. 187 #if (/[^\s,:]\s{2,}[^\s\\=]/) { 188 # msg "X X:$fn:$.\n"; 189 #} 190 ## Warn about { with stuff after. 191 #s/\s+$//; 192 #if (/\{[^\}\\]+$/) { 193 # msg "{X:$fn:$.\n"; 194 #} 195 ## Warn about function calls with space before parens. 196 # (Don't put a space between the name of a function and its 197 # arguments.) 198 if (/(\w+)\s\(([A-Z]*)/) { 199 if (! $allow_space_after{$1} && $2 ne 'WINAPI') { 200 msg "fn ():$fn:$.\n"; 201 } 202 } 203 ## Warn about functions not declared at start of line. 204 # (When you're declaring functions, put "static" and "const" 205 # and the return type on one line, and the function name at 206 # the start of a new line.) 207 if ($in_func_head || 208 ($fn !~ /\.h$/ && /^[a-zA-Z0-9_]/ && 209 ! /^(?:const |static )*(?:typedef|struct|union)[^\(]*$/ && 210 ! /= *\{$/ && ! /;$/) && ! /^[a-zA-Z0-9_]+\s*:/) { 211 if (/[^,\s]\s*\{$/){ 212 msg "fn() {:$fn:$.\n"; 213 $in_func_head = 0; 214 } elsif (/^\S[^\(]* +\**[a-zA-Z0-9_]+\(/) { 215 $in_func_head = -1; # started with tp fn 216 } elsif (/;$/) { 217 $in_func_head = 0; 218 } elsif (/\{/) { 219 if ($in_func_head == -1) { 220 msg "tp fn():$fn:$.\n"; 221 } 222 $in_func_head = 0; 223 } 224 } 225 226 ## Check for forbidden functions except when they are 227 # explicitly permitted 228 if (/\bassert\(/ && not /assert OK/) { 229 msg "assert:$fn:$. (use tor_assert)\n"; 230 } 231 if (/\bmemcmp\(/ && not /memcmp OK/) { 232 msg "memcmp:$fn:$. (use {tor,fast}_mem{eq,neq,cmp}\n"; 233 } 234 # always forbidden. 235 if (not /\ OVERRIDE\ /) { 236 if (/\bstrcat\(/ or /\bstrcpy\(/ or /\bsprintf\(/) { 237 msg "$&:$fn:$.\n"; 238 } 239 if (/\bmalloc\(/ or /\bfree\(/ or /\brealloc\(/ or 240 /\bstrdup\(/ or /\bstrndup\(/ or /\bcalloc\(/) { 241 msg "$&:$fn:$. (use tor_malloc, tor_free, etc)\n"; 242 } 243 } 244 } 245 } 246 if ($isheader && $C) { 247 if ($seenguard < 2) { 248 msg "noguard:$fn (No #ifndef/#define header guard pair found)\n"; 249 } elsif ($guardnames{$guardname}) { 250 msg "dupguard:$fn (Guard macro $guardname also used in $guardnames{$guardname})\n"; 251 } else { 252 $guardnames{$guardname} = $fn; 253 } 254 } 255 close(F); 256 } 257 258 exit $found;