Add new replace script.

Message ID 01a68ba6-fffc-4ca3-135d-791441e666fd@suse.cz
State New
Headers
Series Add new replace script. |

Commit Message

Martin Liška Oct. 20, 2021, 8:41 a.m. UTC
  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
  

Patch

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}')