#!/usr/bin/env -S python3 -B # This script checks the *.c files for extraneous "extern" variables, # for vars that are defined but not used, and for inconsistent array # sizes. Run it from inside the main rsync directory. import os, sys, re, argparse, glob VARS_RE = re.compile(r'^(?!(?:extern|enum)\s)([a-zA-Z][^ \n\t:]*\s+.*);', re.M) EXTERNS_RE = re.compile(r'^extern\s+(.*);', re.M) types = { } sizes = { } def main(): add_syscall_c = set('t_stub.c t_unsafe.c tls.c trimslash.c'.split()) add_util_c = set('t_stub.c t_unsafe.c'.split()) if not os.path.exists('syscall.c'): if os.path.exists('var-checker'): os.chdir('..') else: print("Couldn't find the source dir.") sys.exit(1) syscall_c = slurp_file('syscall.c', True) util_c = slurp_file('util1.c', True) for fn in sorted(glob.glob('*.c')): txt = slurp_file(fn) var_list = parse_vars(fn, VARS_RE.findall(txt)) extern_list = parse_vars(fn, EXTERNS_RE.findall(txt)) if not var_list and not extern_list: continue if fn in add_syscall_c: txt += syscall_c if fn in add_util_c: txt += util_c txt = re.sub(r'INFO_GTE', 'info_levels ', txt) txt = re.sub(r'DEBUG_GTE', 'debug_levels ', txt) txt = re.sub(r'SIGACTION\(', 'sigact (', txt) find = '|'.join([ re.escape(x) for x in var_list + extern_list ]) var_re = re.compile(r'(?[^\[,]+?)(?P\w+([\[,].+)?)$', line) if not m: print(f"Bogus match? ({line})") continue items = m['vars'] main_type = m['type'].strip() mt_len = len(main_type) main_type = main_type.rstrip('*') first_stars = '*' * (mt_len - len(main_type)) if first_stars: main_type = main_type.rstrip() items = first_stars + items for item in re.split(r'\s*,\s*', items): m = re.search(r'(?P\*+\s*)?(?P\w+)(?P\[.*?\])?$', item) if not m: print(f"Bogus match? ({item})") continue typ = main_type if m['stars']: typ = typ + m['stars'].strip() chk = [ 'type', typ, types, 'size', m['sz'], sizes, ] while chk: label = chk.pop(0) new = chk.pop(0) lst = chk.pop(0) if label == 'type': new = ' '.join(new.split()).replace(' *', '*') if m['var'] in lst: old = lst[m['var']] if new != old: var = m['var'] print(fn, f'has inconsistent {label} for "{var}":', new, 'vs', old) else: lst[m['var']] = new 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