xref: /aosp_15_r20/external/AFLplusplus/.custom-format.py (revision 08b48e0b10e97b33e7b60c5b6e2243bd915777f2)
1#!/usr/bin/env python3
2#
3# american fuzzy lop++ - custom code formatter
4# --------------------------------------------
5#
6# Written and maintained by Andrea Fioraldi <[email protected]>
7#
8# Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
9# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
10#
11# Licensed under the Apache License, Version 2.0 (the "License");
12# you may not use this file except in compliance with the License.
13# You may obtain a copy of the License at:
14#
15#   http://www.apache.org/licenses/LICENSE-2.0
16#
17
18import subprocess
19import sys
20import os
21# import re # TODO: for future use
22import shutil
23import importlib.metadata
24
25# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
26
27CURRENT_LLVM = os.getenv('LLVM_VERSION', 17)
28CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
29
30
31def check_clang_format_pip_version():
32    """
33    Check if the correct version of clang-format is installed via pip.
34
35    Returns:
36        bool: True if the correct version of clang-format is installed,
37        False otherwise.
38    """
39    # Check if clang-format is installed
40    if importlib.util.find_spec('clang_format'):
41        # Check if the installed version is the expected LLVM version
42        if importlib.metadata.version('clang-format')\
43                .startswith(str(CURRENT_LLVM)+'.'):
44            return True
45        else:
46            # Return False, because the clang-format version does not match
47            return False
48    else:
49        # If the 'clang_format' package isn't installed, return False
50        return False
51
52
53with open(".clang-format") as f:
54    fmt = f.read()
55
56
57CLANG_FORMAT_PIP = check_clang_format_pip_version()
58
59if shutil.which(CLANG_FORMAT_BIN) is None:
60    CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}"
61
62if shutil.which(CLANG_FORMAT_BIN) is None \
63        and CLANG_FORMAT_PIP is False:
64    print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.")
65    print(f"Run `pip3 install \"clang-format=={CURRENT_LLVM}.*\"` \
66to install via pip.")
67    exit(1)
68
69if CLANG_FORMAT_PIP:
70    CLANG_FORMAT_BIN = shutil.which("clang-format")
71
72COLUMN_LIMIT = 80
73for line in fmt.split("\n"):
74    line = line.split(":")
75    if line[0].strip() == "ColumnLimit":
76        COLUMN_LIMIT = int(line[1].strip())
77
78
79def custom_format(filename):
80    p = subprocess.Popen([CLANG_FORMAT_BIN, filename], stdout=subprocess.PIPE)
81    src, _ = p.communicate()
82    src = str(src, "utf-8")
83
84    in_define = False
85    last_line = None
86    out = ""
87
88    for line in src.split("\n"):
89        if line.lstrip().startswith("#"):
90            if line[line.find("#") + 1:].lstrip().startswith("define"):
91                in_define = True
92
93        if (
94                "/*" in line
95                and not line.strip().startswith("/*")
96                and line.endswith("*/")
97                and len(line) < (COLUMN_LIMIT - 2)
98        ):
99            cmt_start = line.rfind("/*")
100            line = (
101                    line[:cmt_start]
102                    + " " * (COLUMN_LIMIT - 2 - len(line))
103                    + line[cmt_start:]
104            )
105
106        define_padding = 0
107        if last_line is not None and in_define and last_line.endswith("\\"):
108            last_line = last_line[:-1]
109            define_padding = max(0, len(last_line[last_line.rfind("\n") + 1:]))
110
111        if (
112                last_line is not None
113                and last_line.strip().endswith("{")
114                and line.strip() != ""
115        ):
116            line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
117        elif (
118                last_line is not None
119                and last_line.strip().startswith("}")
120                and line.strip() != ""
121        ):
122            line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
123        elif (
124                line.strip().startswith("}")
125                and last_line is not None
126                and last_line.strip() != ""
127        ):
128            line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
129
130        if not line.endswith("\\"):
131            in_define = False
132
133        out += line + "\n"
134        last_line = line
135
136    return out
137
138
139args = sys.argv[1:]
140if len(args) == 0:
141    print("Usage: ./format.py [-i] <filename>")
142    print()
143    print(" The -i option, if specified, let the script to modify in-place")
144    print(" the source files. By default the results are written to stdout.")
145    print()
146    exit(1)
147
148in_place = False
149if args[0] == "-i":
150    in_place = True
151    args = args[1:]
152
153for filename in args:
154    code = custom_format(filename)
155    if in_place:
156        with open(filename, "w") as f:
157            f.write(code)
158    else:
159        print(code)
160