2 # -*- coding: utf-8 -*-
3 # nghttp2 - HTTP/2 C Library
5 # Copyright (c) 2012 Tatsuhiro Tsujikawa
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
15 # The above copyright notice and this permission notice shall be
16 # included in all copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 # Generates API reference from C source code.
28 from __future__ import unicode_literals
29 from __future__ import print_function # At least python 2.6 is required
30 import re, sys, argparse, os.path
33 def __init__(self, name, content, domain):
35 self.content = content
37 if self.domain == 'function':
38 self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
41 out.write('.. {}:: {}\n'.format(self.domain, self.name))
43 for line in self.content:
44 out.write(' {}\n'.format(line))
47 def __init__(self, name, content, members, member_domain):
49 self.content = content
50 self.members = members
51 self.member_domain = member_domain
55 out.write('.. type:: {}\n'.format(self.name))
57 for line in self.content:
58 out.write(' {}\n'.format(line))
60 for name, content in self.members:
61 out.write(' .. {}:: {}\n'.format(self.member_domain, name))
64 out.write(' {}\n'.format(line))
68 def __init__(self, name, content):
70 self.content = content
73 out.write('''.. macro:: {}\n'''.format(self.name))
75 for line in self.content:
76 out.write(' {}\n'.format(line))
78 def make_api_ref(infiles):
83 for infile in infiles:
85 line = infile.readline()
89 line = infile.readline()
90 doctype = line.split()[1]
91 if doctype == '@function':
92 functions.append(process_function('function', infile))
93 elif doctype == '@functypedef':
94 types.append(process_function('type', infile))
95 elif doctype == '@struct' or doctype == '@union':
96 types.append(process_struct(infile))
97 elif doctype == '@enum':
98 enums.append(process_enum(infile))
99 elif doctype == '@macro':
100 macros.append(process_macro(infile))
101 return macros, enums, types, functions
103 alldocs = [('Macros', macros),
105 ('Types (structs, unions and typedefs)', types),
106 ('Functions', functions)]
109 indexfile, macrosfile, enumsfile, typesfile, funcsdir,
110 macros, enums, types, functions):
123 for doc in functions:
124 indexfile.write(' {}\n'.format(doc.funcname))
131 doc.write(macrosfile)
141 Types (structs, unions and typedefs)
142 ====================================
147 for doc in functions:
148 with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
156 *#include <nghttp2/nghttp2.h>*
158 '''.format(funcname=doc.funcname, secul='='*len(doc.funcname)))
161 def process_macro(infile):
162 content = read_content(infile)
163 line = infile.readline()
164 macro_name = line.split()[1]
165 return MacroDoc(macro_name, content)
167 def process_enum(infile):
170 content = read_content(infile)
172 line = infile.readline()
175 elif re.match(r'\s*/\*\*\n', line):
176 member_content = read_content(infile)
177 line = infile.readline()
179 member_name = items[0]
181 member_content.insert(0, '(``{}``) '\
182 .format(' '.join(items[2:]).rstrip(',')))
183 members.append((member_name, member_content))
184 elif line.startswith('}'):
185 enum_name = line.rstrip().split()[1]
186 enum_name = re.sub(r';$', '', enum_name)
188 return StructDoc(enum_name, content, members, 'macro')
190 def process_struct(infile):
193 content = read_content(infile)
195 line = infile.readline()
198 elif re.match(r'\s*/\*\*\n', line):
199 member_content = read_content(infile)
200 line = infile.readline()
201 member_name = line.rstrip().rstrip(';')
202 members.append((member_name, member_content))
203 elif line.startswith('}') or\
204 (line.startswith('typedef ') and line.endswith(';\n')):
205 if line.startswith('}'):
209 struct_name = line.rstrip().split()[index]
210 struct_name = re.sub(r';$', '', struct_name)
212 return StructDoc(struct_name, content, members, 'member')
214 def process_function(domain, infile):
215 content = read_content(infile)
218 line = infile.readline()
224 func_proto.append(line)
225 func_proto = ''.join(func_proto)
226 func_proto = re.sub(r';\n$', '', func_proto)
227 func_proto = re.sub(r'\s+', ' ', func_proto)
228 func_proto = re.sub(r'NGHTTP2_EXTERN ', '', func_proto)
229 return FunctionDoc(func_proto, content, domain)
231 def read_content(infile):
234 line = infile.readline()
237 if re.match(r'\s*\*/\n', line):
240 content.append(transform_content(line.rstrip()))
243 def arg_repl(matchobj):
244 return '*{}*'.format(matchobj.group(1).replace('*', '\\*'))
246 def transform_content(content):
247 content = re.sub(r'^\s+\* ?', '', content)
248 content = re.sub(r'\|([^\s|]+)\|', arg_repl, content)
249 content = re.sub(r':enum:', ':macro:', content)
252 if __name__ == '__main__':
253 parser = argparse.ArgumentParser(description="Generate API reference")
254 parser.add_argument('index', type=argparse.FileType('w'),
255 help='index output file')
256 parser.add_argument('macros', type=argparse.FileType('w'),
257 help='macros section output file. The filename should be macros.rst')
258 parser.add_argument('enums', type=argparse.FileType('w'),
259 help='enums section output file. The filename should be enums.rst')
260 parser.add_argument('types', type=argparse.FileType('w'),
261 help='types section output file. The filename should be types.rst')
262 parser.add_argument('funcsdir',
263 help='functions doc output dir')
264 parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
266 args = parser.parse_args()
271 for infile in args.files:
272 m, e, t, f = make_api_ref(args.files)
277 funcs.sort(key=lambda x: x.funcname)
279 args.index, args.macros, args.enums, args.types, args.funcsdir,
280 macros, enums, types, funcs)