- add C/C++ statistics script
This commit is contained in:
123
count_cpp_stats.py
Executable file
123
count_cpp_stats.py
Executable file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Count C/C++ files and lines in the project.
|
||||||
|
Works on both Linux and Windows.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# C/C++ file extensions
|
||||||
|
CPP_EXTENSIONS = {'.c', '.cc', '.cpp', '.cxx', '.h', '.hh', '.hpp', '.hxx'}
|
||||||
|
|
||||||
|
|
||||||
|
def is_cpp_file(filepath: Path) -> bool:
|
||||||
|
"""Check if file has a C/C++ extension."""
|
||||||
|
return filepath.suffix.lower() in CPP_EXTENSIONS
|
||||||
|
|
||||||
|
|
||||||
|
def count_lines_in_file(filepath: Path) -> int:
|
||||||
|
"""Count lines in a single file."""
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
||||||
|
return sum(1 for _ in f)
|
||||||
|
except (IOError, OSError):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def collect_cpp_files(root_dir: Path) -> list[Path]:
|
||||||
|
"""Collect all C/C++ files recursively from root directory."""
|
||||||
|
cpp_files = []
|
||||||
|
for path in root_dir.rglob('*'):
|
||||||
|
if path.is_file() and is_cpp_file(path):
|
||||||
|
cpp_files.append(path)
|
||||||
|
return cpp_files
|
||||||
|
|
||||||
|
|
||||||
|
def get_directory_stats(root_dir: Path, cpp_files: list[Path]) -> dict[str, dict]:
|
||||||
|
"""Get statistics grouped by immediate subdirectories."""
|
||||||
|
stats = {}
|
||||||
|
|
||||||
|
# Initialize stats for immediate subdirectories
|
||||||
|
for item in root_dir.iterdir():
|
||||||
|
if item.is_dir():
|
||||||
|
stats[item.name] = {'files': 0, 'lines': 0}
|
||||||
|
|
||||||
|
# Also count files directly in root
|
||||||
|
stats['.'] = {'files': 0, 'lines': 0}
|
||||||
|
|
||||||
|
for filepath in cpp_files:
|
||||||
|
try:
|
||||||
|
# Get relative path from root
|
||||||
|
rel_path = filepath.relative_to(root_dir)
|
||||||
|
|
||||||
|
# Determine which immediate subdirectory this file belongs to
|
||||||
|
if len(rel_path.parts) == 1:
|
||||||
|
# File is directly in root
|
||||||
|
dir_key = '.'
|
||||||
|
else:
|
||||||
|
# File is in a subdirectory
|
||||||
|
dir_key = rel_path.parts[0]
|
||||||
|
|
||||||
|
if dir_key in stats:
|
||||||
|
line_count = count_lines_in_file(filepath)
|
||||||
|
stats[dir_key]['files'] += 1
|
||||||
|
stats[dir_key]['lines'] += line_count
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
return stats
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Use current directory as root, or accept a path argument
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
root_dir = Path(sys.argv[1]).resolve()
|
||||||
|
else:
|
||||||
|
root_dir = Path.cwd()
|
||||||
|
|
||||||
|
if not root_dir.exists():
|
||||||
|
print(f"Error: Directory '{root_dir}' does not exist.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Scanning C/C++ files in: {root_dir}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Collect all C/C++ files
|
||||||
|
cpp_files = collect_cpp_files(root_dir)
|
||||||
|
|
||||||
|
if not cpp_files:
|
||||||
|
print("No C/C++ files found.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Get directory statistics
|
||||||
|
dir_stats = get_directory_stats(root_dir, cpp_files)
|
||||||
|
|
||||||
|
# Print per-directory statistics
|
||||||
|
print("\nPer-directory C/C++ statistics:")
|
||||||
|
print("-" * 60)
|
||||||
|
print(f"{'Directory':<30} {'Files':>10} {'Lines':>15}")
|
||||||
|
print("-" * 60)
|
||||||
|
|
||||||
|
total_files = 0
|
||||||
|
total_lines = 0
|
||||||
|
|
||||||
|
# Sort directories: root first, then alphabetically
|
||||||
|
sorted_dirs = sorted(dir_stats.keys(), key=lambda x: (x != '.', x.lower()))
|
||||||
|
|
||||||
|
for dir_name in sorted_dirs:
|
||||||
|
stat = dir_stats[dir_name]
|
||||||
|
if stat['files'] > 0:
|
||||||
|
display_name = '(root)' if dir_name == '.' else dir_name
|
||||||
|
print(f"{display_name:<30} {stat['files']:>10} {stat['lines']:>15,}")
|
||||||
|
total_files += stat['files']
|
||||||
|
total_lines += stat['lines']
|
||||||
|
|
||||||
|
print("-" * 60)
|
||||||
|
print(f"{'TOTAL':<30} {total_files:>10} {total_lines:>15,}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user