blob: e5606fef6bc9c833e8adeafb0f38ce0855ece20c [file] [log] [blame]
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +00001#!/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
12This script is used to reformat WebRTC code from the old code style to Google
phoglund@webrtc.org17238572013-02-15 09:43:20 +000013C++ code style. This script does not indent code; use clang-reformat-chrome.py
14as described in go/webrtc/engineering/reformatting-gips---google.
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000015"""
16
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000017__author__ = 'mflodman@webrtc.org (Magnus Flodman)'
18
19import fnmatch
20import os
21import re
22import subprocess
23import sys
24
25
26def LowerWord(obj):
27 """Helper for DeCamelCase."""
phoglund@webrtc.org943770b2013-01-02 15:46:43 +000028 optional_last_letters = obj.group(3) or ''
29 return obj.group(1) + '_' + obj.group(2).lower() + optional_last_letters
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000030
31
32def DeCamelCase(text):
33 """De-camelize variable names."""
phoglund@webrtc.org943770b2013-01-02 15:46:43 +000034 pattern = re.compile(r'(?<=[ _*\(\&\!])([a-z]+)(?<!k)([A-Z]+)([a-z])?')
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000035 while re.search(pattern, text):
36 text = re.sub(pattern, LowerWord, text)
37 return text
38
39
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000040def MoveUnderScore(text):
41 """Moves the underscore from beginning of variable name to the end."""
42 # TODO(mflodman) Replace \1 with ?-expression.
43 # We don't want to change macros and #defines though, so don't do anything
44 # if the first character is uppercase (normal variables shouldn't have that).
phoglund@webrtc.org943770b2013-01-02 15:46:43 +000045 pattern = r'([ \*\!\&\(\[\]])_(?!_)(?![A-Z])(\w+)'
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000046 return re.sub(pattern, r'\1\2_', text)
47
48
phoglund@webrtc.org943770b2013-01-02 15:46:43 +000049def PostfixToPrefixInForLoops(text):
50 """Converts x++ to ++x in the increment part of a for loop."""
51 pattern = r'(for \(.*;.*;) (\w+)\+\+\)'
52 return re.sub(pattern, r'\1++\2)', text)
53
54
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000055def CPPComments(text):
56 """Remove all C-comments and replace with C++ comments."""
57
58 # Keep the copyright header style.
59 line_list = text.splitlines(True)
60 copyright_list = line_list[0:10]
61 code_list = line_list[10:]
62 copy_text = ''.join(copyright_list)
63 code_text = ''.join(code_list)
64
65 # Remove */ for C-comments, don't care about trailing blanks.
66 comment_end = re.compile(r'\n[ ]*\*/[ ]*')
67 code_text = re.sub(comment_end, '', code_text)
68 comment_end = re.compile(r'\*/')
69 code_text = re.sub(comment_end, '', code_text)
70 # Remove comment lines in the middle of comments, replace with C++ comments.
phoglund@webrtc.org78bec2d2012-12-03 08:48:07 +000071 comment_star = re.compile(r'(?<=\n)[ ]*(?!\*\w)\*[ ]*')
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000072 code_text = re.sub(comment_star, r'// ', code_text)
73 # Remove start of C comment and replace with C++ comment.
74 comment_start = re.compile(r'/\*[ ]*\n')
75 code_text = re.sub(comment_start, '', code_text)
76 comment_start = re.compile(r'/\*[ ]*(.)')
77 code_text = re.sub(comment_start, r'// \1', code_text)
78
79 # Add copyright info.
80 return copy_text + code_text
81
82
83def SortIncludeHeaders(text, filename):
84 """Sorts all include headers in alphabetic order.
85
86 The file's own header goes first, followed by system headers and then
87 project headers. This function will exit if we detect any fancy #ifdef logic
88 among the includes - that's a lot harder to sort.
89
90 Args:
91 text: The file text.
92 filename: The file we are reformatting.
93
94 Returns:
95 The text with includes sorted.
96 """
97 # Get all includes in file.
98 include_pattern = re.compile('#include.+\n')
99 includes = re.findall(include_pattern, text)
100
101 # Sort system headers and project headers separately.
102 sys_includes = []
103 project_includes = []
104 self_include = ''
105 sys_pattern = re.compile('#include <')
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000106 h_filename, _ = os.path.splitext(os.path.basename(filename))
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000107
108 for item in includes:
109 if re.search(h_filename, item):
110 self_include = item
111 elif re.search(sys_pattern, item):
112 sys_includes.append(item)
113 else:
114 project_includes.append(item)
115
116 sys_includes = sorted(sys_includes)
117 project_includes = sorted(project_includes)
118 headers = (self_include + '\n' + ''.join(sys_includes) + '\n' +
119 ''.join(project_includes))
120
121 # Replace existing headers with the sorted string.
122 text_no_hdrs = re.sub(include_pattern, r'???', text)
123
phoglund@webrtc.org943770b2013-01-02 15:46:43 +0000124 # Insert sorted headers unless we detect #ifdefs right next to the headers.
125 if re.search(r'(#ifdef|#ifndef|#if).*\s*\?{3,}\s*#endif', text_no_hdrs):
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000126 print 'WARNING: Include headers not sorted in ' + filename
127 return text
128
129 return_text = re.sub(r'\?{3,}', headers, text_no_hdrs, 1)
130 if re.search(r'\?{3,}', text_no_hdrs):
131 # Remove possible remaining ???.
132 return_text = re.sub(r'\?{3,}', r'', return_text)
133
134 return return_text
135
136
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000137def AddPath(match):
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000138 """Helper for adding file path for WebRTC header files, ignoring other."""
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000139 file_to_examine = match.group(1) + '.h'
140 # TODO(mflodman) Use current directory and find webrtc/.
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000141 for path, _, files in os.walk('./webrtc'):
142 for filename in files:
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000143 if fnmatch.fnmatch(filename, file_to_examine):
144 path_name = os.path.join(path, filename).replace('./', '')
145 return '#include "%s"\n' % path_name
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000146
147 # No path found, return original string.
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000148 return '#include "'+ file_to_examine + '"\n'
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000149
150
151def AddHeaderPath(text):
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000152 """Add path to all included header files that have no path yet."""
153 headers = re.compile('#include "(.+).h"\n')
154 return re.sub(headers, AddPath, text)
155
156
157def AddWebrtcToOldSrcRelativePath(match):
158 file_to_examine = match.group(1) + '.h'
159 path, filename = os.path.split(file_to_examine)
160 dirs_in_webrtc = [name for name in os.listdir('./webrtc')
161 if os.path.isdir(os.path.join('./webrtc', name))]
162 for dir_in_webrtc in dirs_in_webrtc:
163 if path.startswith(dir_in_webrtc):
164 return '#include "%s"\n' % os.path.join('webrtc', path, filename)
165 return '#include "%s"\n' % file_to_examine
166
167def AddWebrtcPrefixToOldSrcRelativePaths(text):
168 """For all paths starting with for instance video_engine, add webrtc/."""
169 headers = re.compile('#include "(.+).h"\n')
170 return re.sub(headers, AddWebrtcToOldSrcRelativePath, text)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000171
172
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000173def FixIncludeGuards(text, file_name):
174 """Change include guard according to the stantard."""
175 # Remove a possible webrtc/ from the path.
176 file_name = re.sub(r'(webrtc\/)(.+)', r'\2', file_name)
177 new_guard = 'WEBRTC_' + file_name
178 new_guard = new_guard.upper()
179 new_guard = re.sub(r'([/\.])', r'_', new_guard)
180 new_guard += '_'
181
182 text = re.sub(r'#ifndef WEBRTC_.+\n', r'#ifndef ' + new_guard + '\n', text, 1)
183 text = re.sub(r'#define WEBRTC_.+\n', r'#define ' + new_guard + '\n', text, 1)
184 text = re.sub(r'#endif *\/\/ *WEBRTC_.+\n', r'#endif // ' + new_guard + '\n',
185 text, 1)
186
187 return text
188
189
190def SaveFile(filename, text):
191 os.remove(filename)
192 f = open(filename, 'w')
193 f.write(text)
194 f.close()
195
196
197def main():
198 args = sys.argv[1:]
199 if not args:
200 print 'Usage: %s <filename>' % sys.argv[0]
201 sys.exit(1)
202
203 for filename in args:
204 f = open(filename)
205 text = f.read()
206 f.close()
207
208 text = DeCamelCase(text)
209 text = MoveUnderScore(text)
phoglund@webrtc.org943770b2013-01-02 15:46:43 +0000210 text = PostfixToPrefixInForLoops(text)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000211 text = CPPComments(text)
212 text = AddHeaderPath(text)
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000213 text = AddWebrtcPrefixToOldSrcRelativePaths(text)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000214 text = SortIncludeHeaders(text, filename)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000215
216 # Remove the original file and re-create it with the reformatted content.
217 SaveFile(filename, text)
218
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000219 if filename.endswith('.h'):
220 f = open(filename)
221 text = f.read()
222 f.close()
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000223 text = FixIncludeGuards(text, filename)
224 SaveFile(filename, text)
225
226 print filename + ' done.'
227
228
229if __name__ == '__main__':
230 main()