phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 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 |
phoglund@webrtc.org | 1723857 | 2013-02-15 09:43:20 +0000 | [diff] [blame] | 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. |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 15 | """ |
| 16 | |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 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.""" |
phoglund@webrtc.org | 943770b | 2013-01-02 15:46:43 +0000 | [diff] [blame] | 28 | optional_last_letters = obj.group(3) or '' |
| 29 | return obj.group(1) + '_' + obj.group(2).lower() + optional_last_letters |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 30 | |
| 31 | |
| 32 | def DeCamelCase(text): |
phoglund@webrtc.org | aeb7d87 | 2013-05-08 13:56:23 +0000 | [diff] [blame] | 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])?') |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 46 | while re.search(pattern, text): |
| 47 | text = re.sub(pattern, LowerWord, text) |
| 48 | return text |
| 49 | |
| 50 | |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 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). |
phoglund@webrtc.org | 943770b | 2013-01-02 15:46:43 +0000 | [diff] [blame] | 56 | pattern = r'([ \*\!\&\(\[\]])_(?!_)(?![A-Z])(\w+)' |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 57 | return re.sub(pattern, r'\1\2_', text) |
| 58 | |
| 59 | |
phoglund@webrtc.org | 943770b | 2013-01-02 15:46:43 +0000 | [diff] [blame] | 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 | |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 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 <') |
phoglund@webrtc.org | e3b2bc6 | 2012-11-23 09:09:59 +0000 | [diff] [blame] | 89 | h_filename, _ = os.path.splitext(os.path.basename(filename)) |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 90 | |
| 91 | for item in includes: |
phoglund@webrtc.org | aeb7d87 | 2013-05-08 13:56:23 +0000 | [diff] [blame] | 92 | if re.search(h_filename + '\.', item): |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 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 | |
phoglund@webrtc.org | 943770b | 2013-01-02 15:46:43 +0000 | [diff] [blame] | 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): |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 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 | |
phoglund@webrtc.org | e3b2bc6 | 2012-11-23 09:09:59 +0000 | [diff] [blame] | 120 | def AddPath(match): |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 121 | """Helper for adding file path for WebRTC header files, ignoring other.""" |
phoglund@webrtc.org | e3b2bc6 | 2012-11-23 09:09:59 +0000 | [diff] [blame] | 122 | file_to_examine = match.group(1) + '.h' |
| 123 | # TODO(mflodman) Use current directory and find webrtc/. |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 124 | for path, _, files in os.walk('./webrtc'): |
| 125 | for filename in files: |
phoglund@webrtc.org | e3b2bc6 | 2012-11-23 09:09:59 +0000 | [diff] [blame] | 126 | 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.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 129 | |
| 130 | # No path found, return original string. |
phoglund@webrtc.org | e3b2bc6 | 2012-11-23 09:09:59 +0000 | [diff] [blame] | 131 | return '#include "'+ file_to_examine + '"\n' |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 132 | |
| 133 | |
| 134 | def AddHeaderPath(text): |
phoglund@webrtc.org | e3b2bc6 | 2012-11-23 09:09:59 +0000 | [diff] [blame] | 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) |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 154 | |
| 155 | |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 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) |
phoglund@webrtc.org | 943770b | 2013-01-02 15:46:43 +0000 | [diff] [blame] | 193 | text = PostfixToPrefixInForLoops(text) |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 194 | text = AddHeaderPath(text) |
phoglund@webrtc.org | e3b2bc6 | 2012-11-23 09:09:59 +0000 | [diff] [blame] | 195 | text = AddWebrtcPrefixToOldSrcRelativePaths(text) |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 196 | text = SortIncludeHeaders(text, filename) |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 197 | |
| 198 | # Remove the original file and re-create it with the reformatted content. |
| 199 | SaveFile(filename, text) |
| 200 | |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 201 | if filename.endswith('.h'): |
| 202 | f = open(filename) |
| 203 | text = f.read() |
| 204 | f.close() |
phoglund@webrtc.org | 3ec52c0 | 2012-11-21 13:28:52 +0000 | [diff] [blame] | 205 | text = FixIncludeGuards(text, filename) |
| 206 | SaveFile(filename, text) |
| 207 | |
| 208 | print filename + ' done.' |
| 209 | |
| 210 | |
| 211 | if __name__ == '__main__': |
| 212 | main() |