|
| 1 | +import os |
| 2 | +import re |
| 3 | +import argparse |
| 4 | + |
| 5 | +# ANSI color codes |
| 6 | +CYAN = '\033[96m' |
| 7 | +BLUE = '\033[94m' |
| 8 | +YELLOW = '\033[93m' |
| 9 | +RED = '\033[91m' |
| 10 | +RESET = '\033[0m' |
| 11 | + |
| 12 | +def check_format_issues(filepath): |
| 13 | + issues = [] |
| 14 | + |
| 15 | + # Pattern: enforce * next to variable name, e.g., "int* ptr", not "int * ptr" |
| 16 | + pointer_pattern = re.compile( |
| 17 | + r'\b(?:const\s+|volatile\s+|restrict\s+)?' |
| 18 | + r'(?:unsigned\s+|signed\s+)?' |
| 19 | + r'(?:int|char|float|double|void|size_t|ptrdiff_t|uint\d+_t|int\d+_t)\s+\*\s+\w+' |
| 20 | + ) |
| 21 | + |
| 22 | + with open(filepath, 'r', encoding='utf-8', errors='ignore') as file: |
| 23 | + for lineno, line in enumerate(file, start=1): |
| 24 | + if '\t' in line: |
| 25 | + issues.append((lineno, 'Tab character found', 'warning')) |
| 26 | + if 'goto' in line: |
| 27 | + issues.append((lineno, 'Usage of "goto" is not allowed', 'error')) |
| 28 | + if pointer_pattern.search(line): |
| 29 | + issues.append((lineno, 'Pointer symbol (*) should be adjacent to variable name (e.g., `int* ptr`)', 'error')) |
| 30 | + if line.strip().startswith('//') and len(line.strip()) > 80: |
| 31 | + issues.append((lineno, 'Comment exceeds 80 characters', 'warning')) |
| 32 | + if line.strip().endswith(';') and line.strip() == ';': |
| 33 | + issues.append((lineno, 'Empty statement found', 'warning')) |
| 34 | + return issues |
| 35 | + |
| 36 | +def scan_directory_for_issues(directory): |
| 37 | + issue_report = {} |
| 38 | + for root, _, files in os.walk(directory): |
| 39 | + for file in files: |
| 40 | + if file.endswith(('.c', '.cpp', '.h', '.hpp')): |
| 41 | + full_path = os.path.join(root, file) |
| 42 | + issues = check_format_issues(full_path) |
| 43 | + if issues: |
| 44 | + issue_report[full_path] = issues |
| 45 | + return issue_report |
| 46 | + |
| 47 | +if __name__ == '__main__': |
| 48 | + parser = argparse.ArgumentParser(description="Check C/C++ files for formatting issues.") |
| 49 | + parser.add_argument('directory', help="Directory to scan for source files.") |
| 50 | + args = parser.parse_args() |
| 51 | + |
| 52 | + report = scan_directory_for_issues(args.directory) |
| 53 | + for filepath, issues in report.items(): |
| 54 | + print(f"\n{BLUE}{filepath}:{RESET}") |
| 55 | + for lineno, message, severity in issues: |
| 56 | + color = RED if severity == 'error' else YELLOW |
| 57 | + print(f" {CYAN}Line {lineno}:{RESET} {color}{message}{RESET}") |
0 commit comments