Initial import to Tizen
[profile/ivi/gstreamer-python.git] / codegen / docextract.py
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.'''
4
5 import sys, os, string, re
6
7 __all__ = ['extract']
8
9 class FunctionDoc:
10     def __init__(self):
11         self.name = None
12         self.params = []
13         self.description = ''
14         self.ret = ''
15     def set_name(self, name):
16         self.name = name
17     def add_param(self, name, description):
18         if name == '...':
19             name = 'Varargs'
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)
27                 return
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
34
35     def get_param_description(self, name):
36         for param, description in self.params:
37             if param == name:
38                 return description
39         else:
40             return ''
41
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?)$',
47                         re.IGNORECASE)
48 param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$')
49
50 def parse_file(fp, doc_dict):
51     line = fp.readline()
52     in_comment_block = 0
53     while line:
54         if not in_comment_block:
55             if comment_start_pat.match(line):
56                 in_comment_block = 1
57                 cur_doc = FunctionDoc()
58                 in_description = 0
59                 in_return = 0
60             line = fp.readline()
61             continue
62
63         # we are inside a comment block ...
64         if comment_end_pat.match(line):
65             if not cur_doc.name:
66                 sys.stderr.write("no function name found in doc comment\n")
67             else:
68                 doc_dict[cur_doc.name] = cur_doc
69             in_comment_block = 0
70             line = fp.readline()
71             continue
72
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'
76
77         if not cur_doc.name:
78             match = funcname_pat.match(line)
79             if match:
80                 cur_doc.set_name(match.group(1))
81         elif in_return:
82             match = return_pat.match(line)
83             if match:
84                 # assume the last return statement was really part of the
85                 # description
86                 return_start = match.group(1)
87                 cur_doc.ret = match.group(2)
88                 cur_doc.description = cur_doc.description + return_start + \
89                                       cur_doc.ret
90             else:
91                 cur_doc.append_return(line)
92         elif in_description:
93             if line[:12] == 'Description:':
94                 line = line[12:]
95             match = return_pat.match(line)
96             if match:
97                 in_return = 1
98                 return_start = match.group(1)
99                 cur_doc.append_return(match.group(2))
100             else:
101                 cur_doc.append_description(line)
102         elif line == '\n':
103             # end of parameters
104             in_description = 1
105         else:
106             match = param_pat.match(line)
107             if match:
108                 param = match.group(1)
109                 desc = match.group(2)
110                 if param == 'returns':
111                     cur_doc.ret = desc
112                 else:
113                     cur_doc.add_param(param, desc)
114             else:
115                 # must be continuation
116                 try:
117                     if param == 'returns':
118                         cur_doc.append_return(line)
119                     else:
120                         cur_doc.append_to_last_param(line)
121                 except:
122                     sys.stderr.write('something weird while reading param\n')
123         line = fp.readline()
124
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)
133
134 def extract(dirs, doc_dict=None):
135     if not doc_dict: doc_dict = {}
136     for dir in dirs:
137         parse_dir(dir, doc_dict)
138     return doc_dict
139
140 tmpl_section_pat = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
141 def parse_tmpl(fp, doc_dict):
142     cur_doc = None
143
144     line = fp.readline()
145     while line:
146         match = tmpl_section_pat.match(line)
147         if match:
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)
151
152             if sect_type == 'FUNCTION':
153                 cur_doc = doc_dict.get(sect_name)
154                 if not cur_doc:
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.
160         elif cur_doc:
161             if line[:10] == '@Returns: ':
162                 if string.strip(line[10:]):
163                     cur_doc.append_return(line[10:])
164             elif line[0] == '@':
165                 pos = string.find(line, ':')
166                 if pos >= 0:
167                     cur_doc.append_to_named_param(line[1:pos], line[pos+1:])
168                 else:
169                     cur_doc.append_description(line)
170             else:
171                 cur_doc.append_description(line)
172
173         line = fp.readline()
174
175 def extract_tmpl(dirs, doc_dict=None):
176     if not doc_dict: doc_dict = {}
177     for dir in dirs:
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):
182                 continue
183             if len(file) > 2 and file[-2:] == '.sgml':
184                 parse_tmpl(open(path, 'r'), doc_dict)
185     return doc_dict