blob: 269d1c3f6c9c00740f2f23d065fc8cbd6b73ec92 [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):
phoglund@webrtc.orgaeb7d872013-05-08 13:56:23 +000033 """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])?')
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000046 while re.search(pattern, text):
47 text = re.sub(pattern, LowerWord, text)
48 return text
49
50
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000051def 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).
phoglund@webrtc.org943770b2013-01-02 15:46:43 +000056 pattern = r'([ \*\!\&\(\[\]])_(?!_)(?![A-Z])(\w+)'
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000057 return re.sub(pattern, r'\1\2_', text)
58
59
phoglund@webrtc.org943770b2013-01-02 15:46:43 +000060def 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
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000066def 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 <')
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +000089 h_filename, _ = os.path.splitext(os.path.basename(filename))
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000090
91 for item in includes:
phoglund@webrtc.orgaeb7d872013-05-08 13:56:23 +000092 if re.search(h_filename + '\.', item):
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +000093 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
phoglund@webrtc.org943770b2013-01-02 15:46:43 +0000107 # 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):
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000109 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
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000120def AddPath(match):
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000121 """Helper for adding file path for WebRTC header files, ignoring other."""
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000122 file_to_examine = match.group(1) + '.h'
123 # TODO(mflodman) Use current directory and find webrtc/.
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000124 for path, _, files in os.walk('./webrtc'):
125 for filename in files:
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000126 if fnmatch.fnmatch(filename, file_to_examine):
127 path_name = os.path.join(path, filename).replace('./', '')
128 return '#include "%s"\n' % path_name
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000129
130 # No path found, return original string.
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000131 return '#include "'+ file_to_examine + '"\n'
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000132
133
134def AddHeaderPath(text):
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000135 """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
140def 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
150def 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)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000154
155
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000156def 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
173def SaveFile(filename, text):
174 os.remove(filename)
175 f = open(filename, 'w')
176 f.write(text)
177 f.close()
178
179
180def 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)
phoglund@webrtc.org943770b2013-01-02 15:46:43 +0000193 text = PostfixToPrefixInForLoops(text)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000194 text = AddHeaderPath(text)
phoglund@webrtc.orge3b2bc62012-11-23 09:09:59 +0000195 text = AddWebrtcPrefixToOldSrcRelativePaths(text)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000196 text = SortIncludeHeaders(text, filename)
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000197
198 # Remove the original file and re-create it with the reformatted content.
199 SaveFile(filename, text)
200
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000201 if filename.endswith('.h'):
202 f = open(filename)
203 text = f.read()
204 f.close()
phoglund@webrtc.org3ec52c02012-11-21 13:28:52 +0000205 text = FixIncludeGuards(text, filename)
206 SaveFile(filename, text)
207
208 print filename + ' done.'
209
210
211if __name__ == '__main__':
212 main()