| #!/usr/bin/python |
| # Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| # |
| # Use of this source code is governed by a BSD-style license |
| # that can be found in the LICENSE file in the root of the source |
| # tree. An additional intellectual property rights grant can be found |
| # in the file PATENTS. All contributing project authors may |
| # be found in the AUTHORS file in the root of the source tree. |
| |
| """WebRTC reformat script. |
| |
| This script is used to reformat WebRTC code from the old code style to Google |
| C++ code style. This script does not indent code; use clang-reformat-chrome.py |
| as described in go/webrtc/engineering/reformatting-gips---google. |
| """ |
| |
| __author__ = 'mflodman@webrtc.org (Magnus Flodman)' |
| |
| import fnmatch |
| import os |
| import re |
| import subprocess |
| import sys |
| |
| |
| def LowerWord(obj): |
| """Helper for DeCamelCase.""" |
| optional_last_letters = obj.group(3) or '' |
| return obj.group(1) + '_' + obj.group(2).lower() + optional_last_letters |
| |
| |
| def DeCamelCase(text): |
| """De-camelize variable names. |
| |
| This function will look at any stringLikeThis and format it in steps. The |
| sequence will be stringLikeThis -> string_likeThis -> string_like_this. |
| """ |
| possible_tokens_before_vars = '[ _*\(\&\!\[]' |
| pattern = re.compile(r'(?<=' + possible_tokens_before_vars + ')' + |
| # Match some lower-case characters |
| '([a-z]+)' + |
| # Don't match kFoo, !kFoo, [kFoo], etc |
| '(?<!' + possible_tokens_before_vars + 'k)' + |
| # Match some upper-case characters |
| '([A-Z]+)([a-z])?') |
| while re.search(pattern, text): |
| text = re.sub(pattern, LowerWord, text) |
| return text |
| |
| |
| def MoveUnderScore(text): |
| """Moves the underscore from beginning of variable name to the end.""" |
| # TODO(mflodman) Replace \1 with ?-expression. |
| # We don't want to change macros and #defines though, so don't do anything |
| # if the first character is uppercase (normal variables shouldn't have that). |
| pattern = r'([ \*\!\&\(\[\]])_(?!_)(?![A-Z])(\w+)' |
| return re.sub(pattern, r'\1\2_', text) |
| |
| |
| def PostfixToPrefixInForLoops(text): |
| """Converts x++ to ++x in the increment part of a for loop.""" |
| pattern = r'(for \(.*;.*;) (\w+)\+\+\)' |
| return re.sub(pattern, r'\1++\2)', text) |
| |
| |
| def SortIncludeHeaders(text, filename): |
| """Sorts all include headers in alphabetic order. |
| |
| The file's own header goes first, followed by system headers and then |
| project headers. This function will exit if we detect any fancy #ifdef logic |
| among the includes - that's a lot harder to sort. |
| |
| Args: |
| text: The file text. |
| filename: The file we are reformatting. |
| |
| Returns: |
| The text with includes sorted. |
| """ |
| # Get all includes in file. |
| include_pattern = re.compile('#include.+\n') |
| includes = re.findall(include_pattern, text) |
| |
| # Sort system headers and project headers separately. |
| sys_includes = [] |
| project_includes = [] |
| self_include = '' |
| sys_pattern = re.compile('#include <') |
| h_filename, _ = os.path.splitext(os.path.basename(filename)) |
| |
| for item in includes: |
| if re.search(h_filename + '\.', item): |
| self_include = item |
| elif re.search(sys_pattern, item): |
| sys_includes.append(item) |
| else: |
| project_includes.append(item) |
| |
| sys_includes = sorted(sys_includes) |
| project_includes = sorted(project_includes) |
| headers = (self_include + '\n' + ''.join(sys_includes) + '\n' + |
| ''.join(project_includes)) |
| |
| # Replace existing headers with the sorted string. |
| text_no_hdrs = re.sub(include_pattern, r'???', text) |
| |
| # Insert sorted headers unless we detect #ifdefs right next to the headers. |
| if re.search(r'(#ifdef|#ifndef|#if).*\s*\?{3,}\s*#endif', text_no_hdrs): |
| print 'WARNING: Include headers not sorted in ' + filename |
| return text |
| |
| return_text = re.sub(r'\?{3,}', headers, text_no_hdrs, 1) |
| if re.search(r'\?{3,}', text_no_hdrs): |
| # Remove possible remaining ???. |
| return_text = re.sub(r'\?{3,}', r'', return_text) |
| |
| return return_text |
| |
| |
| def AddPath(match): |
| """Helper for adding file path for WebRTC header files, ignoring other.""" |
| file_to_examine = match.group(1) + '.h' |
| # TODO(mflodman) Use current directory and find webrtc/. |
| for path, _, files in os.walk('./webrtc'): |
| for filename in files: |
| if fnmatch.fnmatch(filename, file_to_examine): |
| path_name = os.path.join(path, filename).replace('./', '') |
| return '#include "%s"\n' % path_name |
| |
| # No path found, return original string. |
| return '#include "'+ file_to_examine + '"\n' |
| |
| |
| def AddHeaderPath(text): |
| """Add path to all included header files that have no path yet.""" |
| headers = re.compile('#include "(.+).h"\n') |
| return re.sub(headers, AddPath, text) |
| |
| |
| def AddWebrtcToOldSrcRelativePath(match): |
| file_to_examine = match.group(1) + '.h' |
| path, filename = os.path.split(file_to_examine) |
| dirs_in_webrtc = [name for name in os.listdir('./webrtc') |
| if os.path.isdir(os.path.join('./webrtc', name))] |
| for dir_in_webrtc in dirs_in_webrtc: |
| if path.startswith(dir_in_webrtc): |
| return '#include "%s"\n' % os.path.join('webrtc', path, filename) |
| return '#include "%s"\n' % file_to_examine |
| |
| def AddWebrtcPrefixToOldSrcRelativePaths(text): |
| """For all paths starting with for instance video_engine, add webrtc/.""" |
| headers = re.compile('#include "(.+).h"\n') |
| return re.sub(headers, AddWebrtcToOldSrcRelativePath, text) |
| |
| |
| def FixIncludeGuards(text, file_name): |
| """Change include guard according to the stantard.""" |
| # Remove a possible webrtc/ from the path. |
| file_name = re.sub(r'(webrtc\/)(.+)', r'\2', file_name) |
| new_guard = 'WEBRTC_' + file_name |
| new_guard = new_guard.upper() |
| new_guard = re.sub(r'([/\.])', r'_', new_guard) |
| new_guard += '_' |
| |
| text = re.sub(r'#ifndef WEBRTC_.+\n', r'#ifndef ' + new_guard + '\n', text, 1) |
| text = re.sub(r'#define WEBRTC_.+\n', r'#define ' + new_guard + '\n', text, 1) |
| text = re.sub(r'#endif *\/\/ *WEBRTC_.+\n', r'#endif // ' + new_guard + '\n', |
| text, 1) |
| |
| return text |
| |
| |
| def SaveFile(filename, text): |
| os.remove(filename) |
| f = open(filename, 'w') |
| f.write(text) |
| f.close() |
| |
| |
| def main(): |
| args = sys.argv[1:] |
| if not args: |
| print 'Usage: %s <filename>' % sys.argv[0] |
| sys.exit(1) |
| |
| for filename in args: |
| f = open(filename) |
| text = f.read() |
| f.close() |
| |
| text = DeCamelCase(text) |
| text = MoveUnderScore(text) |
| text = PostfixToPrefixInForLoops(text) |
| text = AddHeaderPath(text) |
| text = AddWebrtcPrefixToOldSrcRelativePaths(text) |
| text = SortIncludeHeaders(text, filename) |
| |
| # Remove the original file and re-create it with the reformatted content. |
| SaveFile(filename, text) |
| |
| if filename.endswith('.h'): |
| f = open(filename) |
| text = f.read() |
| f.close() |
| text = FixIncludeGuards(text, filename) |
| SaveFile(filename, text) |
| |
| print filename + ' done.' |
| |
| |
| if __name__ == '__main__': |
| main() |