Blame doc/apibuild.py

Packit 423ecb
#!/usr/bin/python -u
Packit 423ecb
#
Packit 423ecb
# This is the API builder, it parses the C sources and build the
Packit 423ecb
# API formal description in XML.
Packit 423ecb
#
Packit 423ecb
# See Copyright for the status of this software.
Packit 423ecb
#
Packit 423ecb
# daniel@veillard.com
Packit 423ecb
#
Packit 423ecb
import os, sys
Packit 423ecb
import string
Packit 423ecb
import glob
Packit 423ecb
Packit 423ecb
debug=0
Packit 423ecb
#debugsym='ignorableWhitespaceSAXFunc'
Packit 423ecb
debugsym=None
Packit 423ecb
Packit 423ecb
#
Packit 423ecb
# C parser analysis code
Packit 423ecb
#
Packit 423ecb
ignored_files = {
Packit 423ecb
  "trio": "too many non standard macros",
Packit 423ecb
  "trio.c": "too many non standard macros",
Packit 423ecb
  "trionan.c": "too many non standard macros",
Packit 423ecb
  "triostr.c": "too many non standard macros",
Packit 423ecb
  "acconfig.h": "generated portability layer",
Packit 423ecb
  "config.h": "generated portability layer",
Packit 423ecb
  "libxml.h": "internal only",
Packit 423ecb
  "testOOM.c": "out of memory tester",
Packit 423ecb
  "testOOMlib.h": "out of memory tester",
Packit 423ecb
  "testOOMlib.c": "out of memory tester",
Packit 423ecb
  "rngparser.c": "not yet integrated",
Packit 423ecb
  "rngparser.h": "not yet integrated",
Packit 423ecb
  "elfgcchack.h": "not a normal header",
Packit 423ecb
  "testHTML.c": "test tool",
Packit 423ecb
  "testReader.c": "test tool",
Packit 423ecb
  "testSchemas.c": "test tool",
Packit 423ecb
  "testXPath.c": "test tool",
Packit 423ecb
  "testAutomata.c": "test tool",
Packit 423ecb
  "testModule.c": "test tool",
Packit 423ecb
  "testRegexp.c": "test tool",
Packit 423ecb
  "testThreads.c": "test tool",
Packit 423ecb
  "testC14N.c": "test tool",
Packit 423ecb
  "testRelax.c": "test tool",
Packit 423ecb
  "testThreadsWin32.c": "test tool",
Packit 423ecb
  "testSAX.c": "test tool",
Packit 423ecb
  "testURI.c": "test tool",
Packit 423ecb
  "testapi.c": "generated regression tests",
Packit 423ecb
  "runtest.c": "regression tests program",
Packit 423ecb
  "runsuite.c": "regression tests program",
Packit 423ecb
  "tst.c": "not part of the library",
Packit 423ecb
  "test.c": "not part of the library",
Packit 423ecb
  "testdso.c": "test for dynamid shared libraries",
Packit 423ecb
  "testrecurse.c": "test for entities recursions",
Packit 423ecb
  "xzlib.h": "Internal API only 2.8.0",
Packit 423ecb
  "buf.h": "Internal API only 2.9.0",
Packit 423ecb
  "enc.h": "Internal API only 2.9.0",
Packit 423ecb
  "/save.h": "Internal API only 2.9.0",
Packit 423ecb
  "timsort.h": "Internal header only for xpath.c 2.9.0",
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
ignored_words = {
Packit 423ecb
  "WINAPI": (0, "Windows keyword"),
Packit 423ecb
  "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
Packit 423ecb
  "XMLPUBVAR": (0, "Special macro for extern vars for win32"),
Packit 423ecb
  "XSLTPUBVAR": (0, "Special macro for extern vars for win32"),
Packit 423ecb
  "EXSLTPUBVAR": (0, "Special macro for extern vars for win32"),
Packit 423ecb
  "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
Packit 423ecb
  "XSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
Packit 423ecb
  "EXSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
Packit 423ecb
  "XMLCALL": (0, "Special macro for win32 calls"),
Packit 423ecb
  "XSLTCALL": (0, "Special macro for win32 calls"),
Packit 423ecb
  "XMLCDECL": (0, "Special macro for win32 calls"),
Packit 423ecb
  "EXSLTCALL": (0, "Special macro for win32 calls"),
Packit 423ecb
  "__declspec": (3, "Windows keyword"),
Packit 423ecb
  "__stdcall": (0, "Windows keyword"),
Packit 423ecb
  "ATTRIBUTE_UNUSED": (0, "macro keyword"),
Packit 423ecb
  "LIBEXSLT_PUBLIC": (0, "macro keyword"),
Packit 423ecb
  "X_IN_Y": (5, "macro function builder"),
Packit 423ecb
  "ATTRIBUTE_ALLOC_SIZE": (3, "macro for gcc checking extension"),
Packit 423ecb
  "ATTRIBUTE_PRINTF": (5, "macro for gcc printf args checking extension"),
Packit 423ecb
  "LIBXML_ATTR_FORMAT": (5, "macro for gcc printf args checking extension"),
Packit 423ecb
  "LIBXML_ATTR_ALLOC_SIZE": (3, "macro for gcc checking extension"),
Packit 423ecb
  "__XML_EXTERNC": (0, "Special macro added for os400"),
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
def escape(raw):
Packit 423ecb
    raw = raw.replace('&', '&')
Packit 423ecb
    raw = raw.replace('<', '<')
Packit 423ecb
    raw = raw.replace('>', '>')
Packit 423ecb
    raw = raw.replace("'", ''')
Packit 423ecb
    raw = raw.replace('"', '"')
Packit 423ecb
    return raw
Packit 423ecb
Packit 423ecb
def uniq(items):
Packit 423ecb
    d = {}
Packit 423ecb
    for item in items:
Packit 423ecb
        d[item]=1
Packit 423ecb
    return list(d.keys())
Packit 423ecb
Packit 423ecb
class identifier:
Packit 423ecb
    def __init__(self, name, header=None, module=None, type=None, lineno = 0,
Packit 423ecb
                 info=None, extra=None, conditionals = None):
Packit 423ecb
        self.name = name
Packit 423ecb
        self.header = header
Packit 423ecb
        self.module = module
Packit 423ecb
        self.type = type
Packit 423ecb
        self.info = info
Packit 423ecb
        self.extra = extra
Packit 423ecb
        self.lineno = lineno
Packit 423ecb
        self.static = 0
Packit 423ecb
        if conditionals == None or len(conditionals) == 0:
Packit 423ecb
            self.conditionals = None
Packit 423ecb
        else:
Packit 423ecb
            self.conditionals = conditionals[:]
Packit 423ecb
        if self.name == debugsym:
Packit 423ecb
            print("=> define %s : %s" % (debugsym, (module, type, info,
Packit 423ecb
                                         extra, conditionals)))
Packit 423ecb
Packit 423ecb
    def __repr__(self):
Packit 423ecb
        r = "%s %s:" % (self.type, self.name)
Packit 423ecb
        if self.static:
Packit 423ecb
            r = r + " static"
Packit 423ecb
        if self.module != None:
Packit 423ecb
            r = r + " from %s" % (self.module)
Packit 423ecb
        if self.info != None:
Packit 423ecb
            r = r + " " +  repr(self.info)
Packit 423ecb
        if self.extra != None:
Packit 423ecb
            r = r + " " + repr(self.extra)
Packit 423ecb
        if self.conditionals != None:
Packit 423ecb
            r = r + " " + repr(self.conditionals)
Packit 423ecb
        return r
Packit 423ecb
Packit 423ecb
Packit 423ecb
    def set_header(self, header):
Packit 423ecb
        self.header = header
Packit 423ecb
    def set_module(self, module):
Packit 423ecb
        self.module = module
Packit 423ecb
    def set_type(self, type):
Packit 423ecb
        self.type = type
Packit 423ecb
    def set_info(self, info):
Packit 423ecb
        self.info = info
Packit 423ecb
    def set_extra(self, extra):
Packit 423ecb
        self.extra = extra
Packit 423ecb
    def set_lineno(self, lineno):
Packit 423ecb
        self.lineno = lineno
Packit 423ecb
    def set_static(self, static):
Packit 423ecb
        self.static = static
Packit 423ecb
    def set_conditionals(self, conditionals):
Packit 423ecb
        if conditionals == None or len(conditionals) == 0:
Packit 423ecb
            self.conditionals = None
Packit 423ecb
        else:
Packit 423ecb
            self.conditionals = conditionals[:]
Packit 423ecb
Packit 423ecb
    def get_name(self):
Packit 423ecb
        return self.name
Packit 423ecb
    def get_header(self):
Packit 423ecb
        return self.module
Packit 423ecb
    def get_module(self):
Packit 423ecb
        return self.module
Packit 423ecb
    def get_type(self):
Packit 423ecb
        return self.type
Packit 423ecb
    def get_info(self):
Packit 423ecb
        return self.info
Packit 423ecb
    def get_lineno(self):
Packit 423ecb
        return self.lineno
Packit 423ecb
    def get_extra(self):
Packit 423ecb
        return self.extra
Packit 423ecb
    def get_static(self):
Packit 423ecb
        return self.static
Packit 423ecb
    def get_conditionals(self):
Packit 423ecb
        return self.conditionals
Packit 423ecb
Packit 423ecb
    def update(self, header, module, type = None, info = None, extra=None,
Packit 423ecb
               conditionals=None):
Packit 423ecb
        if self.name == debugsym:
Packit 423ecb
            print("=> update %s : %s" % (debugsym, (module, type, info,
Packit 423ecb
                                         extra, conditionals)))
Packit 423ecb
        if header != None and self.header == None:
Packit 423ecb
            self.set_header(module)
Packit 423ecb
        if module != None and (self.module == None or self.header == self.module):
Packit 423ecb
            self.set_module(module)
Packit 423ecb
        if type != None and self.type == None:
Packit 423ecb
            self.set_type(type)
Packit 423ecb
        if info != None:
Packit 423ecb
            self.set_info(info)
Packit 423ecb
        if extra != None:
Packit 423ecb
            self.set_extra(extra)
Packit 423ecb
        if conditionals != None:
Packit 423ecb
            self.set_conditionals(conditionals)
Packit 423ecb
Packit 423ecb
class index:
Packit 423ecb
    def __init__(self, name = "noname"):
Packit 423ecb
        self.name = name
Packit 423ecb
        self.identifiers = {}
Packit 423ecb
        self.functions = {}
Packit 423ecb
        self.variables = {}
Packit 423ecb
        self.includes = {}
Packit 423ecb
        self.structs = {}
Packit 423ecb
        self.enums = {}
Packit 423ecb
        self.typedefs = {}
Packit 423ecb
        self.macros = {}
Packit 423ecb
        self.references = {}
Packit 423ecb
        self.info = {}
Packit 423ecb
Packit 423ecb
    def add_ref(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
Packit 423ecb
        if name[0:2] == '__':
Packit 423ecb
            return None
Packit 423ecb
        d = None
Packit 423ecb
        try:
Packit 423ecb
           d = self.identifiers[name]
Packit 423ecb
           d.update(header, module, type, lineno, info, extra, conditionals)
Packit 423ecb
        except:
Packit 423ecb
           d = identifier(name, header, module, type, lineno, info, extra, conditionals)
Packit 423ecb
           self.identifiers[name] = d
Packit 423ecb
Packit 423ecb
        if d != None and static == 1:
Packit 423ecb
            d.set_static(1)
Packit 423ecb
Packit 423ecb
        if d != None and name != None and type != None:
Packit 423ecb
            self.references[name] = d
Packit 423ecb
Packit 423ecb
        if name == debugsym:
Packit 423ecb
            print("New ref: %s" % (d))
Packit 423ecb
Packit 423ecb
        return d
Packit 423ecb
Packit 423ecb
    def add(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
Packit 423ecb
        if name[0:2] == '__':
Packit 423ecb
            return None
Packit 423ecb
        d = None
Packit 423ecb
        try:
Packit 423ecb
           d = self.identifiers[name]
Packit 423ecb
           d.update(header, module, type, lineno, info, extra, conditionals)
Packit 423ecb
        except:
Packit 423ecb
           d = identifier(name, header, module, type, lineno, info, extra, conditionals)
Packit 423ecb
           self.identifiers[name] = d
Packit 423ecb
Packit 423ecb
        if d != None and static == 1:
Packit 423ecb
            d.set_static(1)
Packit 423ecb
Packit 423ecb
        if d != None and name != None and type != None:
Packit 423ecb
            if type == "function":
Packit 423ecb
                self.functions[name] = d
Packit 423ecb
            elif type == "functype":
Packit 423ecb
                self.functions[name] = d
Packit 423ecb
            elif type == "variable":
Packit 423ecb
                self.variables[name] = d
Packit 423ecb
            elif type == "include":
Packit 423ecb
                self.includes[name] = d
Packit 423ecb
            elif type == "struct":
Packit 423ecb
                self.structs[name] = d
Packit 423ecb
            elif type == "enum":
Packit 423ecb
                self.enums[name] = d
Packit 423ecb
            elif type == "typedef":
Packit 423ecb
                self.typedefs[name] = d
Packit 423ecb
            elif type == "macro":
Packit 423ecb
                self.macros[name] = d
Packit 423ecb
            else:
Packit 423ecb
                print("Unable to register type ", type)
Packit 423ecb
Packit 423ecb
        if name == debugsym:
Packit 423ecb
            print("New symbol: %s" % (d))
Packit 423ecb
Packit 423ecb
        return d
Packit 423ecb
Packit 423ecb
    def merge(self, idx):
Packit 423ecb
        for id in list(idx.functions.keys()):
Packit 423ecb
              #
Packit 423ecb
              # macro might be used to override functions or variables
Packit 423ecb
              # definitions
Packit 423ecb
              #
Packit 423ecb
             if id in self.macros:
Packit 423ecb
                 del self.macros[id]
Packit 423ecb
             if id in self.functions:
Packit 423ecb
                 print("function %s from %s redeclared in %s" % (
Packit 423ecb
                    id, self.functions[id].header, idx.functions[id].header))
Packit 423ecb
             else:
Packit 423ecb
                 self.functions[id] = idx.functions[id]
Packit 423ecb
                 self.identifiers[id] = idx.functions[id]
Packit 423ecb
        for id in list(idx.variables.keys()):
Packit 423ecb
              #
Packit 423ecb
              # macro might be used to override functions or variables
Packit 423ecb
              # definitions
Packit 423ecb
              #
Packit 423ecb
             if id in self.macros:
Packit 423ecb
                 del self.macros[id]
Packit 423ecb
             if id in self.variables:
Packit 423ecb
                 print("variable %s from %s redeclared in %s" % (
Packit 423ecb
                    id, self.variables[id].header, idx.variables[id].header))
Packit 423ecb
             else:
Packit 423ecb
                 self.variables[id] = idx.variables[id]
Packit 423ecb
                 self.identifiers[id] = idx.variables[id]
Packit 423ecb
        for id in list(idx.structs.keys()):
Packit 423ecb
             if id in self.structs:
Packit 423ecb
                 print("struct %s from %s redeclared in %s" % (
Packit 423ecb
                    id, self.structs[id].header, idx.structs[id].header))
Packit 423ecb
             else:
Packit 423ecb
                 self.structs[id] = idx.structs[id]
Packit 423ecb
                 self.identifiers[id] = idx.structs[id]
Packit 423ecb
        for id in list(idx.typedefs.keys()):
Packit 423ecb
             if id in self.typedefs:
Packit 423ecb
                 print("typedef %s from %s redeclared in %s" % (
Packit 423ecb
                    id, self.typedefs[id].header, idx.typedefs[id].header))
Packit 423ecb
             else:
Packit 423ecb
                 self.typedefs[id] = idx.typedefs[id]
Packit 423ecb
                 self.identifiers[id] = idx.typedefs[id]
Packit 423ecb
        for id in list(idx.macros.keys()):
Packit 423ecb
              #
Packit 423ecb
              # macro might be used to override functions or variables
Packit 423ecb
              # definitions
Packit 423ecb
              #
Packit 423ecb
             if id in self.variables:
Packit 423ecb
                 continue
Packit 423ecb
             if id in self.functions:
Packit 423ecb
                 continue
Packit 423ecb
             if id in self.enums:
Packit 423ecb
                 continue
Packit 423ecb
             if id in self.macros:
Packit 423ecb
                 print("macro %s from %s redeclared in %s" % (
Packit 423ecb
                    id, self.macros[id].header, idx.macros[id].header))
Packit 423ecb
             else:
Packit 423ecb
                 self.macros[id] = idx.macros[id]
Packit 423ecb
                 self.identifiers[id] = idx.macros[id]
Packit 423ecb
        for id in list(idx.enums.keys()):
Packit 423ecb
             if id in self.enums:
Packit 423ecb
                 print("enum %s from %s redeclared in %s" % (
Packit 423ecb
                    id, self.enums[id].header, idx.enums[id].header))
Packit 423ecb
             else:
Packit 423ecb
                 self.enums[id] = idx.enums[id]
Packit 423ecb
                 self.identifiers[id] = idx.enums[id]
Packit 423ecb
Packit 423ecb
    def merge_public(self, idx):
Packit 423ecb
        for id in list(idx.functions.keys()):
Packit 423ecb
             if id in self.functions:
Packit 423ecb
                 # check that function condition agrees with header
Packit 423ecb
                 if idx.functions[id].conditionals != \
Packit 423ecb
                    self.functions[id].conditionals:
Packit 423ecb
                     print("Header condition differs from Function for %s:" \
Packit 423ecb
                        % id)
Packit 423ecb
                     print("  H: %s" % self.functions[id].conditionals)
Packit 423ecb
                     print("  C: %s" % idx.functions[id].conditionals)
Packit 423ecb
                 up = idx.functions[id]
Packit 423ecb
                 self.functions[id].update(None, up.module, up.type, up.info, up.extra)
Packit 423ecb
         #     else:
Packit 423ecb
         #         print "Function %s from %s is not declared in headers" % (
Packit 423ecb
         #                id, idx.functions[id].module)
Packit 423ecb
         # TODO: do the same for variables.
Packit 423ecb
Packit 423ecb
    def analyze_dict(self, type, dict):
Packit 423ecb
        count = 0
Packit 423ecb
        public = 0
Packit 423ecb
        for name in list(dict.keys()):
Packit 423ecb
            id = dict[name]
Packit 423ecb
            count = count + 1
Packit 423ecb
            if id.static == 0:
Packit 423ecb
                public = public + 1
Packit 423ecb
        if count != public:
Packit 423ecb
            print("  %d %s , %d public" % (count, type, public))
Packit 423ecb
        elif count != 0:
Packit 423ecb
            print("  %d public %s" % (count, type))
Packit 423ecb
Packit 423ecb
Packit 423ecb
    def analyze(self):
Packit 423ecb
        self.analyze_dict("functions", self.functions)
Packit 423ecb
        self.analyze_dict("variables", self.variables)
Packit 423ecb
        self.analyze_dict("structs", self.structs)
Packit 423ecb
        self.analyze_dict("typedefs", self.typedefs)
Packit 423ecb
        self.analyze_dict("macros", self.macros)
Packit 423ecb
Packit 423ecb
class CLexer:
Packit 423ecb
    """A lexer for the C language, tokenize the input by reading and
Packit 423ecb
       analyzing it line by line"""
Packit 423ecb
    def __init__(self, input):
Packit 423ecb
        self.input = input
Packit 423ecb
        self.tokens = []
Packit 423ecb
        self.line = ""
Packit 423ecb
        self.lineno = 0
Packit 423ecb
Packit 423ecb
    def getline(self):
Packit 423ecb
        line = ''
Packit 423ecb
        while line == '':
Packit 423ecb
            line = self.input.readline()
Packit 423ecb
            if not line:
Packit 423ecb
                return None
Packit 423ecb
            self.lineno = self.lineno + 1
Packit 423ecb
            line = line.lstrip()
Packit 423ecb
            line = line.rstrip()
Packit 423ecb
            if line == '':
Packit 423ecb
                continue
Packit 423ecb
            while line[-1] == '\\':
Packit 423ecb
                line = line[:-1]
Packit 423ecb
                n = self.input.readline()
Packit 423ecb
                self.lineno = self.lineno + 1
Packit 423ecb
                n = n.lstrip()
Packit 423ecb
                n = n.rstrip()
Packit 423ecb
                if not n:
Packit 423ecb
                    break
Packit 423ecb
                else:
Packit 423ecb
                    line = line + n
Packit 423ecb
        return line
Packit 423ecb
Packit 423ecb
    def getlineno(self):
Packit 423ecb
        return self.lineno
Packit 423ecb
Packit 423ecb
    def push(self, token):
Packit 423ecb
        self.tokens.insert(0, token);
Packit 423ecb
Packit 423ecb
    def debug(self):
Packit 423ecb
        print("Last token: ", self.last)
Packit 423ecb
        print("Token queue: ", self.tokens)
Packit 423ecb
        print("Line %d end: " % (self.lineno), self.line)
Packit 423ecb
Packit 423ecb
    def token(self):
Packit 423ecb
        while self.tokens == []:
Packit 423ecb
            if self.line == "":
Packit 423ecb
                line = self.getline()
Packit 423ecb
            else:
Packit 423ecb
                line = self.line
Packit 423ecb
                self.line = ""
Packit 423ecb
            if line == None:
Packit 423ecb
                return None
Packit 423ecb
Packit 423ecb
            if line[0] == '#':
Packit 423ecb
                self.tokens = list(map((lambda x: ('preproc', x)),
Packit 423ecb
                                  line.split()))
Packit 423ecb
                break;
Packit 423ecb
            l = len(line)
Packit 423ecb
            if line[0] == '"' or line[0] == "'":
Packit 423ecb
                end = line[0]
Packit 423ecb
                line = line[1:]
Packit 423ecb
                found = 0
Packit 423ecb
                tok = ""
Packit 423ecb
                while found == 0:
Packit 423ecb
                    i = 0
Packit 423ecb
                    l = len(line)
Packit 423ecb
                    while i < l:
Packit 423ecb
                        if line[i] == end:
Packit 423ecb
                            self.line = line[i+1:]
Packit 423ecb
                            line = line[:i]
Packit 423ecb
                            l = i
Packit 423ecb
                            found = 1
Packit 423ecb
                            break
Packit 423ecb
                        if line[i] == '\\':
Packit 423ecb
                            i = i + 1
Packit 423ecb
                        i = i + 1
Packit 423ecb
                    tok = tok + line
Packit 423ecb
                    if found == 0:
Packit 423ecb
                        line = self.getline()
Packit 423ecb
                        if line == None:
Packit 423ecb
                            return None
Packit 423ecb
                self.last = ('string', tok)
Packit 423ecb
                return self.last
Packit 423ecb
Packit 423ecb
            if l >= 2 and line[0] == '/' and line[1] == '*':
Packit 423ecb
                line = line[2:]
Packit 423ecb
                found = 0
Packit 423ecb
                tok = ""
Packit 423ecb
                while found == 0:
Packit 423ecb
                    i = 0
Packit 423ecb
                    l = len(line)
Packit 423ecb
                    while i < l:
Packit 423ecb
                        if line[i] == '*' and i+1 < l and line[i+1] == '/':
Packit 423ecb
                            self.line = line[i+2:]
Packit 423ecb
                            line = line[:i-1]
Packit 423ecb
                            l = i
Packit 423ecb
                            found = 1
Packit 423ecb
                            break
Packit 423ecb
                        i = i + 1
Packit 423ecb
                    if tok != "":
Packit 423ecb
                        tok = tok + "\n"
Packit 423ecb
                    tok = tok + line
Packit 423ecb
                    if found == 0:
Packit 423ecb
                        line = self.getline()
Packit 423ecb
                        if line == None:
Packit 423ecb
                            return None
Packit 423ecb
                self.last = ('comment', tok)
Packit 423ecb
                return self.last
Packit 423ecb
            if l >= 2 and line[0] == '/' and line[1] == '/':
Packit 423ecb
                line = line[2:]
Packit 423ecb
                self.last = ('comment', line)
Packit 423ecb
                return self.last
Packit 423ecb
            i = 0
Packit 423ecb
            while i < l:
Packit 423ecb
                if line[i] == '/' and i+1 < l and line[i+1] == '/':
Packit 423ecb
                    self.line = line[i:]
Packit 423ecb
                    line = line[:i]
Packit 423ecb
                    break
Packit 423ecb
                if line[i] == '/' and i+1 < l and line[i+1] == '*':
Packit 423ecb
                    self.line = line[i:]
Packit 423ecb
                    line = line[:i]
Packit 423ecb
                    break
Packit 423ecb
                if line[i] == '"' or line[i] == "'":
Packit 423ecb
                    self.line = line[i:]
Packit 423ecb
                    line = line[:i]
Packit 423ecb
                    break
Packit 423ecb
                i = i + 1
Packit 423ecb
            l = len(line)
Packit 423ecb
            i = 0
Packit 423ecb
            while i < l:
Packit 423ecb
                if line[i] == ' ' or line[i] == '\t':
Packit 423ecb
                    i = i + 1
Packit 423ecb
                    continue
Packit 423ecb
                o = ord(line[i])
Packit 423ecb
                if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
Packit 423ecb
                   (o >= 48 and o <= 57):
Packit 423ecb
                    s = i
Packit 423ecb
                    while i < l:
Packit 423ecb
                        o = ord(line[i])
Packit 423ecb
                        if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
Packit 423ecb
                           (o >= 48 and o <= 57) or \
Packit 423ecb
			   (" \t(){}:;,+-*/%&!|[]=><".find(line[i])) == -1:
Packit 423ecb
                            i = i + 1
Packit 423ecb
                        else:
Packit 423ecb
                            break
Packit 423ecb
                    self.tokens.append(('name', line[s:i]))
Packit 423ecb
                    continue
Packit 423ecb
                if "(){}:;,[]".find(line[i]) != -1:
Packit 423ecb
#                 if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
Packit 423ecb
#                    line[i] == '}' or line[i] == ':' or line[i] == ';' or \
Packit 423ecb
#                    line[i] == ',' or line[i] == '[' or line[i] == ']':
Packit 423ecb
                    self.tokens.append(('sep', line[i]))
Packit 423ecb
                    i = i + 1
Packit 423ecb
                    continue
Packit 423ecb
                if "+-*><=/%&!|.".find(line[i]) != -1:
Packit 423ecb
#                 if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
Packit 423ecb
#                    line[i] == '>' or line[i] == '<' or line[i] == '=' or \
Packit 423ecb
#                    line[i] == '/' or line[i] == '%' or line[i] == '&' or \
Packit 423ecb
#                    line[i] == '!' or line[i] == '|' or line[i] == '.':
Packit 423ecb
                    if line[i] == '.' and  i + 2 < l and \
Packit 423ecb
                       line[i+1] == '.' and line[i+2] == '.':
Packit 423ecb
                        self.tokens.append(('name', '...'))
Packit 423ecb
                        i = i + 3
Packit 423ecb
                        continue
Packit 423ecb
Packit 423ecb
                    j = i + 1
Packit 423ecb
                    if j < l and (
Packit 423ecb
                       "+-*><=/%&!|".find(line[j]) != -1):
Packit 423ecb
#                        line[j] == '+' or line[j] == '-' or line[j] == '*' or \
Packit 423ecb
#                        line[j] == '>' or line[j] == '<' or line[j] == '=' or \
Packit 423ecb
#                        line[j] == '/' or line[j] == '%' or line[j] == '&' or \
Packit 423ecb
#                        line[j] == '!' or line[j] == '|'):
Packit 423ecb
                        self.tokens.append(('op', line[i:j+1]))
Packit 423ecb
                        i = j + 1
Packit 423ecb
                    else:
Packit 423ecb
                        self.tokens.append(('op', line[i]))
Packit 423ecb
                        i = i + 1
Packit 423ecb
                    continue
Packit 423ecb
                s = i
Packit 423ecb
                while i < l:
Packit 423ecb
                    o = ord(line[i])
Packit 423ecb
                    if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
Packit 423ecb
                       (o >= 48 and o <= 57) or (
Packit 423ecb
                        " \t(){}:;,+-*/%&!|[]=><".find(line[i]) == -1):
Packit 423ecb
#                         line[i] != ' ' and line[i] != '\t' and
Packit 423ecb
#                         line[i] != '(' and line[i] != ')' and
Packit 423ecb
#                         line[i] != '{'  and line[i] != '}' and
Packit 423ecb
#                         line[i] != ':' and line[i] != ';' and
Packit 423ecb
#                         line[i] != ',' and line[i] != '+' and
Packit 423ecb
#                         line[i] != '-' and line[i] != '*' and
Packit 423ecb
#                         line[i] != '/' and line[i] != '%' and
Packit 423ecb
#                         line[i] != '&' and line[i] != '!' and
Packit 423ecb
#                         line[i] != '|' and line[i] != '[' and
Packit 423ecb
#                         line[i] != ']' and line[i] != '=' and
Packit 423ecb
#                         line[i] != '*' and line[i] != '>' and
Packit 423ecb
#                         line[i] != '<'):
Packit 423ecb
                        i = i + 1
Packit 423ecb
                    else:
Packit 423ecb
                        break
Packit 423ecb
                self.tokens.append(('name', line[s:i]))
Packit 423ecb
Packit 423ecb
        tok = self.tokens[0]
Packit 423ecb
        self.tokens = self.tokens[1:]
Packit 423ecb
        self.last = tok
Packit 423ecb
        return tok
Packit 423ecb
Packit 423ecb
class CParser:
Packit 423ecb
    """The C module parser"""
Packit 423ecb
    def __init__(self, filename, idx = None):
Packit 423ecb
        self.filename = filename
Packit 423ecb
        if len(filename) > 2 and filename[-2:] == '.h':
Packit 423ecb
            self.is_header = 1
Packit 423ecb
        else:
Packit 423ecb
            self.is_header = 0
Packit 423ecb
        self.input = open(filename)
Packit 423ecb
        self.lexer = CLexer(self.input)
Packit 423ecb
        if idx == None:
Packit 423ecb
            self.index = index()
Packit 423ecb
        else:
Packit 423ecb
            self.index = idx
Packit 423ecb
        self.top_comment = ""
Packit 423ecb
        self.last_comment = ""
Packit 423ecb
        self.comment = None
Packit 423ecb
        self.collect_ref = 0
Packit 423ecb
        self.no_error = 0
Packit 423ecb
        self.conditionals = []
Packit 423ecb
        self.defines = []
Packit 423ecb
Packit 423ecb
    def collect_references(self):
Packit 423ecb
        self.collect_ref = 1
Packit 423ecb
Packit 423ecb
    def stop_error(self):
Packit 423ecb
        self.no_error = 1
Packit 423ecb
Packit 423ecb
    def start_error(self):
Packit 423ecb
        self.no_error = 0
Packit 423ecb
Packit 423ecb
    def lineno(self):
Packit 423ecb
        return self.lexer.getlineno()
Packit 423ecb
Packit 423ecb
    def index_add(self, name, module, static, type, info=None, extra = None):
Packit 423ecb
        if self.is_header == 1:
Packit 423ecb
            self.index.add(name, module, module, static, type, self.lineno(),
Packit 423ecb
                           info, extra, self.conditionals)
Packit 423ecb
        else:
Packit 423ecb
            self.index.add(name, None, module, static, type, self.lineno(),
Packit 423ecb
                           info, extra, self.conditionals)
Packit 423ecb
Packit 423ecb
    def index_add_ref(self, name, module, static, type, info=None,
Packit 423ecb
                      extra = None):
Packit 423ecb
        if self.is_header == 1:
Packit 423ecb
            self.index.add_ref(name, module, module, static, type,
Packit 423ecb
                               self.lineno(), info, extra, self.conditionals)
Packit 423ecb
        else:
Packit 423ecb
            self.index.add_ref(name, None, module, static, type, self.lineno(),
Packit 423ecb
                               info, extra, self.conditionals)
Packit 423ecb
Packit 423ecb
    def warning(self, msg):
Packit 423ecb
        if self.no_error:
Packit 423ecb
            return
Packit 423ecb
        print(msg)
Packit 423ecb
Packit 423ecb
    def error(self, msg, token=-1):
Packit 423ecb
        if self.no_error:
Packit 423ecb
            return
Packit 423ecb
Packit 423ecb
        print("Parse Error: " + msg)
Packit 423ecb
        if token != -1:
Packit 423ecb
            print("Got token ", token)
Packit 423ecb
        self.lexer.debug()
Packit 423ecb
        sys.exit(1)
Packit 423ecb
Packit 423ecb
    def debug(self, msg, token=-1):
Packit 423ecb
        print("Debug: " + msg)
Packit 423ecb
        if token != -1:
Packit 423ecb
            print("Got token ", token)
Packit 423ecb
        self.lexer.debug()
Packit 423ecb
Packit 423ecb
    def parseTopComment(self, comment):
Packit 423ecb
        res = {}
Packit 423ecb
        lines = comment.split("\n")
Packit 423ecb
        item = None
Packit 423ecb
        for line in lines:
Packit 423ecb
            while line != "" and (line[0] == ' ' or line[0] == '\t'):
Packit 423ecb
                line = line[1:]
Packit 423ecb
            while line != "" and line[0] == '*':
Packit 423ecb
                line = line[1:]
Packit 423ecb
            while line != "" and (line[0] == ' ' or line[0] == '\t'):
Packit 423ecb
                line = line[1:]
Packit 423ecb
            try:
Packit 423ecb
                (it, line) = line.split(":", 1)
Packit 423ecb
                item = it
Packit 423ecb
                while line != "" and (line[0] == ' ' or line[0] == '\t'):
Packit 423ecb
                    line = line[1:]
Packit 423ecb
                if item in res:
Packit 423ecb
                    res[item] = res[item] + " " + line
Packit 423ecb
                else:
Packit 423ecb
                    res[item] = line
Packit 423ecb
            except:
Packit 423ecb
                if item != None:
Packit 423ecb
                    if item in res:
Packit 423ecb
                        res[item] = res[item] + " " + line
Packit 423ecb
                    else:
Packit 423ecb
                        res[item] = line
Packit 423ecb
        self.index.info = res
Packit 423ecb
Packit 423ecb
    def parseComment(self, token):
Packit 423ecb
        if self.top_comment == "":
Packit 423ecb
            self.top_comment = token[1]
Packit 423ecb
        if self.comment == None or token[1][0] == '*':
Packit 423ecb
            self.comment = token[1];
Packit 423ecb
        else:
Packit 423ecb
            self.comment = self.comment + token[1]
Packit 423ecb
        token = self.lexer.token()
Packit 423ecb
Packit 423ecb
        if self.comment.find("DOC_DISABLE") != -1:
Packit 423ecb
            self.stop_error()
Packit 423ecb
Packit 423ecb
        if self.comment.find("DOC_ENABLE") != -1:
Packit 423ecb
            self.start_error()
Packit 423ecb
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
    #
Packit 423ecb
    # Parse a comment block associate to a typedef
Packit 423ecb
    #
Packit 423ecb
    def parseTypeComment(self, name, quiet = 0):
Packit 423ecb
        if name[0:2] == '__':
Packit 423ecb
            quiet = 1
Packit 423ecb
Packit 423ecb
        args = []
Packit 423ecb
        desc = ""
Packit 423ecb
Packit 423ecb
        if self.comment == None:
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Missing comment for type %s" % (name))
Packit 423ecb
            return((args, desc))
Packit 423ecb
        if self.comment[0] != '*':
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Missing * in type comment for %s" % (name))
Packit 423ecb
            return((args, desc))
Packit 423ecb
        lines = self.comment.split('\n')
Packit 423ecb
        if lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        if lines[0] != "* %s:" % (name):
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Misformatted type comment for %s" % (name))
Packit 423ecb
                self.warning("  Expecting '* %s:' got '%s'" % (name, lines[0]))
Packit 423ecb
            return((args, desc))
Packit 423ecb
        del lines[0]
Packit 423ecb
        while len(lines) > 0 and lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        desc = ""
Packit 423ecb
        while len(lines) > 0:
Packit 423ecb
            l = lines[0]
Packit 423ecb
            while len(l) > 0 and l[0] == '*':
Packit 423ecb
                l = l[1:]
Packit 423ecb
            l = l.strip()
Packit 423ecb
            desc = desc + " " + l
Packit 423ecb
            del lines[0]
Packit 423ecb
Packit 423ecb
        desc = desc.strip()
Packit 423ecb
Packit 423ecb
        if quiet == 0:
Packit 423ecb
            if desc == "":
Packit 423ecb
                self.warning("Type comment for %s lack description of the macro" % (name))
Packit 423ecb
Packit 423ecb
        return(desc)
Packit 423ecb
    #
Packit 423ecb
    # Parse a comment block associate to a macro
Packit 423ecb
    #
Packit 423ecb
    def parseMacroComment(self, name, quiet = 0):
Packit 423ecb
        if name[0:2] == '__':
Packit 423ecb
            quiet = 1
Packit 423ecb
Packit 423ecb
        args = []
Packit 423ecb
        desc = ""
Packit 423ecb
Packit 423ecb
        if self.comment == None:
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Missing comment for macro %s" % (name))
Packit 423ecb
            return((args, desc))
Packit 423ecb
        if self.comment[0] != '*':
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Missing * in macro comment for %s" % (name))
Packit 423ecb
            return((args, desc))
Packit 423ecb
        lines = self.comment.split('\n')
Packit 423ecb
        if lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        if lines[0] != "* %s:" % (name):
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Misformatted macro comment for %s" % (name))
Packit 423ecb
                self.warning("  Expecting '* %s:' got '%s'" % (name, lines[0]))
Packit 423ecb
            return((args, desc))
Packit 423ecb
        del lines[0]
Packit 423ecb
        while lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        while len(lines) > 0 and lines[0][0:3] == '* @':
Packit 423ecb
            l = lines[0][3:]
Packit 423ecb
            try:
Packit 423ecb
                (arg, desc) = l.split(':', 1)
Packit 423ecb
                desc=desc.strip()
Packit 423ecb
                arg=arg.strip()
Packit 423ecb
            except:
Packit 423ecb
                if not quiet:
Packit 423ecb
                    self.warning("Misformatted macro comment for %s" % (name))
Packit 423ecb
                    self.warning("  problem with '%s'" % (lines[0]))
Packit 423ecb
                del lines[0]
Packit 423ecb
                continue
Packit 423ecb
            del lines[0]
Packit 423ecb
            l = lines[0].strip()
Packit 423ecb
            while len(l) > 2 and l[0:3] != '* @':
Packit 423ecb
                while l[0] == '*':
Packit 423ecb
                    l = l[1:]
Packit 423ecb
                desc = desc + ' ' + l.strip()
Packit 423ecb
                del lines[0]
Packit 423ecb
                if len(lines) == 0:
Packit 423ecb
                    break
Packit 423ecb
                l = lines[0]
Packit 423ecb
            args.append((arg, desc))
Packit 423ecb
        while len(lines) > 0 and lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        desc = ""
Packit 423ecb
        while len(lines) > 0:
Packit 423ecb
            l = lines[0]
Packit 423ecb
            while len(l) > 0 and l[0] == '*':
Packit 423ecb
                l = l[1:]
Packit 423ecb
            l = l.strip()
Packit 423ecb
            desc = desc + " " + l
Packit 423ecb
            del lines[0]
Packit 423ecb
Packit 423ecb
        desc = desc.strip()
Packit 423ecb
Packit 423ecb
        if quiet == 0:
Packit 423ecb
            if desc == "":
Packit 423ecb
                self.warning("Macro comment for %s lack description of the macro" % (name))
Packit 423ecb
Packit 423ecb
        return((args, desc))
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a comment block and merge the informations found in the
Packit 423ecb
     # parameters descriptions, finally returns a block as complete
Packit 423ecb
     # as possible
Packit 423ecb
     #
Packit 423ecb
    def mergeFunctionComment(self, name, description, quiet = 0):
Packit 423ecb
        if name == 'main':
Packit 423ecb
            quiet = 1
Packit 423ecb
        if name[0:2] == '__':
Packit 423ecb
            quiet = 1
Packit 423ecb
Packit 423ecb
        (ret, args) = description
Packit 423ecb
        desc = ""
Packit 423ecb
        retdesc = ""
Packit 423ecb
Packit 423ecb
        if self.comment == None:
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Missing comment for function %s" % (name))
Packit 423ecb
            return(((ret[0], retdesc), args, desc))
Packit 423ecb
        if self.comment[0] != '*':
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Missing * in function comment for %s" % (name))
Packit 423ecb
            return(((ret[0], retdesc), args, desc))
Packit 423ecb
        lines = self.comment.split('\n')
Packit 423ecb
        if lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        if lines[0] != "* %s:" % (name):
Packit 423ecb
            if not quiet:
Packit 423ecb
                self.warning("Misformatted function comment for %s" % (name))
Packit 423ecb
                self.warning("  Expecting '* %s:' got '%s'" % (name, lines[0]))
Packit 423ecb
            return(((ret[0], retdesc), args, desc))
Packit 423ecb
        del lines[0]
Packit 423ecb
        while lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        nbargs = len(args)
Packit 423ecb
        while len(lines) > 0 and lines[0][0:3] == '* @':
Packit 423ecb
            l = lines[0][3:]
Packit 423ecb
            try:
Packit 423ecb
                (arg, desc) = l.split(':', 1)
Packit 423ecb
                desc=desc.strip()
Packit 423ecb
                arg=arg.strip()
Packit 423ecb
            except:
Packit 423ecb
                if not quiet:
Packit 423ecb
                    self.warning("Misformatted function comment for %s" % (name))
Packit 423ecb
                    self.warning("  problem with '%s'" % (lines[0]))
Packit 423ecb
                del lines[0]
Packit 423ecb
                continue
Packit 423ecb
            del lines[0]
Packit 423ecb
            l = lines[0].strip()
Packit 423ecb
            while len(l) > 2 and l[0:3] != '* @':
Packit 423ecb
                while l[0] == '*':
Packit 423ecb
                    l = l[1:]
Packit 423ecb
                desc = desc + ' ' + l.strip()
Packit 423ecb
                del lines[0]
Packit 423ecb
                if len(lines) == 0:
Packit 423ecb
                    break
Packit 423ecb
                l = lines[0]
Packit 423ecb
            i = 0
Packit 423ecb
            while i < nbargs:
Packit 423ecb
                if args[i][1] == arg:
Packit 423ecb
                    args[i] = (args[i][0], arg, desc)
Packit 423ecb
                    break;
Packit 423ecb
                i = i + 1
Packit 423ecb
            if i >= nbargs:
Packit 423ecb
                if not quiet:
Packit 423ecb
                    self.warning("Unable to find arg %s from function comment for %s" % (
Packit 423ecb
                       arg, name))
Packit 423ecb
        while len(lines) > 0 and lines[0] == '*':
Packit 423ecb
            del lines[0]
Packit 423ecb
        desc = ""
Packit 423ecb
        while len(lines) > 0:
Packit 423ecb
            l = lines[0]
Packit 423ecb
            while len(l) > 0 and l[0] == '*':
Packit 423ecb
                l = l[1:]
Packit 423ecb
            l = l.strip()
Packit 423ecb
            if len(l) >= 6 and  l[0:6] == "return" or l[0:6] == "Return":
Packit 423ecb
                try:
Packit 423ecb
                    l = l.split(' ', 1)[1]
Packit 423ecb
                except:
Packit 423ecb
                    l = ""
Packit 423ecb
                retdesc = l.strip()
Packit 423ecb
                del lines[0]
Packit 423ecb
                while len(lines) > 0:
Packit 423ecb
                    l = lines[0]
Packit 423ecb
                    while len(l) > 0 and l[0] == '*':
Packit 423ecb
                        l = l[1:]
Packit 423ecb
                    l = l.strip()
Packit 423ecb
                    retdesc = retdesc + " " + l
Packit 423ecb
                    del lines[0]
Packit 423ecb
            else:
Packit 423ecb
                desc = desc + " " + l
Packit 423ecb
                del lines[0]
Packit 423ecb
Packit 423ecb
        retdesc = retdesc.strip()
Packit 423ecb
        desc = desc.strip()
Packit 423ecb
Packit 423ecb
        if quiet == 0:
Packit 423ecb
             #
Packit 423ecb
             # report missing comments
Packit 423ecb
             #
Packit 423ecb
            i = 0
Packit 423ecb
            while i < nbargs:
Packit 423ecb
                if args[i][2] == None and args[i][0] != "void" and \
Packit 423ecb
                   ((args[i][1] != None) or (args[i][1] == '')):
Packit 423ecb
                    self.warning("Function comment for %s lacks description of arg %s" % (name, args[i][1]))
Packit 423ecb
                i = i + 1
Packit 423ecb
            if retdesc == "" and ret[0] != "void":
Packit 423ecb
                self.warning("Function comment for %s lacks description of return value" % (name))
Packit 423ecb
            if desc == "":
Packit 423ecb
                self.warning("Function comment for %s lacks description of the function" % (name))
Packit 423ecb
Packit 423ecb
        return(((ret[0], retdesc), args, desc))
Packit 423ecb
Packit 423ecb
    def parsePreproc(self, token):
Packit 423ecb
        if debug:
Packit 423ecb
            print("=> preproc ", token, self.lexer.tokens)
Packit 423ecb
        name = token[1]
Packit 423ecb
        if name == "#include":
Packit 423ecb
            token = self.lexer.token()
Packit 423ecb
            if token == None:
Packit 423ecb
                return None
Packit 423ecb
            if token[0] == 'preproc':
Packit 423ecb
                self.index_add(token[1], self.filename, not self.is_header,
Packit 423ecb
                                "include")
Packit 423ecb
                return self.lexer.token()
Packit 423ecb
            return token
Packit 423ecb
        if name == "#define":
Packit 423ecb
            token = self.lexer.token()
Packit 423ecb
            if token == None:
Packit 423ecb
                return None
Packit 423ecb
            if token[0] == 'preproc':
Packit 423ecb
                 # TODO macros with arguments
Packit 423ecb
                name = token[1]
Packit 423ecb
                lst = []
Packit 423ecb
                token = self.lexer.token()
Packit 423ecb
                while token != None and token[0] == 'preproc' and \
Packit 423ecb
                      token[1][0] != '#':
Packit 423ecb
                    lst.append(token[1])
Packit 423ecb
                    token = self.lexer.token()
Packit 423ecb
                try:
Packit 423ecb
                    name = name.split('(') [0]
Packit 423ecb
                except:
Packit 423ecb
                    pass
Packit 423ecb
                info = self.parseMacroComment(name, not self.is_header)
Packit 423ecb
                self.index_add(name, self.filename, not self.is_header,
Packit 423ecb
                                "macro", info)
Packit 423ecb
                return token
Packit 423ecb
Packit 423ecb
        #
Packit 423ecb
        # Processing of conditionals modified by Bill 1/1/05
Packit 423ecb
        #
Packit 423ecb
        # We process conditionals (i.e. tokens from #ifdef, #ifndef,
Packit 423ecb
        # #if, #else and #endif) for headers and mainline code,
Packit 423ecb
        # store the ones from the header in libxml2-api.xml, and later
Packit 423ecb
        # (in the routine merge_public) verify that the two (header and
Packit 423ecb
        # mainline code) agree.
Packit 423ecb
        #
Packit 423ecb
        # There is a small problem with processing the headers. Some of
Packit 423ecb
        # the variables are not concerned with enabling / disabling of
Packit 423ecb
        # library functions (e.g. '__XML_PARSER_H__'), and we don't want
Packit 423ecb
        # them to be included in libxml2-api.xml, or involved in
Packit 423ecb
        # the check between the header and the mainline code.  To
Packit 423ecb
        # accomplish this, we ignore any conditional which doesn't include
Packit 423ecb
        # the string 'ENABLED'
Packit 423ecb
        #
Packit 423ecb
        if name == "#ifdef":
Packit 423ecb
            apstr = self.lexer.tokens[0][1]
Packit 423ecb
            try:
Packit 423ecb
                self.defines.append(apstr)
Packit 423ecb
                if apstr.find('ENABLED') != -1:
Packit 423ecb
                    self.conditionals.append("defined(%s)" % apstr)
Packit 423ecb
            except:
Packit 423ecb
                pass
Packit 423ecb
        elif name == "#ifndef":
Packit 423ecb
            apstr = self.lexer.tokens[0][1]
Packit 423ecb
            try:
Packit 423ecb
                self.defines.append(apstr)
Packit 423ecb
                if apstr.find('ENABLED') != -1:
Packit 423ecb
                    self.conditionals.append("!defined(%s)" % apstr)
Packit 423ecb
            except:
Packit 423ecb
                pass
Packit 423ecb
        elif name == "#if":
Packit 423ecb
            apstr = ""
Packit 423ecb
            for tok in self.lexer.tokens:
Packit 423ecb
                if apstr != "":
Packit 423ecb
                    apstr = apstr + " "
Packit 423ecb
                apstr = apstr + tok[1]
Packit 423ecb
            try:
Packit 423ecb
                self.defines.append(apstr)
Packit 423ecb
                if apstr.find('ENABLED') != -1:
Packit 423ecb
                    self.conditionals.append(apstr)
Packit 423ecb
            except:
Packit 423ecb
                pass
Packit 423ecb
        elif name == "#else":
Packit 423ecb
            if self.conditionals != [] and \
Packit 423ecb
               self.defines[-1].find('ENABLED') != -1:
Packit 423ecb
                self.conditionals[-1] = "!(%s)" % self.conditionals[-1]
Packit 423ecb
        elif name == "#endif":
Packit 423ecb
            if self.conditionals != [] and \
Packit 423ecb
               self.defines[-1].find('ENABLED') != -1:
Packit 423ecb
                self.conditionals = self.conditionals[:-1]
Packit 423ecb
            self.defines = self.defines[:-1]
Packit 423ecb
        token = self.lexer.token()
Packit 423ecb
        while token != None and token[0] == 'preproc' and \
Packit 423ecb
            token[1][0] != '#':
Packit 423ecb
            token = self.lexer.token()
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # token acquisition on top of the lexer, it handle internally
Packit 423ecb
     # preprocessor and comments since they are logically not part of
Packit 423ecb
     # the program structure.
Packit 423ecb
     #
Packit 423ecb
    def token(self):
Packit 423ecb
        global ignored_words
Packit 423ecb
Packit 423ecb
        token = self.lexer.token()
Packit 423ecb
        while token != None:
Packit 423ecb
            if token[0] == 'comment':
Packit 423ecb
                token = self.parseComment(token)
Packit 423ecb
                continue
Packit 423ecb
            elif token[0] == 'preproc':
Packit 423ecb
                token = self.parsePreproc(token)
Packit 423ecb
                continue
Packit 423ecb
            elif token[0] == "name" and token[1] == "__const":
Packit 423ecb
                token = ("name", "const")
Packit 423ecb
                return token
Packit 423ecb
            elif token[0] == "name" and token[1] == "__attribute":
Packit 423ecb
                token = self.lexer.token()
Packit 423ecb
                while token != None and token[1] != ";":
Packit 423ecb
                    token = self.lexer.token()
Packit 423ecb
                return token
Packit 423ecb
            elif token[0] == "name" and token[1] in ignored_words:
Packit 423ecb
                (n, info) = ignored_words[token[1]]
Packit 423ecb
                i = 0
Packit 423ecb
                while i < n:
Packit 423ecb
                    token = self.lexer.token()
Packit 423ecb
                    i = i + 1
Packit 423ecb
                token = self.lexer.token()
Packit 423ecb
                continue
Packit 423ecb
            else:
Packit 423ecb
                if debug:
Packit 423ecb
                    print("=> ", token)
Packit 423ecb
                return token
Packit 423ecb
        return None
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a typedef, it records the type and its name.
Packit 423ecb
     #
Packit 423ecb
    def parseTypedef(self, token):
Packit 423ecb
        if token == None:
Packit 423ecb
            return None
Packit 423ecb
        token = self.parseType(token)
Packit 423ecb
        if token == None:
Packit 423ecb
            self.error("parsing typedef")
Packit 423ecb
            return None
Packit 423ecb
        base_type = self.type
Packit 423ecb
        type = base_type
Packit 423ecb
         #self.debug("end typedef type", token)
Packit 423ecb
        while token != None:
Packit 423ecb
            if token[0] == "name":
Packit 423ecb
                name = token[1]
Packit 423ecb
                signature = self.signature
Packit 423ecb
                if signature != None:
Packit 423ecb
                    type = type.split('(')[0]
Packit 423ecb
                    d = self.mergeFunctionComment(name,
Packit 423ecb
                            ((type, None), signature), 1)
Packit 423ecb
                    self.index_add(name, self.filename, not self.is_header,
Packit 423ecb
                                    "functype", d)
Packit 423ecb
                else:
Packit 423ecb
                    if base_type == "struct":
Packit 423ecb
                        self.index_add(name, self.filename, not self.is_header,
Packit 423ecb
                                        "struct", type)
Packit 423ecb
                        base_type = "struct " + name
Packit 423ecb
                    else:
Packit 423ecb
                        # TODO report missing or misformatted comments
Packit 423ecb
                        info = self.parseTypeComment(name, 1)
Packit 423ecb
                        self.index_add(name, self.filename, not self.is_header,
Packit 423ecb
                                    "typedef", type, info)
Packit 423ecb
                token = self.token()
Packit 423ecb
            else:
Packit 423ecb
                self.error("parsing typedef: expecting a name")
Packit 423ecb
                return token
Packit 423ecb
             #self.debug("end typedef", token)
Packit 423ecb
            if token != None and token[0] == 'sep' and token[1] == ',':
Packit 423ecb
                type = base_type
Packit 423ecb
                token = self.token()
Packit 423ecb
                while token != None and token[0] == "op":
Packit 423ecb
                    type = type + token[1]
Packit 423ecb
                    token = self.token()
Packit 423ecb
            elif token != None and token[0] == 'sep' and token[1] == ';':
Packit 423ecb
                break;
Packit 423ecb
            elif token != None and token[0] == 'name':
Packit 423ecb
                type = base_type
Packit 423ecb
                continue;
Packit 423ecb
            else:
Packit 423ecb
                self.error("parsing typedef: expecting ';'", token)
Packit 423ecb
                return token
Packit 423ecb
        token = self.token()
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a C code block, used for functions it parse till
Packit 423ecb
     # the balancing } included
Packit 423ecb
     #
Packit 423ecb
    def parseBlock(self, token):
Packit 423ecb
        while token != None:
Packit 423ecb
            if token[0] == "sep" and token[1] == "{":
Packit 423ecb
                token = self.token()
Packit 423ecb
                token = self.parseBlock(token)
Packit 423ecb
            elif token[0] == "sep" and token[1] == "}":
Packit 423ecb
                self.comment = None
Packit 423ecb
                token = self.token()
Packit 423ecb
                return token
Packit 423ecb
            else:
Packit 423ecb
                if self.collect_ref == 1:
Packit 423ecb
                    oldtok = token
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
Packit 423ecb
                        if token[0] == "sep" and token[1] == "(":
Packit 423ecb
                            self.index_add_ref(oldtok[1], self.filename,
Packit 423ecb
                                                0, "function")
Packit 423ecb
                            token = self.token()
Packit 423ecb
                        elif token[0] == "name":
Packit 423ecb
                            token = self.token()
Packit 423ecb
                            if token[0] == "sep" and (token[1] == ";" or
Packit 423ecb
                               token[1] == "," or token[1] == "="):
Packit 423ecb
                                self.index_add_ref(oldtok[1], self.filename,
Packit 423ecb
                                                    0, "type")
Packit 423ecb
                    elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
Packit 423ecb
                        self.index_add_ref(oldtok[1], self.filename,
Packit 423ecb
                                            0, "typedef")
Packit 423ecb
                    elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
Packit 423ecb
                        self.index_add_ref(oldtok[1], self.filename,
Packit 423ecb
                                            0, "typedef")
Packit 423ecb
Packit 423ecb
                else:
Packit 423ecb
                    token = self.token()
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a C struct definition till the balancing }
Packit 423ecb
     #
Packit 423ecb
    def parseStruct(self, token):
Packit 423ecb
        fields = []
Packit 423ecb
         #self.debug("start parseStruct", token)
Packit 423ecb
        while token != None:
Packit 423ecb
            if token[0] == "sep" and token[1] == "{":
Packit 423ecb
                token = self.token()
Packit 423ecb
                token = self.parseTypeBlock(token)
Packit 423ecb
            elif token[0] == "sep" and token[1] == "}":
Packit 423ecb
                self.struct_fields = fields
Packit 423ecb
                 #self.debug("end parseStruct", token)
Packit 423ecb
                 #print fields
Packit 423ecb
                token = self.token()
Packit 423ecb
                return token
Packit 423ecb
            else:
Packit 423ecb
                base_type = self.type
Packit 423ecb
                 #self.debug("before parseType", token)
Packit 423ecb
                token = self.parseType(token)
Packit 423ecb
                 #self.debug("after parseType", token)
Packit 423ecb
                if token != None and token[0] == "name":
Packit 423ecb
                    fname = token[1]
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    if token[0] == "sep" and token[1] == ";":
Packit 423ecb
                        self.comment = None
Packit 423ecb
                        token = self.token()
Packit 423ecb
                        fields.append((self.type, fname, self.comment))
Packit 423ecb
                        self.comment = None
Packit 423ecb
                    else:
Packit 423ecb
                        self.error("parseStruct: expecting ;", token)
Packit 423ecb
                elif token != None and token[0] == "sep" and token[1] == "{":
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    token = self.parseTypeBlock(token)
Packit 423ecb
                    if token != None and token[0] == "name":
Packit 423ecb
                        token = self.token()
Packit 423ecb
                    if token != None and token[0] == "sep" and token[1] == ";":
Packit 423ecb
                        token = self.token()
Packit 423ecb
                    else:
Packit 423ecb
                        self.error("parseStruct: expecting ;", token)
Packit 423ecb
                else:
Packit 423ecb
                    self.error("parseStruct: name", token)
Packit 423ecb
                    token = self.token()
Packit 423ecb
                self.type = base_type;
Packit 423ecb
        self.struct_fields = fields
Packit 423ecb
         #self.debug("end parseStruct", token)
Packit 423ecb
         #print fields
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a C enum block, parse till the balancing }
Packit 423ecb
     #
Packit 423ecb
    def parseEnumBlock(self, token):
Packit 423ecb
        self.enums = []
Packit 423ecb
        name = None
Packit 423ecb
        self.comment = None
Packit 423ecb
        comment = ""
Packit 423ecb
        value = "0"
Packit 423ecb
        while token != None:
Packit 423ecb
            if token[0] == "sep" and token[1] == "{":
Packit 423ecb
                token = self.token()
Packit 423ecb
                token = self.parseTypeBlock(token)
Packit 423ecb
            elif token[0] == "sep" and token[1] == "}":
Packit 423ecb
                if name != None:
Packit 423ecb
                    if self.comment != None:
Packit 423ecb
                        comment = self.comment
Packit 423ecb
                        self.comment = None
Packit 423ecb
                    self.enums.append((name, value, comment))
Packit 423ecb
                token = self.token()
Packit 423ecb
                return token
Packit 423ecb
            elif token[0] == "name":
Packit 423ecb
                    if name != None:
Packit 423ecb
                        if self.comment != None:
Packit 423ecb
                            comment = self.comment.strip()
Packit 423ecb
                            self.comment = None
Packit 423ecb
                        self.enums.append((name, value, comment))
Packit 423ecb
                    name = token[1]
Packit 423ecb
                    comment = ""
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    if token[0] == "op" and token[1][0] == "=":
Packit 423ecb
                        value = ""
Packit 423ecb
                        if len(token[1]) > 1:
Packit 423ecb
                            value = token[1][1:]
Packit 423ecb
                        token = self.token()
Packit 423ecb
                        while token[0] != "sep" or (token[1] != ',' and
Packit 423ecb
                              token[1] != '}'):
Packit 423ecb
                            value = value + token[1]
Packit 423ecb
                            token = self.token()
Packit 423ecb
                    else:
Packit 423ecb
                        try:
Packit 423ecb
                            value = "%d" % (int(value) + 1)
Packit 423ecb
                        except:
Packit 423ecb
                            self.warning("Failed to compute value of enum %s" % (name))
Packit 423ecb
                            value=""
Packit 423ecb
                    if token[0] == "sep" and token[1] == ",":
Packit 423ecb
                        token = self.token()
Packit 423ecb
            else:
Packit 423ecb
                token = self.token()
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a C definition block, used for structs it parse till
Packit 423ecb
     # the balancing }
Packit 423ecb
     #
Packit 423ecb
    def parseTypeBlock(self, token):
Packit 423ecb
        while token != None:
Packit 423ecb
            if token[0] == "sep" and token[1] == "{":
Packit 423ecb
                token = self.token()
Packit 423ecb
                token = self.parseTypeBlock(token)
Packit 423ecb
            elif token[0] == "sep" and token[1] == "}":
Packit 423ecb
                token = self.token()
Packit 423ecb
                return token
Packit 423ecb
            else:
Packit 423ecb
                token = self.token()
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a type: the fact that the type name can either occur after
Packit 423ecb
     #    the definition or within the definition makes it a little harder
Packit 423ecb
     #    if inside, the name token is pushed back before returning
Packit 423ecb
     #
Packit 423ecb
    def parseType(self, token):
Packit 423ecb
        self.type = ""
Packit 423ecb
        self.struct_fields = []
Packit 423ecb
        self.signature = None
Packit 423ecb
        if token == None:
Packit 423ecb
            return token
Packit 423ecb
Packit 423ecb
        while token[0] == "name" and (
Packit 423ecb
              token[1] == "const" or \
Packit 423ecb
              token[1] == "unsigned" or \
Packit 423ecb
              token[1] == "signed"):
Packit 423ecb
            if self.type == "":
Packit 423ecb
                self.type = token[1]
Packit 423ecb
            else:
Packit 423ecb
                self.type = self.type + " " + token[1]
Packit 423ecb
            token = self.token()
Packit 423ecb
Packit 423ecb
        if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
Packit 423ecb
            if self.type == "":
Packit 423ecb
                self.type = token[1]
Packit 423ecb
            else:
Packit 423ecb
                self.type = self.type + " " + token[1]
Packit 423ecb
            if token[0] == "name" and token[1] == "int":
Packit 423ecb
                if self.type == "":
Packit 423ecb
                    self.type = tmp[1]
Packit 423ecb
                else:
Packit 423ecb
                    self.type = self.type + " " + tmp[1]
Packit 423ecb
Packit 423ecb
        elif token[0] == "name" and token[1] == "struct":
Packit 423ecb
            if self.type == "":
Packit 423ecb
                self.type = token[1]
Packit 423ecb
            else:
Packit 423ecb
                self.type = self.type + " " + token[1]
Packit 423ecb
            token = self.token()
Packit 423ecb
            nametok = None
Packit 423ecb
            if token[0] == "name":
Packit 423ecb
                nametok = token
Packit 423ecb
                token = self.token()
Packit 423ecb
            if token != None and token[0] == "sep" and token[1] == "{":
Packit 423ecb
                token = self.token()
Packit 423ecb
                token = self.parseStruct(token)
Packit 423ecb
            elif token != None and token[0] == "op" and token[1] == "*":
Packit 423ecb
                self.type = self.type + " " + nametok[1] + " *"
Packit 423ecb
                token = self.token()
Packit 423ecb
                while token != None and token[0] == "op" and token[1] == "*":
Packit 423ecb
                    self.type = self.type + " *"
Packit 423ecb
                    token = self.token()
Packit 423ecb
                if token[0] == "name":
Packit 423ecb
                    nametok = token
Packit 423ecb
                    token = self.token()
Packit 423ecb
                else:
Packit 423ecb
                    self.error("struct : expecting name", token)
Packit 423ecb
                    return token
Packit 423ecb
            elif token != None and token[0] == "name" and nametok != None:
Packit 423ecb
                self.type = self.type + " " + nametok[1]
Packit 423ecb
                return token
Packit 423ecb
Packit 423ecb
            if nametok != None:
Packit 423ecb
                self.lexer.push(token)
Packit 423ecb
                token = nametok
Packit 423ecb
            return token
Packit 423ecb
Packit 423ecb
        elif token[0] == "name" and token[1] == "enum":
Packit 423ecb
            if self.type == "":
Packit 423ecb
                self.type = token[1]
Packit 423ecb
            else:
Packit 423ecb
                self.type = self.type + " " + token[1]
Packit 423ecb
            self.enums = []
Packit 423ecb
            token = self.token()
Packit 423ecb
            if token != None and token[0] == "sep" and token[1] == "{":
Packit 423ecb
                token = self.token()
Packit 423ecb
                token = self.parseEnumBlock(token)
Packit 423ecb
            else:
Packit 423ecb
                self.error("parsing enum: expecting '{'", token)
Packit 423ecb
            enum_type = None
Packit 423ecb
            if token != None and token[0] != "name":
Packit 423ecb
                self.lexer.push(token)
Packit 423ecb
                token = ("name", "enum")
Packit 423ecb
            else:
Packit 423ecb
                enum_type = token[1]
Packit 423ecb
            for enum in self.enums:
Packit 423ecb
                self.index_add(enum[0], self.filename,
Packit 423ecb
                               not self.is_header, "enum",
Packit 423ecb
                               (enum[1], enum[2], enum_type))
Packit 423ecb
            return token
Packit 423ecb
Packit 423ecb
        elif token[0] == "name":
Packit 423ecb
            if self.type == "":
Packit 423ecb
                self.type = token[1]
Packit 423ecb
            else:
Packit 423ecb
                self.type = self.type + " " + token[1]
Packit 423ecb
        else:
Packit 423ecb
            self.error("parsing type %s: expecting a name" % (self.type),
Packit 423ecb
                       token)
Packit 423ecb
            return token
Packit 423ecb
        token = self.token()
Packit 423ecb
        while token != None and (token[0] == "op" or
Packit 423ecb
              token[0] == "name" and token[1] == "const"):
Packit 423ecb
            self.type = self.type + " " + token[1]
Packit 423ecb
            token = self.token()
Packit 423ecb
Packit 423ecb
         #
Packit 423ecb
         # if there is a parenthesis here, this means a function type
Packit 423ecb
         #
Packit 423ecb
        if token != None and token[0] == "sep" and token[1] == '(':
Packit 423ecb
            self.type = self.type + token[1]
Packit 423ecb
            token = self.token()
Packit 423ecb
            while token != None and token[0] == "op" and token[1] == '*':
Packit 423ecb
                self.type = self.type + token[1]
Packit 423ecb
                token = self.token()
Packit 423ecb
            if token == None or token[0] != "name" :
Packit 423ecb
                self.error("parsing function type, name expected", token);
Packit 423ecb
                return token
Packit 423ecb
            self.type = self.type + token[1]
Packit 423ecb
            nametok = token
Packit 423ecb
            token = self.token()
Packit 423ecb
            if token != None and token[0] == "sep" and token[1] == ')':
Packit 423ecb
                self.type = self.type + token[1]
Packit 423ecb
                token = self.token()
Packit 423ecb
                if token != None and token[0] == "sep" and token[1] == '(':
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    type = self.type;
Packit 423ecb
                    token = self.parseSignature(token);
Packit 423ecb
                    self.type = type;
Packit 423ecb
                else:
Packit 423ecb
                    self.error("parsing function type, '(' expected", token);
Packit 423ecb
                    return token
Packit 423ecb
            else:
Packit 423ecb
                self.error("parsing function type, ')' expected", token);
Packit 423ecb
                return token
Packit 423ecb
            self.lexer.push(token)
Packit 423ecb
            token = nametok
Packit 423ecb
            return token
Packit 423ecb
Packit 423ecb
         #
Packit 423ecb
         # do some lookahead for arrays
Packit 423ecb
         #
Packit 423ecb
        if token != None and token[0] == "name":
Packit 423ecb
            nametok = token
Packit 423ecb
            token = self.token()
Packit 423ecb
            if token != None and token[0] == "sep" and token[1] == '[':
Packit 423ecb
                self.type = self.type + nametok[1]
Packit 423ecb
                while token != None and token[0] == "sep" and token[1] == '[':
Packit 423ecb
                    self.type = self.type + token[1]
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    while token != None and token[0] != 'sep' and \
Packit 423ecb
                          token[1] != ']' and token[1] != ';':
Packit 423ecb
                        self.type = self.type + token[1]
Packit 423ecb
                        token = self.token()
Packit 423ecb
                if token != None and token[0] == 'sep' and token[1] == ']':
Packit 423ecb
                    self.type = self.type + token[1]
Packit 423ecb
                    token = self.token()
Packit 423ecb
                else:
Packit 423ecb
                    self.error("parsing array type, ']' expected", token);
Packit 423ecb
                    return token
Packit 423ecb
            elif token != None and token[0] == "sep" and token[1] == ':':
Packit 423ecb
                 # remove :12 in case it's a limited int size
Packit 423ecb
                token = self.token()
Packit 423ecb
                token = self.token()
Packit 423ecb
            self.lexer.push(token)
Packit 423ecb
            token = nametok
Packit 423ecb
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a signature: '(' has been parsed and we scan the type definition
Packit 423ecb
     #    up to the ')' included
Packit 423ecb
    def parseSignature(self, token):
Packit 423ecb
        signature = []
Packit 423ecb
        if token != None and token[0] == "sep" and token[1] == ')':
Packit 423ecb
            self.signature = []
Packit 423ecb
            token = self.token()
Packit 423ecb
            return token
Packit 423ecb
        while token != None:
Packit 423ecb
            token = self.parseType(token)
Packit 423ecb
            if token != None and token[0] == "name":
Packit 423ecb
                signature.append((self.type, token[1], None))
Packit 423ecb
                token = self.token()
Packit 423ecb
            elif token != None and token[0] == "sep" and token[1] == ',':
Packit 423ecb
                token = self.token()
Packit 423ecb
                continue
Packit 423ecb
            elif token != None and token[0] == "sep" and token[1] == ')':
Packit 423ecb
                 # only the type was provided
Packit 423ecb
                if self.type == "...":
Packit 423ecb
                    signature.append((self.type, "...", None))
Packit 423ecb
                else:
Packit 423ecb
                    signature.append((self.type, None, None))
Packit 423ecb
            if token != None and token[0] == "sep":
Packit 423ecb
                if token[1] == ',':
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    continue
Packit 423ecb
                elif token[1] == ')':
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    break
Packit 423ecb
        self.signature = signature
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
     #
Packit 423ecb
     # Parse a global definition, be it a type, variable or function
Packit 423ecb
     # the extern "C" blocks are a bit nasty and require it to recurse.
Packit 423ecb
     #
Packit 423ecb
    def parseGlobal(self, token):
Packit 423ecb
        static = 0
Packit 423ecb
        if token[1] == 'extern':
Packit 423ecb
            token = self.token()
Packit 423ecb
            if token == None:
Packit 423ecb
                return token
Packit 423ecb
            if token[0] == 'string':
Packit 423ecb
                if token[1] == 'C':
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    if token == None:
Packit 423ecb
                        return token
Packit 423ecb
                    if token[0] == 'sep' and token[1] == "{":
Packit 423ecb
                        token = self.token()
Packit 423ecb
#                         print 'Entering extern "C line ', self.lineno()
Packit 423ecb
                        while token != None and (token[0] != 'sep' or
Packit 423ecb
                              token[1] != "}"):
Packit 423ecb
                            if token[0] == 'name':
Packit 423ecb
                                token = self.parseGlobal(token)
Packit 423ecb
                            else:
Packit 423ecb
                                self.error(
Packit 423ecb
                                 "token %s %s unexpected at the top level" % (
Packit 423ecb
                                        token[0], token[1]))
Packit 423ecb
                                token = self.parseGlobal(token)
Packit 423ecb
#                         print 'Exiting extern "C" line', self.lineno()
Packit 423ecb
                        token = self.token()
Packit 423ecb
                        return token
Packit 423ecb
                else:
Packit 423ecb
                    return token
Packit 423ecb
        elif token[1] == 'static':
Packit 423ecb
            static = 1
Packit 423ecb
            token = self.token()
Packit 423ecb
            if token == None or  token[0] != 'name':
Packit 423ecb
                return token
Packit 423ecb
Packit 423ecb
        if token[1] == 'typedef':
Packit 423ecb
            token = self.token()
Packit 423ecb
            return self.parseTypedef(token)
Packit 423ecb
        else:
Packit 423ecb
            token = self.parseType(token)
Packit 423ecb
            type_orig = self.type
Packit 423ecb
        if token == None or token[0] != "name":
Packit 423ecb
            return token
Packit 423ecb
        type = type_orig
Packit 423ecb
        self.name = token[1]
Packit 423ecb
        token = self.token()
Packit 423ecb
        while token != None and (token[0] == "sep" or token[0] == "op"):
Packit 423ecb
            if token[0] == "sep":
Packit 423ecb
                if token[1] == "[":
Packit 423ecb
                    type = type + token[1]
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    while token != None and (token[0] != "sep" or \
Packit 423ecb
                          token[1] != ";"):
Packit 423ecb
                        type = type + token[1]
Packit 423ecb
                        token = self.token()
Packit 423ecb
Packit 423ecb
            if token != None and token[0] == "op" and token[1] == "=":
Packit 423ecb
                 #
Packit 423ecb
                 # Skip the initialization of the variable
Packit 423ecb
                 #
Packit 423ecb
                token = self.token()
Packit 423ecb
                if token[0] == 'sep' and token[1] == '{':
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    token = self.parseBlock(token)
Packit 423ecb
                else:
Packit 423ecb
                    self.comment = None
Packit 423ecb
                    while token != None and (token[0] != "sep" or \
Packit 423ecb
                          (token[1] != ';' and token[1] != ',')):
Packit 423ecb
                            token = self.token()
Packit 423ecb
                self.comment = None
Packit 423ecb
                if token == None or token[0] != "sep" or (token[1] != ';' and
Packit 423ecb
                   token[1] != ','):
Packit 423ecb
                    self.error("missing ';' or ',' after value")
Packit 423ecb
Packit 423ecb
            if token != None and token[0] == "sep":
Packit 423ecb
                if token[1] == ";":
Packit 423ecb
                    self.comment = None
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    if type == "struct":
Packit 423ecb
                        self.index_add(self.name, self.filename,
Packit 423ecb
                             not self.is_header, "struct", self.struct_fields)
Packit 423ecb
                    else:
Packit 423ecb
                        self.index_add(self.name, self.filename,
Packit 423ecb
                             not self.is_header, "variable", type)
Packit 423ecb
                    break
Packit 423ecb
                elif token[1] == "(":
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    token = self.parseSignature(token)
Packit 423ecb
                    if token == None:
Packit 423ecb
                        return None
Packit 423ecb
                    if token[0] == "sep" and token[1] == ";":
Packit 423ecb
                        d = self.mergeFunctionComment(self.name,
Packit 423ecb
                                ((type, None), self.signature), 1)
Packit 423ecb
                        self.index_add(self.name, self.filename, static,
Packit 423ecb
                                        "function", d)
Packit 423ecb
                        token = self.token()
Packit 423ecb
                    elif token[0] == "sep" and token[1] == "{":
Packit 423ecb
                        d = self.mergeFunctionComment(self.name,
Packit 423ecb
                                ((type, None), self.signature), static)
Packit 423ecb
                        self.index_add(self.name, self.filename, static,
Packit 423ecb
                                        "function", d)
Packit 423ecb
                        token = self.token()
Packit 423ecb
                        token = self.parseBlock(token);
Packit 423ecb
                elif token[1] == ',':
Packit 423ecb
                    self.comment = None
Packit 423ecb
                    self.index_add(self.name, self.filename, static,
Packit 423ecb
                                    "variable", type)
Packit 423ecb
                    type = type_orig
Packit 423ecb
                    token = self.token()
Packit 423ecb
                    while token != None and token[0] == "sep":
Packit 423ecb
                        type = type + token[1]
Packit 423ecb
                        token = self.token()
Packit 423ecb
                    if token != None and token[0] == "name":
Packit 423ecb
                        self.name = token[1]
Packit 423ecb
                        token = self.token()
Packit 423ecb
                else:
Packit 423ecb
                    break
Packit 423ecb
Packit 423ecb
        return token
Packit 423ecb
Packit 423ecb
    def parse(self):
Packit 423ecb
        self.warning("Parsing %s" % (self.filename))
Packit 423ecb
        token = self.token()
Packit 423ecb
        while token != None:
Packit 423ecb
            if token[0] == 'name':
Packit 423ecb
                token = self.parseGlobal(token)
Packit 423ecb
            else:
Packit 423ecb
                self.error("token %s %s unexpected at the top level" % (
Packit 423ecb
                       token[0], token[1]))
Packit 423ecb
                token = self.parseGlobal(token)
Packit 423ecb
                return
Packit 423ecb
        self.parseTopComment(self.top_comment)
Packit 423ecb
        return self.index
Packit 423ecb
Packit 423ecb
Packit 423ecb
class docBuilder:
Packit 423ecb
    """A documentation builder"""
Packit 423ecb
    def __init__(self, name, directories=['.'], excludes=[]):
Packit 423ecb
        self.name = name
Packit 423ecb
        self.directories = directories
Packit 423ecb
        self.excludes = excludes + list(ignored_files.keys())
Packit 423ecb
        self.modules = {}
Packit 423ecb
        self.headers = {}
Packit 423ecb
        self.idx = index()
Packit 423ecb
        self.xref = {}
Packit 423ecb
        self.index = {}
Packit 423ecb
        if name == 'libxml2':
Packit 423ecb
            self.basename = 'libxml'
Packit 423ecb
        else:
Packit 423ecb
            self.basename = name
Packit 423ecb
Packit 423ecb
    def indexString(self, id, str):
Packit 423ecb
        if str == None:
Packit 423ecb
            return
Packit 423ecb
        str = str.replace("'", ' ')
Packit 423ecb
        str = str.replace('"', ' ')
Packit 423ecb
        str = str.replace("/", ' ')
Packit 423ecb
        str = str.replace('*', ' ')
Packit 423ecb
        str = str.replace("[", ' ')
Packit 423ecb
        str = str.replace("]", ' ')
Packit 423ecb
        str = str.replace("(", ' ')
Packit 423ecb
        str = str.replace(")", ' ')
Packit 423ecb
        str = str.replace("<", ' ')
Packit 423ecb
        str = str.replace('>', ' ')
Packit 423ecb
        str = str.replace("&", ' ')
Packit 423ecb
        str = str.replace('#', ' ')
Packit 423ecb
        str = str.replace(",", ' ')
Packit 423ecb
        str = str.replace('.', ' ')
Packit 423ecb
        str = str.replace(';', ' ')
Packit 423ecb
        tokens = str.split()
Packit 423ecb
        for token in tokens:
Packit 423ecb
            try:
Packit 423ecb
                c = token[0]
Packit 423ecb
                if string.ascii_letters.find(c) < 0:
Packit 423ecb
                    pass
Packit 423ecb
                elif len(token) < 3:
Packit 423ecb
                    pass
Packit 423ecb
                else:
Packit 423ecb
                    lower = token.lower()
Packit 423ecb
                    # TODO: generalize this a bit
Packit 423ecb
                    if lower == 'and' or lower == 'the':
Packit 423ecb
                        pass
Packit 423ecb
                    elif token in self.xref:
Packit 423ecb
                        self.xref[token].append(id)
Packit 423ecb
                    else:
Packit 423ecb
                        self.xref[token] = [id]
Packit 423ecb
            except:
Packit 423ecb
                pass
Packit 423ecb
Packit 423ecb
    def analyze(self):
Packit 423ecb
        print("Project %s : %d headers, %d modules" % (self.name, len(list(self.headers.keys())), len(list(self.modules.keys()))))
Packit 423ecb
        self.idx.analyze()
Packit 423ecb
Packit 423ecb
    def scanHeaders(self):
Packit 423ecb
        for header in list(self.headers.keys()):
Packit 423ecb
            parser = CParser(header)
Packit 423ecb
            idx = parser.parse()
Packit 423ecb
            self.headers[header] = idx;
Packit 423ecb
            self.idx.merge(idx)
Packit 423ecb
Packit 423ecb
    def scanModules(self):
Packit 423ecb
        for module in list(self.modules.keys()):
Packit 423ecb
            parser = CParser(module)
Packit 423ecb
            idx = parser.parse()
Packit 423ecb
            # idx.analyze()
Packit 423ecb
            self.modules[module] = idx
Packit 423ecb
            self.idx.merge_public(idx)
Packit 423ecb
Packit 423ecb
    def scan(self):
Packit 423ecb
        for directory in self.directories:
Packit 423ecb
            files = glob.glob(directory + "/*.c")
Packit 423ecb
            for file in files:
Packit 423ecb
                skip = 0
Packit 423ecb
                for excl in self.excludes:
Packit 423ecb
                    if file.find(excl) != -1:
Packit 423ecb
                        print("Skipping %s" % file)
Packit 423ecb
                        skip = 1
Packit 423ecb
                        break
Packit 423ecb
                if skip == 0:
Packit 423ecb
                    self.modules[file] = None;
Packit 423ecb
            files = glob.glob(directory + "/*.h")
Packit 423ecb
            for file in files:
Packit 423ecb
                skip = 0
Packit 423ecb
                for excl in self.excludes:
Packit 423ecb
                    if file.find(excl) != -1:
Packit 423ecb
                        print("Skipping %s" % file)
Packit 423ecb
                        skip = 1
Packit 423ecb
                        break
Packit 423ecb
                if skip == 0:
Packit 423ecb
                    self.headers[file] = None;
Packit 423ecb
        self.scanHeaders()
Packit 423ecb
        self.scanModules()
Packit 423ecb
Packit 423ecb
    def modulename_file(self, file):
Packit 423ecb
        module = os.path.basename(file)
Packit 423ecb
        if module[-2:] == '.h':
Packit 423ecb
            module = module[:-2]
Packit 423ecb
        elif module[-2:] == '.c':
Packit 423ecb
            module = module[:-2]
Packit 423ecb
        return module
Packit 423ecb
Packit 423ecb
    def serialize_enum(self, output, name):
Packit 423ecb
        id = self.idx.enums[name]
Packit 423ecb
        output.write("    
Packit 423ecb
                     self.modulename_file(id.header)))
Packit 423ecb
        if id.info != None:
Packit 423ecb
            info = id.info
Packit 423ecb
            if info[0] != None and info[0] != '':
Packit 423ecb
                try:
Packit 423ecb
                    val = eval(info[0])
Packit 423ecb
                except:
Packit 423ecb
                    val = info[0]
Packit 423ecb
                output.write(" value='%s'" % (val));
Packit 423ecb
            if info[2] != None and info[2] != '':
Packit 423ecb
                output.write(" type='%s'" % info[2]);
Packit 423ecb
            if info[1] != None and info[1] != '':
Packit 423ecb
                output.write(" info='%s'" % escape(info[1]));
Packit 423ecb
        output.write("/>\n")
Packit 423ecb
Packit 423ecb
    def serialize_macro(self, output, name):
Packit 423ecb
        id = self.idx.macros[name]
Packit 423ecb
        output.write("    <macro name='%s' file='%s'>\n" % (name,
Packit 423ecb
                     self.modulename_file(id.header)))
Packit 423ecb
        if id.info != None:
Packit 423ecb
            try:
Packit 423ecb
                (args, desc) = id.info
Packit 423ecb
                if desc != None and desc != "":
Packit 423ecb
                    output.write("      <info>%s</info>\n" % (escape(desc)))
Packit 423ecb
                    self.indexString(name, desc)
Packit 423ecb
                for arg in args:
Packit 423ecb
                    (name, desc) = arg
Packit 423ecb
                    if desc != None and desc != "":
Packit 423ecb
                        output.write("      <arg name='%s' info='%s'/>\n" % (
Packit 423ecb
                                     name, escape(desc)))
Packit 423ecb
                        self.indexString(name, desc)
Packit 423ecb
                    else:
Packit 423ecb
                        output.write("      <arg name='%s'/>\n" % (name))
Packit 423ecb
            except:
Packit 423ecb
                pass
Packit 423ecb
        output.write("    </macro>\n")
Packit 423ecb
Packit 423ecb
    def serialize_typedef(self, output, name):
Packit 423ecb
        id = self.idx.typedefs[name]
Packit 423ecb
        if id.info[0:7] == 'struct ':
Packit 423ecb
            output.write("    
Packit 423ecb
                     name, self.modulename_file(id.header), id.info))
Packit 423ecb
            name = id.info[7:]
Packit 423ecb
            if name in self.idx.structs and ( \
Packit 423ecb
               type(self.idx.structs[name].info) == type(()) or
Packit 423ecb
                type(self.idx.structs[name].info) == type([])):
Packit 423ecb
                output.write(">\n");
Packit 423ecb
                try:
Packit 423ecb
                    for field in self.idx.structs[name].info:
Packit 423ecb
                        desc = field[2]
Packit 423ecb
                        self.indexString(name, desc)
Packit 423ecb
                        if desc == None:
Packit 423ecb
                            desc = ''
Packit 423ecb
                        else:
Packit 423ecb
                            desc = escape(desc)
Packit 423ecb
                        output.write("      <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
Packit 423ecb
                except:
Packit 423ecb
                    print("Failed to serialize struct %s" % (name))
Packit 423ecb
                output.write("    </struct>\n")
Packit 423ecb
            else:
Packit 423ecb
                output.write("/>\n");
Packit 423ecb
        else :
Packit 423ecb
            output.write("    
Packit 423ecb
                         name, self.modulename_file(id.header), id.info))
Packit 423ecb
            try:
Packit 423ecb
                desc = id.extra
Packit 423ecb
                if desc != None and desc != "":
Packit 423ecb
                    output.write(">\n      <info>%s</info>\n" % (escape(desc)))
Packit 423ecb
                    output.write("    </typedef>\n")
Packit 423ecb
                else:
Packit 423ecb
                    output.write("/>\n")
Packit 423ecb
            except:
Packit 423ecb
                output.write("/>\n")
Packit 423ecb
Packit 423ecb
    def serialize_variable(self, output, name):
Packit 423ecb
        id = self.idx.variables[name]
Packit 423ecb
        if id.info != None:
Packit 423ecb
            output.write("    <variable name='%s' file='%s' type='%s'/>\n" % (
Packit 423ecb
                    name, self.modulename_file(id.header), id.info))
Packit 423ecb
        else:
Packit 423ecb
            output.write("    <variable name='%s' file='%s'/>\n" % (
Packit 423ecb
                    name, self.modulename_file(id.header)))
Packit 423ecb
Packit 423ecb
    def serialize_function(self, output, name):
Packit 423ecb
        id = self.idx.functions[name]
Packit 423ecb
        if name == debugsym:
Packit 423ecb
            print("=>", id)
Packit 423ecb
Packit 423ecb
        output.write("    <%s name='%s' file='%s' module='%s'>\n" % (id.type,
Packit 423ecb
                     name, self.modulename_file(id.header),
Packit 423ecb
                     self.modulename_file(id.module)))
Packit 423ecb
        #
Packit 423ecb
        # Processing of conditionals modified by Bill 1/1/05
Packit 423ecb
        #
Packit 423ecb
        if id.conditionals != None:
Packit 423ecb
            apstr = ""
Packit 423ecb
            for cond in id.conditionals:
Packit 423ecb
                if apstr != "":
Packit 423ecb
                    apstr = apstr + " && "
Packit 423ecb
                apstr = apstr + cond
Packit 423ecb
            output.write("      <cond>%s</cond>\n"% (apstr));
Packit 423ecb
        try:
Packit 423ecb
            (ret, params, desc) = id.info
Packit 423ecb
            if (desc == None or desc == '') and \
Packit 423ecb
               name[0:9] != "xmlThrDef" and name != "xmlDllMain":
Packit 423ecb
                print("%s %s from %s has no description" % (id.type, name,
Packit 423ecb
                       self.modulename_file(id.module)))
Packit 423ecb
Packit 423ecb
            output.write("      <info>%s</info>\n" % (escape(desc)))
Packit 423ecb
            self.indexString(name, desc)
Packit 423ecb
            if ret[0] != None:
Packit 423ecb
                if ret[0] == "void":
Packit 423ecb
                    output.write("      <return type='void'/>\n")
Packit 423ecb
                else:
Packit 423ecb
                    output.write("      <return type='%s' info='%s'/>\n" % (
Packit 423ecb
                             ret[0], escape(ret[1])))
Packit 423ecb
                    self.indexString(name, ret[1])
Packit 423ecb
            for param in params:
Packit 423ecb
                if param[0] == 'void':
Packit 423ecb
                    continue
Packit 423ecb
                if param[2] == None:
Packit 423ecb
                    output.write("      <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
Packit 423ecb
                else:
Packit 423ecb
                    output.write("      <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
Packit 423ecb
                    self.indexString(name, param[2])
Packit 423ecb
        except:
Packit 423ecb
            print("Failed to save function %s info: " % name, repr(id.info))
Packit 423ecb
        output.write("    </%s>\n" % (id.type))
Packit 423ecb
Packit 423ecb
    def serialize_exports(self, output, file):
Packit 423ecb
        module = self.modulename_file(file)
Packit 423ecb
        output.write("    <file name='%s'>\n" % (module))
Packit 423ecb
        dict = self.headers[file]
Packit 423ecb
        if dict.info != None:
Packit 423ecb
            for data in ('Summary', 'Description', 'Author'):
Packit 423ecb
                try:
Packit 423ecb
                    output.write("     <%s>%s</%s>\n" % (
Packit 423ecb
                                 data.lower(),
Packit 423ecb
                                 escape(dict.info[data]),
Packit 423ecb
                                 data.lower()))
Packit 423ecb
                except:
Packit 423ecb
                    print("Header %s lacks a %s description" % (module, data))
Packit 423ecb
            if 'Description' in dict.info:
Packit 423ecb
                desc = dict.info['Description']
Packit 423ecb
                if desc.find("DEPRECATED") != -1:
Packit 423ecb
                    output.write("     <deprecated/>\n")
Packit 423ecb
Packit 423ecb
        ids = list(dict.macros.keys())
Packit 423ecb
        ids.sort()
Packit 423ecb
        for id in uniq(ids):
Packit 423ecb
            # Macros are sometime used to masquerade other types.
Packit 423ecb
            if id in dict.functions:
Packit 423ecb
                continue
Packit 423ecb
            if id in dict.variables:
Packit 423ecb
                continue
Packit 423ecb
            if id in dict.typedefs:
Packit 423ecb
                continue
Packit 423ecb
            if id in dict.structs:
Packit 423ecb
                continue
Packit 423ecb
            if id in dict.enums:
Packit 423ecb
                continue
Packit 423ecb
            output.write("     <exports symbol='%s' type='macro'/>\n" % (id))
Packit 423ecb
        ids = list(dict.enums.keys())
Packit 423ecb
        ids.sort()
Packit 423ecb
        for id in uniq(ids):
Packit 423ecb
            output.write("     <exports symbol='%s' type='enum'/>\n" % (id))
Packit 423ecb
        ids = list(dict.typedefs.keys())
Packit 423ecb
        ids.sort()
Packit 423ecb
        for id in uniq(ids):
Packit 423ecb
            output.write("     <exports symbol='%s' type='typedef'/>\n" % (id))
Packit 423ecb
        ids = list(dict.structs.keys())
Packit 423ecb
        ids.sort()
Packit 423ecb
        for id in uniq(ids):
Packit 423ecb
            output.write("     <exports symbol='%s' type='struct'/>\n" % (id))
Packit 423ecb
        ids = list(dict.variables.keys())
Packit 423ecb
        ids.sort()
Packit 423ecb
        for id in uniq(ids):
Packit 423ecb
            output.write("     <exports symbol='%s' type='variable'/>\n" % (id))
Packit 423ecb
        ids = list(dict.functions.keys())
Packit 423ecb
        ids.sort()
Packit 423ecb
        for id in uniq(ids):
Packit 423ecb
            output.write("     <exports symbol='%s' type='function'/>\n" % (id))
Packit 423ecb
        output.write("    </file>\n")
Packit 423ecb
Packit 423ecb
    def serialize_xrefs_files(self, output):
Packit 423ecb
        headers = list(self.headers.keys())
Packit 423ecb
        headers.sort()
Packit 423ecb
        for file in headers:
Packit 423ecb
            module = self.modulename_file(file)
Packit 423ecb
            output.write("    <file name='%s'>\n" % (module))
Packit 423ecb
            dict = self.headers[file]
Packit 423ecb
            ids = uniq(list(dict.functions.keys()) + list(dict.variables.keys()) + \
Packit 423ecb
                  list(dict.macros.keys()) + list(dict.typedefs.keys()) + \
Packit 423ecb
                  list(dict.structs.keys()) + list(dict.enums.keys()))
Packit 423ecb
            ids.sort()
Packit 423ecb
            for id in ids:
Packit 423ecb
                output.write("      <ref name='%s'/>\n" % (id))
Packit 423ecb
            output.write("    </file>\n")
Packit 423ecb
        pass
Packit 423ecb
Packit 423ecb
    def serialize_xrefs_functions(self, output):
Packit 423ecb
        funcs = {}
Packit 423ecb
        for name in list(self.idx.functions.keys()):
Packit 423ecb
            id = self.idx.functions[name]
Packit 423ecb
            try:
Packit 423ecb
                (ret, params, desc) = id.info
Packit 423ecb
                for param in params:
Packit 423ecb
                    if param[0] == 'void':
Packit 423ecb
                        continue
Packit 423ecb
                    if param[0] in funcs:
Packit 423ecb
                        funcs[param[0]].append(name)
Packit 423ecb
                    else:
Packit 423ecb
                        funcs[param[0]] = [name]
Packit 423ecb
            except:
Packit 423ecb
                pass
Packit 423ecb
        typ = list(funcs.keys())
Packit 423ecb
        typ.sort()
Packit 423ecb
        for type in typ:
Packit 423ecb
            if type == '' or type == 'void' or type == "int" or \
Packit 423ecb
               type == "char *" or type == "const char *" :
Packit 423ecb
                continue
Packit 423ecb
            output.write("    <type name='%s'>\n" % (type))
Packit 423ecb
            ids = funcs[type]
Packit 423ecb
            ids.sort()
Packit 423ecb
            pid = ''        # not sure why we have dups, but get rid of them!
Packit 423ecb
            for id in ids:
Packit 423ecb
                if id != pid:
Packit 423ecb
                    output.write("      <ref name='%s'/>\n" % (id))
Packit 423ecb
                    pid = id
Packit 423ecb
            output.write("    </type>\n")
Packit 423ecb
Packit 423ecb
    def serialize_xrefs_constructors(self, output):
Packit 423ecb
        funcs = {}
Packit 423ecb
        for name in list(self.idx.functions.keys()):
Packit 423ecb
            id = self.idx.functions[name]
Packit 423ecb
            try:
Packit 423ecb
                (ret, params, desc) = id.info
Packit 423ecb
                if ret[0] == "void":
Packit 423ecb
                    continue
Packit 423ecb
                if ret[0] in funcs:
Packit 423ecb
                    funcs[ret[0]].append(name)
Packit 423ecb
                else:
Packit 423ecb
                    funcs[ret[0]] = [name]
Packit 423ecb
            except:
Packit 423ecb
                pass
Packit 423ecb
        typ = list(funcs.keys())
Packit 423ecb
        typ.sort()
Packit 423ecb
        for type in typ:
Packit 423ecb
            if type == '' or type == 'void' or type == "int" or \
Packit 423ecb
               type == "char *" or type == "const char *" :
Packit 423ecb
                continue
Packit 423ecb
            output.write("    <type name='%s'>\n" % (type))
Packit 423ecb
            ids = funcs[type]
Packit 423ecb
            ids.sort()
Packit 423ecb
            for id in ids:
Packit 423ecb
                output.write("      <ref name='%s'/>\n" % (id))
Packit 423ecb
            output.write("    </type>\n")
Packit 423ecb
Packit 423ecb
    def serialize_xrefs_alpha(self, output):
Packit 423ecb
        letter = None
Packit 423ecb
        ids = list(self.idx.identifiers.keys())
Packit 423ecb
        ids.sort()
Packit 423ecb
        for id in ids:
Packit 423ecb
            if id[0] != letter:
Packit 423ecb
                if letter != None:
Packit 423ecb
                    output.write("    </letter>\n")
Packit 423ecb
                letter = id[0]
Packit 423ecb
                output.write("    <letter name='%s'>\n" % (letter))
Packit 423ecb
            output.write("      <ref name='%s'/>\n" % (id))
Packit 423ecb
        if letter != None:
Packit 423ecb
            output.write("    </letter>\n")
Packit 423ecb
Packit 423ecb
    def serialize_xrefs_references(self, output):
Packit 423ecb
        typ = list(self.idx.identifiers.keys())
Packit 423ecb
        typ.sort()
Packit 423ecb
        for id in typ:
Packit 423ecb
            idf = self.idx.identifiers[id]
Packit 423ecb
            module = idf.header
Packit 423ecb
            output.write("    <reference name='%s' href='%s'/>\n" % (id,
Packit 423ecb
                         'html/' + self.basename + '-' +
Packit 423ecb
                         self.modulename_file(module) + '.html#' +
Packit 423ecb
                         id))
Packit 423ecb
Packit 423ecb
    def serialize_xrefs_index(self, output):
Packit 423ecb
        index = self.xref
Packit 423ecb
        typ = list(index.keys())
Packit 423ecb
        typ.sort()
Packit 423ecb
        letter = None
Packit 423ecb
        count = 0
Packit 423ecb
        chunk = 0
Packit 423ecb
        chunks = []
Packit 423ecb
        for id in typ:
Packit 423ecb
            if len(index[id]) > 30:
Packit 423ecb
                continue
Packit 423ecb
            if id[0] != letter:
Packit 423ecb
                if letter == None or count > 200:
Packit 423ecb
                    if letter != None:
Packit 423ecb
                        output.write("      </letter>\n")
Packit 423ecb
                        output.write("    </chunk>\n")
Packit 423ecb
                        count = 0
Packit 423ecb
                        chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
Packit 423ecb
                    output.write("    <chunk name='chunk%s'>\n" % (chunk))
Packit 423ecb
                    first_letter = id[0]
Packit 423ecb
                    chunk = chunk + 1
Packit 423ecb
                elif letter != None:
Packit 423ecb
                    output.write("      </letter>\n")
Packit 423ecb
                letter = id[0]
Packit 423ecb
                output.write("      <letter name='%s'>\n" % (letter))
Packit 423ecb
            output.write("        <word name='%s'>\n" % (id))
Packit 423ecb
            tokens = index[id];
Packit 423ecb
            tokens.sort()
Packit 423ecb
            tok = None
Packit 423ecb
            for token in tokens:
Packit 423ecb
                if tok == token:
Packit 423ecb
                    continue
Packit 423ecb
                tok = token
Packit 423ecb
                output.write("          <ref name='%s'/>\n" % (token))
Packit 423ecb
                count = count + 1
Packit 423ecb
            output.write("        </word>\n")
Packit 423ecb
        if letter != None:
Packit 423ecb
            output.write("      </letter>\n")
Packit 423ecb
            output.write("    </chunk>\n")
Packit 423ecb
            if count != 0:
Packit 423ecb
                chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
Packit 423ecb
            output.write("    <chunks>\n")
Packit 423ecb
            for ch in chunks:
Packit 423ecb
                output.write("      <chunk name='%s' start='%s' end='%s'/>\n" % (
Packit 423ecb
                             ch[0], ch[1], ch[2]))
Packit 423ecb
            output.write("    </chunks>\n")
Packit 423ecb
Packit 423ecb
    def serialize_xrefs(self, output):
Packit 423ecb
        output.write("  <references>\n")
Packit 423ecb
        self.serialize_xrefs_references(output)
Packit 423ecb
        output.write("  </references>\n")
Packit 423ecb
        output.write("  <alpha>\n")
Packit 423ecb
        self.serialize_xrefs_alpha(output)
Packit 423ecb
        output.write("  </alpha>\n")
Packit 423ecb
        output.write("  <constructors>\n")
Packit 423ecb
        self.serialize_xrefs_constructors(output)
Packit 423ecb
        output.write("  </constructors>\n")
Packit 423ecb
        output.write("  <functions>\n")
Packit 423ecb
        self.serialize_xrefs_functions(output)
Packit 423ecb
        output.write("  </functions>\n")
Packit 423ecb
        output.write("  <files>\n")
Packit 423ecb
        self.serialize_xrefs_files(output)
Packit 423ecb
        output.write("  </files>\n")
Packit 423ecb
        output.write("  <index>\n")
Packit 423ecb
        self.serialize_xrefs_index(output)
Packit 423ecb
        output.write("  </index>\n")
Packit 423ecb
Packit 423ecb
    def serialize(self):
Packit 423ecb
        filename = "%s-api.xml" % self.name
Packit 423ecb
        print("Saving XML description %s" % (filename))
Packit 423ecb
        output = open(filename, "w")
Packit 423ecb
        output.write('\n')
Packit 423ecb
        output.write("<api name='%s'>\n" % self.name)
Packit 423ecb
        output.write("  <files>\n")
Packit 423ecb
        headers = list(self.headers.keys())
Packit 423ecb
        headers.sort()
Packit 423ecb
        for file in headers:
Packit 423ecb
            self.serialize_exports(output, file)
Packit 423ecb
        output.write("  </files>\n")
Packit 423ecb
        output.write("  <symbols>\n")
Packit 423ecb
        macros = list(self.idx.macros.keys())
Packit 423ecb
        macros.sort()
Packit 423ecb
        for macro in macros:
Packit 423ecb
            self.serialize_macro(output, macro)
Packit 423ecb
        enums = list(self.idx.enums.keys())
Packit 423ecb
        enums.sort()
Packit 423ecb
        for enum in enums:
Packit 423ecb
            self.serialize_enum(output, enum)
Packit 423ecb
        typedefs = list(self.idx.typedefs.keys())
Packit 423ecb
        typedefs.sort()
Packit 423ecb
        for typedef in typedefs:
Packit 423ecb
            self.serialize_typedef(output, typedef)
Packit 423ecb
        variables = list(self.idx.variables.keys())
Packit 423ecb
        variables.sort()
Packit 423ecb
        for variable in variables:
Packit 423ecb
            self.serialize_variable(output, variable)
Packit 423ecb
        functions = list(self.idx.functions.keys())
Packit 423ecb
        functions.sort()
Packit 423ecb
        for function in functions:
Packit 423ecb
            self.serialize_function(output, function)
Packit 423ecb
        output.write("  </symbols>\n")
Packit 423ecb
        output.write("</api>\n")
Packit 423ecb
        output.close()
Packit 423ecb
Packit 423ecb
        filename = "%s-refs.xml" % self.name
Packit 423ecb
        print("Saving XML Cross References %s" % (filename))
Packit 423ecb
        output = open(filename, "w")
Packit 423ecb
        output.write('\n')
Packit 423ecb
        output.write("<apirefs name='%s'>\n" % self.name)
Packit 423ecb
        self.serialize_xrefs(output)
Packit 423ecb
        output.write("</apirefs>\n")
Packit 423ecb
        output.close()
Packit 423ecb
Packit 423ecb
Packit 423ecb
def rebuild():
Packit 423ecb
    builder = None
Packit 423ecb
    if glob.glob("parser.c") != [] :
Packit 423ecb
        print("Rebuilding API description for libxml2")
Packit 423ecb
        builder = docBuilder("libxml2", [".", "."],
Packit 423ecb
                             ["xmlwin32version.h", "tst.c"])
Packit 423ecb
    elif glob.glob("../parser.c") != [] :
Packit 423ecb
        print("Rebuilding API description for libxml2")
Packit 423ecb
        builder = docBuilder("libxml2", ["..", "../include/libxml"],
Packit 423ecb
                             ["xmlwin32version.h", "tst.c"])
Packit 423ecb
    elif glob.glob("../libxslt/transform.c") != [] :
Packit 423ecb
        print("Rebuilding API description for libxslt")
Packit 423ecb
        builder = docBuilder("libxslt", ["../libxslt"],
Packit 423ecb
                             ["win32config.h", "libxslt.h", "tst.c"])
Packit 423ecb
    else:
Packit 423ecb
        print("rebuild() failed, unable to guess the module")
Packit 423ecb
        return None
Packit 423ecb
    builder.scan()
Packit 423ecb
    builder.analyze()
Packit 423ecb
    builder.serialize()
Packit 423ecb
    if glob.glob("../libexslt/exslt.c") != [] :
Packit 423ecb
        extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
Packit 423ecb
        extra.scan()
Packit 423ecb
        extra.analyze()
Packit 423ecb
        extra.serialize()
Packit 423ecb
    return builder
Packit 423ecb
Packit 423ecb
#
Packit 423ecb
# for debugging the parser
Packit 423ecb
#
Packit 423ecb
def parse(filename):
Packit 423ecb
    parser = CParser(filename)
Packit 423ecb
    idx = parser.parse()
Packit 423ecb
    return idx
Packit 423ecb
Packit 423ecb
if __name__ == "__main__":
Packit 423ecb
    if len(sys.argv) > 1:
Packit 423ecb
        debug = 1
Packit 423ecb
        parse(sys.argv[1])
Packit 423ecb
    else:
Packit 423ecb
        rebuild()