| #!/usr/bin/python -u | |
| # | |
| # Indexes the examples and build an XML description | |
| # | |
| import string | |
| import glob | |
| import sys | |
| try: | |
| import libxml2 | |
| except: | |
| sys.exit(1) | |
| sys.path.insert(0, "..") | |
| from apibuild import CParser, escape | |
| examples = [] | |
| extras = ['examples.xsl', 'index.html', 'index.py'] | |
| tests = [] | |
| sections = {} | |
| symbols = {} | |
| api_dict = None | |
| api_doc = None | |
| def load_api(): | |
| global api_dict | |
| global api_doc | |
| if api_dict != None: | |
| return | |
| api_dict = {} | |
| try: | |
| print "loading ../libxml2-api.xml" | |
| api_doc = libxml2.parseFile("../libxml2-api.xml") | |
| except: | |
| print "failed to parse ../libxml2-api.xml" | |
| sys.exit(1) | |
| def find_symbol(name): | |
| global api_dict | |
| global api_doc | |
| if api_doc == None: | |
| load_api() | |
| if name == None: | |
| return | |
| if api_dict.has_key(name): | |
| return api_dict[name] | |
| ctxt = api_doc.xpathNewContext() | |
| res = ctxt.xpathEval("/api/symbols/*[@name = '%s']" % (name)) | |
| if type(res) == type([]) and len(res) >= 1: | |
| if len(res) > 1: | |
| print "Found %d references to %s in the API" % (len(res), name) | |
| node = res[0] | |
| typ = node.name | |
| file = node.xpathEval("string(@file)") | |
| info = node.xpathEval("string(info)") | |
| else: | |
| print "Reference %s not found in the API" % (name) | |
| return None | |
| ret = (typ, file, info) | |
| api_dict[name] = ret | |
| return ret | |
| def parse_top_comment(filename, comment): | |
| res = {} | |
| lines = string.split(comment, "\n") | |
| item = None | |
| for line in lines: | |
| while line != "" and (line[0] == ' ' or line[0] == '\t'): | |
| line = line[1:] | |
| while line != "" and line[0] == '*': | |
| line = line[1:] | |
| while line != "" and (line[0] == ' ' or line[0] == '\t'): | |
| line = line[1:] | |
| try: | |
| (it, line) = string.split(line, ":", 1) | |
| item = it | |
| while line != "" and (line[0] == ' ' or line[0] == '\t'): | |
| line = line[1:] | |
| if res.has_key(item): | |
| res[item] = res[item] + " " + line | |
| else: | |
| res[item] = line | |
| except: | |
| if item != None: | |
| if res.has_key(item): | |
| res[item] = res[item] + " " + line | |
| else: | |
| res[item] = line | |
| return res | |
| def parse(filename, output): | |
| global symbols | |
| global sections | |
| parser = CParser(filename) | |
| parser.collect_references() | |
| idx = parser.parse() | |
| info = parse_top_comment(filename, parser.top_comment) | |
| output.write(" <example filename='%s'>\n" % filename) | |
| try: | |
| synopsis = info['synopsis'] | |
| output.write(" <synopsis>%s</synopsis>\n" % escape(synopsis)); | |
| except: | |
| print "Example %s lacks a synopsis description" % (filename) | |
| try: | |
| purpose = info['purpose'] | |
| output.write(" <purpose>%s</purpose>\n" % escape(purpose)); | |
| except: | |
| print "Example %s lacks a purpose description" % (filename) | |
| try: | |
| usage = info['usage'] | |
| output.write(" <usage>%s</usage>\n" % escape(usage)); | |
| except: | |
| print "Example %s lacks an usage description" % (filename) | |
| try: | |
| test = info['test'] | |
| output.write(" <test>%s</test>\n" % escape(test)); | |
| progname=filename[0:-2] | |
| command=string.replace(test, progname, './' + progname, 1) | |
| tests.append(command) | |
| except: | |
| pass | |
| try: | |
| author = info['author'] | |
| output.write(" <author>%s</author>\n" % escape(author)); | |
| except: | |
| print "Example %s lacks an author description" % (filename) | |
| try: | |
| copy = info['copy'] | |
| output.write(" <copy>%s</copy>\n" % escape(copy)); | |
| except: | |
| print "Example %s lacks a copyright description" % (filename) | |
| try: | |
| section = info['section'] | |
| output.write(" <section>%s</section>\n" % escape(section)); | |
| if sections.has_key(section): | |
| sections[section].append(filename) | |
| else: | |
| sections[section] = [filename] | |
| except: | |
| print "Example %s lacks a section description" % (filename) | |
| for topic in info.keys(): | |
| if topic != "purpose" and topic != "usage" and \ | |
| topic != "author" and topic != "copy" and \ | |
| topic != "section" and topic != "synopsis" and topic != "test": | |
| str = info[topic] | |
| output.write(" <extra topic='%s'>%s</extra>\n" % ( | |
| escape(topic), escape(str))) | |
| output.write(" <includes>\n") | |
| for include in idx.includes.keys(): | |
| if include.find("libxml") != -1: | |
| output.write(" <include>%s</include>\n" % (escape(include))) | |
| output.write(" </includes>\n") | |
| output.write(" <uses>\n") | |
| for ref in idx.references.keys(): | |
| id = idx.references[ref] | |
| name = id.get_name() | |
| line = id.get_lineno() | |
| if symbols.has_key(name): | |
| sinfo = symbols[name] | |
| refs = sinfo[0] | |
| # gather at most 5 references per symbols | |
| if refs > 5: | |
| continue | |
| sinfo.append(filename) | |
| sinfo[0] = refs + 1 | |
| else: | |
| symbols[name] = [1, filename] | |
| info = find_symbol(name) | |
| if info != None: | |
| type = info[0] | |
| file = info[1] | |
| output.write(" <%s line='%d' file='%s' name='%s'/>\n" % (type, | |
| line, file, name)) | |
| else: | |
| type = id.get_type() | |
| output.write(" <%s line='%d' name='%s'/>\n" % (type, | |
| line, name)) | |
| output.write(" </uses>\n") | |
| output.write(" </example>\n") | |
| return idx | |
| def dump_symbols(output): | |
| global symbols | |
| output.write(" <symbols>\n") | |
| keys = symbols.keys() | |
| keys.sort() | |
| for symbol in keys: | |
| output.write(" <symbol name='%s'>\n" % (symbol)) | |
| info = symbols[symbol] | |
| i = 1 | |
| while i < len(info): | |
| output.write(" <ref filename='%s'/>\n" % (info[i])) | |
| i = i + 1 | |
| output.write(" </symbol>\n") | |
| output.write(" </symbols>\n") | |
| def dump_sections(output): | |
| global sections | |
| output.write(" <sections>\n") | |
| keys = sections.keys() | |
| keys.sort() | |
| for section in keys: | |
| output.write(" <section name='%s'>\n" % (section)) | |
| info = sections[section] | |
| i = 0 | |
| while i < len(info): | |
| output.write(" <example filename='%s'/>\n" % (info[i])) | |
| i = i + 1 | |
| output.write(" </section>\n") | |
| output.write(" </sections>\n") | |
| def dump_Makefile(): | |
| for file in glob.glob('*.xml'): | |
| extras.append(file) | |
| for file in glob.glob('*.res'): | |
| extras.append(file) | |
| Makefile="""## | |
| ## This file is auto-generated by index.py | |
| ## DO NOT EDIT !!! | |
| ## | |
| AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir)/include | |
| AM_CFLAGS = $(THREAD_CFLAGS) $(Z_CFLAGS) | |
| LDADD = $(RDL_LIBS) $(STATIC_BINARIES) $(top_builddir)/libxml2.la $(THREAD_LIBS) $(Z_LIBS) $(ICONV_LIBS) -lm $(WIN32_EXTRA_LIBADD) | |
| CLEANFILES = *.tmp | |
| if REBUILD_DOCS | |
| rebuild: examples.xml index.html | |
| .PHONY: rebuild | |
| examples.xml: index.py $(noinst_PROGRAMS:=.c) | |
| cd $(srcdir) && $(PYTHON) index.py | |
| $(MAKE) Makefile | |
| index.html: examples.xml examples.xsl | |
| cd $(srcdir) && xsltproc examples.xsl examples.xml && echo "Rebuilt web page" | |
| -cd $(srcdir) && xmllint --valid --noout index.html | |
| endif | |
| install-data-local: | |
| $(MKDIR_P) $(DESTDIR)$(HTML_DIR) | |
| -$(INSTALL) -m 0644 $(srcdir)/*.html $(srcdir)/*.c $(srcdir)/*.xml $(srcdir)/*.xsl $(srcdir)/*.res $(DESTDIR)$(HTML_DIR) | |
| clean-local: | |
| test -f Makefile.am || rm -f test?.xml | |
| """ | |
| examples.sort() | |
| extras.sort() | |
| tests.sort() | |
| EXTRA_DIST="" | |
| for extra in extras: | |
| EXTRA_DIST = EXTRA_DIST + " \\\n\t" + extra | |
| Makefile = Makefile + "EXTRA_DIST =%s\n\n" % (EXTRA_DIST) | |
| noinst_PROGRAMS="" | |
| for example in examples: | |
| noinst_PROGRAMS = noinst_PROGRAMS + " \\\n\t" + example | |
| Makefile = Makefile + "noinst_PROGRAMS =%s\n\n" % (noinst_PROGRAMS) | |
| for example in examples: | |
| Makefile = Makefile + "%s_SOURCES = %s.c\n\n" % (example, example) | |
| Makefile = Makefile + "valgrind: \n\t$(MAKE) CHECKER='valgrind' tests\n\n" | |
| Makefile = Makefile + "tests: $(noinst_PROGRAMS)\n" | |
| Makefile = Makefile + "\ttest -f Makefile.am || test -f test1.xml || $(LN_S) $(srcdir)/test?.xml .\n" | |
| Makefile = Makefile + "\t@(echo '## examples regression tests')\n" | |
| Makefile = Makefile + "\t@(echo > .memdump)\n" | |
| for test in tests: | |
| Makefile = Makefile + "\t$(CHECKER) %s\n" % (test) | |
| Makefile = Makefile + '\t@grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0" ; exit 0\n' | |
| try: | |
| old = open("Makefile.am", "r").read() | |
| if old != Makefile: | |
| n = open("Makefile.am", "w").write(Makefile) | |
| print "Updated Makefile.am" | |
| except: | |
| print "Failed to read or save Makefile.am" | |
| # # | |
| # # Autogenerate the .cvsignore too ... DEPRECATED | |
| # # | |
| # ignore = """.memdump | |
| #Makefile.in | |
| #Makefile | |
| #""" | |
| # for example in examples: | |
| # ignore = ignore + "%s\n" % (example) | |
| # try: | |
| # old = open(".cvsignore", "r").read() | |
| # if old != ignore: | |
| # n = open(".cvsignore", "w").write(ignore) | |
| # print "Updated .cvsignore" | |
| # except: | |
| # print "Failed to read or save .cvsignore" | |
| if __name__ == "__main__": | |
| load_api() | |
| output = open("examples.xml", "w") | |
| output.write("<examples>\n") | |
| for file in glob.glob('*.c'): | |
| parse(file, output) | |
| examples.append(file[:-2]) | |
| dump_symbols(output) | |
| dump_sections(output) | |
| output.write("</examples>\n") | |
| output.close() | |
| dump_Makefile() | |