OLD | NEW |
| (Empty) |
1 #!/usr/bin/python | |
2 # Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 # | |
4 # Use of this source code is governed by a BSD-style license | |
5 # that can be found in the LICENSE file in the root of the source | |
6 # tree. An additional intellectual property rights grant can be found | |
7 # in the file PATENTS. All contributing project authors may | |
8 # be found in the AUTHORS file in the root of the source tree. | |
9 | |
10 """WebRTC reformat script. | |
11 | |
12 This script is used to reformat WebRTC code from the old code style to Google | |
13 C++ code style. This script does not indent code; use clang-reformat-chrome.py | |
14 as described in go/webrtc/engineering/reformatting-gips---google. | |
15 """ | |
16 | |
17 __author__ = 'mflodman@webrtc.org (Magnus Flodman)' | |
18 | |
19 import fnmatch | |
20 import os | |
21 import re | |
22 import subprocess | |
23 import sys | |
24 | |
25 | |
26 def LowerWord(obj): | |
27 """Helper for DeCamelCase.""" | |
28 optional_last_letters = obj.group(3) or '' | |
29 return obj.group(1) + '_' + obj.group(2).lower() + optional_last_letters | |
30 | |
31 | |
32 def DeCamelCase(text): | |
33 """De-camelize variable names. | |
34 | |
35 This function will look at any stringLikeThis and format it in steps. The | |
36 sequence will be stringLikeThis -> string_likeThis -> string_like_this. | |
37 """ | |
38 possible_tokens_before_vars = '[ _*\(\&\!\[]' | |
39 pattern = re.compile(r'(?<=' + possible_tokens_before_vars + ')' + | |
40 # Match some lower-case characters | |
41 '([a-z]+)' + | |
42 # Don't match kFoo, !kFoo, [kFoo], etc | |
43 '(?<!' + possible_tokens_before_vars + 'k)' + | |
44 # Match some upper-case characters | |
45 '([A-Z]+)([a-z])?') | |
46 while re.search(pattern, text): | |
47 text = re.sub(pattern, LowerWord, text) | |
48 return text | |
49 | |
50 | |
51 def MoveUnderScore(text): | |
52 """Moves the underscore from beginning of variable name to the end.""" | |
53 # TODO(mflodman) Replace \1 with ?-expression. | |
54 # We don't want to change macros and #defines though, so don't do anything | |
55 # if the first character is uppercase (normal variables shouldn't have that). | |
56 pattern = r'([ \*\!\&\(\[\]])_(?!_)(?![A-Z])(\w+)' | |
57 return re.sub(pattern, r'\1\2_', text) | |
58 | |
59 | |
60 def PostfixToPrefixInForLoops(text): | |
61 """Converts x++ to ++x in the increment part of a for loop.""" | |
62 pattern = r'(for \(.*;.*;) (\w+)\+\+\)' | |
63 return re.sub(pattern, r'\1++\2)', text) | |
64 | |
65 | |
66 def SortIncludeHeaders(text, filename): | |
67 """Sorts all include headers in alphabetic order. | |
68 | |
69 The file's own header goes first, followed by system headers and then | |
70 project headers. This function will exit if we detect any fancy #ifdef logic | |
71 among the includes - that's a lot harder to sort. | |
72 | |
73 Args: | |
74 text: The file text. | |
75 filename: The file we are reformatting. | |
76 | |
77 Returns: | |
78 The text with includes sorted. | |
79 """ | |
80 # Get all includes in file. | |
81 include_pattern = re.compile('#include.+\n') | |
82 includes = re.findall(include_pattern, text) | |
83 | |
84 # Sort system headers and project headers separately. | |
85 sys_includes = [] | |
86 project_includes = [] | |
87 self_include = '' | |
88 sys_pattern = re.compile('#include <') | |
89 h_filename, _ = os.path.splitext(os.path.basename(filename)) | |
90 | |
91 for item in includes: | |
92 if re.search(h_filename + '\.', item): | |
93 self_include = item | |
94 elif re.search(sys_pattern, item): | |
95 sys_includes.append(item) | |
96 else: | |
97 project_includes.append(item) | |
98 | |
99 sys_includes = sorted(sys_includes) | |
100 project_includes = sorted(project_includes) | |
101 headers = (self_include + '\n' + ''.join(sys_includes) + '\n' + | |
102 ''.join(project_includes)) | |
103 | |
104 # Replace existing headers with the sorted string. | |
105 text_no_hdrs = re.sub(include_pattern, r'???', text) | |
106 | |
107 # Insert sorted headers unless we detect #ifdefs right next to the headers. | |
108 if re.search(r'(#ifdef|#ifndef|#if).*\s*\?{3,}\s*#endif', text_no_hdrs): | |
109 print 'WARNING: Include headers not sorted in ' + filename | |
110 return text | |
111 | |
112 return_text = re.sub(r'\?{3,}', headers, text_no_hdrs, 1) | |
113 if re.search(r'\?{3,}', text_no_hdrs): | |
114 # Remove possible remaining ???. | |
115 return_text = re.sub(r'\?{3,}', r'', return_text) | |
116 | |
117 return return_text | |
118 | |
119 | |
120 def AddPath(match): | |
121 """Helper for adding file path for WebRTC header files, ignoring other.""" | |
122 file_to_examine = match.group(1) + '.h' | |
123 # TODO(mflodman) Use current directory and find webrtc/. | |
124 for path, _, files in os.walk('./webrtc'): | |
125 for filename in files: | |
126 if fnmatch.fnmatch(filename, file_to_examine): | |
127 path_name = os.path.join(path, filename).replace('./', '') | |
128 return '#include "%s"\n' % path_name | |
129 | |
130 # No path found, return original string. | |
131 return '#include "'+ file_to_examine + '"\n' | |
132 | |
133 | |
134 def AddHeaderPath(text): | |
135 """Add path to all included header files that have no path yet.""" | |
136 headers = re.compile('#include "(.+).h"\n') | |
137 return re.sub(headers, AddPath, text) | |
138 | |
139 | |
140 def AddWebrtcToOldSrcRelativePath(match): | |
141 file_to_examine = match.group(1) + '.h' | |
142 path, filename = os.path.split(file_to_examine) | |
143 dirs_in_webrtc = [name for name in os.listdir('./webrtc') | |
144 if os.path.isdir(os.path.join('./webrtc', name))] | |
145 for dir_in_webrtc in dirs_in_webrtc: | |
146 if path.startswith(dir_in_webrtc): | |
147 return '#include "%s"\n' % os.path.join('webrtc', path, filename) | |
148 return '#include "%s"\n' % file_to_examine | |
149 | |
150 def AddWebrtcPrefixToOldSrcRelativePaths(text): | |
151 """For all paths starting with for instance video_engine, add webrtc/.""" | |
152 headers = re.compile('#include "(.+).h"\n') | |
153 return re.sub(headers, AddWebrtcToOldSrcRelativePath, text) | |
154 | |
155 | |
156 def FixIncludeGuards(text, file_name): | |
157 """Change include guard according to the stantard.""" | |
158 # Remove a possible webrtc/ from the path. | |
159 file_name = re.sub(r'(webrtc\/)(.+)', r'\2', file_name) | |
160 new_guard = 'WEBRTC_' + file_name | |
161 new_guard = new_guard.upper() | |
162 new_guard = re.sub(r'([/\.])', r'_', new_guard) | |
163 new_guard += '_' | |
164 | |
165 text = re.sub(r'#ifndef WEBRTC_.+\n', r'#ifndef ' + new_guard + '\n', text, 1) | |
166 text = re.sub(r'#define WEBRTC_.+\n', r'#define ' + new_guard + '\n', text, 1) | |
167 text = re.sub(r'#endif *\/\/ *WEBRTC_.+\n', r'#endif // ' + new_guard + '\n', | |
168 text, 1) | |
169 | |
170 return text | |
171 | |
172 | |
173 def SaveFile(filename, text): | |
174 os.remove(filename) | |
175 f = open(filename, 'w') | |
176 f.write(text) | |
177 f.close() | |
178 | |
179 | |
180 def main(): | |
181 args = sys.argv[1:] | |
182 if not args: | |
183 print 'Usage: %s <filename>' % sys.argv[0] | |
184 sys.exit(1) | |
185 | |
186 for filename in args: | |
187 f = open(filename) | |
188 text = f.read() | |
189 f.close() | |
190 | |
191 text = DeCamelCase(text) | |
192 text = MoveUnderScore(text) | |
193 text = PostfixToPrefixInForLoops(text) | |
194 text = AddHeaderPath(text) | |
195 text = AddWebrtcPrefixToOldSrcRelativePaths(text) | |
196 text = SortIncludeHeaders(text, filename) | |
197 | |
198 # Remove the original file and re-create it with the reformatted content. | |
199 SaveFile(filename, text) | |
200 | |
201 if filename.endswith('.h'): | |
202 f = open(filename) | |
203 text = f.read() | |
204 f.close() | |
205 text = FixIncludeGuards(text, filename) | |
206 SaveFile(filename, text) | |
207 | |
208 print filename + ' done.' | |
209 | |
210 | |
211 if __name__ == '__main__': | |
212 main() | |
OLD | NEW |