tizen 2.4 release
[external/nghttp2.git] / doc / mkapiref.py
1 #!/usr/bin/env python
2 # nghttp2 - HTTP/2 C Library
3
4 # Copyright (c) 2012 Tatsuhiro Tsujikawa
5
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
13
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
16
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 # Generates API reference from C source code.
26 from __future__ import print_function # At least python 2.6 is required
27 import re, sys, argparse
28
29 class FunctionDoc:
30     def __init__(self, name, content, domain):
31         self.name = name
32         self.content = content
33         self.domain = domain
34
35     def write(self, out):
36         print('''.. {}:: {}'''.format(self.domain, self.name))
37         print('')
38         for line in self.content:
39             print('    {}'.format(line))
40
41 class StructDoc:
42     def __init__(self, name, content, members, member_domain):
43         self.name = name
44         self.content = content
45         self.members = members
46         self.member_domain = member_domain
47
48     def write(self, out):
49         if self.name:
50             print('''.. type:: {}'''.format(self.name))
51             print('')
52             for line in self.content:
53                 print('    {}'.format(line))
54             print('')
55             for name, content in self.members:
56                 print('''    .. {}:: {}'''.format(self.member_domain, name))
57                 print('')
58                 for line in content:
59                     print('''        {}'''.format(line))
60             print('')
61
62 class MacroDoc:
63     def __init__(self, name, content):
64         self.name = name
65         self.content = content
66
67     def write(self, out):
68         print('''.. macro:: {}'''.format(self.name))
69         print('')
70         for line in self.content:
71             print('    {}'.format(line))
72
73 def make_api_ref(infiles):
74     macros = []
75     enums = []
76     types = []
77     functions = []
78     for infile in infiles:
79         while True:
80             line = infile.readline()
81             if not line:
82                 break
83             elif line == '/**\n':
84                 line = infile.readline()
85                 doctype = line.split()[1]
86                 if doctype == '@function':
87                     functions.append(process_function('function', infile))
88                 elif doctype == '@functypedef':
89                     types.append(process_function('type', infile))
90                 elif doctype == '@struct' or doctype == '@union':
91                     types.append(process_struct(infile))
92                 elif doctype == '@enum':
93                     enums.append(process_enum(infile))
94                 elif doctype == '@macro':
95                     macros.append(process_macro(infile))
96     alldocs = [('Macros', macros),
97                ('Enums', enums),
98                ('Types (structs, unions and typedefs)', types),
99                ('Functions', functions)]
100     for title, docs in alldocs:
101         if not docs:
102             continue
103         print(title)
104         print('-'*len(title))
105         for doc in docs:
106             doc.write(sys.stdout)
107             print('')
108         print('')
109
110 def process_macro(infile):
111     content = read_content(infile)
112     line = infile.readline()
113     macro_name = line.split()[1]
114     return MacroDoc(macro_name, content)
115
116 def process_enum(infile):
117     members = []
118     enum_name = None
119     content = read_content(infile)
120     while True:
121         line = infile.readline()
122         if not line:
123             break
124         elif re.match(r'\s*/\*\*\n', line):
125             member_content = read_content(infile)
126             line = infile.readline()
127             items = line.split()
128             member_name = items[0]
129             if len(items) >= 3:
130                 member_content.insert(0, '(``{}``) '\
131                                       .format(' '.join(items[2:]).rstrip(',')))
132             members.append((member_name, member_content))
133         elif line.startswith('}'):
134             enum_name = line.rstrip().split()[1]
135             enum_name = re.sub(r';$', '', enum_name)
136             break
137     return StructDoc(enum_name, content, members, 'macro')
138
139 def process_struct(infile):
140     members = []
141     struct_name = None
142     content = read_content(infile)
143     while True:
144         line = infile.readline()
145         if not line:
146             break
147         elif re.match(r'\s*/\*\*\n', line):
148             member_content = read_content(infile)
149             line = infile.readline()
150             member_name = line.rstrip().rstrip(';')
151             members.append((member_name, member_content))
152         elif line.startswith('}') or\
153                 (line.startswith('typedef ') and line.endswith(';\n')):
154             if line.startswith('}'):
155                 index = 1
156             else:
157                 index = 3
158             struct_name = line.rstrip().split()[index]
159             struct_name = re.sub(r';$', '', struct_name)
160             break
161     return StructDoc(struct_name, content, members, 'member')
162
163 def process_function(domain, infile):
164     content = read_content(infile)
165     func_proto = []
166     while True:
167         line = infile.readline()
168         if not line:
169             break
170         elif line == '\n':
171             break
172         else:
173             func_proto.append(line)
174     func_proto = ''.join(func_proto)
175     func_proto = re.sub(r';\n$', '', func_proto)
176     func_proto = re.sub(r'\s+', ' ', func_proto)
177     return FunctionDoc(func_proto, content, domain)
178
179 def read_content(infile):
180     content = []
181     while True:
182         line = infile.readline()
183         if not line:
184             break
185         if re.match(r'\s*\*/\n', line):
186             break
187         else:
188             content.append(transform_content(line.rstrip()))
189     return content
190
191 def arg_repl(matchobj):
192     return '*{}*'.format(matchobj.group(1).replace('*', '\\*'))
193
194 def transform_content(content):
195     content = re.sub(r'^\s+\* ?', '', content)
196     content = re.sub(r'\|([^\s|]+)\|', arg_repl, content)
197     content = re.sub(r':enum:', ':macro:', content)
198     return content
199
200 if __name__ == '__main__':
201     parser = argparse.ArgumentParser(description="Generate API reference")
202     parser.add_argument('--header', type=argparse.FileType('r'),
203                         help='header inserted at the top of the page')
204     parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
205                         help='source file')
206     args = parser.parse_args()
207     if args.header:
208         print(args.header.read())
209     for infile in args.files:
210         make_api_ref(args.files)