1c8c342a6SMilanka Ringwald#!/usr/bin/env python3 2c8c342a6SMilanka Ringwaldimport os, sys, getopt, re, pickle 3c8c342a6SMilanka Ringwaldimport subprocess 4c8c342a6SMilanka Ringwald 5c8c342a6SMilanka Ringwaldclass State: 6d7ef0676SMilanka Ringwald SearchTitle = 0 7d7ef0676SMilanka Ringwald SearchEndTitle = 1 8d7ef0676SMilanka Ringwald SearchStartAPI = 2 9d7ef0676SMilanka Ringwald SearchEndAPI = 3 10d7ef0676SMilanka Ringwald DoneAPI = 4 11c8c342a6SMilanka Ringwald 124a400a05SMilanka Ringwaldheader_files = {} 13c8c342a6SMilanka Ringwaldfunctions = {} 14c8c342a6SMilanka Ringwaldtypedefs = {} 15c8c342a6SMilanka Ringwald 164a400a05SMilanka Ringwaldlinenr = 0 174a400a05SMilanka RingwaldtypedefFound = 0 184a400a05SMilanka Ringwaldmultiline_function_def = 0 194a400a05SMilanka Ringwaldstate = State.SearchStartAPI 20c8c342a6SMilanka Ringwald 214a400a05SMilanka Ringwald# if dash is used in api_header, the windmill theme will repeat the same API_TITLE twice in the menu (i.e: APIs/API_TITLE/API_TITLE) 224a400a05SMilanka Ringwald# if <h2> is used, this is avoided (i.e: APIs/API_TITLE), but reference {...} is not translated to HTML 234a400a05SMilanka Ringwaldapi_header = """ 244a400a05SMilanka Ringwald# API_TITLE API {#sec:API_LABEL_api} 25c8c342a6SMilanka Ringwald 26c8c342a6SMilanka Ringwald""" 27*78fab72eSMilanka Ringwaldapi_subheader = """ 28*78fab72eSMilanka Ringwald## API_TITLE API {#sec:API_LABEL_api} 29*78fab72eSMilanka Ringwald 30*78fab72eSMilanka Ringwald""" 31c8c342a6SMilanka Ringwald 32c8c342a6SMilanka Ringwaldapi_ending = """ 33c8c342a6SMilanka Ringwald""" 34c8c342a6SMilanka Ringwald 35c8c342a6SMilanka Ringwaldcode_ref = """GITHUBFPATH#LLINENR""" 36c8c342a6SMilanka Ringwald 37c8c342a6SMilanka Ringwald 38d7ef0676SMilanka Ringwalddef isEndOfComment(line): 39d7ef0676SMilanka Ringwald return re.match('\s*\*/.*', line) 40d7ef0676SMilanka Ringwald 41d7ef0676SMilanka Ringwalddef isStartOfComment(line): 42d7ef0676SMilanka Ringwald return re.match('\s*\/\*/.*', line) 43d7ef0676SMilanka Ringwald 44d7ef0676SMilanka Ringwalddef isTypedefStart(line): 45d7ef0676SMilanka Ringwald return re.match('.*typedef\s+struct.*', line) 46d7ef0676SMilanka Ringwald 47c8c342a6SMilanka Ringwalddef codeReference(fname, githuburl, filepath, linenr): 48c8c342a6SMilanka Ringwald global code_ref 49c8c342a6SMilanka Ringwald ref = code_ref.replace("GITHUB", githuburl) 50c8c342a6SMilanka Ringwald ref = ref.replace("FPATH", filepath) 51c8c342a6SMilanka Ringwald ref = ref.replace("LINENR", str(linenr)) 52c8c342a6SMilanka Ringwald return ref 53c8c342a6SMilanka Ringwald 544a400a05SMilanka Ringwalddef isTagAPI(line): 554a400a05SMilanka Ringwald return re.match('(.*)(-\s*\')(APIs).*',line) 564a400a05SMilanka Ringwald 574a400a05SMilanka Ringwalddef getSecondLevelIdentation(line): 584a400a05SMilanka Ringwald indentation = "" 594a400a05SMilanka Ringwald parts = re.match('(.*)(-\s*\')(APIs).*',line) 604a400a05SMilanka Ringwald if parts: 614a400a05SMilanka Ringwald # return double identation for the submenu 624a400a05SMilanka Ringwald indentation = parts.group(1) + parts.group(1) + "- " 634a400a05SMilanka Ringwald return indentation 644a400a05SMilanka Ringwald 654a400a05SMilanka Ringwalddef filename_stem(filepath): 664a400a05SMilanka Ringwald return os.path.splitext(os.path.basename(filepath))[0] 67c8c342a6SMilanka Ringwald 68d7ef0676SMilanka Ringwalddef writeAPI(fout, fin, mk_codeidentation): 69c8c342a6SMilanka Ringwald state = State.SearchStartAPI 70d7ef0676SMilanka Ringwald 71c8c342a6SMilanka Ringwald for line in fin: 72c8c342a6SMilanka Ringwald if state == State.SearchStartAPI: 73c8c342a6SMilanka Ringwald parts = re.match('.*API_START.*',line) 74c8c342a6SMilanka Ringwald if parts: 75c8c342a6SMilanka Ringwald state = State.SearchEndAPI 76c8c342a6SMilanka Ringwald continue 77c8c342a6SMilanka Ringwald 78c8c342a6SMilanka Ringwald if state == State.SearchEndAPI: 79c8c342a6SMilanka Ringwald parts = re.match('.*API_END.*',line) 80c8c342a6SMilanka Ringwald if parts: 81c8c342a6SMilanka Ringwald state = State.DoneAPI 82c8c342a6SMilanka Ringwald continue 83c8c342a6SMilanka Ringwald fout.write(mk_codeidentation + line) 84c8c342a6SMilanka Ringwald continue 85c8c342a6SMilanka Ringwald 86c8c342a6SMilanka Ringwald 87c8c342a6SMilanka Ringwald 884a400a05SMilanka Ringwalddef createIndex(fin, api_filepath, api_title, api_label, githuburl): 89d7ef0676SMilanka Ringwald global typedefs, functions 90d7ef0676SMilanka Ringwald global linenr, multiline_function_def, typedefFound, state 91d7ef0676SMilanka Ringwald 92d7ef0676SMilanka Ringwald 93c8c342a6SMilanka Ringwald for line in fin: 94c8c342a6SMilanka Ringwald if state == State.DoneAPI: 95c8c342a6SMilanka Ringwald continue 96c8c342a6SMilanka Ringwald 97c8c342a6SMilanka Ringwald linenr = linenr + 1 98c8c342a6SMilanka Ringwald 99c8c342a6SMilanka Ringwald if state == State.SearchStartAPI: 100c8c342a6SMilanka Ringwald parts = re.match('.*API_START.*',line) 101c8c342a6SMilanka Ringwald if parts: 102c8c342a6SMilanka Ringwald state = State.SearchEndAPI 103c8c342a6SMilanka Ringwald continue 104c8c342a6SMilanka Ringwald 105c8c342a6SMilanka Ringwald if state == State.SearchEndAPI: 106c8c342a6SMilanka Ringwald parts = re.match('.*API_END.*',line) 107c8c342a6SMilanka Ringwald if parts: 108c8c342a6SMilanka Ringwald state = State.DoneAPI 109c8c342a6SMilanka Ringwald continue 110c8c342a6SMilanka Ringwald 111c8c342a6SMilanka Ringwald if multiline_function_def: 112c8c342a6SMilanka Ringwald function_end = re.match('.*;\n', line) 113c8c342a6SMilanka Ringwald if function_end: 114c8c342a6SMilanka Ringwald multiline_function_def = 0 115c8c342a6SMilanka Ringwald continue 116c8c342a6SMilanka Ringwald 117c8c342a6SMilanka Ringwald param = re.match(".*@brief.*", line) 118c8c342a6SMilanka Ringwald if param: 119c8c342a6SMilanka Ringwald continue 120c8c342a6SMilanka Ringwald param = re.match(".*@param.*", line) 121c8c342a6SMilanka Ringwald if param: 122c8c342a6SMilanka Ringwald continue 123c8c342a6SMilanka Ringwald param = re.match(".*@return.*", line) 124c8c342a6SMilanka Ringwald if param: 125c8c342a6SMilanka Ringwald continue 126c8c342a6SMilanka Ringwald 127c8c342a6SMilanka Ringwald # search typedef struct begin 128d7ef0676SMilanka Ringwald if isTypedefStart(line): 129c8c342a6SMilanka Ringwald typedefFound = 1 130c8c342a6SMilanka Ringwald 131c8c342a6SMilanka Ringwald # search typedef struct end 132c8c342a6SMilanka Ringwald if typedefFound: 133c8c342a6SMilanka Ringwald typedef = re.match('}\s*(.*);\n', line) 134c8c342a6SMilanka Ringwald if typedef: 135c8c342a6SMilanka Ringwald typedefFound = 0 1364a400a05SMilanka Ringwald typedefs[typedef.group(1)] = codeReference(typedef.group(1), githuburl, api_filepath, linenr) 137c8c342a6SMilanka Ringwald continue 138c8c342a6SMilanka Ringwald 139c8c342a6SMilanka Ringwald ref_function = re.match('.*typedef\s+void\s+\(\s*\*\s*(.*?)\)\(.*', line) 140c8c342a6SMilanka Ringwald if ref_function: 1414a400a05SMilanka Ringwald functions[ref_function.group(1)] = codeReference(ref_function.group(1), githuburl, api_filepath, linenr) 142c8c342a6SMilanka Ringwald continue 143c8c342a6SMilanka Ringwald 144d7ef0676SMilanka Ringwald 145d7ef0676SMilanka Ringwald one_line_function_definition = re.match('(.*?)\s*\(.*\(*.*;\n', line) 146d7ef0676SMilanka Ringwald if one_line_function_definition: 147d7ef0676SMilanka Ringwald parts = one_line_function_definition.group(1).split(" "); 148c8c342a6SMilanka Ringwald name = parts[len(parts)-1] 149c8c342a6SMilanka Ringwald if len(name) == 0: 150c8c342a6SMilanka Ringwald print(parts); 151c8c342a6SMilanka Ringwald sys.exit(10) 1524a400a05SMilanka Ringwald functions[name] = codeReference( name, githuburl, api_filepath, linenr) 153c8c342a6SMilanka Ringwald continue 154c8c342a6SMilanka Ringwald 155d7ef0676SMilanka Ringwald multi_line_function_definition = re.match('.(.*?)\s*\(.*\(*.*', line) 156d7ef0676SMilanka Ringwald if multi_line_function_definition: 157d7ef0676SMilanka Ringwald parts = multi_line_function_definition.group(1).split(" "); 158d7ef0676SMilanka Ringwald 159d7ef0676SMilanka Ringwald name = parts[len(parts)-1] 160c8c342a6SMilanka Ringwald if len(name) == 0: 161c8c342a6SMilanka Ringwald print(parts); 162c8c342a6SMilanka Ringwald sys.exit(10) 163c8c342a6SMilanka Ringwald multiline_function_def = 1 1644a400a05SMilanka Ringwald functions[name] = codeReference(name, githuburl, api_filepath, linenr) 165c8c342a6SMilanka Ringwald 166c8c342a6SMilanka Ringwald 167d7ef0676SMilanka Ringwalddef findTitle(fin): 168d7ef0676SMilanka Ringwald title = None 169d7ef0676SMilanka Ringwald desc = "" 170d7ef0676SMilanka Ringwald state = State.SearchTitle 171d7ef0676SMilanka Ringwald 172d7ef0676SMilanka Ringwald for line in fin: 173d7ef0676SMilanka Ringwald if state == State.SearchTitle: 174d7ef0676SMilanka Ringwald if isStartOfComment(line): 175d7ef0676SMilanka Ringwald continue 176d7ef0676SMilanka Ringwald 177d7ef0676SMilanka Ringwald parts = re.match('.*(@title)(.*)', line) 178d7ef0676SMilanka Ringwald if parts: 179d7ef0676SMilanka Ringwald title = parts.group(2).strip() 180d7ef0676SMilanka Ringwald state = State.SearchEndTitle 181d7ef0676SMilanka Ringwald continue 182d7ef0676SMilanka Ringwald 183d7ef0676SMilanka Ringwald if state == State.SearchEndTitle: 184d7ef0676SMilanka Ringwald if (isEndOfComment(line)): 185d7ef0676SMilanka Ringwald state = State.DoneAPI 186d7ef0676SMilanka Ringwald break 187d7ef0676SMilanka Ringwald 188d7ef0676SMilanka Ringwald parts = re.match('(\s*\*\s*)(.*\n)',line) 189d7ef0676SMilanka Ringwald if parts: 190d7ef0676SMilanka Ringwald desc = desc + parts.group(2) 1914a400a05SMilanka Ringwald return [title, desc] 192d7ef0676SMilanka Ringwald 193c8c342a6SMilanka Ringwalddef main(argv): 194d7ef0676SMilanka Ringwald global linenr, multiline_function_def, typedefFound, state 195d7ef0676SMilanka Ringwald 196c8c342a6SMilanka Ringwald mk_codeidentation = " " 197c8c342a6SMilanka Ringwald git_branch_name = "master" 198c8c342a6SMilanka Ringwald btstackfolder = "../../" 199c8c342a6SMilanka Ringwald githuburl = "https://github.com/bluekitchen/btstack/blob/master/" 200c8c342a6SMilanka Ringwald markdownfolder = "docs-markdown/" 201c8c342a6SMilanka Ringwald 202c8c342a6SMilanka Ringwald cmd = 'markdown_create_apis.py [-r <root_btstackfolder>] [-g <githuburl>] [-o <output_markdownfolder>]' 203c8c342a6SMilanka Ringwald try: 204c8c342a6SMilanka Ringwald opts, args = getopt.getopt(argv,"r:g:o:",["rfolder=","github=","ofolder="]) 205c8c342a6SMilanka Ringwald except getopt.GetoptError: 206c8c342a6SMilanka Ringwald print (cmd) 207c8c342a6SMilanka Ringwald sys.exit(2) 208c8c342a6SMilanka Ringwald for opt, arg in opts: 209c8c342a6SMilanka Ringwald if opt == '-h': 210c8c342a6SMilanka Ringwald print (cmd) 211c8c342a6SMilanka Ringwald sys.exit() 212c8c342a6SMilanka Ringwald elif opt in ("-r", "--rfolder"): 213c8c342a6SMilanka Ringwald btstackfolder = arg 214c8c342a6SMilanka Ringwald elif opt in ("-g", "--github"): 215c8c342a6SMilanka Ringwald githuburl = arg 216c8c342a6SMilanka Ringwald elif opt in ("-o", "--ofolder"): 217c8c342a6SMilanka Ringwald markdownfolder = arg 218c8c342a6SMilanka Ringwald 219c8c342a6SMilanka Ringwald apifile = markdownfolder + "appendix/apis.md" 220c8c342a6SMilanka Ringwald # indexfile = markdownfolder + "api_index.md" 221d7ef0676SMilanka Ringwald btstack_srcfolder = btstackfolder + "src/" 222c8c342a6SMilanka Ringwald 223c8c342a6SMilanka Ringwald try: 224c8c342a6SMilanka Ringwald output = subprocess.check_output("git symbolic-ref --short HEAD", stderr=subprocess.STDOUT, timeout=3, shell=True) 225c8c342a6SMilanka Ringwald git_branch_name = output.decode().rstrip() 226c8c342a6SMilanka Ringwald except subprocess.CalledProcessError as exc: 227c8c342a6SMilanka Ringwald print('GIT branch name: failed to get, use default value \"%s\"" ', git_branch_name, exc.returncode, exc.output) 228c8c342a6SMilanka Ringwald else: 229c8c342a6SMilanka Ringwald print ('GIT branch name : %s' % git_branch_name) 230c8c342a6SMilanka Ringwald 231c8c342a6SMilanka Ringwald githuburl = githuburl + git_branch_name 232c8c342a6SMilanka Ringwald 233d7ef0676SMilanka Ringwald print ('BTstack src folder is : ' + btstack_srcfolder) 234c8c342a6SMilanka Ringwald print ('API file is : ' + apifile) 235c8c342a6SMilanka Ringwald print ('Github URL is : ' + githuburl) 236c8c342a6SMilanka Ringwald 2374a400a05SMilanka Ringwald # create a dictionary of header files {file_path : [title, description]} 2384a400a05SMilanka Ringwald # title and desctiption are extracted from the file 239d7ef0676SMilanka Ringwald for root, dirs, files in os.walk(btstack_srcfolder, topdown=True): 240d7ef0676SMilanka Ringwald for f in files: 241d7ef0676SMilanka Ringwald if not f.endswith(".h"): 242d7ef0676SMilanka Ringwald continue 243d7ef0676SMilanka Ringwald 2444a400a05SMilanka Ringwald if not root.endswith("/"): 2454a400a05SMilanka Ringwald root = root + "/" 246d7ef0676SMilanka Ringwald 2474a400a05SMilanka Ringwald header_filepath = root + f 248d7ef0676SMilanka Ringwald 2494a400a05SMilanka Ringwald with open(header_filepath, 'rt') as fin: 2504a400a05SMilanka Ringwald [header_title, header_desc] = findTitle(fin) 251d7ef0676SMilanka Ringwald 2524a400a05SMilanka Ringwald if header_title: 2534a400a05SMilanka Ringwald header_files[header_filepath] = [header_title, header_desc] 2544a400a05SMilanka Ringwald else: 2554a400a05SMilanka Ringwald print("No @title flag found. Skip %s" % header_filepath) 256d7ef0676SMilanka Ringwald 257d7ef0676SMilanka Ringwald 2584a400a05SMilanka Ringwald for header_filepath in sorted(header_files.keys()): 2594a400a05SMilanka Ringwald header_label = filename_stem(header_filepath) # file name without 2604a400a05SMilanka Ringwald header_description = header_files[header_filepath][1] 2614a400a05SMilanka Ringwald header_title = api_header.replace("API_TITLE", header_files[header_filepath][0]).replace("API_LABEL", header_label) 2624a400a05SMilanka Ringwald markdown_filepath = markdownfolder + "appendix/" + header_label + ".md" 263d7ef0676SMilanka Ringwald 2644a400a05SMilanka Ringwald with open(header_filepath, 'rt') as fin: 2654a400a05SMilanka Ringwald with open(markdown_filepath, 'wt') as fout: 2664a400a05SMilanka Ringwald fout.write(header_title) 2674a400a05SMilanka Ringwald fout.write(header_description) 268d7ef0676SMilanka Ringwald writeAPI(fout, fin, mk_codeidentation) 269d7ef0676SMilanka Ringwald 2704a400a05SMilanka Ringwald with open(header_filepath, 'rt') as fin: 271d7ef0676SMilanka Ringwald linenr = 0 272d7ef0676SMilanka Ringwald typedefFound = 0 273d7ef0676SMilanka Ringwald multiline_function_def = 0 274d7ef0676SMilanka Ringwald state = State.SearchStartAPI 2754a400a05SMilanka Ringwald createIndex(fin, markdown_filepath, header_title, header_label, githuburl) 276d7ef0676SMilanka Ringwald 2774a400a05SMilanka Ringwald # add API list to the navigation menu 2784a400a05SMilanka Ringwald with open("mkdocs-temp.yml", 'rt') as fin: 2794a400a05SMilanka Ringwald with open("mkdocs.yml", 'wt') as fout: 2804a400a05SMilanka Ringwald for line in fin: 2814a400a05SMilanka Ringwald fout.write(line) 2824a400a05SMilanka Ringwald 2834a400a05SMilanka Ringwald if not isTagAPI(line): 2844a400a05SMilanka Ringwald continue 2854a400a05SMilanka Ringwald 2864a400a05SMilanka Ringwald identation = getSecondLevelIdentation(line) 2874a400a05SMilanka Ringwald 2884a400a05SMilanka Ringwald for header_filepath in sorted(header_files.keys()): 2894a400a05SMilanka Ringwald header_title = header_files[header_filepath][0] 2904a400a05SMilanka Ringwald markdown_reference = "appendix/" + filename_stem(header_filepath) + ".md" 2914a400a05SMilanka Ringwald 2924a400a05SMilanka Ringwald fout.write(identation + "'" + header_title + "': " + markdown_reference + "\n") 293c8c342a6SMilanka Ringwald 294*78fab72eSMilanka Ringwald 295*78fab72eSMilanka Ringwald # create singe appendix/apis.md for latex 296*78fab72eSMilanka Ringwald with open("mkdocs-temp.yml", 'rt') as fin: 297*78fab72eSMilanka Ringwald with open("mkdocs-latex.yml", 'wt') as fout: 298*78fab72eSMilanka Ringwald for line in fin: 299*78fab72eSMilanka Ringwald if not isTagAPI(line): 300*78fab72eSMilanka Ringwald fout.write(line) 301*78fab72eSMilanka Ringwald continue 302*78fab72eSMilanka Ringwald 303*78fab72eSMilanka Ringwald fout.write(" - 'APIs': appendix/apis.md\n") 304*78fab72eSMilanka Ringwald 305*78fab72eSMilanka Ringwald 306*78fab72eSMilanka Ringwald markdown_filepath = markdownfolder + "appendix/apis.md" 307*78fab72eSMilanka Ringwald with open(markdown_filepath, 'wt') as fout: 308*78fab72eSMilanka Ringwald fout.write("\n# APIs\n\n") 309*78fab72eSMilanka Ringwald for header_filepath in sorted(header_files.keys()): 310*78fab72eSMilanka Ringwald header_label = filename_stem(header_filepath) # file name without 311*78fab72eSMilanka Ringwald header_description = header_files[header_filepath][1] 312*78fab72eSMilanka Ringwald subheader_title = api_subheader.replace("API_TITLE", header_files[header_filepath][0]).replace("API_LABEL", header_label) 313*78fab72eSMilanka Ringwald 314*78fab72eSMilanka Ringwald with open(header_filepath, 'rt') as fin: 315*78fab72eSMilanka Ringwald fout.write(subheader_title) 316*78fab72eSMilanka Ringwald fout.write(header_description) 317*78fab72eSMilanka Ringwald writeAPI(fout, fin, mk_codeidentation) 318*78fab72eSMilanka Ringwald 319c8c342a6SMilanka Ringwald 320c8c342a6SMilanka Ringwald references = functions.copy() 321c8c342a6SMilanka Ringwald references.update(typedefs) 322c8c342a6SMilanka Ringwald 323c8c342a6SMilanka Ringwald # with open(indexfile, 'w') as fout: 324c8c342a6SMilanka Ringwald # for function, reference in references.items(): 325c8c342a6SMilanka Ringwald # fout.write("[" + function + "](" + reference + ")\n") 326c8c342a6SMilanka Ringwald 327c8c342a6SMilanka Ringwald pickle.dump(references, open("references.p", "wb" ) ) 328c8c342a6SMilanka Ringwald 329c8c342a6SMilanka Ringwaldif __name__ == "__main__": 330c8c342a6SMilanka Ringwald main(sys.argv[1:]) 331