@ -3,6 +3,7 @@
c_util - C code navigation utility
Commands:
toc - Show table of contents for all files
description <names...> - Show selected items with comments
func <file> <name> - Show function code
struct <file> <name> - Show struct definition
enum <file> <name> - Show enum definition
@ -570,7 +571,7 @@ def get_function_signature(lines, func):
return sig
def get_declaration_text(lines, decl):
def get_declaration_text(lines, decl, include_comments=False ):
"""Get normalized declaration text for struct/enum."""
start = decl['start']
end = decl['end']
@ -579,21 +580,86 @@ def get_declaration_text(lines, decl):
decl_lines = []
for i in range(start, min(end + 1, len(lines))):
line = lines[i]
# Remove comments
if '//' in line:
line = line[:line.index('//')]
if not include_comments:
# Remove comments
if '//' in line:
line = line[:line.index('//')]
decl_lines.append(line)
# Join and normalize
text = ' '.join(decl_lines)
text = normalize_whitespace(text)
if include_comments:
# Normalize: one tab indent, remove empty lines, normalize whitespace
result_lines = []
for line in decl_lines:
# Skip empty lines
if not line.strip():
continue
# Normalize whitespace and use one tab for indentation
normalized = normalize_whitespace(line)
if normalized:
result_lines.append('\t' + normalized)
return '\n'.join(result_lines)
else:
# Join and normalize for toc mode
text = ' '.join(decl_lines)
text = normalize_whitespace(text)
return text
def get_function_comments(pre_lines):
"""Extract function comments from pre_lines.
Returns:
- Last /* */ block if found (including single-line /* */)
- Or consecutive // lines (without empty lines or non-comment lines)
- Empty string if no suitable comments
"""
if not pre_lines:
return ""
return text
# Look for last /* */ block
last_block_comment = ""
in_block = False
block_start = -1
for i, line in enumerate(pre_lines):
stripped = line.strip()
if stripped.startswith('/*'):
# Check if it's a single-line comment /* ... */
if stripped.endswith('*/'):
# Single-line block comment
last_block_comment = line
else:
# Start of multi-line block comment
in_block = True
block_start = i
elif in_block and stripped.endswith('*/'):
in_block = False
# Extract the block
block_lines = pre_lines[block_start:i+1]
last_block_comment = '\n'.join(block_lines)
elif stripped.startswith('*/'):
in_block = False
if last_block_comment:
return last_block_comment
# Look for consecutive // lines (from the end, backwards)
comment_lines = []
for line in reversed(pre_lines):
stripped = line.strip()
if stripped.startswith('//'):
comment_lines.insert(0, stripped)
elif not stripped: # Skip empty lines
continue
else: # Non-comment line breaks the sequence
break
return '\n'.join(comment_lines) if comment_lines else ""
def main():
if len(sys.argv) < 2:
print("Usage: c_util toc | func <file> <funcname> | struct <file> <structname> | enum <file> <enumname>")
print("Usage: c_util toc | description <name1> [name2] ... | func <file> <funcname> | struct <file> <structname> | enum <file> <enumname>")
sys.exit(1)
cmd = sys.argv[1]
@ -654,6 +720,70 @@ def main():
for start, end, text in declarations:
print(f"[{start + 1}-{end + 1}] {text}")
elif cmd == 'description':
# Get list of names to look for
if len(sys.argv) < 3:
print("Usage: c_util description <name1> [name2] ...")
sys.exit(1)
target_names = set(sys.argv[2:])
first_file = True
for f in files:
if f not in contents:
continue
# Collect all matching declarations with full info
declarations = []
# Check functions
for func in project_functions.get(f, []):
if func['name'] in target_names:
# Get signature
sig = get_function_signature(contents[f], func)
# Get comments
comments = get_function_comments(func['pre'])
declarations.append((func['start'], func['end'], 'function', sig, comments))
# Check structs
for s in project_structs.get(f, []):
if s['name'] in target_names:
# Get full text with formatting and comments
text = get_declaration_text(contents[f], s, include_comments=True)
declarations.append((s['start'], s['end'], 'struct', s['name'], text))
# Check enums
for e in project_enums.get(f, []):
if e['name'] in target_names:
# Get full text with formatting and comments
text = get_declaration_text(contents[f], e, include_comments=True)
declarations.append((e['start'], e['end'], 'enum', e['name'], text))
if not declarations:
continue
# Sort by line number
declarations.sort(key=lambda x: x[0])
# Print empty line between files (except before first)
if not first_file:
print()
first_file = False
# Print filename header
print(f"{f}:")
# Print declarations with full formatting
for start, end, decl_type, content, extra in declarations:
if decl_type == 'function':
# Print comments first if any
if extra:
print(extra)
print(f"[{start + 1}-{end + 1}] {content}")
else:
# struct or enum - print with preserved formatting on multiple lines
print(f"[{start + 1}-{end + 1}] {extra}")
elif cmd == 'func':
if len(sys.argv) < 4:
print("Usage: c_util func <file> <funcname>")