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