index.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #!/usr/bin/python -u
  2. #
  3. # Indexes the examples and build an XML description
  4. #
  5. import string
  6. import glob
  7. import sys
  8. try:
  9. import libxml2
  10. except:
  11. sys.exit(1)
  12. sys.path.insert(0, "..")
  13. from apibuild import CParser, escape
  14. examples = []
  15. extras = ['examples.xsl', 'index.py']
  16. tests = []
  17. sections = {}
  18. symbols = {}
  19. api_dict = None
  20. api_doc = None
  21. def load_api():
  22. global api_dict
  23. global api_doc
  24. if api_dict != None:
  25. return
  26. api_dict = {}
  27. try:
  28. print "loading ../libxml2-api.xml"
  29. api_doc = libxml2.parseFile("../libxml2-api.xml")
  30. except:
  31. print "failed to parse ../libxml2-api.xml"
  32. sys.exit(1)
  33. def find_symbol(name):
  34. global api_dict
  35. global api_doc
  36. if api_doc == None:
  37. load_api()
  38. if name == None:
  39. return
  40. if api_dict.has_key(name):
  41. return api_dict[name]
  42. ctxt = api_doc.xpathNewContext()
  43. res = ctxt.xpathEval("/api/symbols/*[@name = '%s']" % (name))
  44. if type(res) == type([]) and len(res) >= 1:
  45. if len(res) > 1:
  46. print "Found %d references to %s in the API" % (len(res), name)
  47. node = res[0]
  48. typ = node.name
  49. file = node.xpathEval("string(@file)")
  50. info = node.xpathEval("string(info)")
  51. else:
  52. print "Reference %s not found in the API" % (name)
  53. return None
  54. ret = (typ, file, info)
  55. api_dict[name] = ret
  56. return ret
  57. def parse_top_comment(filename, comment):
  58. res = {}
  59. lines = string.split(comment, "\n")
  60. item = None
  61. for line in lines:
  62. while line != "" and (line[0] == ' ' or line[0] == '\t'):
  63. line = line[1:]
  64. while line != "" and line[0] == '*':
  65. line = line[1:]
  66. while line != "" and (line[0] == ' ' or line[0] == '\t'):
  67. line = line[1:]
  68. try:
  69. (it, line) = string.split(line, ":", 1)
  70. item = it
  71. while line != "" and (line[0] == ' ' or line[0] == '\t'):
  72. line = line[1:]
  73. if res.has_key(item):
  74. res[item] = res[item] + " " + line
  75. else:
  76. res[item] = line
  77. except:
  78. if item != None:
  79. if res.has_key(item):
  80. res[item] = res[item] + " " + line
  81. else:
  82. res[item] = line
  83. return res
  84. def parse(filename, output):
  85. global symbols
  86. global sections
  87. parser = CParser(filename)
  88. parser.collect_references()
  89. idx = parser.parse()
  90. info = parse_top_comment(filename, parser.top_comment)
  91. output.write(" <example filename='%s'>\n" % filename)
  92. try:
  93. synopsis = info['synopsis']
  94. output.write(" <synopsis>%s</synopsis>\n" % escape(synopsis));
  95. except:
  96. print "Example %s lacks a synopsis description" % (filename)
  97. try:
  98. purpose = info['purpose']
  99. output.write(" <purpose>%s</purpose>\n" % escape(purpose));
  100. except:
  101. print "Example %s lacks a purpose description" % (filename)
  102. try:
  103. usage = info['usage']
  104. output.write(" <usage>%s</usage>\n" % escape(usage));
  105. except:
  106. print "Example %s lacks an usage description" % (filename)
  107. try:
  108. test = info['test']
  109. output.write(" <test>%s</test>\n" % escape(test));
  110. progname=filename[0:-2]
  111. command=string.replace(test, progname, './' + progname, 1)
  112. tests.append(command)
  113. except:
  114. pass
  115. try:
  116. author = info['author']
  117. output.write(" <author>%s</author>\n" % escape(author));
  118. except:
  119. print "Example %s lacks an author description" % (filename)
  120. try:
  121. copy = info['copy']
  122. output.write(" <copy>%s</copy>\n" % escape(copy));
  123. except:
  124. print "Example %s lacks a copyright description" % (filename)
  125. try:
  126. section = info['section']
  127. output.write(" <section>%s</section>\n" % escape(section));
  128. if sections.has_key(section):
  129. sections[section].append(filename)
  130. else:
  131. sections[section] = [filename]
  132. except:
  133. print "Example %s lacks a section description" % (filename)
  134. for topic in info.keys():
  135. if topic != "purpose" and topic != "usage" and \
  136. topic != "author" and topic != "copy" and \
  137. topic != "section" and topic != "synopsis" and topic != "test":
  138. str = info[topic]
  139. output.write(" <extra topic='%s'>%s</extra>\n" % (
  140. escape(topic), escape(str)))
  141. output.write(" <includes>\n")
  142. for include in idx.includes.keys():
  143. if include.find("libxml") != -1:
  144. output.write(" <include>%s</include>\n" % (escape(include)))
  145. output.write(" </includes>\n")
  146. output.write(" <uses>\n")
  147. for ref in idx.references.keys():
  148. id = idx.references[ref]
  149. name = id.get_name()
  150. line = id.get_lineno()
  151. if symbols.has_key(name):
  152. sinfo = symbols[name]
  153. refs = sinfo[0]
  154. # gather at most 5 references per symbols
  155. if refs > 5:
  156. continue
  157. sinfo.append(filename)
  158. sinfo[0] = refs + 1
  159. else:
  160. symbols[name] = [1, filename]
  161. info = find_symbol(name)
  162. if info != None:
  163. type = info[0]
  164. file = info[1]
  165. output.write(" <%s line='%d' file='%s' name='%s'/>\n" % (type,
  166. line, file, name))
  167. else:
  168. type = id.get_type()
  169. output.write(" <%s line='%d' name='%s'/>\n" % (type,
  170. line, name))
  171. output.write(" </uses>\n")
  172. output.write(" </example>\n")
  173. return idx
  174. def dump_symbols(output):
  175. global symbols
  176. output.write(" <symbols>\n")
  177. keys = symbols.keys()
  178. keys.sort()
  179. for symbol in keys:
  180. output.write(" <symbol name='%s'>\n" % (symbol))
  181. info = symbols[symbol]
  182. i = 1
  183. while i < len(info):
  184. output.write(" <ref filename='%s'/>\n" % (info[i]))
  185. i = i + 1
  186. output.write(" </symbol>\n")
  187. output.write(" </symbols>\n")
  188. def dump_sections(output):
  189. global sections
  190. output.write(" <sections>\n")
  191. keys = sections.keys()
  192. keys.sort()
  193. for section in keys:
  194. output.write(" <section name='%s'>\n" % (section))
  195. info = sections[section]
  196. i = 0
  197. while i < len(info):
  198. output.write(" <example filename='%s'/>\n" % (info[i]))
  199. i = i + 1
  200. output.write(" </section>\n")
  201. output.write(" </sections>\n")
  202. def dump_Makefile():
  203. for file in glob.glob('*.xml'):
  204. extras.append(file)
  205. for file in glob.glob('*.res'):
  206. extras.append(file)
  207. Makefile="""# Beware this is autogenerated by index.py
  208. INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I@srcdir@/include @THREAD_CFLAGS@ @Z_CFLAGS@
  209. DEPS = $(top_builddir)/libxml2.la
  210. LDADDS = @STATIC_BINARIES@ $(top_builddir)/libxml2.la @THREAD_LIBS@ @Z_LIBS@ $(ICONV_LIBS) -lm @WIN32_EXTRA_LIBADD@
  211. rebuild: examples.xml index.html
  212. examples.xml: index.py *.c
  213. -@($(srcdir)/index.py)
  214. index.html: examples.xml examples.xsl
  215. -@(xsltproc examples.xsl examples.xml && echo "Rebuilt web page" && xmllint --valid --noout index.html)
  216. install-data-local:
  217. $(mkinstalldirs) $(DESTDIR)$(HTML_DIR)
  218. -@INSTALL@ -m 0644 $(srcdir)/*.html $(srcdir)/*.c $(srcdir)/*.xml $(srcdir)/*.xsl $(srcdir)/*.res $(DESTDIR)$(HTML_DIR)
  219. """
  220. EXTRA_DIST=""
  221. for extra in extras:
  222. EXTRA_DIST = EXTRA_DIST + extra + " "
  223. Makefile = Makefile + "EXTRA_DIST=%s\n\n" % (EXTRA_DIST)
  224. noinst_PROGRAMS=""
  225. for example in examples:
  226. noinst_PROGRAMS = noinst_PROGRAMS + example + " "
  227. Makefile = Makefile + "noinst_PROGRAMS=%s\n\n" % (noinst_PROGRAMS)
  228. for example in examples:
  229. Makefile = Makefile + "%s_SOURCES=%s.c\n%s_LDFLAGS=\n%s_DEPENDENCIES= $(DEPS)\n%s_LDADD= @RDL_LIBS@ $(LDADDS)\n\n" % (example, example, example,
  230. example, example)
  231. Makefile = Makefile + "valgrind: \n\t$(MAKE) CHECKER='valgrind' tests\n\n"
  232. Makefile = Makefile + "tests: $(noinst_PROGRAMS)\n"
  233. Makefile = Makefile + "\t@(echo '## examples regression tests')\n"
  234. Makefile = Makefile + "\t@(echo > .memdump)\n"
  235. for test in tests:
  236. Makefile = Makefile + "\t@($(CHECKER) %s)\n" % (test)
  237. Makefile = Makefile + '\t@(grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0" ; exit 0)\n'
  238. Makefile = Makefile + "\n\n"
  239. try:
  240. old = open("Makefile.am", "r").read()
  241. if old != Makefile:
  242. n = open("Makefile.am", "w").write(Makefile)
  243. print "Updated Makefile.am"
  244. except:
  245. print "Failed to read or save Makefile.am"
  246. #
  247. # Autogenerate the .cvsignore too ...
  248. #
  249. ignore = """.memdump
  250. Makefile.in
  251. Makefile
  252. """
  253. for example in examples:
  254. ignore = ignore + "%s\n" % (example)
  255. try:
  256. old = open(".cvsignore", "r").read()
  257. if old != ignore:
  258. n = open(".cvsignore", "w").write(ignore)
  259. print "Updated .cvsignore"
  260. except:
  261. print "Failed to read or save .cvsignore"
  262. if __name__ == "__main__":
  263. load_api()
  264. output = open("examples.xml", "w")
  265. output.write("<examples>\n")
  266. for file in glob.glob('*.c'):
  267. parse(file, output)
  268. examples.append(file[:-2])
  269. dump_symbols(output)
  270. dump_sections(output)
  271. output.write("</examples>\n")
  272. output.close()
  273. dump_Makefile()