Hello. Sometimes, one needs a more complex replacement in source files and an editor can be a weak tool. That has happened to me in the recent time and so I made the replacement in Python.
The script provides simple API: - handle_file_p - return True if you want to touch the file - modify_line - return modified line (if you want) Are others also interested or should I put it to my internal tools? Cheers, Martin contrib/ChangeLog: * replace.py: New file. --- contrib/replace.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100755 contrib/replace.py diff --git a/contrib/replace.py b/contrib/replace.py new file mode 100755 index 00000000000..a510c6cd32c --- /dev/null +++ b/contrib/replace.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING. If not, write to +# the Free Software Foundation, 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# The script can be used for more complex replacements in the source code. +# + +import argparse +import os +import re +import sys + +EXTENSIONS = ('.h', '.c', '.cc', '.C') + + +def handle_file_p(filename): + if 'testsuite' in filename: + return False + if all(not filename.endswith(ext) for ext in EXTENSIONS): + return False + + return True + + +def modify_line(line): + # Example replacement: + # m = re.match(r'.*time_function\(&([^,]*),', line) + # if m: + # e = m.end(1) + # name = m.group(1) + # line = line[:e + 1] + f' "{name}",' + line[e + 1:] + + return line + + +parser = argparse.ArgumentParser(description='Make a custom replacements ' + 'for source files') +parser.add_argument('directory', help='Root directory') +parser.add_argument('-v', '--verbose', action='store_true', + help='Verbose output') +args = parser.parse_args() + +visited_files = 0 +modified_files = 0 + +for root, _, files in os.walk(sys.argv[1]): + for file in files: + full = os.path.join(root, file) + if not handle_file_p(full): + continue + + visited_files += 1 + + modified = False + try: + modified_lines = [] + with open(full) as f: + lines = f.readlines() + for line in lines: + modified_line = modify_line(line) + if line != modified_line: + modified = True + modified_lines.append(line) + if modified: + with open(full, 'w') as w: + w.write('\n'.join(modified_lines)) + modified_files += 1 + if args.verbose: + print(f'File modified: {full}') + except UnicodeDecodeError as e: + print(f'Skipping file: {full} ({e})') + + +print(f'Visited files: {visited_files}') +print(f'Modified files: {modified_files}') -- 2.33.1