xref: /btstack/doc/manual/markdown_create_apis.py (revision d7ef06763dbbdaadb5793c01f64e681cf932d402)
1#!/usr/bin/env python3
2import os, sys, getopt, re, pickle
3import subprocess
4
5class State:
6    SearchTitle = 0
7    SearchEndTitle = 1
8    SearchStartAPI = 2
9    SearchEndAPI = 3
10    DoneAPI = 4
11
12api_files = []
13functions = {}
14typedefs = {}
15
16api_header = """
17
18## API_TITLE API {#sec:API_LABLEAPIAppendix}
19
20"""
21
22api_ending = """
23"""
24
25code_ref = """GITHUBFPATH#LLINENR"""
26
27
28def isEndOfComment(line):
29    return re.match('\s*\*/.*', line)
30
31def isStartOfComment(line):
32    return re.match('\s*\/\*/.*', line)
33
34def isTypedefStart(line):
35    return re.match('.*typedef\s+struct.*', line)
36
37def codeReference(fname, githuburl, filepath, linenr):
38    global code_ref
39    ref = code_ref.replace("GITHUB", githuburl)
40    ref = ref.replace("FPATH", filepath)
41    ref = ref.replace("LINENR", str(linenr))
42    return ref
43
44
45def writeAPI(fout, fin, mk_codeidentation):
46    state = State.SearchStartAPI
47
48    for line in fin:
49        if state == State.SearchStartAPI:
50            parts = re.match('.*API_START.*',line)
51            if parts:
52                state = State.SearchEndAPI
53            continue
54
55        if state == State.SearchEndAPI:
56            parts = re.match('.*API_END.*',line)
57            if parts:
58                state = State.DoneAPI
59                continue
60            fout.write(mk_codeidentation + line)
61            continue
62
63
64linenr = 0
65typedefFound = 0
66multiline_function_def = 0
67state = State.SearchStartAPI
68
69def createIndex(fin, api_filename, api_title, api_lable, githuburl):
70    global typedefs, functions
71    global linenr, multiline_function_def, typedefFound, state
72
73
74    for line in fin:
75        if state == State.DoneAPI:
76            continue
77
78        linenr = linenr + 1
79
80        if state == State.SearchStartAPI:
81            parts = re.match('.*API_START.*',line)
82            if parts:
83                state = State.SearchEndAPI
84            continue
85
86        if state == State.SearchEndAPI:
87            parts = re.match('.*API_END.*',line)
88            if parts:
89                state = State.DoneAPI
90                continue
91
92        if multiline_function_def:
93            function_end = re.match('.*;\n', line)
94            if function_end:
95                multiline_function_def = 0
96            continue
97
98        param = re.match(".*@brief.*", line)
99        if param:
100            continue
101        param = re.match(".*@param.*", line)
102        if param:
103            continue
104        param = re.match(".*@return.*", line)
105        if param:
106            continue
107
108        # search typedef struct begin
109        if isTypedefStart(line):
110            typedefFound = 1
111
112        # search typedef struct end
113        if typedefFound:
114            typedef = re.match('}\s*(.*);\n', line)
115            if typedef:
116                typedefFound = 0
117                typedefs[typedef.group(1)] = codeReference(typedef.group(1), githuburl, api_filename, linenr)
118            continue
119
120        ref_function =  re.match('.*typedef\s+void\s+\(\s*\*\s*(.*?)\)\(.*', line)
121        if ref_function:
122            functions[ref_function.group(1)] = codeReference(ref_function.group(1), githuburl, api_filename, linenr)
123            continue
124
125
126        one_line_function_definition = re.match('(.*?)\s*\(.*\(*.*;\n', line)
127        if one_line_function_definition:
128            parts = one_line_function_definition.group(1).split(" ");
129            name = parts[len(parts)-1]
130            if len(name) == 0:
131                print(parts);
132                sys.exit(10)
133            functions[name] = codeReference( name, githuburl, api_filename, linenr)
134            continue
135
136        multi_line_function_definition = re.match('.(.*?)\s*\(.*\(*.*', line)
137        if multi_line_function_definition:
138            parts = multi_line_function_definition.group(1).split(" ");
139
140            name = parts[len(parts)-1]
141            if len(name) == 0:
142                print(parts);
143                sys.exit(10)
144            multiline_function_def = 1
145            functions[name] = codeReference(name, githuburl, api_filename, linenr)
146
147
148def findTitle(fin):
149    title = None
150    desc = ""
151    state = State.SearchTitle
152
153    for line in fin:
154        if state == State.SearchTitle:
155            if isStartOfComment(line):
156                continue
157
158            parts = re.match('.*(@title)(.*)', line)
159            if parts:
160                title = parts.group(2).strip()
161                state = State.SearchEndTitle
162                continue
163
164        if state == State.SearchEndTitle:
165            if (isEndOfComment(line)):
166                state = State.DoneAPI
167                break
168
169            parts = re.match('(\s*\*\s*)(.*\n)',line)
170            if parts:
171                desc = desc + parts.group(2)
172    return title, desc
173
174def main(argv):
175    global linenr, multiline_function_def, typedefFound, state
176
177    mk_codeidentation = "    "
178    git_branch_name = "master"
179    btstackfolder = "../../"
180    githuburl  = "https://github.com/bluekitchen/btstack/blob/master/"
181    markdownfolder = "docs-markdown/"
182
183    cmd = 'markdown_create_apis.py [-r <root_btstackfolder>] [-g <githuburl>] [-o <output_markdownfolder>]'
184    try:
185        opts, args = getopt.getopt(argv,"r:g:o:",["rfolder=","github=","ofolder="])
186    except getopt.GetoptError:
187        print (cmd)
188        sys.exit(2)
189    for opt, arg in opts:
190        if opt == '-h':
191            print (cmd)
192            sys.exit()
193        elif opt in ("-r", "--rfolder"):
194            btstackfolder = arg
195        elif opt in ("-g", "--github"):
196            githuburl = arg
197        elif opt in ("-o", "--ofolder"):
198            markdownfolder = arg
199
200    apifile   = markdownfolder + "appendix/apis.md"
201    # indexfile = markdownfolder + "api_index.md"
202    btstack_srcfolder = btstackfolder + "src/"
203
204    try:
205        output = subprocess.check_output("git symbolic-ref --short HEAD", stderr=subprocess.STDOUT, timeout=3, shell=True)
206        git_branch_name = output.decode().rstrip()
207    except subprocess.CalledProcessError as exc:
208        print('GIT branch name: failed to get, use default value \"%s\""  ', git_branch_name, exc.returncode, exc.output)
209    else:
210        print ('GIT branch name :  %s' % git_branch_name)
211
212    githuburl = githuburl + git_branch_name
213
214    print ('BTstack src folder is : ' + btstack_srcfolder)
215    print ('API file is       : ' + apifile)
216    print ('Github URL is    : ' +  githuburl)
217    # print ('Index file is     : ' + indexfile)
218
219
220    for root, dirs, files in os.walk(btstack_srcfolder, topdown=True):
221        for f in files:
222            if not f.endswith(".h"):
223                continue
224            api_files.append(root + "/" + f)
225
226    api_files.sort()
227
228    print(api_files)
229
230    with open(apifile, 'w') as fout:
231        fout.write("#\n\n")
232
233        for api_filename in api_files:
234            api_title = None
235            api_lable = None
236
237            print(api_filename)
238
239            with open(api_filename, 'r') as fin:
240                api_title, api_desc = findTitle(fin)
241                if api_title:
242                    api_lable = f[:-2]
243
244                    title = api_header.replace("API_TITLE", api_title).replace("API_LABLE", api_lable)
245                    fout.write(title)
246                    fout.write(api_desc)
247
248                    writeAPI(fout, fin, mk_codeidentation)
249                fin.close()
250
251            if api_title:
252
253                linenr = 0
254                typedefFound = 0
255                multiline_function_def = 0
256                state = State.SearchStartAPI
257
258                with open(api_filename, 'r') as fin:
259                    createIndex(fin, api_filename, api_title, api_lable, githuburl)
260                    fin.close()
261
262    for function in functions:
263        parts = function.split(' ')
264        if (len(parts) > 1):
265            print (parts)
266
267    references = functions.copy()
268    references.update(typedefs)
269
270    # with open(indexfile, 'w') as fout:
271    #     for function, reference in references.items():
272    #         fout.write("[" + function + "](" + reference + ")\n")
273
274    pickle.dump(references, open("references.p", "wb" ) )
275
276if __name__ == "__main__":
277   main(sys.argv[1:])
278