Skip to content

Instantly share code, notes, and snippets.

@mgerhardy
Created September 3, 2025 08:01
Show Gist options
  • Select an option

  • Save mgerhardy/ab6b87ba5af1ed22a3327ed8e8195b4f to your computer and use it in GitHub Desktop.

Select an option

Save mgerhardy/ab6b87ba5af1ed22a3327ed8e8195b4f to your computer and use it in GitHub Desktop.
convert quake style comments to doxygen style comments
#!/usr/bin/env python3
# Converts Quake-style comments to Doxygen-style comments in C/C++ source files for easier IDE integration
# Usage: python quake_comment_to_doxygen.py <file.c|file.h>
# Example: python quake_comment_to_doxygen.py mysource.c
import re
import os
import sys
def convert_comment_block(comment, func_name):
# Split the comment into lines and clean up whitespace
lines = [line.strip() for line in comment.split('\n')]
# Remove empty lines from start and end, and filter out function name and separator lines
desc_lines = []
for line in lines:
if line and line != func_name and not re.match(r"=+", line):
desc_lines.append(line)
if not desc_lines:
# Return empty string to remove the comment entirely
return ""
# Check if we have a single line or multiple lines
if len(desc_lines) == 1:
# Single line - add @brief
return f"/**\n * @brief {desc_lines[0]}\n */"
else:
# Multiple lines - first line gets @brief, preserve paragraph structure
result = ["/**"]
# Add @brief to the first line
result.append(f" * @brief {desc_lines[0]}")
# Process remaining lines, preserving empty lines for paragraph breaks
original_lines = comment.split('\n')
in_description = False
found_first_desc_line = False
for original_line in original_lines:
stripped = original_line.strip()
# Skip function name and separator lines
if stripped == func_name or re.match(r"=+", stripped):
continue
# Skip empty lines at the beginning
if not stripped and not found_first_desc_line:
continue
# If this is the first description line, skip it (already handled with @brief)
if not found_first_desc_line and stripped:
found_first_desc_line = True
in_description = True
continue
if in_description:
if stripped:
result.append(f" * {stripped}")
else:
# Empty line - preserve as paragraph break
result.append(" *")
result.append(" */")
return "\n".join(result)
def process_file(filepath):
# Check if file is a C or H file
if not filepath.endswith(('.c', '.h')):
print(f"Error: Only .c and .h files are supported. Got: {filepath}")
return False
if not os.path.exists(filepath):
print(f"Error: File not found: {filepath}")
return False
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# Improved regex to find Quake-style comments before a function
# This pattern looks for comments that start with /* followed by = lines, function name, description, = lines, and */
pattern = re.compile(
r"/\*\s*\n\s*=+\s*\n\s*([A-Za-z_][A-Za-z0-9_]*)\s*\n((?:(?!^\s*=+\s*$).*\n)*?)\s*=+\s*\n\s*\*/",
re.MULTILINE
)
def replacer(match):
func_name = match.group(1).strip()
comment_body = match.group(2).strip()
new_comment = convert_comment_block(comment_body, func_name)
# If new_comment is empty, just remove the entire comment block
if not new_comment:
return ""
return new_comment
new_content, count = pattern.subn(replacer, content)
if count > 0:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"Updated {count} comments in {filepath}")
return True
else:
print(f"No Quake-style comments found in {filepath}")
return True
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python quake_comment_to_doxygen.py <file.c|file.h>")
print("Converts Quake-style function comments to Doxygen format")
sys.exit(1)
filepath = sys.argv[1]
if process_file(filepath):
print("Conversion completed successfully")
else:
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment