1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
#!/usr/bin/env python
# Check the style of WiredTiger C code.
from __future__ import print_function
import fnmatch, os, re, sys
from dist import all_c_files, compare_srcfile, source_files
# Complain if a function comment is missing.
def missing_comment():
for f in source_files():
skip_re = re.compile(r'DO NOT EDIT: automatically built')
func_re = re.compile(
r'(/\*(?:[^\*]|\*[^/])*\*/)?\n\w[\w \*]+\n(\w+)', re.DOTALL)
s = open(f, 'r').read()
if skip_re.search(s):
continue
for m in func_re.finditer(s):
if not m.group(1) or \
not m.group(1).startswith('/*\n * %s --\n' % m.group(2)):
print("%s:%d: missing or malformed comment for %s" % \
(f, s[:m.start(2)].count('\n'), m.group(2)))
# Sort helper function, discard * operators so a pointer doesn't necessarily
# sort before non-pointers, ignore const/static/volatile keywords.
def function_args_alpha(text):
s = text.strip()
s = re.sub("[*]","", s)
s = s.split()
def merge_specifier(words, specifier):
if len(words) > 2 and words[0] == specifier:
words[1] += specifier
words = words[1:]
return words
s = merge_specifier(s, 'const')
s = merge_specifier(s, 'static')
s = merge_specifier(s, 'volatile')
s = ' '.join(s)
return s
# List of illegal types.
illegal_types = [
'u_int16_t',
'u_int32_t',
'u_int64_t',
'u_int8_t',
'u_quad',
'uint '
]
# List of legal types in sort order.
types = [
'struct',
'union',
'enum',
'DIR',
'FILE',
'TEST_',
'WT_',
'wt_',
'DWORD',
'double',
'float',
'intmax_t',
'intptr_t',
'clock_t',
'pid_t',
'pthread_t',
'size_t',
'ssize_t',
'time_t',
'uintmax_t',
'uintptr_t',
'u_long',
'long',
'uint64_t',
'int64_t',
'uint32_t',
'int32_t',
'uint16_t',
'int16_t',
'uint8_t',
'int8_t',
'u_int',
'int',
'u_char',
'char',
'bool',
'va_list',
'void '
]
# Return the sort order of a variable declaration, or no-match.
# This order isn't defensible: it's roughly how WiredTiger looked when we
# settled on a style, and it's roughly what the KNF/BSD styles look like.
def function_args(name, line):
line = line.strip()
line = re.sub("^const ", "", line)
line = re.sub("^static ", "", line)
line = re.sub("^volatile ", "", line)
# Let WT_ASSERT, WT_UNUSED and WT_RET terminate the parse. They often appear
# at the beginning of the function and looks like a WT_XXX variable
# declaration.
if re.search('^WT_ASSERT', line):
return False,0
if re.search('^WT_UNUSED', line):
return False,0
if re.search('^WT_RET', line):
return False,0
# Let lines not terminated with a semicolon terminate the parse, it means
# there's some kind of interesting line split we probably can't handle.
if not re.search(';$', line):
return False,0
# Check for illegal types.
for m in illegal_types:
if re.search('^' + m + "\s*[\w(*]", line):
print(name + ": illegal type: " + line.strip(), file=sys.stderr)
sys.exit(1)
# Check for matching types.
for n,m in enumerate(types, 0):
# Don't list '{' as a legal character in a declaration, that's what
# prevents us from sorting inline union/struct declarations.
if re.search('^' + m + "\s*[\w(*]", line):
return True,n
return False,0
# Put function arguments in correct sort order.
def function_declaration():
tmp_file = '__tmp'
for name in all_c_files():
skip_re = re.compile(r'DO NOT EDIT: automatically built')
s = open(name, 'r').read()
if skip_re.search(s):
continue
# Read through the file, and for each function, do a style pass over
# the local declarations. Quit tracking declarations as soon as we
# find anything we don't understand, leaving it untouched.
with open(name, 'r') as f:
tfile = open(tmp_file, 'w')
tracking = False
for line in f:
if not tracking:
tfile.write(line)
if re.search('^{$', line):
list = [[] for i in range(len(types))]
static_list = [[] for i in range(len(types))]
tracking = True;
continue
found,n = function_args(name, line)
if found:
# List statics first.
if re.search("^\s+static", line):
static_list[n].append(line)
continue
# Disallow assignments in the declaration. Ignore braces
# to allow automatic array initialization using constant
# initializers (and we've already skipped statics, which
# are also typically initialized in the declaration).
if re.search("\s=\s[-\w]", line):
print(name + ": assignment in string: " + line.strip(),\
file=sys.stderr)
sys.exit(1);
list[n].append(line)
else:
# Sort the resulting lines (we don't yet sort declarations
# within a single line). It's two passes, first to catch
# the statics, then to catch everything else.
for arg in filter(None, static_list):
for p in sorted(arg, key=function_args_alpha):
tfile.write(p)
for arg in filter(None, list):
for p in sorted(arg, key=function_args_alpha):
tfile.write(p)
tfile.write(line)
tracking = False
continue
tfile.close()
compare_srcfile(tmp_file, name)
# Report missing function comments.
missing_comment()
# Update function argument declarations.
function_declaration()
|