process-text-files.py: Implement command indent-cpp-macros

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2019-03-15 20:05:48 +01:00
commit a676ff5cdf

View file

@ -78,6 +78,84 @@ class Cmd(jwutils.Cmd):
return data
return r
@staticmethod
def _indent_cpp_macros(data, src, target, context=None):
def __ctx(context, key, default):
if key in context:
return context[key]
return default
def format_line(context, indent, directive, rhs):
if indent < 0:
indent = 0
spaces = __ctx(context, 'spaces', 2)
indent_macro = __ctx(context, 'indent-macro', 0)
indent_def = __ctx(context, 'indent-definiton', 40)
indent_comment = __ctx(context, 'indent-comment', 70)
rhs = rhs.strip()
directive = directive.strip()
r = '#' + ' ' * indent * spaces + directive
if len(rhs) == 0:
return r + '\n'
r += ' '
if indent_macro > 1:
r = r.ljust(indent_macro - 1)
if not directive in [ 'define' ]:
return (r + rhs).rstrip() + '\n'
#slog(NOTICE, "dissecting", rhs)
m = re.match("^\s*(\w+(\([^)]*\))*)(\s+(.*))*", rhs)
if m is None:
raise Exception("invalid rhs", rhs)
macro = m.group(1)
def_and_comment = m.group(4)
#slog(NOTICE, "macro=>{}<, def+comment=>{}<".format(macro, def_and_comment))
r += macro
if def_and_comment is None:
return r.rstrip() + '\n'
r += ' '
if indent_def > 1:
r = r.ljust(indent_def - 1)
parts = re.split("(//|/\*)", def_and_comment)
if len(parts) <= 1:
return r + def_and_comment + '\n'
if len(parts) == 2:
raise Exception("Failed to dissect definition + comment", def_and_comment)
return (r + parts[0].strip()).ljust(indent_comment) + parts[1].strip() + ' ' + ''.join(parts[2:]).strip() + '\n'
skip_outer = True
if context is not None:
if 'skip-outer' in context:
skip_outer = context['skip-outer']
r = ''
lnum = 0
level = -1 if context['skip-outer'] else 0
lines = data.splitlines()
for line in iter(lines):
lnum += 1
m = re.match("^\s*#\s*(\w+)(\W*)(.*)", line)
if m is None:
r += line + '\n'
continue
directive = m.group(1)
rhs = (m.group(2) + m.group(3)).strip()
#slog(NOTICE, "{}: directive=>{}<, rhs=>{}<".format(level, directive, rhs))
if directive is None or rhs is None:
raise Exception("Syntax error in line", lnum, ":", line)
if directive in [ "if", "ifdef", "ifndef" ]:
r += format_line(context, level, directive, rhs)
level += 1
continue
if directive in [ "else" ]:
r += format_line(context, level - 1, directive, rhs)
continue
if directive in [ "endif" ]:
level -= 1
r += format_line(context, level, directive, rhs)
continue
r += format_line(context, level, directive, rhs)
return r
@staticmethod
def _cleanup_spaces(data, src, target, context=None):
lines = data.splitlines()
@ -346,6 +424,34 @@ class CmdIndentMakefileEquals(Cmd):
if self._replace_in_file(path, replacements, func=self._indent_pattern, context=context):
slog(NOTICE, "+ aligned equals :", path)
class CmdIndentCppMacros(Cmd):
def __init__(self):
super(CmdIndentCppMacros, self).__init__("indent-cpp-macros", "Indent and beautify C/C++ preprocessor macros")
def add_parser(self, parsers):
p = super(CmdIndentCppMacros, self).add_parser(parsers)
p.add_argument('-w', "--spaces", help="Number of spaces per indentation level", type=int, default=2)
p.add_argument('-s', "--skip-outer", help="Skip the outmost macro (read multiple-inclusion guards)", action='store_true', default=True)
p.add_argument('-S', "--skip-outer-name-regex", help="Regex for file names that --skip-outer should be applied to", default="\.h$|\.H$|\.hpp$")
return p
def process(self, args, files):
slog(NOTICE, "Beautifying", len(files), "C++ files:")
context = dict()
context["spaces"] = args.spaces
replacements = {"blah": "blub"} # just a dummy to use _replace_in_file, TODO: obviate the need
for dir, name in files:
path = dir + '/' + name
if self._replace_in_file(path, replacements, func=self._cleanup_spaces):
slog(NOTICE, "+ purged spaces :", path)
if args.skip_outer and re.search(args.skip_outer_name_regex, path):
context["skip-outer"] = True
else:
context["skip-outer"] = False
if self._replace_in_file(path, replacements, func=self._indent_cpp_macros, context=context):
slog(NOTICE, "+ indented C++ macros :", path)
class CmdCleanupSpaces(Cmd):
def __init__(self):