| import logging | |
| import sys | |
| from c_common.scriptutil import ( | |
| add_verbosity_cli, | |
| add_traceback_cli, | |
| add_kind_filtering_cli, | |
| add_files_cli, | |
| add_commands_cli, | |
| process_args_by_key, | |
| configure_logger, | |
| get_prog, | |
| main_for_filenames, | |
| ) | |
| from .preprocessor.__main__ import ( | |
| add_common_cli as add_preprocessor_cli, | |
| ) | |
| from .info import KIND | |
| from . import parse_file as _iter_parsed | |
| logger = logging.getLogger(__name__) | |
| def _format_vartype(vartype): | |
| if isinstance(vartype, str): | |
| return vartype | |
| data = vartype | |
| try: | |
| vartype = data['vartype'] | |
| except KeyError: | |
| storage, typequal, typespec, abstract = vartype.values() | |
| else: | |
| storage = data.get('storage') | |
| if storage: | |
| _, typequal, typespec, abstract = vartype.values() | |
| else: | |
| storage, typequal, typespec, abstract = vartype.values() | |
| vartype = f'{typespec} {abstract}' | |
| if typequal: | |
| vartype = f'{typequal} {vartype}' | |
| if storage: | |
| vartype = f'{storage} {vartype}' | |
| return vartype | |
| def _get_preprocessor(filename, **kwargs): | |
| return get_processor(filename, | |
| log_err=print, | |
| **kwargs | |
| ) | |
| ####################################### | |
| # the formats | |
| def fmt_raw(filename, item, *, showfwd=None): | |
| yield str(tuple(item)) | |
| def fmt_summary(filename, item, *, showfwd=None): | |
| if item.filename != filename: | |
| yield f'> {item.filename}' | |
| if showfwd is None: | |
| LINE = ' {lno:>5} {kind:10} {funcname:40} {fwd:1} {name:40} {data}' | |
| else: | |
| LINE = ' {lno:>5} {kind:10} {funcname:40} {name:40} {data}' | |
| lno = kind = funcname = fwd = name = data = '' | |
| MIN_LINE = len(LINE.format(**locals())) | |
| fileinfo, kind, funcname, name, data = item | |
| lno = fileinfo.lno if fileinfo and fileinfo.lno >= 0 else '' | |
| funcname = funcname or ' --' | |
| name = name or ' --' | |
| isforward = False | |
| if kind is KIND.FUNCTION: | |
| storage, inline, params, returntype, isforward = data.values() | |
| returntype = _format_vartype(returntype) | |
| data = returntype + params | |
| if inline: | |
| data = f'inline {data}' | |
| if storage: | |
| data = f'{storage} {data}' | |
| elif kind is KIND.VARIABLE: | |
| data = _format_vartype(data) | |
| elif kind is KIND.STRUCT or kind is KIND.UNION: | |
| if data is None: | |
| isforward = True | |
| else: | |
| fields = data | |
| data = f'({len(data)}) {{ ' | |
| indent = ',\n' + ' ' * (MIN_LINE + len(data)) | |
| data += ', '.join(f.name for f in fields[:5]) | |
| fields = fields[5:] | |
| while fields: | |
| data = f'{data}{indent}{", ".join(f.name for f in fields[:5])}' | |
| fields = fields[5:] | |
| data += ' }' | |
| elif kind is KIND.ENUM: | |
| if data is None: | |
| isforward = True | |
| else: | |
| names = [d if isinstance(d, str) else d.name | |
| for d in data] | |
| data = f'({len(data)}) {{ ' | |
| indent = ',\n' + ' ' * (MIN_LINE + len(data)) | |
| data += ', '.join(names[:5]) | |
| names = names[5:] | |
| while names: | |
| data = f'{data}{indent}{", ".join(names[:5])}' | |
| names = names[5:] | |
| data += ' }' | |
| elif kind is KIND.TYPEDEF: | |
| data = f'typedef {data}' | |
| elif kind == KIND.STATEMENT: | |
| pass | |
| else: | |
| raise NotImplementedError(item) | |
| if isforward: | |
| fwd = '*' | |
| if not showfwd and showfwd is not None: | |
| return | |
| elif showfwd: | |
| return | |
| kind = kind.value | |
| yield LINE.format(**locals()) | |
| def fmt_full(filename, item, *, showfwd=None): | |
| raise NotImplementedError | |
| FORMATS = { | |
| 'raw': fmt_raw, | |
| 'summary': fmt_summary, | |
| 'full': fmt_full, | |
| } | |
| def add_output_cli(parser): | |
| parser.add_argument('--format', dest='fmt', default='summary', choices=tuple(FORMATS)) | |
| parser.add_argument('--showfwd', action='store_true', default=None) | |
| parser.add_argument('--no-showfwd', dest='showfwd', action='store_false', default=None) | |
| def process_args(args, *, argv=None): | |
| pass | |
| return process_args | |
| ####################################### | |
| # the commands | |
| def _cli_parse(parser, excluded=None, **prepr_kwargs): | |
| process_output = add_output_cli(parser) | |
| process_kinds = add_kind_filtering_cli(parser) | |
| process_preprocessor = add_preprocessor_cli(parser, **prepr_kwargs) | |
| process_files = add_files_cli(parser, excluded=excluded) | |
| return [ | |
| process_output, | |
| process_kinds, | |
| process_preprocessor, | |
| process_files, | |
| ] | |
| def cmd_parse(filenames, *, | |
| fmt='summary', | |
| showfwd=None, | |
| iter_filenames=None, | |
| relroot=None, | |
| **kwargs | |
| ): | |
| if 'get_file_preprocessor' not in kwargs: | |
| kwargs['get_file_preprocessor'] = _get_preprocessor() | |
| try: | |
| do_fmt = FORMATS[fmt] | |
| except KeyError: | |
| raise ValueError(f'unsupported fmt {fmt!r}') | |
| for filename, relfile in main_for_filenames(filenames, iter_filenames, relroot): | |
| for item in _iter_parsed(filename, **kwargs): | |
| item = item.fix_filename(relroot, fixroot=False, normalize=False) | |
| for line in do_fmt(relfile, item, showfwd=showfwd): | |
| print(line) | |
| def _cli_data(parser): | |
| ... | |
| return [] | |
| def cmd_data(filenames, | |
| **kwargs | |
| ): | |
| # XXX | |
| raise NotImplementedError | |
| COMMANDS = { | |
| 'parse': ( | |
| 'parse the given C source & header files', | |
| [_cli_parse], | |
| cmd_parse, | |
| ), | |
| 'data': ( | |
| 'check/manage local data (e.g. excludes, macros)', | |
| [_cli_data], | |
| cmd_data, | |
| ), | |
| } | |
| ####################################### | |
| # the script | |
| def parse_args(argv=sys.argv[1:], prog=sys.argv[0], *, subset='parse'): | |
| import argparse | |
| parser = argparse.ArgumentParser( | |
| prog=prog or get_prog, | |
| ) | |
| processors = add_commands_cli( | |
| parser, | |
| commands={k: v[1] for k, v in COMMANDS.items()}, | |
| commonspecs=[ | |
| add_verbosity_cli, | |
| add_traceback_cli, | |
| ], | |
| subset=subset, | |
| ) | |
| args = parser.parse_args(argv) | |
| ns = vars(args) | |
| cmd = ns.pop('cmd') | |
| verbosity, traceback_cm = process_args_by_key( | |
| args, | |
| argv, | |
| processors[cmd], | |
| ['verbosity', 'traceback_cm'], | |
| ) | |
| return cmd, ns, verbosity, traceback_cm | |
| def main(cmd, cmd_kwargs): | |
| try: | |
| run_cmd = COMMANDS[cmd][0] | |
| except KeyError: | |
| raise ValueError(f'unsupported cmd {cmd!r}') | |
| run_cmd(**cmd_kwargs) | |
| if __name__ == '__main__': | |
| cmd, cmd_kwargs, verbosity, traceback_cm = parse_args() | |
| configure_logger(verbosity) | |
| with traceback_cm: | |
| main(cmd, cmd_kwargs) |