compile_documentation.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #!/usr/bin/env python3
  2. import json
  3. import os
  4. import sys
  5. import re
  6. from datetime import date
  7. #type_file=xoronosconfidential ; legal_info="Confidential document"
  8. #type_file=xoronosinternal ; legal_info="Internal document"
  9. type_file="xoronosopen" ; legal_info="Public document"
  10. template = "/usr/share/pandoc/data/templates/xoronos.tex"
  11. texmfhome = ".local/xoronos/texmf/"
  12. # read the file list
  13. with open('./backend/filelist.json', 'r') as file:
  14. jsondata = file.read()
  15. filelists_json = json.loads( jsondata )
  16. script_dir = os.popen("pwd").read().replace("\n", "")
  17. project_dir = os.path.dirname(script_dir)
  18. cache_dir = project_dir + "/cache"
  19. build_dir = project_dir + "/build"
  20. doc_dir = build_dir + "/doc"
  21. html_dir = doc_dir + "/html"
  22. pdf_dir = doc_dir + "/pdf"
  23. svg_dir = html_dir + "/svg"
  24. out_dir = cache_dir + "/libdoc"
  25. resdir = project_dir + "/archives/resources/miscellaneus/"
  26. # extract archive
  27. if not os.path.exists(resdir):
  28. cmd = "cd ../archives ; tar -xzf resources.tar.gz"
  29. os.system(cmd)
  30. # create directories
  31. cmd = ""
  32. if not os.path.exists(cache_dir):
  33. cmd = cmd + "; mkdir " + cache_dir
  34. if not os.path.exists(out_dir):
  35. cmd = cmd + "; mkdir " + out_dir
  36. if not os.path.exists(build_dir):
  37. cmd = cmd + "; mkdir " + build_dir
  38. if not os.path.exists(html_dir):
  39. cmd = cmd + "; mkdir " + html_dir
  40. if not os.path.exists(pdf_dir):
  41. cmd = cmd + "; mkdir " + pdf_dir
  42. if not os.path.exists(svg_dir):
  43. cmd = cmd + "; mkdir " + svg_dir + "/ ;"
  44. os.system(cmd[2:])
  45. # clean content of directories
  46. cmd = ""
  47. cmd = cmd + "; rm -rf " + out_dir + "/*"
  48. cmd = cmd + "; rm -rf " + svg_dir + "/*"
  49. cmd = cmd + "; rm -rf " + html_dir + "/*.html"
  50. cmd = cmd + "; rm -rf " + pdf_dir + "/*"
  51. os.system(cmd[2:])
  52. # get all the files to analyze
  53. all_files_doc = []
  54. all_files_src = []
  55. for file in filelists_json["lib-function-docs"]:
  56. if os.path.exists( project_dir + "/" + file ) == True :
  57. all_files_doc.append( project_dir + "/" + file )
  58. path_file_src = "/".join(file.split("/")[:-2]) + "/src/" + file.split("/")[-1]
  59. path_file_src = path_file_src[:-3] + ".c"
  60. if os.path.exists( project_dir + "/" + path_file_src ) == True :
  61. all_files_src.append( project_dir + "/" + path_file_src )
  62. # construct a keyword database
  63. functions_keywords = ""
  64. functions_returns = ""
  65. for file in all_files_doc :
  66. cmd = "cat " + file + " | awk '/int .*\(/||/void .*\(/{print $0}' | sed 's/(.*$//' | tr -d '*' | awk '//{print $2}'"
  67. outcmd = os.popen( cmd ).read()
  68. functions_keywords = functions_keywords + "\n" + outcmd
  69. if "xrn_common" in file :
  70. cmd = "cat " + file + " | grep define | grep '(' | awk '//{print $2 }'"
  71. outcmd = os.popen( cmd ).read()
  72. functions_returns = functions_returns + "\n" + outcmd
  73. functions_keywords = "\n".join([s for s in functions_keywords.split("\n") if s])
  74. functions_returns = "\n".join([s for s in functions_returns.split("\n") if s])
  75. list_functions = functions_keywords.split("\n")
  76. list_return = functions_returns.split("\n")
  77. list_return_msgs = []
  78. # construct the error warning messages
  79. for file in all_files_doc :
  80. if "xrn_common" in file :
  81. for returnstr in list_return :
  82. cmd = "cat " + file + " | grep " + returnstr +"_MSG | sed 's/^.* \"//' | tr -d \"\\\"\" | tr -d '\n' "
  83. outcmd = os.popen( cmd ).read()
  84. list_return_msgs.append( dict( code = returnstr , msg = outcmd) )
  85. # get library version
  86. lib_version = ""
  87. for file in filelists_json["libh"]:
  88. if "xrn_settings" in file :
  89. cmd = "cat " + project_dir + "/"+ file + " | awk '/XRN_ALGORITHM_VERSION/ {print $3}' | head -n 1 "
  90. algorithm_version = os.popen( cmd ).read()
  91. cmd = "cat " + project_dir + "/"+ file + " | awk '/XRN_IO_VERSION/ {print $3}' | head -n 1 "
  92. ioversion = os.popen( cmd ).read()
  93. lib_version = algorithm_version[:-1] + "." + ioversion[:-1]
  94. break
  95. #file, function, list of ret, list of calls
  96. database = []
  97. # read the src files and compile a list of functions and keywords
  98. firstentry = 0
  99. for file in all_files_src :
  100. filep = open(file, 'r')
  101. lines = filep.readlines()
  102. filep.close()
  103. for line in lines :
  104. # get function name
  105. if ((None != re.search("^int .*\(", line)) or (None != re.search("^void .*\(", line))) :
  106. funcstr = line
  107. funcstr = funcstr.replace('*','')
  108. funcstr = funcstr.split(" ")[1]
  109. funcstr = funcstr.split("(")[0]
  110. found = 0
  111. for function in list_functions:
  112. if (( found == 0 ) and ( function == funcstr )):
  113. database = database + [ dict(srcfile = file, func = function, lst_ret = [], lst_call = [])]
  114. firstentry = 1
  115. found = 1
  116. if found == 0 :
  117. print ( "error in line: "+line + "\nfile: " + file )
  118. exit(-1)
  119. # get return values
  120. for return_value in list_return :
  121. if return_value in line :
  122. if not ( return_value in database[-1]['lst_ret'] ):
  123. database[-1]['lst_ret'].append(return_value)
  124. # get function calls
  125. for call_funct in list_functions :
  126. if (( call_funct in line ) and ( firstentry == 1 )):
  127. if (not "strcmp" in line ):
  128. if not database[-1]['func'] in line :
  129. database[-1]['lst_call'].append(call_funct)
  130. # remove duplicates
  131. database[-1]['lst_call'] = list(dict.fromkeys(database[-1]['lst_call']))
  132. # print info
  133. def print_autocomplete ( name , file ):
  134. for entry in database :
  135. if name == entry['func'] :
  136. string = "\n**Return values:**\n\n"
  137. for ret in entry['lst_ret'] :
  138. if 'XERR_' in ret :
  139. string = string + "> **error:** " + ret + " $\\rightarrow$ "
  140. elif 'XWAR_' in ret :
  141. string = string + "> **warning:** " + ret + " $\\rightarrow$ "
  142. else :
  143. string = string + "> **standard:** " + ret + " $\\rightarrow$ "
  144. for code_dic in list_return_msgs :
  145. if ret == code_dic['code'] :
  146. string = string + code_dic['msg'] + ".\\\n"
  147. if ( string != "\n**Return values:**\n\n") :
  148. string = string[:-2] + "\n\n"
  149. file.write(string)
  150. string = "\n**Function calls:**\n\n"
  151. already_called = []
  152. for call in entry['lst_call'] :
  153. for entry2 in database :
  154. if ( call == entry2['func'] ) and ( not ( call in already_called ) ) :
  155. already_called.append(call)
  156. string = string + "> **" + os.path.basename(entry2['srcfile'])[:-2] + ".md:** " + call + "\\\n"
  157. #if ( call == entry2['func'] ) :
  158. if ( string != "\n**Function calls:**\n\n") :
  159. string = string[:-2] + "\n\n"
  160. file.write(string)
  161. break
  162. for file in all_files_doc :
  163. print( "file " + file)
  164. title = os.path.basename(file).replace("_", " ")[:-3]
  165. filep = open(file, 'r')
  166. lines = filep.readlines()
  167. filep.close()
  168. fileo = open(out_dir + "/" +os.path.basename(file), 'w')
  169. # dump header
  170. today = date.today()
  171. fileo.write("---\n")
  172. fileo.write("title: \"" + title + "\""+ "\n")
  173. fileo.write("author: []\n")
  174. fileo.write("legalinfo: \""+ legal_info+"\""+ "\n")
  175. fileo.write("page-background: \""+ os.path.expanduser('~') + "/" + texmfhome + "tex/" + type_file + ".pdf"+"\""+ "\n")
  176. fileo.write("date: \""+today.strftime("%d-%m-%Y")+"\""+ "\n")
  177. fileo.write("lang: en"+"\n")
  178. fileo.write("titlepage: true,"+"\n")
  179. fileo.write("titlepage-background: \"" + os.path.expanduser('~') + "/" +texmfhome + "tex/xoronostitlepage.pdf" + "\""+ "\n")
  180. fileo.write("titlepage-text-color: \"000000\"" + "\n")
  181. fileo.write("titlepage-rule-color: \"360049\"" + "\n")
  182. fileo.write("titlepage-rule-height: 0" + "\n")
  183. fileo.write("..." + "\n")
  184. fileo.write("\\vspace*{2cm}" + "\n")
  185. fileo.write("\\centerline{" + "\n")
  186. fileo.write("\\Large" + "\n")
  187. fileo.write("\\textbf{" + "\n")
  188. fileo.write("Xoron Library Version " + lib_version + "\n")
  189. fileo.write("}" + "\n")
  190. fileo.write("}" + "\n")
  191. fileo.write("\\vspace*{2cm}" + "\n")
  192. # dump lines
  193. for line in lines :
  194. # check for autocomplete
  195. if "docautocomplete" in line :
  196. maxlen = 0
  197. for function in list_functions :
  198. if function in line :
  199. if maxlen < len ( function ) :
  200. best_match = function
  201. maxlen = len ( function )
  202. if ( maxlen != 0 ) :
  203. print_autocomplete ( best_match, fileo )
  204. else :
  205. fileo.write(line)
  206. fileo.close()
  207. # dump pdf
  208. cmd = "pandoc " + out_dir + "/" +os.path.basename(file) + " -o "
  209. cmd = cmd + pdf_dir + "/" + os.path.basename(file)[:-3] + ".pdf --from markdown --template "
  210. cmd = cmd + " " + template + " --listings --toc "
  211. os.system(cmd)
  212. name6 = out_dir + "/" + os.path.basename(file)[:-3] + "6.html"
  213. name5 = out_dir + "/" + os.path.basename(file)[:-3] + "5.html"
  214. name4 = out_dir + "/" + os.path.basename(file)[:-3] + "4.html"
  215. name3 = out_dir + "/" + os.path.basename(file)[:-3] + "3.html"
  216. name2 = out_dir + "/" + os.path.basename(file)[:-3] + "2.html"
  217. name1 = out_dir + "/" + os.path.basename(file)[:-3] + "1.html"
  218. name = html_dir + "/" + os.path.basename(file)[:-3] + ".html"
  219. cmd = "pandoc --standalone " + out_dir + "/" +os.path.basename(file) + " --from markdown --mathjax --toc "
  220. cmd = cmd + " -o " + name6
  221. os.system(cmd)
  222. # copy css into html
  223. cmd = "line=$(grep -n '/style' " + name6 + " | cut -d ':' -f 1); "
  224. cmd = cmd + "{ head -n $(($line-1)) " + name6 + " ; cat " + resdir + "/xoronos.css; tail -n +$line " + name6 + " ; } > " + name5 + " ;"
  225. os.system(cmd)
  226. # copy fonts into html
  227. cmd = "line=$(grep -n '<body>' " + name5 + " | cut -d ':' -f 1); "
  228. cmd = cmd + "{ head -n $(($line-1)) " + name5 + " ; cat " + resdir + "/xoronos_font.html; tail -n +$line " + name5 + " ; } > " + name4 + " ;"
  229. os.system(cmd)
  230. # fix formatting
  231. cmd = "cat " + name4 + " | sed 's/<\\/nav>/<\/nav>\\n<div>/g; s/<\\/body>/<\\/div>\\n<\\/body>/g' > " + name3
  232. os.system(cmd)
  233. # add java script into html
  234. cmd = "line4=$( grep -n '/body>' " + name3 + " | cut -d ':' -f 1 ); "
  235. cmd = cmd + "{ head -n $(($line4-1)) " + name3 + "; cat " + resdir + "/xoronos.js; tail -n +$line4 " + name3 + "; } > " + name2 + ";"
  236. os.system(cmd)
  237. # add menu collapsable
  238. cmd = "cat " + name2 + " | sed '/<li>.*.<ul>/s/li><a/li><a class=\"caret\"/; /<li>.*.<ul>/s/<ul/<ul class=\"nested\"/; ' > " + name1 + ";"
  239. os.system(cmd)
  240. # fix hdots
  241. cmd = "cat " + name1 + " | sed \"s/\\\hdots/.../g; s/\\././; s/cline[{][^}]*[}]/\\\\\ \\\hline/ \" > " + name
  242. os.system(cmd)
  243. # remove temporary files
  244. cmd = "rm " + name6 + " ; rm " + name5 + " ; rm " + name4 + " ; rm " + name3 + " ; rm " + name2 + " ; rm " + name1
  245. os.system(cmd)