#!/usr/bin/env python3 # utility to check meta errors for simple format spec mistakes. # Copyright (C) 2016-2025 Free Software Foundation, Inc. # # This file is part of GNU Modula-2. # # GNU Modula-2 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. # # GNU Modula-2 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 COPYING3. If not see # . import argparse import os import pathlib import sys exit_code = 0 def visit_dir(directory, ext, func): # visit_dir - call func for each file below, dir, matching extension, ext. list_of_files = os.listdir(directory) list_of_files.sort() for filename in list_of_files: path = pathlib.Path(filename) full = os.path.join(directory, filename) if path.suffix == ext: func(full) def check_format_spec(filename, line, no): global exit_code percent = line.find('%') if percent >= 0: specifier = False for ch in line[percent:]: if ch in ['{', '%']: pass elif ch in ['1', '2', '3', '4']: if specifier: sys.stderr.write('%s:%d: format specifier error, the symbol position digit must be before the specifier: %s\n' % (filename, no, line)) exit_code = 1 else: specifier = True def search_format(filename, line, no): cbra = line.find('{') while cbra >= 0: colon = line.find(':', cbra) end = line.find('}', cbra) if end >= 0: if (colon >= 0) and (colon < end): end = colon check_format_spec(filename, line[cbra:end], no) cbra = line.find('{', end) else: return def check_string_quote (filename, line, no, quote): end = line.find(quote, 1) if end > 0: search_format(filename, line[1:end], no) def check_string (filename, line, no): quote = line.find("'") if quote >= 0: check_string_quote(filename, line[quote:], no, "'") quote = line.find('"') if quote >= 0: check_string_quote(filename, line[quote:], no, '"') def check_meta_spec (filename): lines = open(filename).readlines() extra = 0 for no, line in enumerate(lines): if extra > 0: extra -= 1 check_string(filename, line, no+1) elif "Meta" in line: meta = line.find("Meta") if meta >= 0: bra = line.find("(", meta) if bra >= 0: check_string(filename, line[bra:], no+1) extra = 1 def handle_arguments(): # handle_arguments create and return the args object. parser = argparse.ArgumentParser() parser.add_argument('-s', '--srcdir', help='set source directory.', default='.', action='store') args = parser.parse_args() return args def main(): args = handle_arguments() visit_dir(args.srcdir, '.mod', check_meta_spec) visit_dir(args.srcdir, '.bnf', check_meta_spec) sys.exit(exit_code) main()