Annotation of embedaddon/libxml2/doc/apibuild.py, revision 1.1.1.1

1.1       misho       1: #!/usr/bin/python -u
                      2: #
                      3: # This is the API builder, it parses the C sources and build the
                      4: # API formal description in XML.
                      5: #
                      6: # See Copyright for the status of this software.
                      7: #
                      8: # daniel@veillard.com
                      9: #
                     10: import os, sys
                     11: import string
                     12: import glob
                     13: 
                     14: debug=0
                     15: #debugsym='ignorableWhitespaceSAXFunc'
                     16: debugsym=None
                     17: 
                     18: #
                     19: # C parser analysis code
                     20: #
                     21: ignored_files = {
                     22:   "trio": "too many non standard macros",
                     23:   "trio.c": "too many non standard macros",
                     24:   "trionan.c": "too many non standard macros",
                     25:   "triostr.c": "too many non standard macros",
                     26:   "acconfig.h": "generated portability layer",
                     27:   "config.h": "generated portability layer",
                     28:   "libxml.h": "internal only",
                     29:   "testOOM.c": "out of memory tester",
                     30:   "testOOMlib.h": "out of memory tester",
                     31:   "testOOMlib.c": "out of memory tester",
                     32:   "rngparser.c": "not yet integrated",
                     33:   "rngparser.h": "not yet integrated",
                     34:   "elfgcchack.h": "not a normal header",
                     35:   "testHTML.c": "test tool",
                     36:   "testReader.c": "test tool",
                     37:   "testSchemas.c": "test tool",
                     38:   "testXPath.c": "test tool",
                     39:   "testAutomata.c": "test tool",
                     40:   "testModule.c": "test tool",
                     41:   "testRegexp.c": "test tool",
                     42:   "testThreads.c": "test tool",
                     43:   "testC14N.c": "test tool",
                     44:   "testRelax.c": "test tool",
                     45:   "testThreadsWin32.c": "test tool",
                     46:   "testSAX.c": "test tool",
                     47:   "testURI.c": "test tool",
                     48:   "testapi.c": "generated regression tests",
                     49:   "runtest.c": "regression tests program",
                     50:   "runsuite.c": "regression tests program",
                     51:   "tst.c": "not part of the library",
                     52:   "test.c": "not part of the library",
                     53:   "testdso.c": "test for dynamid shared libraries",
                     54:   "testrecurse.c": "test for entities recursions",
                     55: }
                     56: 
                     57: ignored_words = {
                     58:   "WINAPI": (0, "Windows keyword"),
                     59:   "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
                     60:   "XMLPUBVAR": (0, "Special macro for extern vars for win32"),
                     61:   "XSLTPUBVAR": (0, "Special macro for extern vars for win32"),
                     62:   "EXSLTPUBVAR": (0, "Special macro for extern vars for win32"),
                     63:   "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
                     64:   "XSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
                     65:   "EXSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
                     66:   "XMLCALL": (0, "Special macro for win32 calls"),
                     67:   "XSLTCALL": (0, "Special macro for win32 calls"),
                     68:   "XMLCDECL": (0, "Special macro for win32 calls"),
                     69:   "EXSLTCALL": (0, "Special macro for win32 calls"),
                     70:   "__declspec": (3, "Windows keyword"),
                     71:   "__stdcall": (0, "Windows keyword"),
                     72:   "ATTRIBUTE_UNUSED": (0, "macro keyword"),
                     73:   "LIBEXSLT_PUBLIC": (0, "macro keyword"),
                     74:   "X_IN_Y": (5, "macro function builder"),
                     75:   "ATTRIBUTE_ALLOC_SIZE": (3, "macro for gcc checking extension"),
                     76:   "ATTRIBUTE_PRINTF": (5, "macro for gcc printf args checking extension"),
                     77:   "LIBXML_ATTR_FORMAT": (5, "macro for gcc printf args checking extension"),
                     78:   "LIBXML_ATTR_ALLOC_SIZE": (3, "macro for gcc checking extension"),
                     79: }
                     80: 
                     81: def escape(raw):
                     82:     raw = string.replace(raw, '&', '&')
                     83:     raw = string.replace(raw, '<', '&lt;')
                     84:     raw = string.replace(raw, '>', '&gt;')
                     85:     raw = string.replace(raw, "'", '&apos;')
                     86:     raw = string.replace(raw, '"', '&quot;')
                     87:     return raw
                     88: 
                     89: def uniq(items):
                     90:     d = {}
                     91:     for item in items:
                     92:         d[item]=1
                     93:     return d.keys()
                     94: 
                     95: class identifier:
                     96:     def __init__(self, name, header=None, module=None, type=None, lineno = 0,
                     97:                  info=None, extra=None, conditionals = None):
                     98:         self.name = name
                     99:        self.header = header
                    100:        self.module = module
                    101:        self.type = type
                    102:        self.info = info
                    103:        self.extra = extra
                    104:        self.lineno = lineno
                    105:        self.static = 0
                    106:        if conditionals == None or len(conditionals) == 0:
                    107:            self.conditionals = None
                    108:        else:
                    109:            self.conditionals = conditionals[:]
                    110:        if self.name == debugsym:
                    111:            print "=> define %s : %s" % (debugsym, (module, type, info,
                    112:                                         extra, conditionals))
                    113: 
                    114:     def __repr__(self):
                    115:         r = "%s %s:" % (self.type, self.name)
                    116:        if self.static:
                    117:            r = r + " static"
                    118:        if self.module != None:
                    119:            r = r + " from %s" % (self.module)
                    120:        if self.info != None:
                    121:            r = r + " " +  `self.info`
                    122:        if self.extra != None:
                    123:            r = r + " " + `self.extra`
                    124:        if self.conditionals != None:
                    125:            r = r + " " + `self.conditionals`
                    126:        return r
                    127: 
                    128: 
                    129:     def set_header(self, header):
                    130:         self.header = header
                    131:     def set_module(self, module):
                    132:         self.module = module
                    133:     def set_type(self, type):
                    134:         self.type = type
                    135:     def set_info(self, info):
                    136:         self.info = info
                    137:     def set_extra(self, extra):
                    138:         self.extra = extra
                    139:     def set_lineno(self, lineno):
                    140:         self.lineno = lineno
                    141:     def set_static(self, static):
                    142:         self.static = static
                    143:     def set_conditionals(self, conditionals):
                    144:        if conditionals == None or len(conditionals) == 0:
                    145:            self.conditionals = None
                    146:        else:
                    147:            self.conditionals = conditionals[:]
                    148: 
                    149:     def get_name(self):
                    150:         return self.name
                    151:     def get_header(self):
                    152:         return self.module
                    153:     def get_module(self):
                    154:         return self.module
                    155:     def get_type(self):
                    156:         return self.type
                    157:     def get_info(self):
                    158:         return self.info
                    159:     def get_lineno(self):
                    160:         return self.lineno
                    161:     def get_extra(self):
                    162:         return self.extra
                    163:     def get_static(self):
                    164:         return self.static
                    165:     def get_conditionals(self):
                    166:         return self.conditionals
                    167: 
                    168:     def update(self, header, module, type = None, info = None, extra=None,
                    169:                conditionals=None):
                    170:        if self.name == debugsym:
                    171:            print "=> update %s : %s" % (debugsym, (module, type, info,
                    172:                                         extra, conditionals))
                    173:         if header != None and self.header == None:
                    174:            self.set_header(module)
                    175:         if module != None and (self.module == None or self.header == self.module):
                    176:            self.set_module(module)
                    177:         if type != None and self.type == None:
                    178:            self.set_type(type)
                    179:         if info != None:
                    180:            self.set_info(info)
                    181:         if extra != None:
                    182:            self.set_extra(extra)
                    183:         if conditionals != None:
                    184:            self.set_conditionals(conditionals)
                    185: 
                    186: class index:
                    187:     def __init__(self, name = "noname"):
                    188:         self.name = name
                    189:         self.identifiers = {}
                    190:         self.functions = {}
                    191:        self.variables = {}
                    192:        self.includes = {}
                    193:        self.structs = {}
                    194:        self.enums = {}
                    195:        self.typedefs = {}
                    196:        self.macros = {}
                    197:        self.references = {}
                    198:        self.info = {}
                    199: 
                    200:     def add_ref(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
                    201:         if name[0:2] == '__':
                    202:            return None
                    203:         d = None
                    204:         try:
                    205:           d = self.identifiers[name]
                    206:           d.update(header, module, type, lineno, info, extra, conditionals)
                    207:        except:
                    208:           d = identifier(name, header, module, type, lineno, info, extra, conditionals)
                    209:           self.identifiers[name] = d
                    210: 
                    211:        if d != None and static == 1:
                    212:            d.set_static(1)
                    213: 
                    214:        if d != None and name != None and type != None:
                    215:            self.references[name] = d
                    216: 
                    217:        if name == debugsym:
                    218:            print "New ref: %s" % (d)
                    219: 
                    220:        return d
                    221: 
                    222:     def add(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
                    223:         if name[0:2] == '__':
                    224:            return None
                    225:         d = None
                    226:         try:
                    227:           d = self.identifiers[name]
                    228:           d.update(header, module, type, lineno, info, extra, conditionals)
                    229:        except:
                    230:           d = identifier(name, header, module, type, lineno, info, extra, conditionals)
                    231:           self.identifiers[name] = d
                    232: 
                    233:        if d != None and static == 1:
                    234:            d.set_static(1)
                    235: 
                    236:        if d != None and name != None and type != None:
                    237:            if type == "function":
                    238:                self.functions[name] = d
                    239:            elif type == "functype":
                    240:                self.functions[name] = d
                    241:            elif type == "variable":
                    242:                self.variables[name] = d
                    243:            elif type == "include":
                    244:                self.includes[name] = d
                    245:            elif type == "struct":
                    246:                self.structs[name] = d
                    247:            elif type == "enum":
                    248:                self.enums[name] = d
                    249:            elif type == "typedef":
                    250:                self.typedefs[name] = d
                    251:            elif type == "macro":
                    252:                self.macros[name] = d
                    253:            else:
                    254:                print "Unable to register type ", type
                    255: 
                    256:        if name == debugsym:
                    257:            print "New symbol: %s" % (d)
                    258: 
                    259:        return d
                    260: 
                    261:     def merge(self, idx):
                    262:         for id in idx.functions.keys():
                    263:               #
                    264:               # macro might be used to override functions or variables
                    265:               # definitions
                    266:               #
                    267:             if self.macros.has_key(id):
                    268:                 del self.macros[id]
                    269:             if self.functions.has_key(id):
                    270:                 print "function %s from %s redeclared in %s" % (
                    271:                    id, self.functions[id].header, idx.functions[id].header)
                    272:             else:
                    273:                 self.functions[id] = idx.functions[id]
                    274:                 self.identifiers[id] = idx.functions[id]
                    275:         for id in idx.variables.keys():
                    276:               #
                    277:               # macro might be used to override functions or variables
                    278:               # definitions
                    279:               #
                    280:             if self.macros.has_key(id):
                    281:                 del self.macros[id]
                    282:             if self.variables.has_key(id):
                    283:                 print "variable %s from %s redeclared in %s" % (
                    284:                    id, self.variables[id].header, idx.variables[id].header)
                    285:             else:
                    286:                 self.variables[id] = idx.variables[id]
                    287:                 self.identifiers[id] = idx.variables[id]
                    288:         for id in idx.structs.keys():
                    289:             if self.structs.has_key(id):
                    290:                 print "struct %s from %s redeclared in %s" % (
                    291:                    id, self.structs[id].header, idx.structs[id].header)
                    292:             else:
                    293:                 self.structs[id] = idx.structs[id]
                    294:                 self.identifiers[id] = idx.structs[id]
                    295:         for id in idx.typedefs.keys():
                    296:             if self.typedefs.has_key(id):
                    297:                 print "typedef %s from %s redeclared in %s" % (
                    298:                    id, self.typedefs[id].header, idx.typedefs[id].header)
                    299:             else:
                    300:                 self.typedefs[id] = idx.typedefs[id]
                    301:                 self.identifiers[id] = idx.typedefs[id]
                    302:         for id in idx.macros.keys():
                    303:               #
                    304:               # macro might be used to override functions or variables
                    305:               # definitions
                    306:               #
                    307:              if self.variables.has_key(id):
                    308:                  continue
                    309:              if self.functions.has_key(id):
                    310:                  continue
                    311:              if self.enums.has_key(id):
                    312:                  continue
                    313:             if self.macros.has_key(id):
                    314:                 print "macro %s from %s redeclared in %s" % (
                    315:                    id, self.macros[id].header, idx.macros[id].header)
                    316:             else:
                    317:                 self.macros[id] = idx.macros[id]
                    318:                 self.identifiers[id] = idx.macros[id]
                    319:         for id in idx.enums.keys():
                    320:             if self.enums.has_key(id):
                    321:                 print "enum %s from %s redeclared in %s" % (
                    322:                    id, self.enums[id].header, idx.enums[id].header)
                    323:             else:
                    324:                 self.enums[id] = idx.enums[id]
                    325:                 self.identifiers[id] = idx.enums[id]
                    326: 
                    327:     def merge_public(self, idx):
                    328:         for id in idx.functions.keys():
                    329:             if self.functions.has_key(id):
                    330:                 # check that function condition agrees with header
                    331:                 if idx.functions[id].conditionals != \
                    332:                    self.functions[id].conditionals:
                    333:                     print "Header condition differs from Function for %s:" \
                    334:                        % id
                    335:                     print "  H: %s" % self.functions[id].conditionals
                    336:                     print "  C: %s" % idx.functions[id].conditionals
                    337:                 up = idx.functions[id]
                    338:                 self.functions[id].update(None, up.module, up.type, up.info, up.extra)
                    339:         #     else:
                    340:         #         print "Function %s from %s is not declared in headers" % (
                    341:         #              id, idx.functions[id].module)
                    342:         # TODO: do the same for variables.
                    343: 
                    344:     def analyze_dict(self, type, dict):
                    345:         count = 0
                    346:        public = 0
                    347:         for name in dict.keys():
                    348:            id = dict[name]
                    349:            count = count + 1
                    350:            if id.static == 0:
                    351:                public = public + 1
                    352:         if count != public:
                    353:            print "  %d %s , %d public" % (count, type, public)
                    354:        elif count != 0:
                    355:            print "  %d public %s" % (count, type)
                    356: 
                    357: 
                    358:     def analyze(self):
                    359:        self.analyze_dict("functions", self.functions)
                    360:        self.analyze_dict("variables", self.variables)
                    361:        self.analyze_dict("structs", self.structs)
                    362:        self.analyze_dict("typedefs", self.typedefs)
                    363:        self.analyze_dict("macros", self.macros)
                    364: 
                    365: class CLexer:
                    366:     """A lexer for the C language, tokenize the input by reading and
                    367:        analyzing it line by line"""
                    368:     def __init__(self, input):
                    369:         self.input = input
                    370:        self.tokens = []
                    371:        self.line = ""
                    372:        self.lineno = 0
                    373: 
                    374:     def getline(self):
                    375:         line = ''
                    376:        while line == '':
                    377:            line = self.input.readline()
                    378:            if not line:
                    379:                return None
                    380:            self.lineno = self.lineno + 1
                    381:            line = string.lstrip(line)
                    382:            line = string.rstrip(line)
                    383:            if line == '':
                    384:                continue
                    385:            while line[-1] == '\\':
                    386:                line = line[:-1]
                    387:                n = self.input.readline()
                    388:                self.lineno = self.lineno + 1
                    389:                n = string.lstrip(n)
                    390:                n = string.rstrip(n)
                    391:                if not n:
                    392:                    break
                    393:                else:
                    394:                    line = line + n
                    395:         return line
                    396: 
                    397:     def getlineno(self):
                    398:         return self.lineno
                    399: 
                    400:     def push(self, token):
                    401:         self.tokens.insert(0, token);
                    402: 
                    403:     def debug(self):
                    404:         print "Last token: ", self.last
                    405:        print "Token queue: ", self.tokens
                    406:        print "Line %d end: " % (self.lineno), self.line
                    407: 
                    408:     def token(self):
                    409:         while self.tokens == []:
                    410:            if self.line == "":
                    411:                line = self.getline()
                    412:            else:
                    413:                line = self.line
                    414:                self.line = ""
                    415:            if line == None:
                    416:                return None
                    417: 
                    418:            if line[0] == '#':
                    419:                self.tokens = map((lambda x: ('preproc', x)),
                    420:                                  string.split(line))
                    421:                break;
                    422:            l = len(line)
                    423:            if line[0] == '"' or line[0] == "'":
                    424:                end = line[0]
                    425:                line = line[1:]
                    426:                found = 0
                    427:                tok = ""
                    428:                while found == 0:
                    429:                    i = 0
                    430:                    l = len(line)
                    431:                    while i < l:
                    432:                        if line[i] == end:
                    433:                            self.line = line[i+1:]
                    434:                            line = line[:i]
                    435:                            l = i
                    436:                            found = 1
                    437:                            break
                    438:                        if line[i] == '\\':
                    439:                            i = i + 1
                    440:                        i = i + 1
                    441:                    tok = tok + line
                    442:                    if found == 0:
                    443:                        line = self.getline()
                    444:                        if line == None:
                    445:                            return None
                    446:                self.last = ('string', tok)
                    447:                return self.last
                    448: 
                    449:            if l >= 2 and line[0] == '/' and line[1] == '*':
                    450:                line = line[2:]
                    451:                found = 0
                    452:                tok = ""
                    453:                while found == 0:
                    454:                    i = 0
                    455:                    l = len(line)
                    456:                    while i < l:
                    457:                        if line[i] == '*' and i+1 < l and line[i+1] == '/':
                    458:                            self.line = line[i+2:]
                    459:                            line = line[:i-1]
                    460:                            l = i
                    461:                            found = 1
                    462:                            break
                    463:                        i = i + 1
                    464:                    if tok != "":
                    465:                        tok = tok + "\n"
                    466:                    tok = tok + line
                    467:                    if found == 0:
                    468:                        line = self.getline()
                    469:                        if line == None:
                    470:                            return None
                    471:                self.last = ('comment', tok)
                    472:                return self.last
                    473:            if l >= 2 and line[0] == '/' and line[1] == '/':
                    474:                line = line[2:]
                    475:                self.last = ('comment', line)
                    476:                return self.last
                    477:            i = 0
                    478:            while i < l:
                    479:                if line[i] == '/' and i+1 < l and line[i+1] == '/':
                    480:                    self.line = line[i:]
                    481:                    line = line[:i]
                    482:                    break
                    483:                if line[i] == '/' and i+1 < l and line[i+1] == '*':
                    484:                    self.line = line[i:]
                    485:                    line = line[:i]
                    486:                    break
                    487:                if line[i] == '"' or line[i] == "'":
                    488:                    self.line = line[i:]
                    489:                    line = line[:i]
                    490:                    break
                    491:                i = i + 1
                    492:            l = len(line)
                    493:            i = 0
                    494:            while i < l:
                    495:                if line[i] == ' ' or line[i] == '\t':
                    496:                    i = i + 1
                    497:                    continue
                    498:                o = ord(line[i])
                    499:                if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
                    500:                   (o >= 48 and o <= 57):
                    501:                    s = i
                    502:                    while i < l:
                    503:                        o = ord(line[i])
                    504:                        if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
                    505:                           (o >= 48 and o <= 57) or string.find(
                    506:                               " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1:
                    507:                            i = i + 1
                    508:                        else:
                    509:                            break
                    510:                    self.tokens.append(('name', line[s:i]))
                    511:                    continue
                    512:                if string.find("(){}:;,[]", line[i]) != -1:
                    513: #                 if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
                    514: #                  line[i] == '}' or line[i] == ':' or line[i] == ';' or \
                    515: #                  line[i] == ',' or line[i] == '[' or line[i] == ']':
                    516:                    self.tokens.append(('sep', line[i]))
                    517:                    i = i + 1
                    518:                    continue
                    519:                if string.find("+-*><=/%&!|.", line[i]) != -1:
                    520: #                 if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
                    521: #                  line[i] == '>' or line[i] == '<' or line[i] == '=' or \
                    522: #                  line[i] == '/' or line[i] == '%' or line[i] == '&' or \
                    523: #                  line[i] == '!' or line[i] == '|' or line[i] == '.':
                    524:                    if line[i] == '.' and  i + 2 < l and \
                    525:                       line[i+1] == '.' and line[i+2] == '.':
                    526:                        self.tokens.append(('name', '...'))
                    527:                        i = i + 3
                    528:                        continue
                    529: 
                    530:                    j = i + 1
                    531:                    if j < l and (
                    532:                       string.find("+-*><=/%&!|", line[j]) != -1):
                    533: #                      line[j] == '+' or line[j] == '-' or line[j] == '*' or \
                    534: #                      line[j] == '>' or line[j] == '<' or line[j] == '=' or \
                    535: #                      line[j] == '/' or line[j] == '%' or line[j] == '&' or \
                    536: #                      line[j] == '!' or line[j] == '|'):
                    537:                        self.tokens.append(('op', line[i:j+1]))
                    538:                        i = j + 1
                    539:                    else:
                    540:                        self.tokens.append(('op', line[i]))
                    541:                        i = i + 1
                    542:                    continue
                    543:                s = i
                    544:                while i < l:
                    545:                    o = ord(line[i])
                    546:                    if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
                    547:                       (o >= 48 and o <= 57) or (
                    548:                        string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1):
                    549: #                       line[i] != ' ' and line[i] != '\t' and
                    550: #                       line[i] != '(' and line[i] != ')' and
                    551: #                       line[i] != '{'  and line[i] != '}' and
                    552: #                       line[i] != ':' and line[i] != ';' and
                    553: #                       line[i] != ',' and line[i] != '+' and
                    554: #                       line[i] != '-' and line[i] != '*' and
                    555: #                       line[i] != '/' and line[i] != '%' and
                    556: #                       line[i] != '&' and line[i] != '!' and
                    557: #                       line[i] != '|' and line[i] != '[' and
                    558: #                       line[i] != ']' and line[i] != '=' and
                    559: #                       line[i] != '*' and line[i] != '>' and
                    560: #                       line[i] != '<'):
                    561:                        i = i + 1
                    562:                    else:
                    563:                        break
                    564:                self.tokens.append(('name', line[s:i]))
                    565: 
                    566:        tok = self.tokens[0]
                    567:        self.tokens = self.tokens[1:]
                    568:        self.last = tok
                    569:        return tok
                    570: 
                    571: class CParser:
                    572:     """The C module parser"""
                    573:     def __init__(self, filename, idx = None):
                    574:         self.filename = filename
                    575:        if len(filename) > 2 and filename[-2:] == '.h':
                    576:            self.is_header = 1
                    577:        else:
                    578:            self.is_header = 0
                    579:         self.input = open(filename)
                    580:        self.lexer = CLexer(self.input)
                    581:        if idx == None:
                    582:            self.index = index()
                    583:        else:
                    584:            self.index = idx
                    585:        self.top_comment = ""
                    586:        self.last_comment = ""
                    587:        self.comment = None
                    588:        self.collect_ref = 0
                    589:        self.no_error = 0
                    590:        self.conditionals = []
                    591:        self.defines = []
                    592: 
                    593:     def collect_references(self):
                    594:         self.collect_ref = 1
                    595: 
                    596:     def stop_error(self):
                    597:         self.no_error = 1
                    598: 
                    599:     def start_error(self):
                    600:         self.no_error = 0
                    601: 
                    602:     def lineno(self):
                    603:         return self.lexer.getlineno()
                    604: 
                    605:     def index_add(self, name, module, static, type, info=None, extra = None):
                    606:        if self.is_header == 1:
                    607:            self.index.add(name, module, module, static, type, self.lineno(),
                    608:                           info, extra, self.conditionals)
                    609:        else:
                    610:            self.index.add(name, None, module, static, type, self.lineno(),
                    611:                           info, extra, self.conditionals)
                    612: 
                    613:     def index_add_ref(self, name, module, static, type, info=None,
                    614:                       extra = None):
                    615:        if self.is_header == 1:
                    616:            self.index.add_ref(name, module, module, static, type,
                    617:                               self.lineno(), info, extra, self.conditionals)
                    618:        else:
                    619:            self.index.add_ref(name, None, module, static, type, self.lineno(),
                    620:                               info, extra, self.conditionals)
                    621: 
                    622:     def warning(self, msg):
                    623:         if self.no_error:
                    624:            return
                    625:        print msg
                    626: 
                    627:     def error(self, msg, token=-1):
                    628:         if self.no_error:
                    629:            return
                    630: 
                    631:         print "Parse Error: " + msg
                    632:        if token != -1:
                    633:            print "Got token ", token
                    634:        self.lexer.debug()
                    635:        sys.exit(1)
                    636: 
                    637:     def debug(self, msg, token=-1):
                    638:         print "Debug: " + msg
                    639:        if token != -1:
                    640:            print "Got token ", token
                    641:        self.lexer.debug()
                    642: 
                    643:     def parseTopComment(self, comment):
                    644:        res = {}
                    645:        lines = string.split(comment, "\n")
                    646:        item = None
                    647:        for line in lines:
                    648:            while line != "" and (line[0] == ' ' or line[0] == '\t'):
                    649:                line = line[1:]
                    650:            while line != "" and line[0] == '*':
                    651:                line = line[1:]
                    652:            while line != "" and (line[0] == ' ' or line[0] == '\t'):
                    653:                line = line[1:]
                    654:            try:
                    655:                (it, line) = string.split(line, ":", 1)
                    656:                item = it
                    657:                while line != "" and (line[0] == ' ' or line[0] == '\t'):
                    658:                    line = line[1:]
                    659:                if res.has_key(item):
                    660:                    res[item] = res[item] + " " + line
                    661:                else:
                    662:                    res[item] = line
                    663:            except:
                    664:                if item != None:
                    665:                    if res.has_key(item):
                    666:                        res[item] = res[item] + " " + line
                    667:                    else:
                    668:                        res[item] = line
                    669:        self.index.info = res
                    670: 
                    671:     def parseComment(self, token):
                    672:         if self.top_comment == "":
                    673:            self.top_comment = token[1]
                    674:        if self.comment == None or token[1][0] == '*':
                    675:            self.comment = token[1];
                    676:        else:
                    677:            self.comment = self.comment + token[1]
                    678:        token = self.lexer.token()
                    679: 
                    680:         if string.find(self.comment, "DOC_DISABLE") != -1:
                    681:            self.stop_error()
                    682: 
                    683:         if string.find(self.comment, "DOC_ENABLE") != -1:
                    684:            self.start_error()
                    685: 
                    686:        return token
                    687: 
                    688:     #
                    689:     # Parse a comment block associate to a typedef
                    690:     #
                    691:     def parseTypeComment(self, name, quiet = 0):
                    692:         if name[0:2] == '__':
                    693:            quiet = 1
                    694: 
                    695:         args = []
                    696:        desc = ""
                    697: 
                    698:         if self.comment == None:
                    699:            if not quiet:
                    700:                self.warning("Missing comment for type %s" % (name))
                    701:            return((args, desc))
                    702:         if self.comment[0] != '*':
                    703:            if not quiet:
                    704:                self.warning("Missing * in type comment for %s" % (name))
                    705:            return((args, desc))
                    706:        lines = string.split(self.comment, '\n')
                    707:        if lines[0] == '*':
                    708:            del lines[0]
                    709:        if lines[0] != "* %s:" % (name):
                    710:            if not quiet:
                    711:                self.warning("Misformatted type comment for %s" % (name))
                    712:                self.warning("  Expecting '* %s:' got '%s'" % (name, lines[0]))
                    713:            return((args, desc))
                    714:        del lines[0]
                    715:        while len(lines) > 0 and lines[0] == '*':
                    716:            del lines[0]
                    717:        desc = ""
                    718:        while len(lines) > 0:
                    719:            l = lines[0]
                    720:            while len(l) > 0 and l[0] == '*':
                    721:                l = l[1:]
                    722:            l = string.strip(l)
                    723:            desc = desc + " " + l
                    724:            del lines[0]
                    725: 
                    726:        desc = string.strip(desc)
                    727: 
                    728:        if quiet == 0:
                    729:            if desc == "":
                    730:                self.warning("Type comment for %s lack description of the macro" % (name))
                    731: 
                    732:        return(desc)
                    733:     #
                    734:     # Parse a comment block associate to a macro
                    735:     #
                    736:     def parseMacroComment(self, name, quiet = 0):
                    737:         if name[0:2] == '__':
                    738:            quiet = 1
                    739: 
                    740:         args = []
                    741:        desc = ""
                    742: 
                    743:         if self.comment == None:
                    744:            if not quiet:
                    745:                self.warning("Missing comment for macro %s" % (name))
                    746:            return((args, desc))
                    747:         if self.comment[0] != '*':
                    748:            if not quiet:
                    749:                self.warning("Missing * in macro comment for %s" % (name))
                    750:            return((args, desc))
                    751:        lines = string.split(self.comment, '\n')
                    752:        if lines[0] == '*':
                    753:            del lines[0]
                    754:        if lines[0] != "* %s:" % (name):
                    755:            if not quiet:
                    756:                self.warning("Misformatted macro comment for %s" % (name))
                    757:                self.warning("  Expecting '* %s:' got '%s'" % (name, lines[0]))
                    758:            return((args, desc))
                    759:        del lines[0]
                    760:        while lines[0] == '*':
                    761:            del lines[0]
                    762:        while len(lines) > 0 and lines[0][0:3] == '* @':
                    763:            l = lines[0][3:]
                    764:            try:
                    765:                (arg, desc) = string.split(l, ':', 1)
                    766:                desc=string.strip(desc)
                    767:                arg=string.strip(arg)
                    768:             except:
                    769:                if not quiet:
                    770:                    self.warning("Misformatted macro comment for %s" % (name))
                    771:                    self.warning("  problem with '%s'" % (lines[0]))
                    772:                del lines[0]
                    773:                continue
                    774:            del lines[0]
                    775:            l = string.strip(lines[0])
                    776:            while len(l) > 2 and l[0:3] != '* @':
                    777:                while l[0] == '*':
                    778:                    l = l[1:]
                    779:                desc = desc + ' ' + string.strip(l)
                    780:                del lines[0]
                    781:                if len(lines) == 0:
                    782:                    break
                    783:                l = lines[0]
                    784:             args.append((arg, desc))
                    785:        while len(lines) > 0 and lines[0] == '*':
                    786:            del lines[0]
                    787:        desc = ""
                    788:        while len(lines) > 0:
                    789:            l = lines[0]
                    790:            while len(l) > 0 and l[0] == '*':
                    791:                l = l[1:]
                    792:            l = string.strip(l)
                    793:            desc = desc + " " + l
                    794:            del lines[0]
                    795: 
                    796:        desc = string.strip(desc)
                    797: 
                    798:        if quiet == 0:
                    799:            if desc == "":
                    800:                self.warning("Macro comment for %s lack description of the macro" % (name))
                    801: 
                    802:        return((args, desc))
                    803: 
                    804:      #
                    805:      # Parse a comment block and merge the informations found in the
                    806:      # parameters descriptions, finally returns a block as complete
                    807:      # as possible
                    808:      #
                    809:     def mergeFunctionComment(self, name, description, quiet = 0):
                    810:         if name == 'main':
                    811:            quiet = 1
                    812:         if name[0:2] == '__':
                    813:            quiet = 1
                    814: 
                    815:        (ret, args) = description
                    816:        desc = ""
                    817:        retdesc = ""
                    818: 
                    819:         if self.comment == None:
                    820:            if not quiet:
                    821:                self.warning("Missing comment for function %s" % (name))
                    822:            return(((ret[0], retdesc), args, desc))
                    823:         if self.comment[0] != '*':
                    824:            if not quiet:
                    825:                self.warning("Missing * in function comment for %s" % (name))
                    826:            return(((ret[0], retdesc), args, desc))
                    827:        lines = string.split(self.comment, '\n')
                    828:        if lines[0] == '*':
                    829:            del lines[0]
                    830:        if lines[0] != "* %s:" % (name):
                    831:            if not quiet:
                    832:                self.warning("Misformatted function comment for %s" % (name))
                    833:                self.warning("  Expecting '* %s:' got '%s'" % (name, lines[0]))
                    834:            return(((ret[0], retdesc), args, desc))
                    835:        del lines[0]
                    836:        while lines[0] == '*':
                    837:            del lines[0]
                    838:        nbargs = len(args)
                    839:        while len(lines) > 0 and lines[0][0:3] == '* @':
                    840:            l = lines[0][3:]
                    841:            try:
                    842:                (arg, desc) = string.split(l, ':', 1)
                    843:                desc=string.strip(desc)
                    844:                arg=string.strip(arg)
                    845:             except:
                    846:                if not quiet:
                    847:                    self.warning("Misformatted function comment for %s" % (name))
                    848:                    self.warning("  problem with '%s'" % (lines[0]))
                    849:                del lines[0]
                    850:                continue
                    851:            del lines[0]
                    852:            l = string.strip(lines[0])
                    853:            while len(l) > 2 and l[0:3] != '* @':
                    854:                while l[0] == '*':
                    855:                    l = l[1:]
                    856:                desc = desc + ' ' + string.strip(l)
                    857:                del lines[0]
                    858:                if len(lines) == 0:
                    859:                    break
                    860:                l = lines[0]
                    861:            i = 0
                    862:            while i < nbargs:
                    863:                if args[i][1] == arg:
                    864:                    args[i] = (args[i][0], arg, desc)
                    865:                    break;
                    866:                i = i + 1
                    867:            if i >= nbargs:
                    868:                if not quiet:
                    869:                    self.warning("Unable to find arg %s from function comment for %s" % (
                    870:                       arg, name))
                    871:        while len(lines) > 0 and lines[0] == '*':
                    872:            del lines[0]
                    873:        desc = ""
                    874:        while len(lines) > 0:
                    875:            l = lines[0]
                    876:            while len(l) > 0 and l[0] == '*':
                    877:                l = l[1:]
                    878:            l = string.strip(l)
                    879:            if len(l) >= 6 and  l[0:6] == "return" or l[0:6] == "Return":
                    880:                try:
                    881:                    l = string.split(l, ' ', 1)[1]
                    882:                except:
                    883:                    l = ""
                    884:                retdesc = string.strip(l)
                    885:                del lines[0]
                    886:                while len(lines) > 0:
                    887:                    l = lines[0]
                    888:                    while len(l) > 0 and l[0] == '*':
                    889:                        l = l[1:]
                    890:                    l = string.strip(l)
                    891:                    retdesc = retdesc + " " + l
                    892:                    del lines[0]
                    893:            else:
                    894:                desc = desc + " " + l
                    895:                del lines[0]
                    896: 
                    897:        retdesc = string.strip(retdesc)
                    898:        desc = string.strip(desc)
                    899: 
                    900:        if quiet == 0:
                    901:             #
                    902:             # report missing comments
                    903:             #
                    904:            i = 0
                    905:            while i < nbargs:
                    906:                if args[i][2] == None and args[i][0] != "void" and \
                    907:                   ((args[i][1] != None) or (args[i][1] == '')):
                    908:                    self.warning("Function comment for %s lacks description of arg %s" % (name, args[i][1]))
                    909:                i = i + 1
                    910:            if retdesc == "" and ret[0] != "void":
                    911:                self.warning("Function comment for %s lacks description of return value" % (name))
                    912:            if desc == "":
                    913:                self.warning("Function comment for %s lacks description of the function" % (name))
                    914: 
                    915:        return(((ret[0], retdesc), args, desc))
                    916: 
                    917:     def parsePreproc(self, token):
                    918:        if debug:
                    919:            print "=> preproc ", token, self.lexer.tokens
                    920:         name = token[1]
                    921:        if name == "#include":
                    922:            token = self.lexer.token()
                    923:            if token == None:
                    924:                return None
                    925:            if token[0] == 'preproc':
                    926:                self.index_add(token[1], self.filename, not self.is_header,
                    927:                                "include")
                    928:                return self.lexer.token()
                    929:            return token
                    930:        if name == "#define":
                    931:            token = self.lexer.token()
                    932:            if token == None:
                    933:                return None
                    934:            if token[0] == 'preproc':
                    935:                 # TODO macros with arguments
                    936:                name = token[1]
                    937:                lst = []
                    938:                token = self.lexer.token()
                    939:                while token != None and token[0] == 'preproc' and \
                    940:                      token[1][0] != '#':
                    941:                    lst.append(token[1])
                    942:                    token = self.lexer.token()
                    943:                 try:
                    944:                    name = string.split(name, '(') [0]
                    945:                 except:
                    946:                     pass
                    947:                 info = self.parseMacroComment(name, not self.is_header)
                    948:                self.index_add(name, self.filename, not self.is_header,
                    949:                                "macro", info)
                    950:                return token
                    951: 
                    952:        #
                    953:        # Processing of conditionals modified by Bill 1/1/05
                    954:        #
                    955:        # We process conditionals (i.e. tokens from #ifdef, #ifndef,
                    956:        # #if, #else and #endif) for headers and mainline code,
                    957:        # store the ones from the header in libxml2-api.xml, and later
                    958:        # (in the routine merge_public) verify that the two (header and
                    959:        # mainline code) agree.
                    960:        #
                    961:        # There is a small problem with processing the headers. Some of
                    962:        # the variables are not concerned with enabling / disabling of
                    963:        # library functions (e.g. '__XML_PARSER_H__'), and we don't want
                    964:        # them to be included in libxml2-api.xml, or involved in
                    965:        # the check between the header and the mainline code.  To
                    966:        # accomplish this, we ignore any conditional which doesn't include
                    967:        # the string 'ENABLED'
                    968:        #
                    969:        if name == "#ifdef":
                    970:            apstr = self.lexer.tokens[0][1]
                    971:            try:
                    972:                self.defines.append(apstr)
                    973:                if string.find(apstr, 'ENABLED') != -1:
                    974:                    self.conditionals.append("defined(%s)" % apstr)
                    975:            except:
                    976:                pass
                    977:        elif name == "#ifndef":
                    978:            apstr = self.lexer.tokens[0][1]
                    979:            try:
                    980:                self.defines.append(apstr)
                    981:                if string.find(apstr, 'ENABLED') != -1:
                    982:                    self.conditionals.append("!defined(%s)" % apstr)
                    983:            except:
                    984:                pass
                    985:        elif name == "#if":
                    986:            apstr = ""
                    987:            for tok in self.lexer.tokens:
                    988:                if apstr != "":
                    989:                    apstr = apstr + " "
                    990:                apstr = apstr + tok[1]
                    991:            try:
                    992:                self.defines.append(apstr)
                    993:                if string.find(apstr, 'ENABLED') != -1:
                    994:                    self.conditionals.append(apstr)
                    995:            except:
                    996:                pass
                    997:        elif name == "#else":
                    998:            if self.conditionals != [] and \
                    999:               string.find(self.defines[-1], 'ENABLED') != -1:
                   1000:                self.conditionals[-1] = "!(%s)" % self.conditionals[-1]
                   1001:        elif name == "#endif":
                   1002:            if self.conditionals != [] and \
                   1003:               string.find(self.defines[-1], 'ENABLED') != -1:
                   1004:                self.conditionals = self.conditionals[:-1]
                   1005:            self.defines = self.defines[:-1]
                   1006:        token = self.lexer.token()
                   1007:        while token != None and token[0] == 'preproc' and \
                   1008:            token[1][0] != '#':
                   1009:            token = self.lexer.token()
                   1010:        return token
                   1011: 
                   1012:      #
                   1013:      # token acquisition on top of the lexer, it handle internally
                   1014:      # preprocessor and comments since they are logically not part of
                   1015:      # the program structure.
                   1016:      #
                   1017:     def token(self):
                   1018:         global ignored_words
                   1019: 
                   1020:         token = self.lexer.token()
                   1021:        while token != None:
                   1022:            if token[0] == 'comment':
                   1023:                token = self.parseComment(token)
                   1024:                continue
                   1025:            elif token[0] == 'preproc':
                   1026:                token = self.parsePreproc(token)
                   1027:                continue
                   1028:            elif token[0] == "name" and token[1] == "__const":
                   1029:                token = ("name", "const")
                   1030:                return token
                   1031:            elif token[0] == "name" and token[1] == "__attribute":
                   1032:                token = self.lexer.token()
                   1033:                while token != None and token[1] != ";":
                   1034:                    token = self.lexer.token()
                   1035:                return token
                   1036:            elif token[0] == "name" and ignored_words.has_key(token[1]):
                   1037:                (n, info) = ignored_words[token[1]]
                   1038:                i = 0
                   1039:                while i < n:
                   1040:                    token = self.lexer.token()
                   1041:                    i = i + 1
                   1042:                token = self.lexer.token()
                   1043:                continue
                   1044:            else:
                   1045:                if debug:
                   1046:                    print "=> ", token
                   1047:                return token
                   1048:        return None
                   1049: 
                   1050:      #
                   1051:      # Parse a typedef, it records the type and its name.
                   1052:      #
                   1053:     def parseTypedef(self, token):
                   1054:         if token == None:
                   1055:            return None
                   1056:        token = self.parseType(token)
                   1057:        if token == None:
                   1058:            self.error("parsing typedef")
                   1059:            return None
                   1060:        base_type = self.type
                   1061:        type = base_type
                   1062:         #self.debug("end typedef type", token)
                   1063:        while token != None:
                   1064:            if token[0] == "name":
                   1065:                name = token[1]
                   1066:                signature = self.signature
                   1067:                if signature != None:
                   1068:                    type = string.split(type, '(')[0]
                   1069:                    d = self.mergeFunctionComment(name,
                   1070:                            ((type, None), signature), 1)
                   1071:                    self.index_add(name, self.filename, not self.is_header,
                   1072:                                    "functype", d)
                   1073:                else:
                   1074:                    if base_type == "struct":
                   1075:                        self.index_add(name, self.filename, not self.is_header,
                   1076:                                        "struct", type)
                   1077:                        base_type = "struct " + name
                   1078:                    else:
                   1079:                        # TODO report missing or misformatted comments
                   1080:                        info = self.parseTypeComment(name, 1)
                   1081:                        self.index_add(name, self.filename, not self.is_header,
                   1082:                                    "typedef", type, info)
                   1083:                token = self.token()
                   1084:            else:
                   1085:                self.error("parsing typedef: expecting a name")
                   1086:                return token
                   1087:             #self.debug("end typedef", token)
                   1088:            if token != None and token[0] == 'sep' and token[1] == ',':
                   1089:                type = base_type
                   1090:                token = self.token()
                   1091:                while token != None and token[0] == "op":
                   1092:                    type = type + token[1]
                   1093:                    token = self.token()
                   1094:            elif token != None and token[0] == 'sep' and token[1] == ';':
                   1095:                break;
                   1096:            elif token != None and token[0] == 'name':
                   1097:                type = base_type
                   1098:                continue;
                   1099:            else:
                   1100:                self.error("parsing typedef: expecting ';'", token)
                   1101:                return token
                   1102:        token = self.token()
                   1103:        return token
                   1104: 
                   1105:      #
                   1106:      # Parse a C code block, used for functions it parse till
                   1107:      # the balancing } included
                   1108:      #
                   1109:     def parseBlock(self, token):
                   1110:         while token != None:
                   1111:            if token[0] == "sep" and token[1] == "{":
                   1112:                token = self.token()
                   1113:                token = self.parseBlock(token)
                   1114:            elif token[0] == "sep" and token[1] == "}":
                   1115:                self.comment = None
                   1116:                token = self.token()
                   1117:                return token
                   1118:            else:
                   1119:                if self.collect_ref == 1:
                   1120:                    oldtok = token
                   1121:                    token = self.token()
                   1122:                    if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
                   1123:                        if token[0] == "sep" and token[1] == "(":
                   1124:                            self.index_add_ref(oldtok[1], self.filename,
                   1125:                                                0, "function")
                   1126:                            token = self.token()
                   1127:                        elif token[0] == "name":
                   1128:                            token = self.token()
                   1129:                            if token[0] == "sep" and (token[1] == ";" or
                   1130:                               token[1] == "," or token[1] == "="):
                   1131:                                self.index_add_ref(oldtok[1], self.filename,
                   1132:                                                    0, "type")
                   1133:                    elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
                   1134:                        self.index_add_ref(oldtok[1], self.filename,
                   1135:                                            0, "typedef")
                   1136:                    elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
                   1137:                        self.index_add_ref(oldtok[1], self.filename,
                   1138:                                            0, "typedef")
                   1139: 
                   1140:                else:
                   1141:                    token = self.token()
                   1142:        return token
                   1143: 
                   1144:      #
                   1145:      # Parse a C struct definition till the balancing }
                   1146:      #
                   1147:     def parseStruct(self, token):
                   1148:         fields = []
                   1149:         #self.debug("start parseStruct", token)
                   1150:         while token != None:
                   1151:            if token[0] == "sep" and token[1] == "{":
                   1152:                token = self.token()
                   1153:                token = self.parseTypeBlock(token)
                   1154:            elif token[0] == "sep" and token[1] == "}":
                   1155:                self.struct_fields = fields
                   1156:                 #self.debug("end parseStruct", token)
                   1157:                 #print fields
                   1158:                token = self.token()
                   1159:                return token
                   1160:            else:
                   1161:                base_type = self.type
                   1162:                 #self.debug("before parseType", token)
                   1163:                token = self.parseType(token)
                   1164:                 #self.debug("after parseType", token)
                   1165:                if token != None and token[0] == "name":
                   1166:                    fname = token[1]
                   1167:                    token = self.token()
                   1168:                    if token[0] == "sep" and token[1] == ";":
                   1169:                        self.comment = None
                   1170:                        token = self.token()
                   1171:                        fields.append((self.type, fname, self.comment))
                   1172:                        self.comment = None
                   1173:                    else:
                   1174:                        self.error("parseStruct: expecting ;", token)
                   1175:                elif token != None and token[0] == "sep" and token[1] == "{":
                   1176:                    token = self.token()
                   1177:                    token = self.parseTypeBlock(token)
                   1178:                    if token != None and token[0] == "name":
                   1179:                        token = self.token()
                   1180:                    if token != None and token[0] == "sep" and token[1] == ";":
                   1181:                        token = self.token()
                   1182:                    else:
                   1183:                        self.error("parseStruct: expecting ;", token)
                   1184:                else:
                   1185:                    self.error("parseStruct: name", token)
                   1186:                    token = self.token()
                   1187:                self.type = base_type;
                   1188:         self.struct_fields = fields
                   1189:         #self.debug("end parseStruct", token)
                   1190:         #print fields
                   1191:        return token
                   1192: 
                   1193:      #
                   1194:      # Parse a C enum block, parse till the balancing }
                   1195:      #
                   1196:     def parseEnumBlock(self, token):
                   1197:         self.enums = []
                   1198:        name = None
                   1199:        self.comment = None
                   1200:        comment = ""
                   1201:        value = "0"
                   1202:         while token != None:
                   1203:            if token[0] == "sep" and token[1] == "{":
                   1204:                token = self.token()
                   1205:                token = self.parseTypeBlock(token)
                   1206:            elif token[0] == "sep" and token[1] == "}":
                   1207:                if name != None:
                   1208:                    if self.comment != None:
                   1209:                        comment = self.comment
                   1210:                        self.comment = None
                   1211:                    self.enums.append((name, value, comment))
                   1212:                token = self.token()
                   1213:                return token
                   1214:            elif token[0] == "name":
                   1215:                    if name != None:
                   1216:                        if self.comment != None:
                   1217:                            comment = string.strip(self.comment)
                   1218:                            self.comment = None
                   1219:                        self.enums.append((name, value, comment))
                   1220:                    name = token[1]
                   1221:                    comment = ""
                   1222:                    token = self.token()
                   1223:                    if token[0] == "op" and token[1][0] == "=":
                   1224:                        value = ""
                   1225:                        if len(token[1]) > 1:
                   1226:                            value = token[1][1:]
                   1227:                        token = self.token()
                   1228:                        while token[0] != "sep" or (token[1] != ',' and
                   1229:                              token[1] != '}'):
                   1230:                            value = value + token[1]
                   1231:                            token = self.token()
                   1232:                    else:
                   1233:                        try:
                   1234:                            value = "%d" % (int(value) + 1)
                   1235:                        except:
                   1236:                            self.warning("Failed to compute value of enum %s" % (name))
                   1237:                            value=""
                   1238:                    if token[0] == "sep" and token[1] == ",":
                   1239:                        token = self.token()
                   1240:            else:
                   1241:                token = self.token()
                   1242:        return token
                   1243: 
                   1244:      #
                   1245:      # Parse a C definition block, used for structs it parse till
                   1246:      # the balancing }
                   1247:      #
                   1248:     def parseTypeBlock(self, token):
                   1249:         while token != None:
                   1250:            if token[0] == "sep" and token[1] == "{":
                   1251:                token = self.token()
                   1252:                token = self.parseTypeBlock(token)
                   1253:            elif token[0] == "sep" and token[1] == "}":
                   1254:                token = self.token()
                   1255:                return token
                   1256:            else:
                   1257:                token = self.token()
                   1258:        return token
                   1259: 
                   1260:      #
                   1261:      # Parse a type: the fact that the type name can either occur after
                   1262:      #    the definition or within the definition makes it a little harder
                   1263:      #    if inside, the name token is pushed back before returning
                   1264:      #
                   1265:     def parseType(self, token):
                   1266:         self.type = ""
                   1267:        self.struct_fields = []
                   1268:         self.signature = None
                   1269:        if token == None:
                   1270:            return token
                   1271: 
                   1272:        while token[0] == "name" and (
                   1273:              token[1] == "const" or \
                   1274:              token[1] == "unsigned" or \
                   1275:              token[1] == "signed"):
                   1276:            if self.type == "":
                   1277:                self.type = token[1]
                   1278:            else:
                   1279:                self.type = self.type + " " + token[1]
                   1280:            token = self.token()
                   1281: 
                   1282:         if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
                   1283:            if self.type == "":
                   1284:                self.type = token[1]
                   1285:            else:
                   1286:                self.type = self.type + " " + token[1]
                   1287:            if token[0] == "name" and token[1] == "int":
                   1288:                if self.type == "":
                   1289:                    self.type = tmp[1]
                   1290:                else:
                   1291:                    self.type = self.type + " " + tmp[1]
                   1292: 
                   1293:         elif token[0] == "name" and token[1] == "struct":
                   1294:            if self.type == "":
                   1295:                self.type = token[1]
                   1296:            else:
                   1297:                self.type = self.type + " " + token[1]
                   1298:            token = self.token()
                   1299:            nametok = None
                   1300:            if token[0] == "name":
                   1301:                nametok = token
                   1302:                token = self.token()
                   1303:            if token != None and token[0] == "sep" and token[1] == "{":
                   1304:                token = self.token()
                   1305:                token = self.parseStruct(token)
                   1306:            elif token != None and token[0] == "op" and token[1] == "*":
                   1307:                self.type = self.type + " " + nametok[1] + " *"
                   1308:                token = self.token()
                   1309:                while token != None and token[0] == "op" and token[1] == "*":
                   1310:                    self.type = self.type + " *"
                   1311:                    token = self.token()
                   1312:                if token[0] == "name":
                   1313:                    nametok = token
                   1314:                    token = self.token()
                   1315:                else:
                   1316:                    self.error("struct : expecting name", token)
                   1317:                    return token
                   1318:            elif token != None and token[0] == "name" and nametok != None:
                   1319:                self.type = self.type + " " + nametok[1]
                   1320:                return token
                   1321: 
                   1322:            if nametok != None:
                   1323:                self.lexer.push(token)
                   1324:                token = nametok
                   1325:            return token
                   1326: 
                   1327:         elif token[0] == "name" and token[1] == "enum":
                   1328:            if self.type == "":
                   1329:                self.type = token[1]
                   1330:            else:
                   1331:                self.type = self.type + " " + token[1]
                   1332:            self.enums = []
                   1333:            token = self.token()
                   1334:            if token != None and token[0] == "sep" and token[1] == "{":
                   1335:                token = self.token()
                   1336:                token = self.parseEnumBlock(token)
                   1337:            else:
                   1338:                self.error("parsing enum: expecting '{'", token)
                   1339:            enum_type = None
                   1340:            if token != None and token[0] != "name":
                   1341:                self.lexer.push(token)
                   1342:                token = ("name", "enum")
                   1343:            else:
                   1344:                enum_type = token[1]
                   1345:            for enum in self.enums:
                   1346:                self.index_add(enum[0], self.filename,
                   1347:                               not self.is_header, "enum",
                   1348:                               (enum[1], enum[2], enum_type))
                   1349:            return token
                   1350: 
                   1351:        elif token[0] == "name":
                   1352:            if self.type == "":
                   1353:                self.type = token[1]
                   1354:            else:
                   1355:                self.type = self.type + " " + token[1]
                   1356:        else:
                   1357:            self.error("parsing type %s: expecting a name" % (self.type),
                   1358:                       token)
                   1359:            return token
                   1360:        token = self.token()
                   1361:         while token != None and (token[0] == "op" or
                   1362:              token[0] == "name" and token[1] == "const"):
                   1363:            self.type = self.type + " " + token[1]
                   1364:            token = self.token()
                   1365: 
                   1366:         #
                   1367:         # if there is a parenthesis here, this means a function type
                   1368:         #
                   1369:        if token != None and token[0] == "sep" and token[1] == '(':
                   1370:            self.type = self.type + token[1]
                   1371:            token = self.token()
                   1372:            while token != None and token[0] == "op" and token[1] == '*':
                   1373:                self.type = self.type + token[1]
                   1374:                token = self.token()
                   1375:            if token == None or token[0] != "name" :
                   1376:                self.error("parsing function type, name expected", token);
                   1377:                return token
                   1378:            self.type = self.type + token[1]
                   1379:            nametok = token
                   1380:            token = self.token()
                   1381:            if token != None and token[0] == "sep" and token[1] == ')':
                   1382:                self.type = self.type + token[1]
                   1383:                token = self.token()
                   1384:                if token != None and token[0] == "sep" and token[1] == '(':
                   1385:                    token = self.token()
                   1386:                    type = self.type;
                   1387:                    token = self.parseSignature(token);
                   1388:                    self.type = type;
                   1389:                else:
                   1390:                    self.error("parsing function type, '(' expected", token);
                   1391:                    return token
                   1392:            else:
                   1393:                self.error("parsing function type, ')' expected", token);
                   1394:                return token
                   1395:            self.lexer.push(token)
                   1396:            token = nametok
                   1397:            return token
                   1398: 
                   1399:          #
                   1400:         # do some lookahead for arrays
                   1401:         #
                   1402:        if token != None and token[0] == "name":
                   1403:            nametok = token
                   1404:            token = self.token()
                   1405:            if token != None and token[0] == "sep" and token[1] == '[':
                   1406:                self.type = self.type + nametok[1]
                   1407:                while token != None and token[0] == "sep" and token[1] == '[':
                   1408:                    self.type = self.type + token[1]
                   1409:                    token = self.token()
                   1410:                    while token != None and token[0] != 'sep' and \
                   1411:                          token[1] != ']' and token[1] != ';':
                   1412:                        self.type = self.type + token[1]
                   1413:                        token = self.token()
                   1414:                if token != None and token[0] == 'sep' and token[1] == ']':
                   1415:                    self.type = self.type + token[1]
                   1416:                    token = self.token()
                   1417:                else:
                   1418:                    self.error("parsing array type, ']' expected", token);
                   1419:                    return token
                   1420:            elif token != None and token[0] == "sep" and token[1] == ':':
                   1421:                 # remove :12 in case it's a limited int size
                   1422:                token = self.token()
                   1423:                token = self.token()
                   1424:            self.lexer.push(token)
                   1425:            token = nametok
                   1426: 
                   1427:        return token
                   1428: 
                   1429:      #
                   1430:      # Parse a signature: '(' has been parsed and we scan the type definition
                   1431:      #    up to the ')' included
                   1432:     def parseSignature(self, token):
                   1433:         signature = []
                   1434:        if token != None and token[0] == "sep" and token[1] == ')':
                   1435:            self.signature = []
                   1436:            token = self.token()
                   1437:            return token
                   1438:        while token != None:
                   1439:            token = self.parseType(token)
                   1440:            if token != None and token[0] == "name":
                   1441:                signature.append((self.type, token[1], None))
                   1442:                token = self.token()
                   1443:            elif token != None and token[0] == "sep" and token[1] == ',':
                   1444:                token = self.token()
                   1445:                continue
                   1446:            elif token != None and token[0] == "sep" and token[1] == ')':
                   1447:                 # only the type was provided
                   1448:                if self.type == "...":
                   1449:                    signature.append((self.type, "...", None))
                   1450:                else:
                   1451:                    signature.append((self.type, None, None))
                   1452:            if token != None and token[0] == "sep":
                   1453:                if token[1] == ',':
                   1454:                    token = self.token()
                   1455:                    continue
                   1456:                elif token[1] == ')':
                   1457:                    token = self.token()
                   1458:                    break
                   1459:        self.signature = signature
                   1460:        return token
                   1461: 
                   1462:      #
                   1463:      # Parse a global definition, be it a type, variable or function
                   1464:      # the extern "C" blocks are a bit nasty and require it to recurse.
                   1465:      #
                   1466:     def parseGlobal(self, token):
                   1467:         static = 0
                   1468:         if token[1] == 'extern':
                   1469:            token = self.token()
                   1470:            if token == None:
                   1471:                return token
                   1472:            if token[0] == 'string':
                   1473:                if token[1] == 'C':
                   1474:                    token = self.token()
                   1475:                    if token == None:
                   1476:                        return token
                   1477:                    if token[0] == 'sep' and token[1] == "{":
                   1478:                        token = self.token()
                   1479: #                       print 'Entering extern "C line ', self.lineno()
                   1480:                        while token != None and (token[0] != 'sep' or
                   1481:                              token[1] != "}"):
                   1482:                            if token[0] == 'name':
                   1483:                                token = self.parseGlobal(token)
                   1484:                            else:
                   1485:                                self.error(
                   1486:                                 "token %s %s unexpected at the top level" % (
                   1487:                                        token[0], token[1]))
                   1488:                                token = self.parseGlobal(token)
                   1489: #                       print 'Exiting extern "C" line', self.lineno()
                   1490:                        token = self.token()
                   1491:                        return token
                   1492:                else:
                   1493:                    return token
                   1494:        elif token[1] == 'static':
                   1495:            static = 1
                   1496:            token = self.token()
                   1497:            if token == None or  token[0] != 'name':
                   1498:                return token
                   1499: 
                   1500:        if token[1] == 'typedef':
                   1501:            token = self.token()
                   1502:            return self.parseTypedef(token)
                   1503:        else:
                   1504:            token = self.parseType(token)
                   1505:            type_orig = self.type
                   1506:        if token == None or token[0] != "name":
                   1507:            return token
                   1508:        type = type_orig
                   1509:        self.name = token[1]
                   1510:        token = self.token()
                   1511:        while token != None and (token[0] == "sep" or token[0] == "op"):
                   1512:            if token[0] == "sep":
                   1513:                if token[1] == "[":
                   1514:                    type = type + token[1]
                   1515:                    token = self.token()
                   1516:                    while token != None and (token[0] != "sep" or \
                   1517:                          token[1] != ";"):
                   1518:                        type = type + token[1]
                   1519:                        token = self.token()
                   1520: 
                   1521:            if token != None and token[0] == "op" and token[1] == "=":
                   1522:                 #
                   1523:                 # Skip the initialization of the variable
                   1524:                 #
                   1525:                token = self.token()
                   1526:                if token[0] == 'sep' and token[1] == '{':
                   1527:                    token = self.token()
                   1528:                    token = self.parseBlock(token)
                   1529:                else:
                   1530:                    self.comment = None
                   1531:                    while token != None and (token[0] != "sep" or \
                   1532:                          (token[1] != ';' and token[1] != ',')):
                   1533:                            token = self.token()
                   1534:                self.comment = None
                   1535:                if token == None or token[0] != "sep" or (token[1] != ';' and
                   1536:                   token[1] != ','):
                   1537:                    self.error("missing ';' or ',' after value")
                   1538: 
                   1539:            if token != None and token[0] == "sep":
                   1540:                if token[1] == ";":
                   1541:                    self.comment = None
                   1542:                    token = self.token()
                   1543:                    if type == "struct":
                   1544:                        self.index_add(self.name, self.filename,
                   1545:                             not self.is_header, "struct", self.struct_fields)
                   1546:                    else:
                   1547:                        self.index_add(self.name, self.filename,
                   1548:                             not self.is_header, "variable", type)
                   1549:                    break
                   1550:                elif token[1] == "(":
                   1551:                    token = self.token()
                   1552:                    token = self.parseSignature(token)
                   1553:                    if token == None:
                   1554:                        return None
                   1555:                    if token[0] == "sep" and token[1] == ";":
                   1556:                        d = self.mergeFunctionComment(self.name,
                   1557:                                ((type, None), self.signature), 1)
                   1558:                        self.index_add(self.name, self.filename, static,
                   1559:                                        "function", d)
                   1560:                        token = self.token()
                   1561:                    elif token[0] == "sep" and token[1] == "{":
                   1562:                        d = self.mergeFunctionComment(self.name,
                   1563:                                ((type, None), self.signature), static)
                   1564:                        self.index_add(self.name, self.filename, static,
                   1565:                                        "function", d)
                   1566:                        token = self.token()
                   1567:                        token = self.parseBlock(token);
                   1568:                elif token[1] == ',':
                   1569:                    self.comment = None
                   1570:                    self.index_add(self.name, self.filename, static,
                   1571:                                    "variable", type)
                   1572:                    type = type_orig
                   1573:                    token = self.token()
                   1574:                    while token != None and token[0] == "sep":
                   1575:                        type = type + token[1]
                   1576:                        token = self.token()
                   1577:                    if token != None and token[0] == "name":
                   1578:                        self.name = token[1]
                   1579:                        token = self.token()
                   1580:                else:
                   1581:                    break
                   1582: 
                   1583:        return token
                   1584: 
                   1585:     def parse(self):
                   1586:         self.warning("Parsing %s" % (self.filename))
                   1587:         token = self.token()
                   1588:        while token != None:
                   1589:             if token[0] == 'name':
                   1590:                token = self.parseGlobal(token)
                   1591:             else:
                   1592:                self.error("token %s %s unexpected at the top level" % (
                   1593:                       token[0], token[1]))
                   1594:                token = self.parseGlobal(token)
                   1595:                return
                   1596:        self.parseTopComment(self.top_comment)
                   1597:         return self.index
                   1598: 
                   1599: 
                   1600: class docBuilder:
                   1601:     """A documentation builder"""
                   1602:     def __init__(self, name, directories=['.'], excludes=[]):
                   1603:         self.name = name
                   1604:         self.directories = directories
                   1605:        self.excludes = excludes + ignored_files.keys()
                   1606:        self.modules = {}
                   1607:        self.headers = {}
                   1608:        self.idx = index()
                   1609:         self.xref = {}
                   1610:        self.index = {}
                   1611:        if name == 'libxml2':
                   1612:            self.basename = 'libxml'
                   1613:        else:
                   1614:            self.basename = name
                   1615: 
                   1616:     def indexString(self, id, str):
                   1617:        if str == None:
                   1618:            return
                   1619:        str = string.replace(str, "'", ' ')
                   1620:        str = string.replace(str, '"', ' ')
                   1621:        str = string.replace(str, "/", ' ')
                   1622:        str = string.replace(str, '*', ' ')
                   1623:        str = string.replace(str, "[", ' ')
                   1624:        str = string.replace(str, "]", ' ')
                   1625:        str = string.replace(str, "(", ' ')
                   1626:        str = string.replace(str, ")", ' ')
                   1627:        str = string.replace(str, "<", ' ')
                   1628:        str = string.replace(str, '>', ' ')
                   1629:        str = string.replace(str, "&", ' ')
                   1630:        str = string.replace(str, '#', ' ')
                   1631:        str = string.replace(str, ",", ' ')
                   1632:        str = string.replace(str, '.', ' ')
                   1633:        str = string.replace(str, ';', ' ')
                   1634:        tokens = string.split(str)
                   1635:        for token in tokens:
                   1636:            try:
                   1637:                c = token[0]
                   1638:                if string.find(string.letters, c) < 0:
                   1639:                    pass
                   1640:                elif len(token) < 3:
                   1641:                    pass
                   1642:                else:
                   1643:                    lower = string.lower(token)
                   1644:                    # TODO: generalize this a bit
                   1645:                    if lower == 'and' or lower == 'the':
                   1646:                        pass
                   1647:                    elif self.xref.has_key(token):
                   1648:                        self.xref[token].append(id)
                   1649:                    else:
                   1650:                        self.xref[token] = [id]
                   1651:            except:
                   1652:                pass
                   1653: 
                   1654:     def analyze(self):
                   1655:         print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
                   1656:        self.idx.analyze()
                   1657: 
                   1658:     def scanHeaders(self):
                   1659:        for header in self.headers.keys():
                   1660:            parser = CParser(header)
                   1661:            idx = parser.parse()
                   1662:            self.headers[header] = idx;
                   1663:            self.idx.merge(idx)
                   1664: 
                   1665:     def scanModules(self):
                   1666:        for module in self.modules.keys():
                   1667:            parser = CParser(module)
                   1668:            idx = parser.parse()
                   1669:            # idx.analyze()
                   1670:            self.modules[module] = idx
                   1671:            self.idx.merge_public(idx)
                   1672: 
                   1673:     def scan(self):
                   1674:         for directory in self.directories:
                   1675:            files = glob.glob(directory + "/*.c")
                   1676:            for file in files:
                   1677:                skip = 0
                   1678:                for excl in self.excludes:
                   1679:                    if string.find(file, excl) != -1:
                   1680:                        skip = 1;
                   1681:                        break
                   1682:                if skip == 0:
                   1683:                    self.modules[file] = None;
                   1684:            files = glob.glob(directory + "/*.h")
                   1685:            for file in files:
                   1686:                skip = 0
                   1687:                for excl in self.excludes:
                   1688:                    if string.find(file, excl) != -1:
                   1689:                        skip = 1;
                   1690:                        break
                   1691:                if skip == 0:
                   1692:                    self.headers[file] = None;
                   1693:        self.scanHeaders()
                   1694:        self.scanModules()
                   1695: 
                   1696:     def modulename_file(self, file):
                   1697:         module = os.path.basename(file)
                   1698:        if module[-2:] == '.h':
                   1699:            module = module[:-2]
                   1700:        elif module[-2:] == '.c':
                   1701:            module = module[:-2]
                   1702:        return module
                   1703: 
                   1704:     def serialize_enum(self, output, name):
                   1705:         id = self.idx.enums[name]
                   1706:         output.write("    <enum name='%s' file='%s'" % (name,
                   1707:                     self.modulename_file(id.header)))
                   1708:        if id.info != None:
                   1709:            info = id.info
                   1710:            if info[0] != None and info[0] != '':
                   1711:                try:
                   1712:                    val = eval(info[0])
                   1713:                except:
                   1714:                    val = info[0]
                   1715:                output.write(" value='%s'" % (val));
                   1716:            if info[2] != None and info[2] != '':
                   1717:                output.write(" type='%s'" % info[2]);
                   1718:            if info[1] != None and info[1] != '':
                   1719:                output.write(" info='%s'" % escape(info[1]));
                   1720:         output.write("/>\n")
                   1721: 
                   1722:     def serialize_macro(self, output, name):
                   1723:         id = self.idx.macros[name]
                   1724:         output.write("    <macro name='%s' file='%s'>\n" % (name,
                   1725:                     self.modulename_file(id.header)))
                   1726:        if id.info != None:
                   1727:             try:
                   1728:                (args, desc) = id.info
                   1729:                if desc != None and desc != "":
                   1730:                    output.write("      <info>%s</info>\n" % (escape(desc)))
                   1731:                    self.indexString(name, desc)
                   1732:                for arg in args:
                   1733:                    (name, desc) = arg
                   1734:                    if desc != None and desc != "":
                   1735:                        output.write("      <arg name='%s' info='%s'/>\n" % (
                   1736:                                     name, escape(desc)))
                   1737:                        self.indexString(name, desc)
                   1738:                    else:
                   1739:                        output.write("      <arg name='%s'/>\n" % (name))
                   1740:             except:
                   1741:                 pass
                   1742:         output.write("    </macro>\n")
                   1743: 
                   1744:     def serialize_typedef(self, output, name):
                   1745:         id = self.idx.typedefs[name]
                   1746:        if id.info[0:7] == 'struct ':
                   1747:            output.write("    <struct name='%s' file='%s' type='%s'" % (
                   1748:                     name, self.modulename_file(id.header), id.info))
                   1749:            name = id.info[7:]
                   1750:            if self.idx.structs.has_key(name) and ( \
                   1751:               type(self.idx.structs[name].info) == type(()) or
                   1752:                type(self.idx.structs[name].info) == type([])):
                   1753:                output.write(">\n");
                   1754:                try:
                   1755:                    for field in self.idx.structs[name].info:
                   1756:                        desc = field[2]
                   1757:                        self.indexString(name, desc)
                   1758:                        if desc == None:
                   1759:                            desc = ''
                   1760:                        else:
                   1761:                            desc = escape(desc)
                   1762:                        output.write("      <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
                   1763:                except:
                   1764:                    print "Failed to serialize struct %s" % (name)
                   1765:                output.write("    </struct>\n")
                   1766:            else:
                   1767:                output.write("/>\n");
                   1768:        else :
                   1769:            output.write("    <typedef name='%s' file='%s' type='%s'" % (
                   1770:                         name, self.modulename_file(id.header), id.info))
                   1771:             try:
                   1772:                desc = id.extra
                   1773:                if desc != None and desc != "":
                   1774:                    output.write(">\n      <info>%s</info>\n" % (escape(desc)))
                   1775:                    output.write("    </typedef>\n")
                   1776:                else:
                   1777:                    output.write("/>\n")
                   1778:            except:
                   1779:                output.write("/>\n")
                   1780: 
                   1781:     def serialize_variable(self, output, name):
                   1782:         id = self.idx.variables[name]
                   1783:        if id.info != None:
                   1784:            output.write("    <variable name='%s' file='%s' type='%s'/>\n" % (
                   1785:                    name, self.modulename_file(id.header), id.info))
                   1786:        else:
                   1787:            output.write("    <variable name='%s' file='%s'/>\n" % (
                   1788:                    name, self.modulename_file(id.header)))
                   1789: 
                   1790:     def serialize_function(self, output, name):
                   1791:         id = self.idx.functions[name]
                   1792:        if name == debugsym:
                   1793:            print "=>", id
                   1794: 
                   1795:         output.write("    <%s name='%s' file='%s' module='%s'>\n" % (id.type,
                   1796:                     name, self.modulename_file(id.header),
                   1797:                     self.modulename_file(id.module)))
                   1798:        #
                   1799:        # Processing of conditionals modified by Bill 1/1/05
                   1800:        #
                   1801:        if id.conditionals != None:
                   1802:            apstr = ""
                   1803:            for cond in id.conditionals:
                   1804:                if apstr != "":
                   1805:                    apstr = apstr + " &amp;&amp; "
                   1806:                apstr = apstr + cond
                   1807:            output.write("      <cond>%s</cond>\n"% (apstr));
                   1808:        try:
                   1809:            (ret, params, desc) = id.info
                   1810:            if (desc == None or desc == '') and \
                   1811:               name[0:9] != "xmlThrDef" and name != "xmlDllMain":
                   1812:                print "%s %s from %s has no description" % (id.type, name,
                   1813:                       self.modulename_file(id.module))
                   1814: 
                   1815:            output.write("      <info>%s</info>\n" % (escape(desc)))
                   1816:            self.indexString(name, desc)
                   1817:            if ret[0] != None:
                   1818:                if ret[0] == "void":
                   1819:                    output.write("      <return type='void'/>\n")
                   1820:                else:
                   1821:                    output.write("      <return type='%s' info='%s'/>\n" % (
                   1822:                             ret[0], escape(ret[1])))
                   1823:                    self.indexString(name, ret[1])
                   1824:            for param in params:
                   1825:                if param[0] == 'void':
                   1826:                    continue
                   1827:                if param[2] == None:
                   1828:                    output.write("      <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
                   1829:                else:
                   1830:                    output.write("      <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
                   1831:                    self.indexString(name, param[2])
                   1832:        except:
                   1833:            print "Failed to save function %s info: " % name, `id.info`
                   1834:         output.write("    </%s>\n" % (id.type))
                   1835: 
                   1836:     def serialize_exports(self, output, file):
                   1837:         module = self.modulename_file(file)
                   1838:        output.write("    <file name='%s'>\n" % (module))
                   1839:        dict = self.headers[file]
                   1840:        if dict.info != None:
                   1841:            for data in ('Summary', 'Description', 'Author'):
                   1842:                try:
                   1843:                    output.write("     <%s>%s</%s>\n" % (
                   1844:                                 string.lower(data),
                   1845:                                 escape(dict.info[data]),
                   1846:                                 string.lower(data)))
                   1847:                except:
                   1848:                    print "Header %s lacks a %s description" % (module, data)
                   1849:            if dict.info.has_key('Description'):
                   1850:                desc = dict.info['Description']
                   1851:                if string.find(desc, "DEPRECATED") != -1:
                   1852:                    output.write("     <deprecated/>\n")
                   1853: 
                   1854:         ids = dict.macros.keys()
                   1855:        ids.sort()
                   1856:        for id in uniq(ids):
                   1857:            # Macros are sometime used to masquerade other types.
                   1858:            if dict.functions.has_key(id):
                   1859:                continue
                   1860:            if dict.variables.has_key(id):
                   1861:                continue
                   1862:            if dict.typedefs.has_key(id):
                   1863:                continue
                   1864:            if dict.structs.has_key(id):
                   1865:                continue
                   1866:            if dict.enums.has_key(id):
                   1867:                continue
                   1868:            output.write("     <exports symbol='%s' type='macro'/>\n" % (id))
                   1869:         ids = dict.enums.keys()
                   1870:        ids.sort()
                   1871:        for id in uniq(ids):
                   1872:            output.write("     <exports symbol='%s' type='enum'/>\n" % (id))
                   1873:         ids = dict.typedefs.keys()
                   1874:        ids.sort()
                   1875:        for id in uniq(ids):
                   1876:            output.write("     <exports symbol='%s' type='typedef'/>\n" % (id))
                   1877:         ids = dict.structs.keys()
                   1878:        ids.sort()
                   1879:        for id in uniq(ids):
                   1880:            output.write("     <exports symbol='%s' type='struct'/>\n" % (id))
                   1881:         ids = dict.variables.keys()
                   1882:        ids.sort()
                   1883:        for id in uniq(ids):
                   1884:            output.write("     <exports symbol='%s' type='variable'/>\n" % (id))
                   1885:         ids = dict.functions.keys()
                   1886:        ids.sort()
                   1887:        for id in uniq(ids):
                   1888:            output.write("     <exports symbol='%s' type='function'/>\n" % (id))
                   1889:        output.write("    </file>\n")
                   1890: 
                   1891:     def serialize_xrefs_files(self, output):
                   1892:         headers = self.headers.keys()
                   1893:         headers.sort()
                   1894:         for file in headers:
                   1895:            module = self.modulename_file(file)
                   1896:            output.write("    <file name='%s'>\n" % (module))
                   1897:            dict = self.headers[file]
                   1898:            ids = uniq(dict.functions.keys() + dict.variables.keys() + \
                   1899:                  dict.macros.keys() + dict.typedefs.keys() + \
                   1900:                  dict.structs.keys() + dict.enums.keys())
                   1901:            ids.sort()
                   1902:            for id in ids:
                   1903:                output.write("      <ref name='%s'/>\n" % (id))
                   1904:            output.write("    </file>\n")
                   1905:         pass
                   1906: 
                   1907:     def serialize_xrefs_functions(self, output):
                   1908:         funcs = {}
                   1909:        for name in self.idx.functions.keys():
                   1910:            id = self.idx.functions[name]
                   1911:            try:
                   1912:                (ret, params, desc) = id.info
                   1913:                for param in params:
                   1914:                    if param[0] == 'void':
                   1915:                        continue
                   1916:                    if funcs.has_key(param[0]):
                   1917:                        funcs[param[0]].append(name)
                   1918:                    else:
                   1919:                        funcs[param[0]] = [name]
                   1920:            except:
                   1921:                pass
                   1922:        typ = funcs.keys()
                   1923:        typ.sort()
                   1924:        for type in typ:
                   1925:            if type == '' or type == 'void' or type == "int" or \
                   1926:               type == "char *" or type == "const char *" :
                   1927:                continue
                   1928:            output.write("    <type name='%s'>\n" % (type))
                   1929:            ids = funcs[type]
                   1930:            ids.sort()
                   1931:            pid = ''    # not sure why we have dups, but get rid of them!
                   1932:            for id in ids:
                   1933:                if id != pid:
                   1934:                    output.write("      <ref name='%s'/>\n" % (id))
                   1935:                    pid = id
                   1936:            output.write("    </type>\n")
                   1937: 
                   1938:     def serialize_xrefs_constructors(self, output):
                   1939:         funcs = {}
                   1940:        for name in self.idx.functions.keys():
                   1941:            id = self.idx.functions[name]
                   1942:            try:
                   1943:                (ret, params, desc) = id.info
                   1944:                if ret[0] == "void":
                   1945:                    continue
                   1946:                if funcs.has_key(ret[0]):
                   1947:                    funcs[ret[0]].append(name)
                   1948:                else:
                   1949:                    funcs[ret[0]] = [name]
                   1950:            except:
                   1951:                pass
                   1952:        typ = funcs.keys()
                   1953:        typ.sort()
                   1954:        for type in typ:
                   1955:            if type == '' or type == 'void' or type == "int" or \
                   1956:               type == "char *" or type == "const char *" :
                   1957:                continue
                   1958:            output.write("    <type name='%s'>\n" % (type))
                   1959:            ids = funcs[type]
                   1960:            ids.sort()
                   1961:            for id in ids:
                   1962:                output.write("      <ref name='%s'/>\n" % (id))
                   1963:            output.write("    </type>\n")
                   1964: 
                   1965:     def serialize_xrefs_alpha(self, output):
                   1966:        letter = None
                   1967:        ids = self.idx.identifiers.keys()
                   1968:        ids.sort()
                   1969:        for id in ids:
                   1970:            if id[0] != letter:
                   1971:                if letter != None:
                   1972:                    output.write("    </letter>\n")
                   1973:                letter = id[0]
                   1974:                output.write("    <letter name='%s'>\n" % (letter))
                   1975:            output.write("      <ref name='%s'/>\n" % (id))
                   1976:        if letter != None:
                   1977:            output.write("    </letter>\n")
                   1978: 
                   1979:     def serialize_xrefs_references(self, output):
                   1980:         typ = self.idx.identifiers.keys()
                   1981:        typ.sort()
                   1982:        for id in typ:
                   1983:            idf = self.idx.identifiers[id]
                   1984:            module = idf.header
                   1985:            output.write("    <reference name='%s' href='%s'/>\n" % (id,
                   1986:                         'html/' + self.basename + '-' +
                   1987:                         self.modulename_file(module) + '.html#' +
                   1988:                         id))
                   1989: 
                   1990:     def serialize_xrefs_index(self, output):
                   1991:         index = self.xref
                   1992:        typ = index.keys()
                   1993:        typ.sort()
                   1994:        letter = None
                   1995:        count = 0
                   1996:        chunk = 0
                   1997:        chunks = []
                   1998:        for id in typ:
                   1999:            if len(index[id]) > 30:
                   2000:                continue
                   2001:            if id[0] != letter:
                   2002:                if letter == None or count > 200:
                   2003:                    if letter != None:
                   2004:                        output.write("      </letter>\n")
                   2005:                        output.write("    </chunk>\n")
                   2006:                        count = 0
                   2007:                        chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
                   2008:                    output.write("    <chunk name='chunk%s'>\n" % (chunk))
                   2009:                    first_letter = id[0]
                   2010:                    chunk = chunk + 1
                   2011:                elif letter != None:
                   2012:                    output.write("      </letter>\n")
                   2013:                letter = id[0]
                   2014:                output.write("      <letter name='%s'>\n" % (letter))
                   2015:            output.write("        <word name='%s'>\n" % (id))
                   2016:            tokens = index[id];
                   2017:            tokens.sort()
                   2018:            tok = None
                   2019:            for token in tokens:
                   2020:                if tok == token:
                   2021:                    continue
                   2022:                tok = token
                   2023:                output.write("          <ref name='%s'/>\n" % (token))
                   2024:                count = count + 1
                   2025:            output.write("        </word>\n")
                   2026:        if letter != None:
                   2027:            output.write("      </letter>\n")
                   2028:            output.write("    </chunk>\n")
                   2029:            if count != 0:
                   2030:                chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
                   2031:            output.write("    <chunks>\n")
                   2032:            for ch in chunks:
                   2033:                output.write("      <chunk name='%s' start='%s' end='%s'/>\n" % (
                   2034:                             ch[0], ch[1], ch[2]))
                   2035:            output.write("    </chunks>\n")
                   2036: 
                   2037:     def serialize_xrefs(self, output):
                   2038:        output.write("  <references>\n")
                   2039:        self.serialize_xrefs_references(output)
                   2040:        output.write("  </references>\n")
                   2041:        output.write("  <alpha>\n")
                   2042:        self.serialize_xrefs_alpha(output)
                   2043:        output.write("  </alpha>\n")
                   2044:        output.write("  <constructors>\n")
                   2045:        self.serialize_xrefs_constructors(output)
                   2046:        output.write("  </constructors>\n")
                   2047:        output.write("  <functions>\n")
                   2048:        self.serialize_xrefs_functions(output)
                   2049:        output.write("  </functions>\n")
                   2050:        output.write("  <files>\n")
                   2051:        self.serialize_xrefs_files(output)
                   2052:        output.write("  </files>\n")
                   2053:        output.write("  <index>\n")
                   2054:        self.serialize_xrefs_index(output)
                   2055:        output.write("  </index>\n")
                   2056: 
                   2057:     def serialize(self):
                   2058:         filename = "%s-api.xml" % self.name
                   2059:         print "Saving XML description %s" % (filename)
                   2060:         output = open(filename, "w")
                   2061:         output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
                   2062:         output.write("<api name='%s'>\n" % self.name)
                   2063:         output.write("  <files>\n")
                   2064:         headers = self.headers.keys()
                   2065:         headers.sort()
                   2066:         for file in headers:
                   2067:             self.serialize_exports(output, file)
                   2068:         output.write("  </files>\n")
                   2069:         output.write("  <symbols>\n")
                   2070:         macros = self.idx.macros.keys()
                   2071:         macros.sort()
                   2072:         for macro in macros:
                   2073:             self.serialize_macro(output, macro)
                   2074:         enums = self.idx.enums.keys()
                   2075:         enums.sort()
                   2076:         for enum in enums:
                   2077:             self.serialize_enum(output, enum)
                   2078:         typedefs = self.idx.typedefs.keys()
                   2079:         typedefs.sort()
                   2080:         for typedef in typedefs:
                   2081:             self.serialize_typedef(output, typedef)
                   2082:         variables = self.idx.variables.keys()
                   2083:         variables.sort()
                   2084:         for variable in variables:
                   2085:             self.serialize_variable(output, variable)
                   2086:         functions = self.idx.functions.keys()
                   2087:         functions.sort()
                   2088:         for function in functions:
                   2089:             self.serialize_function(output, function)
                   2090:         output.write("  </symbols>\n")
                   2091:         output.write("</api>\n")
                   2092:         output.close()
                   2093: 
                   2094:         filename = "%s-refs.xml" % self.name
                   2095:         print "Saving XML Cross References %s" % (filename)
                   2096:         output = open(filename, "w")
                   2097:         output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
                   2098:         output.write("<apirefs name='%s'>\n" % self.name)
                   2099:         self.serialize_xrefs(output)
                   2100:         output.write("</apirefs>\n")
                   2101:         output.close()
                   2102: 
                   2103: 
                   2104: def rebuild():
                   2105:     builder = None
                   2106:     if glob.glob("parser.c") != [] :
                   2107:         print "Rebuilding API description for libxml2"
                   2108:        builder = docBuilder("libxml2", [".", "."],
                   2109:                             ["xmlwin32version.h", "tst.c"])
                   2110:     elif glob.glob("../parser.c") != [] :
                   2111:         print "Rebuilding API description for libxml2"
                   2112:        builder = docBuilder("libxml2", ["..", "../include/libxml"],
                   2113:                             ["xmlwin32version.h", "tst.c"])
                   2114:     elif glob.glob("../libxslt/transform.c") != [] :
                   2115:         print "Rebuilding API description for libxslt"
                   2116:        builder = docBuilder("libxslt", ["../libxslt"],
                   2117:                             ["win32config.h", "libxslt.h", "tst.c"])
                   2118:     else:
                   2119:         print "rebuild() failed, unable to guess the module"
                   2120:        return None
                   2121:     builder.scan()
                   2122:     builder.analyze()
                   2123:     builder.serialize()
                   2124:     if glob.glob("../libexslt/exslt.c") != [] :
                   2125:         extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
                   2126:        extra.scan()
                   2127:        extra.analyze()
                   2128:        extra.serialize()
                   2129:     return builder
                   2130: 
                   2131: #
                   2132: # for debugging the parser
                   2133: #
                   2134: def parse(filename):
                   2135:     parser = CParser(filename)
                   2136:     idx = parser.parse()
                   2137:     return idx
                   2138: 
                   2139: if __name__ == "__main__":
                   2140:     if len(sys.argv) > 1:
                   2141:         debug = 1
                   2142:         parse(sys.argv[1])
                   2143:     else:
                   2144:        rebuild()

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>