1#!/usr/bin/env python3 2# 3# american fuzzy lop++ - custom code formatter 4# -------------------------------------------- 5# 6# Written and maintaned by Andrea Fioraldi <andreafioraldi@gmail.com> 7# 8# Copyright 2015, 2016, 2017 Google Inc. All rights reserved. 9# Copyright 2019-2022 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 21import re 22 23# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use 24 25with open(".clang-format") as f: 26 fmt = f.read() 27 28CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN") 29if CLANG_FORMAT_BIN is None: 30 o = 0 31 try: 32 p = subprocess.Popen(["clang-format-11", "--version"], stdout=subprocess.PIPE) 33 o, _ = p.communicate() 34 o = str(o, "utf-8") 35 o = re.sub(r".*ersion ", "", o) 36 # o = o[len("clang-format version "):].strip() 37 o = o[: o.find(".")] 38 o = int(o) 39 except: 40 print("clang-format-11 is needed. Aborted.") 41 exit(1) 42 # if o < 7: 43 # if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0: 44 # CLANG_FORMAT_BIN = 'clang-format-7' 45 # elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0: 46 # CLANG_FORMAT_BIN = 'clang-format-8' 47 # elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0: 48 # CLANG_FORMAT_BIN = 'clang-format-9' 49 # elif subprocess.call(['which', 'clang-format-11'], stdout=subprocess.PIPE) == 0: 50 # CLANG_FORMAT_BIN = 'clang-format-11' 51 # else: 52 # print ("clang-format 7 or above is needed. Aborted.") 53 # exit(1) 54 else: 55 CLANG_FORMAT_BIN = "clang-format-11" 56 57COLUMN_LIMIT = 80 58for line in fmt.split("\n"): 59 line = line.split(":") 60 if line[0].strip() == "ColumnLimit": 61 COLUMN_LIMIT = int(line[1].strip()) 62 63 64def custom_format(filename): 65 p = subprocess.Popen([CLANG_FORMAT_BIN, filename], stdout=subprocess.PIPE) 66 src, _ = p.communicate() 67 src = str(src, "utf-8") 68 69 in_define = False 70 last_line = None 71 out = "" 72 73 for line in src.split("\n"): 74 if line.lstrip().startswith("#"): 75 if line[line.find("#") + 1 :].lstrip().startswith("define"): 76 in_define = True 77 78 if ( 79 "/*" in line 80 and not line.strip().startswith("/*") 81 and line.endswith("*/") 82 and len(line) < (COLUMN_LIMIT - 2) 83 ): 84 cmt_start = line.rfind("/*") 85 line = ( 86 line[:cmt_start] 87 + " " * (COLUMN_LIMIT - 2 - len(line)) 88 + line[cmt_start:] 89 ) 90 91 define_padding = 0 92 if last_line is not None and in_define and last_line.endswith("\\"): 93 last_line = last_line[:-1] 94 define_padding = max(0, len(last_line[last_line.rfind("\n") + 1 :])) 95 96 if ( 97 last_line is not None 98 and last_line.strip().endswith("{") 99 and line.strip() != "" 100 ): 101 line = (" " * define_padding + "\\" if in_define else "") + "\n" + line 102 elif ( 103 last_line is not None 104 and last_line.strip().startswith("}") 105 and line.strip() != "" 106 ): 107 line = (" " * define_padding + "\\" if in_define else "") + "\n" + line 108 elif ( 109 line.strip().startswith("}") 110 and last_line is not None 111 and last_line.strip() != "" 112 ): 113 line = (" " * define_padding + "\\" if in_define else "") + "\n" + line 114 115 if not line.endswith("\\"): 116 in_define = False 117 118 out += line + "\n" 119 last_line = line 120 121 return out 122 123 124args = sys.argv[1:] 125if len(args) == 0: 126 print("Usage: ./format.py [-i] <filename>") 127 print() 128 print(" The -i option, if specified, let the script to modify in-place") 129 print(" the source files. By default the results are written to stdout.") 130 print() 131 exit(1) 132 133in_place = False 134if args[0] == "-i": 135 in_place = True 136 args = args[1:] 137 138for filename in args: 139 code = custom_format(filename) 140 if in_place: 141 with open(filename, "w") as f: 142 f.write(code) 143 else: 144 print(code) 145