|
version 1.1.1.1, 2012/02/17 15:09:30
|
version 1.1.1.2, 2021/03/17 00:32:36
|
|
Line 1
|
Line 1
|
| #!/usr/bin/perl | #!/usr/bin/env -S python3 -B |
| | |
| # This script checks the *.c files for extraneous "extern" variables, |
# This script checks the *.c files for extraneous "extern" variables, |
| # for vars that are defined but not used, and for inconsistent array |
# for vars that are defined but not used, and for inconsistent array |
| # sizes. Run it from inside the main rsync directory. |
# sizes. Run it from inside the main rsync directory. |
| |
|
| use strict; | import re, argparse, glob |
| use warnings; | |
| |
|
| my %add_syscall_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c tls.c trimslash.c ); | VARS_RE = re.compile(r'^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);', re.M) |
| my %add_compat_c = map { $_ => 1 } qw( t_stub.c tls.c trimslash.c wildtest.c ); | EXTERNS_RE = re.compile(r'^extern\s+(.*);', re.M) |
| my %add_util_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c ); | |
| my %sizes; | |
| |
|
| open(IN, '<', 'syscall.c') or die $!; | sizes = { } |
| undef $/; my $syscall_c = <IN>; $/ = "\n"; | |
| close IN; | |
| $syscall_c =~ s/^extern\s.*//mg; | |
| |
|
| open(IN, '<', 'lib/compat.c') or die $!; | def main(): |
| undef $/; my $compat_c = <IN>; $/ = "\n"; | add_syscall_c = set('t_stub.c t_unsafe.c tls.c trimslash.c'.split()) |
| close IN; | add_util_c = set('t_stub.c t_unsafe.c'.split()) |
| $compat_c =~ s/^extern\s.*//mg; | |
| |
|
| open(IN, '<', 'util.c') or die $!; | syscall_c = slurp_file('syscall.c', True) |
| undef $/; my $util_c = <IN>; $/ = "\n"; | util_c = slurp_file('util.c', True) |
| close IN; | |
| $util_c =~ s/^extern\s.*//mg; | |
| |
|
| my @files = glob('*.c'); | for fn in sorted(glob.glob('*.c')): |
| | txt = slurp_file(fn) |
| |
|
| foreach my $fn (@files) { | var_list = parse_vars(fn, VARS_RE.findall(txt)) |
| open(IN, '<', $fn) or die $!; | extern_list = parse_vars(fn, EXTERNS_RE.findall(txt)) |
| undef $/; $_ = <IN>; $/ = "\n"; | if not var_list and not extern_list: |
| close IN; | continue |
| |
|
| my @vars = /^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);/mg; | if fn in add_syscall_c: |
| my @externs = /^extern\s+(.*);/mg; | txt += syscall_c |
| | if fn in add_util_c: |
| | txt += util_c |
| |
|
| $_ .= $syscall_c if $add_syscall_c{$fn}; | txt = re.sub(r'INFO_GTE', 'info_levels ', txt) |
| $_ .= $compat_c if $add_compat_c{$fn}; | txt = re.sub(r'DEBUG_GTE', 'debug_levels ', txt) |
| $_ .= $util_c if $add_util_c{$fn}; | txt = re.sub(r'SIGACTION\(', 'sigact (', txt) |
| s/INFO_GTE/info_levels/g; | |
| s/DEBUG_GTE/debug_levels/g; | |
| |
|
| check_vars($fn, 'var', @vars); | find = '|'.join([ re.escape(x) for x in var_list + extern_list ]) |
| check_vars($fn, 'extern', @externs); | var_re = re.compile(r'(?<!\sstruct )\b(%s)(?!\w)' % find) |
| } | |
| |
|
| exit; | found = { x: 0 for x in var_list + extern_list } |
| | for var in var_re.findall(txt): |
| | found[var] += 1 |
| |
|
| # The file's contents are in $_. | for var in sorted(var_list + extern_list): |
| sub check_vars | if found[var] == 1: |
| { | vtype = 'var' if var in var_list else 'extern' |
| my $fn = shift; | print(fn, f'has extraneous {vtype}: "{var}"') |
| my $type = shift; | |
| |
|
| foreach my $line (@_) { | |
| $line =~ s/\s*\{.*\}//; | def slurp_file(fn, drop_externs=False): |
| $line =~ s/\s*\(.*\)//; | with open(fn, 'r', encoding='utf-8') as fh: |
| foreach my $item (split(/\s*,\s*/, $line)) { | txt = fh.read() |
| $item =~ s/\s*=.*//; | if drop_externs: |
| my $sz = $item =~ s/(\[.*?\])// ? $1 : ''; | txt = EXTERNS_RE.sub('', txt) |
| my($var) = $item =~ /([^*\s]+)$/; | return txt |
| if (!defined $var) { | |
| print "Bogus match? ($item)\n"; | |
| next; | def parse_vars(fn, lines): |
| } | ret = [ ] |
| if ($sz) { | for line in lines: |
| if (defined $sizes{$var}) { | line = re.sub(r'\s*\{.*\}', '', line) |
| if ($sizes{$var} ne $sz) { | line = re.sub(r'\s*\(.*\)', '', line) |
| print $fn, ' has inconsistent size for "', $var, | for item in re.split(r'\s*,\s*', line): |
| "\": $sizes{$var} vs $sz\n"; | item = re.sub(r'\s*=.*', '', item) |
| } | m = re.search(r'(?P<var>\w+)(?P<sz>\[.*?\])?$', item) |
| } else { | if not m: |
| $sizes{$var} = $sz; | print(f"Bogus match? ({item})") |
| } | continue |
| } | if m['sz']: |
| my @matches = /(?<!\sstruct )\b(\Q$var\E)(?!\w)/g; | if m['var'] in sizes: |
| push(@matches, /(\QSIGACTION(\E)/g) if $var eq 'sigact'; | if sizes[m['var']] != m['sz']: |
| print $fn, " has extraneous $type: \"", $var, "\"\n" if @matches == 1; | var = m['var'] |
| } | print(fn, f'has inconsistent size for "{var}":', m['sz'], 'vs', sizes[var]) |
| } | else: |
| } | sizes[m['var']] = m['sz'] |
| | ret.append(m['var']) |
| | return ret |
| | |
| | |
| | if __name__ == '__main__': |
| | parser = argparse.ArgumentParser(description='Check the *.c files for extraneous extern vars.', add_help=False) |
| | parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") |
| | args = parser.parse_args() |
| | main() |
| | |
| | # vim: sw=4 et ft=python |