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