xref: /reactos/sdk/tools/check_packing.py (revision 144e984b)
1'''
2PROJECT:     ReactOS code linter
3LICENSE:     MIT (https://spdx.org/licenses/MIT)
4PURPOSE:     Verifies that there are no headers included where packing is modified
5COPYRIGHT:   Copyright 2021 Mark Jansen <mark.jansen@reactos.org>
6'''
7from pathlib import Path
8import re
9
10DEFAULT_SUFFIXES = [
11    '.cpp', '.cxx', '.cc', '.c', '.idl',
12    '.hpp', '.h', '.inc'
13]
14
15START_HEADERS = [
16    'pshpack1.h',
17    'pshpack2.h',
18    'pshpack4.h',
19    'pshpack8.h',
20]
21
22END_HEADERS = [
23    'poppack.h',
24]
25
26
27def print_error(file, line, text):
28    print(f'{file}({line}): ERROR: {text}')
29
30def print_warning(file, line, text):
31    print(f'{file}({line}): WARNING: {text}')
32
33
34def check_file(filename):
35    cur_packing = []
36    with open (filename, 'rb') as input_file:
37        for line_nr, line in enumerate(input_file):
38            res = re.search(rb'#[\s]*include[\s]+[<"]([^[">]+)[">]', line)
39            if res:
40                header = res.group(1).decode('utf-8')
41                line_nr += 1    # Line numbers start at 1
42                if header in START_HEADERS:
43                    if cur_packing:
44                        print_warning(filename, line_nr, f'Overrides packing from {cur_packing[-1][0]} to {header}')
45                    cur_packing.append([header, line_nr])
46                elif header in END_HEADERS:
47                    if cur_packing:
48                        cur_packing.pop()
49                    else:
50                        print_error(filename, line_nr, f'Unexpected "{header}"')
51                elif cur_packing:
52                    err = f'Include "{header}" while struct packing is modified ({cur_packing[-1][0]})'
53                    print_error(filename, line_nr, err)
54    if cur_packing:
55        print_error(filename, cur_packing[-1][1], 'Struct packing not restored!')
56
57
58def check_packing(path, include_suffixes):
59    global EXCLUDE_SUFFIXES
60    for item in path.iterdir():
61        if item.is_dir() and item.name[0] != '.':
62            check_packing(item, include_suffixes)
63            continue
64        suffix = item.suffix
65        if suffix in include_suffixes:
66            check_file(item)
67
68
69if __name__ == '__main__':
70    # Skip filename and 'sdk/tools'
71    use_path = Path(__file__).parents[2]
72    check_packing(use_path, DEFAULT_SUFFIXES)
73