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