apibuild.py 63 KB

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