summaryrefslogtreecommitdiffstats
path: root/packaging/var-checker
diff options
context:
space:
mode:
Diffstat (limited to 'packaging/var-checker')
-rwxr-xr-xpackaging/var-checker94
1 files changed, 94 insertions, 0 deletions
diff --git a/packaging/var-checker b/packaging/var-checker
new file mode 100755
index 0000000..f17c69a
--- /dev/null
+++ b/packaging/var-checker
@@ -0,0 +1,94 @@
+#!/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]\S*\s+.*);', re.M)
+EXTERNS_RE = re.compile(r'^extern\s+(.*);', re.M)
+
+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'(?<!\sstruct )\b(%s)(?!\w)' % find)
+
+ found = { x: 0 for x in var_list + extern_list }
+ for var in var_re.findall(txt):
+ found[var] += 1
+
+ for var in sorted(var_list + extern_list):
+ if found[var] == 1:
+ vtype = 'var' if var in var_list else 'extern'
+ print(fn, f'has extraneous {vtype}: "{var}"')
+
+
+def slurp_file(fn, drop_externs=False):
+ with open(fn, 'r', encoding='utf-8') as fh:
+ txt = fh.read()
+ if drop_externs:
+ txt = EXTERNS_RE.sub('', txt)
+ return txt
+
+
+def parse_vars(fn, lines):
+ ret = [ ]
+ for line in lines:
+ line = re.sub(r'\s*\{.*\}', '', line)
+ line = re.sub(r'\s*\(.*\)', '', line)
+ for item in re.split(r'\s*,\s*', line):
+ item = re.sub(r'\s*=.*', '', item)
+ m = re.search(r'(?P<var>\w+)(?P<sz>\[.*?\])?$', item)
+ if not m:
+ print(f"Bogus match? ({item})")
+ continue
+ if m['sz']:
+ if m['var'] in sizes:
+ if sizes[m['var']] != m['sz']:
+ 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