tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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;