1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 '''Simple module for extracting GNOME style doc comments from C
3 sources, so I can use them for other purposes.'''
5 import sys, os, string, re
15 def set_name(self, name):
17 def add_param(self, name, description):
20 self.params.append((name, description))
21 def append_to_last_param(self, extra):
22 self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra)
23 def append_to_named_param(self, name, extra):
24 for i in range(len(self.params)):
25 if self.params[i][0] == name:
26 self.params[i] = (name, self.params[i][1] + extra)
28 # fall through to adding extra parameter ...
29 self.add_param(name, extra)
30 def append_description(self, extra):
31 self.description = self.description + extra
32 def append_return(self, extra):
33 self.ret = self.ret + extra
35 def get_param_description(self, name):
36 for param, description in self.params:
42 comment_start_pat = re.compile(r'^\s*/\*\*\s')
43 comment_end_pat = re.compile(r'^\s*\*+/')
44 comment_line_lead = re.compile(r'^\s*\*\s*')
45 funcname_pat = re.compile(r'^(\w+)\s*:?')
46 return_pat = re.compile(r'^(returns:|return\s+value:|returns\s*)(.*\n?)$',
48 param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$')
50 def parse_file(fp, doc_dict):
54 if not in_comment_block:
55 if comment_start_pat.match(line):
57 cur_doc = FunctionDoc()
63 # we are inside a comment block ...
64 if comment_end_pat.match(line):
66 sys.stderr.write("no function name found in doc comment\n")
68 doc_dict[cur_doc.name] = cur_doc
73 # inside a comment block, and not the end of the block ...
74 line = comment_line_lead.sub('', line)
75 if not line: line = '\n'
78 match = funcname_pat.match(line)
80 cur_doc.set_name(match.group(1))
82 match = return_pat.match(line)
84 # assume the last return statement was really part of the
86 return_start = match.group(1)
87 cur_doc.ret = match.group(2)
88 cur_doc.description = cur_doc.description + return_start + \
91 cur_doc.append_return(line)
93 if line[:12] == 'Description:':
95 match = return_pat.match(line)
98 return_start = match.group(1)
99 cur_doc.append_return(match.group(2))
101 cur_doc.append_description(line)
106 match = param_pat.match(line)
108 param = match.group(1)
109 desc = match.group(2)
110 if param == 'returns':
113 cur_doc.add_param(param, desc)
115 # must be continuation
117 if param == 'returns':
118 cur_doc.append_return(line)
120 cur_doc.append_to_last_param(line)
122 sys.stderr.write('something weird while reading param\n')
125 def parse_dir(dir, doc_dict):
126 for file in os.listdir(dir):
127 if file in ('.', '..'): continue
128 path = os.path.join(dir, file)
129 if os.path.isdir(path):
130 parse_dir(path, doc_dict)
131 if len(file) > 2 and file[-2:] == '.c':
132 parse_file(open(path, 'r'), doc_dict)
134 def extract(dirs, doc_dict=None):
135 if not doc_dict: doc_dict = {}
137 parse_dir(dir, doc_dict)
140 tmpl_section_pat = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
141 def parse_tmpl(fp, doc_dict):
146 match = tmpl_section_pat.match(line)
148 cur_doc = None # new input shouldn't affect the old doc dict
149 sect_type = match.group(1)
150 sect_name = match.group(2)
152 if sect_type == 'FUNCTION':
153 cur_doc = doc_dict.get(sect_name)
155 cur_doc = FunctionDoc()
156 cur_doc.set_name(sect_name)
157 doc_dict[sect_name] = cur_doc
158 elif line == '<!-- # Unused Parameters # -->\n':
159 cur_doc = None # don't worry about unused params.
161 if line[:10] == '@Returns: ':
162 if string.strip(line[10:]):
163 cur_doc.append_return(line[10:])
165 pos = string.find(line, ':')
167 cur_doc.append_to_named_param(line[1:pos], line[pos+1:])
169 cur_doc.append_description(line)
171 cur_doc.append_description(line)
175 def extract_tmpl(dirs, doc_dict=None):
176 if not doc_dict: doc_dict = {}
178 for file in os.listdir(dir):
179 if file in ('.', '..'): continue
180 path = os.path.join(dir, file)
181 if os.path.isdir(path):
183 if len(file) > 2 and file[-2:] == '.sgml':
184 parse_tmpl(open(path, 'r'), doc_dict)