Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / doc / mkapiref.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # nghttp2 - HTTP/2 C Library
4
5 # Copyright (c) 2012 Tatsuhiro Tsujikawa
6
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:
14
15 # The above copyright notice and this permission notice shall be
16 # included in all copies or substantial portions of the Software.
17
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.
25
26 # Generates API reference from C source code.
27
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
31
32 class FunctionDoc:
33     def __init__(self, name, content, domain):
34         self.name = name
35         self.content = content
36         self.domain = domain
37         if self.domain == 'function':
38             self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
39
40     def write(self, out):
41         out.write('.. {}:: {}\n'.format(self.domain, self.name))
42         out.write('\n')
43         for line in self.content:
44             out.write('    {}\n'.format(line))
45
46 class StructDoc:
47     def __init__(self, name, content, members, member_domain):
48         self.name = name
49         self.content = content
50         self.members = members
51         self.member_domain = member_domain
52
53     def write(self, out):
54         if self.name:
55             out.write('.. type:: {}\n'.format(self.name))
56             out.write('\n')
57             for line in self.content:
58                 out.write('    {}\n'.format(line))
59             out.write('\n')
60             for name, content in self.members:
61                 out.write('    .. {}:: {}\n'.format(self.member_domain, name))
62                 out.write('\n')
63                 for line in content:
64                     out.write('        {}\n'.format(line))
65             out.write('\n')
66
67 class MacroDoc:
68     def __init__(self, name, content):
69         self.name = name
70         self.content = content
71
72     def write(self, out):
73         out.write('''.. macro:: {}\n'''.format(self.name))
74         out.write('\n')
75         for line in self.content:
76             out.write('    {}\n'.format(line))
77
78 def make_api_ref(infiles):
79     macros = []
80     enums = []
81     types = []
82     functions = []
83     for infile in infiles:
84         while True:
85             line = infile.readline()
86             if not line:
87                 break
88             elif line == '/**\n':
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
102
103     alldocs = [('Macros', macros),
104                ('Enums', enums),
105                ('Types (structs, unions and typedefs)', types),
106                ('Functions', functions)]
107
108 def output(
109         indexfile, macrosfile, enumsfile, typesfile, funcsdir,
110         macros, enums, types, functions):
111     indexfile.write('''
112 API Reference
113 =============
114
115 .. toctree::
116    :maxdepth: 1
117
118    macros
119    enums
120    types
121 ''')
122
123     for doc in functions:
124         indexfile.write('   {}\n'.format(doc.funcname))
125
126     macrosfile.write('''
127 Macros
128 ======
129 ''')
130     for doc in macros:
131         doc.write(macrosfile)
132
133     enumsfile.write('''
134 Enums
135 =====
136 ''')
137     for doc in enums:
138         doc.write(enumsfile)
139
140     typesfile.write('''
141 Types (structs, unions and typedefs)
142 ====================================
143 ''')
144     for doc in types:
145         doc.write(typesfile)
146
147     for doc in functions:
148         with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
149             f.write('''
150 {funcname}
151 {secul}
152
153 Synopsis
154 --------
155
156 *#include <nghttp2/nghttp2.h>*
157
158 '''.format(funcname=doc.funcname, secul='='*len(doc.funcname)))
159             doc.write(f)
160
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)
166
167 def process_enum(infile):
168     members = []
169     enum_name = None
170     content = read_content(infile)
171     while True:
172         line = infile.readline()
173         if not line:
174             break
175         elif re.match(r'\s*/\*\*\n', line):
176             member_content = read_content(infile)
177             line = infile.readline()
178             items = line.split()
179             member_name = items[0]
180             if len(items) >= 3:
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)
187             break
188     return StructDoc(enum_name, content, members, 'macro')
189
190 def process_struct(infile):
191     members = []
192     struct_name = None
193     content = read_content(infile)
194     while True:
195         line = infile.readline()
196         if not line:
197             break
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('}'):
206                 index = 1
207             else:
208                 index = 3
209             struct_name = line.rstrip().split()[index]
210             struct_name = re.sub(r';$', '', struct_name)
211             break
212     return StructDoc(struct_name, content, members, 'member')
213
214 def process_function(domain, infile):
215     content = read_content(infile)
216     func_proto = []
217     while True:
218         line = infile.readline()
219         if not line:
220             break
221         elif line == '\n':
222             break
223         else:
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)
230
231 def read_content(infile):
232     content = []
233     while True:
234         line = infile.readline()
235         if not line:
236             break
237         if re.match(r'\s*\*/\n', line):
238             break
239         else:
240             content.append(transform_content(line.rstrip()))
241     return content
242
243 def arg_repl(matchobj):
244     return '*{}*'.format(matchobj.group(1).replace('*', '\\*'))
245
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)
250     return content
251
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'),
265                         help='source file')
266     args = parser.parse_args()
267     macros = []
268     enums = []
269     types = []
270     funcs = []
271     for infile in args.files:
272         m, e, t, f = make_api_ref(args.files)
273         macros.extend(m)
274         enums.extend(e)
275         types.extend(t)
276         funcs.extend(f)
277     funcs.sort(key=lambda x: x.funcname)
278     output(
279         args.index, args.macros, args.enums, args.types, args.funcsdir,
280         macros, enums, types, funcs)