xref: /btstack/doc/manual/markdown_create_apis.py (revision c8c342a60cecea7e71c1797120a10dfce0796d05)
1#!/usr/bin/env python3
2import os, sys, getopt, re, pickle
3import subprocess
4
5class State:
6    SearchStartAPI = 0
7    SearchEndAPI = 1
8    DoneAPI = 2
9
10# [file_name, api_title, api_label]
11apis = [
12    ["src/ad_parser.h", "AD Data (Advertisements and EIR) Parser", "advParser"],
13    ["src/btstack_chipset.h","BTstack Chipset","btMemory"],
14    ["src/btstack_control.h","BTstack Hardware Control","btControl"],
15    ["src/btstack_event.h","HCI Event Getter","btEvent"],
16    ["src/btstack_linked_list.h","BTstack Linked List","btList"],
17    ["src/btstack_memory.h","BTstack Memory Management","btMemory"],
18    ["src/btstack_run_loop.h", "Run Loop", "runLoop"],
19    ["src/btstack_tlv.h", "Tag Value Length Persistent Storage (TLV)", "tlv"],
20    ["src/btstack_util.h", "Common Utils", "btUtil"],
21    ["src/btstack_hid.h", "HID", "hid"],
22    ["src/gap.h", "GAP", "gap"],
23    ["src/hci.h", "HCI", "hci"],
24    ["src/hci_dump.h","HCI Logging","hciTrace"],
25    ["src/hci_transport.h","HCI Transport","hciTransport"],
26    ["src/l2cap.h", "L2CAP", "l2cap"],
27
28    ["src/ble/att_db_util.h", "ATT Database", "attDb"],
29    ["src/ble/att_server.h", "ATT Server", "attServer"],
30    ["src/ble/gatt_client.h", "GATT Client", "gattClient"],
31    ["src/ble/le_device_db.h", "Device Database", "leDeviceDb"],
32    ["src/ble/le_device_db_tlv.h", "Device Database TLV", "leDeviceDbTLV"],
33    ["src/ble/sm.h", "Security Manager", "sm"],
34
35    ["src/ble/gatt-service/ancs_client.h", "ANCS Client", "ancsClient"],
36    ["src/ble/gatt-service/battery_service_client.h", "Battery Service Client", "gattclient_battery"],
37    ["src/ble/gatt-service/battery_service_server.h", "Battery Service Server", "batteryServiceServer"],
38    ["src/ble/gatt-service/cycling_power_service_server.h", "Cycling Power Service Server", "cyclingPowerServiceServer"],
39    ["src/ble/gatt-service/cycling_speed_and_cadence_service_server.h", "Cycling Speed and Cadence Service Server", "cyclingSpeedCadenceServiceServer"],
40    ["src/ble/gatt-service/device_information_service_client.h", "Device Information Service Client", "gattclient_device_information"],
41    ["src/ble/gatt-service/device_information_service_server.h", "Device Information Service Server", "deviceInformationServiceServer"],
42    ["src/ble/gatt-service/heart_rate_service_server.h", "Heart Rate Service Server", "heartRateServiceServer"],
43    ["src/ble/gatt-service/hids_device.h", "HID Device Service Server", "hidsDevice"],
44    ["src/ble/gatt-service/mesh_provisioning_service_server.h", "Mesh Provisioning Service Server", "meshProvisioningServiceServer"],
45    ["src/ble/gatt-service/mesh_proxy_service_server.h", "Mesh Proxy Service Server", "meshProxyServiceServer"],
46    ["src/ble/gatt-service/nordic_spp_service_server.h", "Nordic SPP Service Server", "nordicSppServiceServer"],
47    ["src/ble/gatt-service/scan_parameters_service_client.h", "Scan Parameters Service Client", "scanParametersServiceClient"],
48    ["src/ble/gatt-service/ublox_spp_service_server.h", "u-blox SPP Service Server", "ubloxSppServiceServer"],
49
50    ["src/classic/a2dp_sink.h", "A2DP Sink", "a2dpSink"],
51    ["src/classic/a2dp_source.h", "A2DP Source", "a2dpSource"],
52    ["src/classic/avdtp_sink.h", "AVDTP Sink", "avdtpSink"],
53    ["src/classic/avdtp_source.h", "AVDTP Source", "avdtpSource"],
54    ["src/classic/avrcp_browsing_controller.h", "AVRCP Browsing Controller", "avrcpBrowsingController"],
55    ["src/classic/avrcp_browsing_target.h", "AVRCP Browsing Target", "avrcpBrowsingTarget"],
56    ["src/classic/avrcp_controller.h", "AVRCP Controller", "avrcpController"],
57    ["src/classic/avrcp_target.h", "AVRCP Target", "avrcpTarget"],
58    ["src/classic/bnep.h", "BNEP", "bnep"],
59    ["src/classic/btstack_link_key_db.h","Link Key DB","lkDb"],
60    ["src/classic/btstack_sbc.h", "SBC", "sbc"],
61    ["src/classic/device_id_server.h", "Device ID Server", "deviceIdServer"],
62    ["src/classic/gatt_sdp.h", "GATT SDP", "gattSdp"],
63    ["src/classic/goep_client.h", "GOEP Client", "goepClient"],
64    ["src/classic/hfp_ag.h","HFP Audio Gateway","hfpAG"],
65    ["src/classic/hfp_hf.h","HFP Hands-Free","hfpHF"],
66    ["src/classic/hid_device.h", "HID Device", "hidDevice"],
67    ["src/classic/hid_host.h", "HID Host", "hidHost"],
68    ["src/classic/hsp_ag.h","HSP Audio Gateway","hspAG"],
69    ["src/classic/hsp_hs.h","HSP Headset","hspHS"],
70    ["src/classic/pan.h", "PAN", "pan"],
71    ["src/classic/pbap_client.h", "PBAP Client", "pbapClient"],
72    ["src/classic/rfcomm.h", "RFCOMM", "rfcomm"],
73    ["src/classic/sdp_client.h", "SDP Client", "sdpClient"],
74    ["src/classic/sdp_client_rfcomm.h", "SDP RFCOMM Query", "sdpQueries"],
75    ["src/classic/sdp_server.h", "SDP Server", "sdpSrv"],
76    ["src/classic/sdp_util.h","SDP Utils", "sdpUtil"],
77]
78
79functions = {}
80typedefs = {}
81
82api_header = """
83
84## API_TITLE API {#sec:API_LABLEAPIAppendix}
85
86"""
87
88api_ending = """
89"""
90
91code_ref = """GITHUBFPATH#LLINENR"""
92
93
94def codeReference(fname, githuburl, filepath, linenr):
95    global code_ref
96    ref = code_ref.replace("GITHUB", githuburl)
97    ref = ref.replace("FPATH", filepath)
98    ref = ref.replace("LINENR", str(linenr))
99    return ref
100
101
102def writeAPI(apifile, btstackfolder, apis, mk_codeidentation):
103    with open(apifile, 'w') as fout:
104        fout.write("#\n\n")
105        for api_tuple in apis:
106            api_filename = btstackfolder + api_tuple[0]
107            api_title = api_tuple[1]
108            api_lable = api_tuple[2]
109
110            title = api_header.replace("API_TITLE", api_title).replace("API_LABLE", api_lable)
111            fout.write(title)
112
113            state = State.SearchStartAPI
114            with open(api_filename, 'r') as fin:
115                for line in fin:
116                    if state == State.SearchStartAPI:
117                        parts = re.match('.*API_START.*',line)
118                        if parts:
119                            state = State.SearchEndAPI
120                        continue
121
122                    if state == State.SearchEndAPI:
123                        parts = re.match('.*API_END.*',line)
124                        if parts:
125                            state = State.DoneAPI
126                            continue
127                        fout.write(mk_codeidentation + line)
128                        continue
129
130
131def createIndex(btstackfolder, apis, githuburl):
132    global typedefs, functions
133
134    for api_tuple in apis:
135        api_filename = btstackfolder + api_tuple[0]
136        api_title = api_tuple[1]
137        api_lable = api_tuple[2]
138
139        linenr = 0
140        with open(api_filename, 'r') as fin:
141            typedefFound = 0
142            multiline_function_def = 0
143            state = State.SearchStartAPI
144
145            for line in fin:
146                if state == State.DoneAPI:
147                    continue
148
149                linenr = linenr + 1
150
151                if state == State.SearchStartAPI:
152                    parts = re.match('.*API_START.*',line)
153                    if parts:
154                        state = State.SearchEndAPI
155                    continue
156
157                if state == State.SearchEndAPI:
158                    parts = re.match('.*API_END.*',line)
159                    if parts:
160                        state = State.DoneAPI
161                        continue
162
163                if multiline_function_def:
164                    function_end = re.match('.*;\n', line)
165                    if function_end:
166                        multiline_function_def = 0
167                    continue
168
169                param = re.match(".*@brief.*", line)
170                if param:
171                    continue
172                param = re.match(".*@param.*", line)
173                if param:
174                    continue
175                param = re.match(".*@return.*", line)
176                if param:
177                    continue
178
179                # search typedef struct begin
180                typedef =  re.match('.*typedef\s+struct.*', line)
181                if typedef:
182                    typedefFound = 1
183
184                # search typedef struct end
185                if typedefFound:
186                    typedef = re.match('}\s*(.*);\n', line)
187                    if typedef:
188                        typedefFound = 0
189                        typedefs[typedef.group(1)] = codeReference(typedef.group(1), githuburl, api_tuple[0], linenr)
190                    continue
191
192                ref_function =  re.match('.*typedef\s+void\s+\(\s*\*\s*(.*?)\)\(.*', line)
193                if ref_function:
194                    functions[ref_function.group(1)] = codeReference(ref_function.group(1), githuburl, api_tuple[0], linenr)
195                    continue
196
197                function = re.match('(.*?)\s*\(.*\(*.*;\n', line)
198                if function:
199                    parts = function.group(1).split(" ");
200                    name = parts[len(parts)-1]
201                    if len(name) == 0:
202                        print(parts);
203                        sys.exit(10)
204                    functions[name] = codeReference( name, githuburl, api_tuple[0], linenr)
205                    continue
206
207                function = re.match('.(.*?)\s*\(.*\(*.*', line)
208                if function:
209                    if len(name) == 0:
210                        print(parts);
211                        sys.exit(10)
212                    parts = function.group(1).split(" ");
213                    name = parts[len(parts)-1]
214                    multiline_function_def = 1
215                    functions[name] = codeReference(name, githuburl, api_tuple[0], linenr)
216
217
218def main(argv):
219    mk_codeidentation = "    "
220    git_branch_name = "master"
221    btstackfolder = "../../"
222    githuburl  = "https://github.com/bluekitchen/btstack/blob/master/"
223    markdownfolder = "docs-markdown/"
224
225    cmd = 'markdown_create_apis.py [-r <root_btstackfolder>] [-g <githuburl>] [-o <output_markdownfolder>]'
226    try:
227        opts, args = getopt.getopt(argv,"r:g:o:",["rfolder=","github=","ofolder="])
228    except getopt.GetoptError:
229        print (cmd)
230        sys.exit(2)
231    for opt, arg in opts:
232        if opt == '-h':
233            print (cmd)
234            sys.exit()
235        elif opt in ("-r", "--rfolder"):
236            btstackfolder = arg
237        elif opt in ("-g", "--github"):
238            githuburl = arg
239        elif opt in ("-o", "--ofolder"):
240            markdownfolder = arg
241
242    apifile   = markdownfolder + "appendix/apis.md"
243    # indexfile = markdownfolder + "api_index.md"
244
245    try:
246        output = subprocess.check_output("git symbolic-ref --short HEAD", stderr=subprocess.STDOUT, timeout=3, shell=True)
247        git_branch_name = output.decode().rstrip()
248    except subprocess.CalledProcessError as exc:
249        print('GIT branch name: failed to get, use default value \"%s\""  ', git_branch_name, exc.returncode, exc.output)
250    else:
251        print ('GIT branch name :  %s' % git_branch_name)
252
253    githuburl = githuburl + git_branch_name
254
255    print ('BTstack folder is : ' + btstackfolder)
256    print ('API file is       : ' + apifile)
257    print ('Github URL is    : ' +  githuburl)
258    # print ('Index file is     : ' + indexfile)
259
260    writeAPI(apifile, btstackfolder, apis, mk_codeidentation)
261    createIndex(btstackfolder, apis, githuburl)
262
263    for function in functions:
264        parts = function.split(' ')
265        if (len(parts) > 1):
266            print (parts)
267
268    references = functions.copy()
269    references.update(typedefs)
270
271    # with open(indexfile, 'w') as fout:
272    #     for function, reference in references.items():
273    #         fout.write("[" + function + "](" + reference + ")\n")
274
275    pickle.dump(references, open("references.p", "wb" ) )
276
277if __name__ == "__main__":
278   main(sys.argv[1:])
279