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*2ea56b0cSMilanka Ringwald 2878fab72eSMilanka Ringwaldapi_subheader = """ 2978fab72eSMilanka Ringwald## API_TITLE API {#sec:API_LABEL_api} 3078fab72eSMilanka Ringwald 3178fab72eSMilanka Ringwald""" 32c8c342a6SMilanka Ringwald 33*2ea56b0cSMilanka Ringwaldapi_description = """ 34*2ea56b0cSMilanka Ringwald**FILENAME** DESCRIPTION 35*2ea56b0cSMilanka Ringwald 36c8c342a6SMilanka Ringwald""" 37c8c342a6SMilanka Ringwald 38c8c342a6SMilanka Ringwaldcode_ref = """GITHUBFPATH#LLINENR""" 39c8c342a6SMilanka Ringwald 40c8c342a6SMilanka Ringwald 41d7ef0676SMilanka Ringwalddef isEndOfComment(line): 42d7ef0676SMilanka Ringwald return re.match('\s*\*/.*', line) 43d7ef0676SMilanka Ringwald 44d7ef0676SMilanka Ringwalddef isStartOfComment(line): 45d7ef0676SMilanka Ringwald return re.match('\s*\/\*/.*', line) 46d7ef0676SMilanka Ringwald 47d7ef0676SMilanka Ringwalddef isTypedefStart(line): 48d7ef0676SMilanka Ringwald return re.match('.*typedef\s+struct.*', line) 49d7ef0676SMilanka Ringwald 50c8c342a6SMilanka Ringwalddef codeReference(fname, githuburl, filepath, linenr): 51c8c342a6SMilanka Ringwald global code_ref 52c8c342a6SMilanka Ringwald ref = code_ref.replace("GITHUB", githuburl) 53c8c342a6SMilanka Ringwald ref = ref.replace("FPATH", filepath) 54c8c342a6SMilanka Ringwald ref = ref.replace("LINENR", str(linenr)) 55c8c342a6SMilanka Ringwald return ref 56c8c342a6SMilanka Ringwald 574a400a05SMilanka Ringwalddef isTagAPI(line): 584a400a05SMilanka Ringwald return re.match('(.*)(-\s*\')(APIs).*',line) 594a400a05SMilanka Ringwald 604a400a05SMilanka Ringwalddef getSecondLevelIdentation(line): 614a400a05SMilanka Ringwald indentation = "" 624a400a05SMilanka Ringwald parts = re.match('(.*)(-\s*\')(APIs).*',line) 634a400a05SMilanka Ringwald if parts: 644a400a05SMilanka Ringwald # return double identation for the submenu 654a400a05SMilanka Ringwald indentation = parts.group(1) + parts.group(1) + "- " 664a400a05SMilanka Ringwald return indentation 674a400a05SMilanka Ringwald 684a400a05SMilanka Ringwalddef filename_stem(filepath): 694a400a05SMilanka Ringwald return os.path.splitext(os.path.basename(filepath))[0] 70c8c342a6SMilanka Ringwald 71d7ef0676SMilanka Ringwalddef writeAPI(fout, fin, mk_codeidentation): 72c8c342a6SMilanka Ringwald state = State.SearchStartAPI 73d7ef0676SMilanka Ringwald 74c8c342a6SMilanka Ringwald for line in fin: 75c8c342a6SMilanka Ringwald if state == State.SearchStartAPI: 76c8c342a6SMilanka Ringwald parts = re.match('.*API_START.*',line) 77c8c342a6SMilanka Ringwald if parts: 78c8c342a6SMilanka Ringwald state = State.SearchEndAPI 79c8c342a6SMilanka Ringwald continue 80c8c342a6SMilanka Ringwald 81c8c342a6SMilanka Ringwald if state == State.SearchEndAPI: 82c8c342a6SMilanka Ringwald parts = re.match('.*API_END.*',line) 83c8c342a6SMilanka Ringwald if parts: 84c8c342a6SMilanka Ringwald state = State.DoneAPI 85c8c342a6SMilanka Ringwald continue 86c8c342a6SMilanka Ringwald fout.write(mk_codeidentation + line) 87c8c342a6SMilanka Ringwald continue 88c8c342a6SMilanka Ringwald 89c8c342a6SMilanka Ringwald 90c8c342a6SMilanka Ringwald 914a400a05SMilanka Ringwalddef createIndex(fin, api_filepath, api_title, api_label, githuburl): 92d7ef0676SMilanka Ringwald global typedefs, functions 93d7ef0676SMilanka Ringwald global linenr, multiline_function_def, typedefFound, state 94d7ef0676SMilanka Ringwald 95d7ef0676SMilanka Ringwald 96c8c342a6SMilanka Ringwald for line in fin: 97c8c342a6SMilanka Ringwald if state == State.DoneAPI: 98c8c342a6SMilanka Ringwald continue 99c8c342a6SMilanka Ringwald 100c8c342a6SMilanka Ringwald linenr = linenr + 1 101c8c342a6SMilanka Ringwald 102c8c342a6SMilanka Ringwald if state == State.SearchStartAPI: 103c8c342a6SMilanka Ringwald parts = re.match('.*API_START.*',line) 104c8c342a6SMilanka Ringwald if parts: 105c8c342a6SMilanka Ringwald state = State.SearchEndAPI 106c8c342a6SMilanka Ringwald continue 107c8c342a6SMilanka Ringwald 108c8c342a6SMilanka Ringwald if state == State.SearchEndAPI: 109c8c342a6SMilanka Ringwald parts = re.match('.*API_END.*',line) 110c8c342a6SMilanka Ringwald if parts: 111c8c342a6SMilanka Ringwald state = State.DoneAPI 112c8c342a6SMilanka Ringwald continue 113c8c342a6SMilanka Ringwald 114c8c342a6SMilanka Ringwald if multiline_function_def: 115c8c342a6SMilanka Ringwald function_end = re.match('.*;\n', line) 116c8c342a6SMilanka Ringwald if function_end: 117c8c342a6SMilanka Ringwald multiline_function_def = 0 118c8c342a6SMilanka Ringwald continue 119c8c342a6SMilanka Ringwald 120c8c342a6SMilanka Ringwald param = re.match(".*@brief.*", line) 121c8c342a6SMilanka Ringwald if param: 122c8c342a6SMilanka Ringwald continue 123c8c342a6SMilanka Ringwald param = re.match(".*@param.*", line) 124c8c342a6SMilanka Ringwald if param: 125c8c342a6SMilanka Ringwald continue 126c8c342a6SMilanka Ringwald param = re.match(".*@return.*", line) 127c8c342a6SMilanka Ringwald if param: 128c8c342a6SMilanka Ringwald continue 129c8c342a6SMilanka Ringwald 130c8c342a6SMilanka Ringwald # search typedef struct begin 131d7ef0676SMilanka Ringwald if isTypedefStart(line): 132c8c342a6SMilanka Ringwald typedefFound = 1 133c8c342a6SMilanka Ringwald 134c8c342a6SMilanka Ringwald # search typedef struct end 135c8c342a6SMilanka Ringwald if typedefFound: 136c8c342a6SMilanka Ringwald typedef = re.match('}\s*(.*);\n', line) 137c8c342a6SMilanka Ringwald if typedef: 138c8c342a6SMilanka Ringwald typedefFound = 0 1394a400a05SMilanka Ringwald typedefs[typedef.group(1)] = codeReference(typedef.group(1), githuburl, api_filepath, linenr) 140c8c342a6SMilanka Ringwald continue 141c8c342a6SMilanka Ringwald 142c8c342a6SMilanka Ringwald ref_function = re.match('.*typedef\s+void\s+\(\s*\*\s*(.*?)\)\(.*', line) 143c8c342a6SMilanka Ringwald if ref_function: 1444a400a05SMilanka Ringwald functions[ref_function.group(1)] = codeReference(ref_function.group(1), githuburl, api_filepath, linenr) 145c8c342a6SMilanka Ringwald continue 146c8c342a6SMilanka Ringwald 147d7ef0676SMilanka Ringwald 148d7ef0676SMilanka Ringwald one_line_function_definition = re.match('(.*?)\s*\(.*\(*.*;\n', line) 149d7ef0676SMilanka Ringwald if one_line_function_definition: 150d7ef0676SMilanka Ringwald parts = one_line_function_definition.group(1).split(" "); 151c8c342a6SMilanka Ringwald name = parts[len(parts)-1] 152c8c342a6SMilanka Ringwald if len(name) == 0: 153c8c342a6SMilanka Ringwald print(parts); 154c8c342a6SMilanka Ringwald sys.exit(10) 1554a400a05SMilanka Ringwald functions[name] = codeReference( name, githuburl, api_filepath, linenr) 156c8c342a6SMilanka Ringwald continue 157c8c342a6SMilanka Ringwald 158d7ef0676SMilanka Ringwald multi_line_function_definition = re.match('.(.*?)\s*\(.*\(*.*', line) 159d7ef0676SMilanka Ringwald if multi_line_function_definition: 160d7ef0676SMilanka Ringwald parts = multi_line_function_definition.group(1).split(" "); 161d7ef0676SMilanka Ringwald 162d7ef0676SMilanka Ringwald name = parts[len(parts)-1] 163c8c342a6SMilanka Ringwald if len(name) == 0: 164c8c342a6SMilanka Ringwald print(parts); 165c8c342a6SMilanka Ringwald sys.exit(10) 166c8c342a6SMilanka Ringwald multiline_function_def = 1 1674a400a05SMilanka Ringwald functions[name] = codeReference(name, githuburl, api_filepath, linenr) 168c8c342a6SMilanka Ringwald 169c8c342a6SMilanka Ringwald 170d7ef0676SMilanka Ringwalddef findTitle(fin): 171d7ef0676SMilanka Ringwald title = None 172d7ef0676SMilanka Ringwald desc = "" 173d7ef0676SMilanka Ringwald state = State.SearchTitle 174d7ef0676SMilanka Ringwald 175d7ef0676SMilanka Ringwald for line in fin: 176d7ef0676SMilanka Ringwald if state == State.SearchTitle: 177d7ef0676SMilanka Ringwald if isStartOfComment(line): 178d7ef0676SMilanka Ringwald continue 179d7ef0676SMilanka Ringwald 180d7ef0676SMilanka Ringwald parts = re.match('.*(@title)(.*)', line) 181d7ef0676SMilanka Ringwald if parts: 182d7ef0676SMilanka Ringwald title = parts.group(2).strip() 183d7ef0676SMilanka Ringwald state = State.SearchEndTitle 184d7ef0676SMilanka Ringwald continue 185d7ef0676SMilanka Ringwald 186d7ef0676SMilanka Ringwald if state == State.SearchEndTitle: 187d7ef0676SMilanka Ringwald if (isEndOfComment(line)): 188d7ef0676SMilanka Ringwald state = State.DoneAPI 189d7ef0676SMilanka Ringwald break 190d7ef0676SMilanka Ringwald 191d7ef0676SMilanka Ringwald parts = re.match('(\s*\*\s*)(.*\n)',line) 192d7ef0676SMilanka Ringwald if parts: 193d7ef0676SMilanka Ringwald desc = desc + parts.group(2) 1944a400a05SMilanka Ringwald return [title, desc] 195d7ef0676SMilanka Ringwald 196c8c342a6SMilanka Ringwalddef main(argv): 197d7ef0676SMilanka Ringwald global linenr, multiline_function_def, typedefFound, state 198d7ef0676SMilanka Ringwald 199c8c342a6SMilanka Ringwald mk_codeidentation = " " 200c8c342a6SMilanka Ringwald git_branch_name = "master" 201c8c342a6SMilanka Ringwald btstackfolder = "../../" 202c8c342a6SMilanka Ringwald githuburl = "https://github.com/bluekitchen/btstack/blob/master/" 203c8c342a6SMilanka Ringwald markdownfolder = "docs-markdown/" 204c8c342a6SMilanka Ringwald 205c8c342a6SMilanka Ringwald cmd = 'markdown_create_apis.py [-r <root_btstackfolder>] [-g <githuburl>] [-o <output_markdownfolder>]' 206c8c342a6SMilanka Ringwald try: 207c8c342a6SMilanka Ringwald opts, args = getopt.getopt(argv,"r:g:o:",["rfolder=","github=","ofolder="]) 208c8c342a6SMilanka Ringwald except getopt.GetoptError: 209c8c342a6SMilanka Ringwald print (cmd) 210c8c342a6SMilanka Ringwald sys.exit(2) 211c8c342a6SMilanka Ringwald for opt, arg in opts: 212c8c342a6SMilanka Ringwald if opt == '-h': 213c8c342a6SMilanka Ringwald print (cmd) 214c8c342a6SMilanka Ringwald sys.exit() 215c8c342a6SMilanka Ringwald elif opt in ("-r", "--rfolder"): 216c8c342a6SMilanka Ringwald btstackfolder = arg 217c8c342a6SMilanka Ringwald elif opt in ("-g", "--github"): 218c8c342a6SMilanka Ringwald githuburl = arg 219c8c342a6SMilanka Ringwald elif opt in ("-o", "--ofolder"): 220c8c342a6SMilanka Ringwald markdownfolder = arg 221c8c342a6SMilanka Ringwald 222c8c342a6SMilanka Ringwald apifile = markdownfolder + "appendix/apis.md" 223c8c342a6SMilanka Ringwald # indexfile = markdownfolder + "api_index.md" 224d7ef0676SMilanka Ringwald btstack_srcfolder = btstackfolder + "src/" 225c8c342a6SMilanka Ringwald 226c8c342a6SMilanka Ringwald try: 227c8c342a6SMilanka Ringwald output = subprocess.check_output("git symbolic-ref --short HEAD", stderr=subprocess.STDOUT, timeout=3, shell=True) 228c8c342a6SMilanka Ringwald git_branch_name = output.decode().rstrip() 229c8c342a6SMilanka Ringwald except subprocess.CalledProcessError as exc: 230c8c342a6SMilanka Ringwald print('GIT branch name: failed to get, use default value \"%s\"" ', git_branch_name, exc.returncode, exc.output) 231c8c342a6SMilanka Ringwald else: 232c8c342a6SMilanka Ringwald print ('GIT branch name : %s' % git_branch_name) 233c8c342a6SMilanka Ringwald 234c8c342a6SMilanka Ringwald githuburl = githuburl + git_branch_name 235c8c342a6SMilanka Ringwald 236d7ef0676SMilanka Ringwald print ('BTstack src folder is : ' + btstack_srcfolder) 237c8c342a6SMilanka Ringwald print ('API file is : ' + apifile) 238c8c342a6SMilanka Ringwald print ('Github URL is : ' + githuburl) 239c8c342a6SMilanka Ringwald 2404a400a05SMilanka Ringwald # create a dictionary of header files {file_path : [title, description]} 2414a400a05SMilanka Ringwald # title and desctiption are extracted from the file 242d7ef0676SMilanka Ringwald for root, dirs, files in os.walk(btstack_srcfolder, topdown=True): 243d7ef0676SMilanka Ringwald for f in files: 244d7ef0676SMilanka Ringwald if not f.endswith(".h"): 245d7ef0676SMilanka Ringwald continue 246d7ef0676SMilanka Ringwald 2474a400a05SMilanka Ringwald if not root.endswith("/"): 2484a400a05SMilanka Ringwald root = root + "/" 249d7ef0676SMilanka Ringwald 2504a400a05SMilanka Ringwald header_filepath = root + f 251d7ef0676SMilanka Ringwald 2524a400a05SMilanka Ringwald with open(header_filepath, 'rt') as fin: 2534a400a05SMilanka Ringwald [header_title, header_desc] = findTitle(fin) 254d7ef0676SMilanka Ringwald 2554a400a05SMilanka Ringwald if header_title: 2564a400a05SMilanka Ringwald header_files[header_filepath] = [header_title, header_desc] 2574a400a05SMilanka Ringwald else: 2584a400a05SMilanka Ringwald print("No @title flag found. Skip %s" % header_filepath) 259d7ef0676SMilanka Ringwald 260*2ea56b0cSMilanka Ringwald # create an >md file, for each header file in header_files dictionary 2614a400a05SMilanka Ringwald for header_filepath in sorted(header_files.keys()): 262*2ea56b0cSMilanka Ringwald filename = os.path.basename(header_filepath) 263*2ea56b0cSMilanka Ringwald filename_without_extension = filename_stem(header_filepath) # file name without .h 264*2ea56b0cSMilanka Ringwald filetitle = header_files[header_filepath][0] 265*2ea56b0cSMilanka Ringwald description = header_files[header_filepath][1] 266*2ea56b0cSMilanka Ringwald 267*2ea56b0cSMilanka Ringwald if len(description) > 1: 268*2ea56b0cSMilanka Ringwald description = ": " + description 269*2ea56b0cSMilanka Ringwald 270*2ea56b0cSMilanka Ringwald header_description = api_description.replace("FILENAME", filename).replace("DESCRIPTION", description) 271*2ea56b0cSMilanka Ringwald 272*2ea56b0cSMilanka Ringwald header_title = api_header.replace("API_TITLE", filetitle).replace("API_LABEL", filename_without_extension) 273*2ea56b0cSMilanka Ringwald markdown_filepath = markdownfolder + "appendix/" + filename_without_extension + ".md" 274d7ef0676SMilanka Ringwald 2754a400a05SMilanka Ringwald with open(header_filepath, 'rt') as fin: 2764a400a05SMilanka Ringwald with open(markdown_filepath, 'wt') as fout: 2774a400a05SMilanka Ringwald fout.write(header_title) 2784a400a05SMilanka Ringwald fout.write(header_description) 279d7ef0676SMilanka Ringwald writeAPI(fout, fin, mk_codeidentation) 280d7ef0676SMilanka Ringwald 2814a400a05SMilanka Ringwald with open(header_filepath, 'rt') as fin: 282d7ef0676SMilanka Ringwald linenr = 0 283d7ef0676SMilanka Ringwald typedefFound = 0 284d7ef0676SMilanka Ringwald multiline_function_def = 0 285d7ef0676SMilanka Ringwald state = State.SearchStartAPI 286*2ea56b0cSMilanka Ringwald createIndex(fin, markdown_filepath, header_title, filename_without_extension, githuburl) 287d7ef0676SMilanka Ringwald 2884a400a05SMilanka Ringwald # add API list to the navigation menu 2894a400a05SMilanka Ringwald with open("mkdocs-temp.yml", 'rt') as fin: 2904a400a05SMilanka Ringwald with open("mkdocs.yml", 'wt') as fout: 2914a400a05SMilanka Ringwald for line in fin: 2924a400a05SMilanka Ringwald fout.write(line) 2934a400a05SMilanka Ringwald 2944a400a05SMilanka Ringwald if not isTagAPI(line): 2954a400a05SMilanka Ringwald continue 2964a400a05SMilanka Ringwald 2974a400a05SMilanka Ringwald identation = getSecondLevelIdentation(line) 2984a400a05SMilanka Ringwald 2994a400a05SMilanka Ringwald for header_filepath in sorted(header_files.keys()): 300*2ea56b0cSMilanka Ringwald header_title = os.path.basename(header_filepath) 3014a400a05SMilanka Ringwald markdown_reference = "appendix/" + filename_stem(header_filepath) + ".md" 3024a400a05SMilanka Ringwald 3034a400a05SMilanka Ringwald fout.write(identation + "'" + header_title + "': " + markdown_reference + "\n") 304c8c342a6SMilanka Ringwald 30578fab72eSMilanka Ringwald 306*2ea56b0cSMilanka Ringwald # create mkdocs-latex.yml with single appendix/apis.md reference for pdf generation 30778fab72eSMilanka Ringwald with open("mkdocs-temp.yml", 'rt') as fin: 30878fab72eSMilanka Ringwald with open("mkdocs-latex.yml", 'wt') as fout: 30978fab72eSMilanka Ringwald for line in fin: 31078fab72eSMilanka Ringwald if not isTagAPI(line): 31178fab72eSMilanka Ringwald fout.write(line) 31278fab72eSMilanka Ringwald continue 31378fab72eSMilanka Ringwald 31478fab72eSMilanka Ringwald fout.write(" - 'APIs': appendix/apis.md\n") 31578fab72eSMilanka Ringwald 316*2ea56b0cSMilanka Ringwald # create single appendix/apis.md file for pdf generation 31778fab72eSMilanka Ringwald markdown_filepath = markdownfolder + "appendix/apis.md" 31878fab72eSMilanka Ringwald with open(markdown_filepath, 'wt') as fout: 31978fab72eSMilanka Ringwald fout.write("\n# APIs\n\n") 32078fab72eSMilanka Ringwald for header_filepath in sorted(header_files.keys()): 321*2ea56b0cSMilanka Ringwald filename = os.path.basename(header_filepath) 322*2ea56b0cSMilanka Ringwald filename_without_extension = filename_stem(header_filepath) # file name without 323*2ea56b0cSMilanka Ringwald filetitle = header_files[header_filepath][0] 32478fab72eSMilanka Ringwald 325*2ea56b0cSMilanka Ringwald description = header_files[header_filepath][1] 326*2ea56b0cSMilanka Ringwald 327*2ea56b0cSMilanka Ringwald if len(description) > 1: 328*2ea56b0cSMilanka Ringwald description = ": " + description 329*2ea56b0cSMilanka Ringwald 330*2ea56b0cSMilanka Ringwald header_description = api_description.replace("FILENAME", filename).replace("DESCRIPTION", description) 331*2ea56b0cSMilanka Ringwald 332*2ea56b0cSMilanka Ringwald subheader_title = api_subheader.replace("API_TITLE", filetitle).replace("API_LABEL", filename_without_extension) 33378fab72eSMilanka Ringwald with open(header_filepath, 'rt') as fin: 33478fab72eSMilanka Ringwald fout.write(subheader_title) 33578fab72eSMilanka Ringwald fout.write(header_description) 33678fab72eSMilanka Ringwald writeAPI(fout, fin, mk_codeidentation) 33778fab72eSMilanka Ringwald 338c8c342a6SMilanka Ringwald 339c8c342a6SMilanka Ringwald references = functions.copy() 340c8c342a6SMilanka Ringwald references.update(typedefs) 341c8c342a6SMilanka Ringwald 342c8c342a6SMilanka Ringwald # with open(indexfile, 'w') as fout: 343c8c342a6SMilanka Ringwald # for function, reference in references.items(): 344c8c342a6SMilanka Ringwald # fout.write("[" + function + "](" + reference + ")\n") 345c8c342a6SMilanka Ringwald 346c8c342a6SMilanka Ringwald pickle.dump(references, open("references.p", "wb" ) ) 347c8c342a6SMilanka Ringwald 348c8c342a6SMilanka Ringwaldif __name__ == "__main__": 349c8c342a6SMilanka Ringwald main(sys.argv[1:]) 350