PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/ExtLibs/wxWidgets/utils/ifacecheck/src/xmlparser.cpp

https://bitbucket.org/cafu/cafu
C++ | 1700 lines | 1131 code | 305 blank | 264 comment | 426 complexity | 1a068a1c5032fbd07830f713c3a3ec58 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, BSD-3-Clause, LGPL-3.0, LGPL-2.1, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: xmlparser.cpp
  3. // Purpose: Parser of the API/interface XML files
  4. // Author: Francesco Montorsi
  5. // Created: 2008/03/17
  6. // Copyright: (c) 2008 Francesco Montorsi
  7. // Licence: wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9. // For compilers that support precompilation, includes "wx/wx.h".
  10. #include "wx/wxprec.h"
  11. #ifdef __BORLANDC__
  12. #pragma hdrstop
  13. #endif
  14. // for all others, include the necessary headers
  15. #ifndef WX_PRECOMP
  16. #include "wx/crt.h"
  17. #endif
  18. #include "wx/xml/xml.h"
  19. #include "wx/wfstream.h"
  20. #include "wx/hashmap.h"
  21. #include "wx/filename.h"
  22. #include "xmlparser.h"
  23. #include <errno.h>
  24. #include <wx/arrimpl.cpp>
  25. WX_DEFINE_OBJARRAY(wxTypeArray)
  26. WX_DEFINE_OBJARRAY(wxArgumentTypeArray)
  27. WX_DEFINE_OBJARRAY(wxMethodArray)
  28. WX_DEFINE_OBJARRAY(wxClassArray)
  29. #define PROGRESS_RATE 1000 // each PROGRESS_RATE nodes processed print a dot
  30. #define ESTIMATED_NUM_CLASSES 600 // used by both wxXmlInterface-derived classes to prealloc mem
  31. // defined in ifacecheck.cpp
  32. extern bool g_verbose;
  33. // global variable:
  34. bool g_bLogEnabled = true;
  35. // ----------------------------------------------------------------------------
  36. // wxType
  37. // ----------------------------------------------------------------------------
  38. wxType wxEmptyType;
  39. void wxType::SetTypeFromString(const wxString& t)
  40. {
  41. /*
  42. TODO: optimize the following code writing a single function
  43. which works at char-level and does everything in a single pass
  44. */
  45. // clean the type string
  46. // ---------------------
  47. m_strType = t;
  48. // [] is the same as * for gccxml
  49. m_strType.Replace("[]", "*");
  50. m_strType.Replace("long int", "long"); // in wx typically we never write "long int", just "long"
  51. m_strType.Replace("long unsigned int", "unsigned long");
  52. m_strType.Replace("short unsigned int", "unsigned short");
  53. // make sure the * and & operator always use the same spacing rules
  54. // (to make sure GetAsString() output is always consistent)
  55. m_strType.Replace("*", "* ");
  56. m_strType.Replace("&", "& ");
  57. m_strType.Replace(" *", "*");
  58. m_strType.Replace(" &", "&");
  59. while (m_strType.Contains(" "))
  60. m_strType.Replace(" ", " "); // do it once again
  61. m_strType.Replace(" ,", ",");
  62. // ADHOC-FIX
  63. m_strType.Replace("_wxArraywxArrayStringBase", "wxString");
  64. m_strType.Replace("ExitCode", "void*"); // used in wxThread stuff
  65. m_strType = m_strType.Strip(wxString::both);
  66. // clean the type string (this time for the comparison)
  67. // ----------------------------------------------------
  68. m_strTypeClean = m_strType; // begin with the already-cleaned string
  69. m_strTypeClean.Replace("const", "");
  70. m_strTypeClean.Replace("static", "");
  71. m_strTypeClean.Replace("*", "");
  72. m_strTypeClean.Replace("&", "");
  73. m_strTypeClean.Replace("[]", "");
  74. m_strTypeClean = m_strTypeClean.Strip(wxString::both);
  75. // to avoid false errors types like wxStandardPaths and wxStandardPathsBase
  76. // need to be considered as the same type
  77. if (m_strTypeClean.EndsWith("Base"))
  78. m_strTypeClean = m_strTypeClean.Left(m_strTypeClean.Len()-4);
  79. // remove the namespace from the types; there's no problem of conflicts
  80. // (except for templates) and this avoids tons of false warnings
  81. if (m_strTypeClean.Contains("::") && !m_strTypeClean.Contains("<"))
  82. m_strTypeClean = m_strTypeClean.Mid(m_strTypeClean.Find("::")+2);
  83. // ADHOC-FIX:
  84. m_strTypeClean.Replace("wxWindowID", "int");
  85. }
  86. bool wxType::IsOk() const
  87. {
  88. // NB: m_strType can contain the :: operator; think to e.g. the
  89. // "reverse_iterator_impl<wxString::const_iterator>" type
  90. // It can also contain commas, * and & operators etc
  91. return !m_strTypeClean.IsEmpty();
  92. }
  93. bool wxType::operator==(const wxType& m) const
  94. {
  95. // brain-dead comparison:
  96. if (m_strTypeClean == m.m_strTypeClean &&
  97. IsConst() == m.IsConst() &&
  98. IsStatic() == m.IsStatic() &&
  99. IsPointer() == m.IsPointer() &&
  100. IsReference() == m.IsReference())
  101. return true;
  102. if (g_verbose)
  103. {
  104. wxLogMessage("Type '%s' does not match type '%s'", m_strType, m.m_strType);
  105. wxLogMessage(" => TypeClean %s / %s; IsConst %d / %d; IsStatic %d / %d; IsPointer %d / %d; IsReference %d / %d",
  106. m_strTypeClean, m.m_strTypeClean, IsConst(), m.IsConst(),
  107. IsStatic(), m.IsStatic(), IsPointer(), m.IsPointer(),
  108. IsReference(), m.IsReference());
  109. }
  110. return false;
  111. }
  112. // ----------------------------------------------------------------------------
  113. // wxArgumentType
  114. // ----------------------------------------------------------------------------
  115. void wxArgumentType::SetDefaultValue(const wxString& defval, const wxString& defvalForCmp)
  116. {
  117. m_strDefaultValue = defval.Strip(wxString::both);
  118. m_strDefaultValueForCmp = defvalForCmp.IsEmpty() ?
  119. m_strDefaultValue : defvalForCmp.Strip(wxString::both);
  120. // clean the default argument strings
  121. // ----------------------------------
  122. // Note: we adjust the aesthetic form of the m_strDefaultValue string for the "modify mode"
  123. // of ifacecheck: we may need to write it out in an interface header
  124. wxString *p = NULL;
  125. for (int i=0; i<2; i++) // to avoid copying&pasting the code!
  126. {
  127. if (i == 0) p = &m_strDefaultValue;
  128. if (i == 1) p = &m_strDefaultValueForCmp;
  129. if (*p == "0u" || *p == "0l") *p = "0";
  130. p->Replace("0x000000001", "1");
  131. p->Replace("\\000\\000\\000", ""); // fix for unicode strings:
  132. p->Replace("\\011", "\\t");
  133. p->Replace("e+0", "");
  134. p->Replace("2147483647", "__INT_MAX__");
  135. // ADHOC-FIX: for wxConv* default values
  136. p->Replace("wxConvAuto(wxFONTENCODING_DEFAULT)", "wxConvAuto()");
  137. p->Replace("wxGet_wxConvUTF8()", "wxConvUTF8");
  138. p->Replace("wxGet_wxConvLocal()", "wxConvLocal");
  139. }
  140. // clean ONLY the default argument string specific for comparison
  141. // --------------------------------------------------------------
  142. if (m_strDefaultValueForCmp.StartsWith("wxT(") &&
  143. m_strDefaultValueForCmp.EndsWith(")"))
  144. {
  145. // get rid of the wxT() part
  146. unsigned int len = m_strDefaultValueForCmp.Len();
  147. m_strDefaultValueForCmp = m_strDefaultValueForCmp.Mid(4,len-5);
  148. }
  149. // ADHOC-FIX:
  150. // doxygen likes to put wxDateTime:: in front of all wxDateTime enums;
  151. // fix this to avoid false positives
  152. m_strDefaultValueForCmp.Replace("wxDateTime::", "");
  153. m_strDefaultValueForCmp.Replace("wxStockGDI::", ""); // same story for some other classes
  154. m_strDefaultValueForCmp.Replace("wxHelpEvent::", ""); // same story for some other classes
  155. m_strDefaultValueForCmp.Replace("* GetColour(COLOUR_BLACK)", "*wxBLACK");
  156. // ADHOC-FIX:
  157. if (m_strDefaultValueForCmp.Contains("wxGetTranslation"))
  158. m_strDefaultValueForCmp = "_(TOFIX)"; // TODO: wxGetTranslation gives problems to gccxml
  159. }
  160. bool wxArgumentType::operator==(const wxArgumentType& m) const
  161. {
  162. if ((const wxType&)(*this) != (const wxType&)m)
  163. return false;
  164. // check if the default values match
  165. // ---------------------------------
  166. // ADHOC-FIX:
  167. // default values for style attributes of wxWindow-derived classes in gccxml appear as raw
  168. // numbers; avoid false positives in this case!
  169. if (m_strArgName == m.m_strArgName && m_strArgName == "style" &&
  170. (m_strDefaultValueForCmp.IsNumber() || m.m_strDefaultValueForCmp.IsNumber()))
  171. return true;
  172. // fix for default values which were replaced by gcc-xml with their numeric values
  173. // (at this point we know that m_strTypeClean == m.m_strTypeClean):
  174. if (m_strTypeClean == "long" || m_strTypeClean == "int")
  175. {
  176. if ((m_strDefaultValueForCmp.IsNumber() && m.m_strDefaultValueForCmp.StartsWith("wx")) ||
  177. (m.m_strDefaultValueForCmp.IsNumber() && m_strDefaultValueForCmp.StartsWith("wx")))
  178. {
  179. if (g_verbose)
  180. {
  181. wxLogMessage("Supposing '%s' default value to be the same of '%s'...",
  182. m_strDefaultValueForCmp, m.m_strDefaultValueForCmp);
  183. }
  184. return true;
  185. }
  186. }
  187. else if (m_strTypeClean == "float" || m_strTypeClean == "double")
  188. // gccXML translates the default floating values in a hardly usable
  189. // format; e.g. 25.2 => 2.51999999999999992894572642398998141288757324219e+1
  190. // we avoid check on these...
  191. return true;
  192. if (m_strDefaultValueForCmp != m.m_strDefaultValueForCmp)
  193. {
  194. // maybe the default values are numbers.
  195. // in this case gccXML gives as default values things like '-0x0000001' instead of just '-1'.
  196. // To handle these cases, we try to convert the default value strings to numbers:
  197. long def1val, def2val;
  198. if (m_strDefaultValueForCmp.ToLong(&def1val, 0 /* auto-detect */) &&
  199. m.m_strDefaultValueForCmp.ToLong(&def2val, 0 /* auto-detect */))
  200. {
  201. if (def1val == def2val)
  202. return true; // the default values match
  203. }
  204. if (g_verbose)
  205. {
  206. wxLogMessage("Argument type '%s = %s' has different default value from '%s = %s'",
  207. m_strType, m_strDefaultValueForCmp, m.m_strType, m.m_strDefaultValueForCmp);
  208. }
  209. return false;
  210. }
  211. // we deliberately avoid checks on the argument name
  212. return true;
  213. }
  214. // ----------------------------------------------------------------------------
  215. // wxMethod
  216. // ----------------------------------------------------------------------------
  217. bool wxMethod::IsOk() const
  218. {
  219. // NOTE: m_retType can be a wxEmptyType, and means that this method
  220. // is a ctor or a dtor.
  221. if (!m_retType.IsOk() && m_retType!=wxEmptyType) {
  222. wxLogError("'%s' method has invalid return type: %s", m_retType.GetAsString());
  223. return false;
  224. }
  225. if (m_strName.IsEmpty())
  226. return false;
  227. // a function can't be both const and static or virtual and static!
  228. if ((m_bConst && m_bStatic) || ((m_bVirtual || m_bPureVirtual) && m_bStatic)) {
  229. wxLogError("'%s' method can't be both const/static or virtual/static", m_strName);
  230. return false;
  231. }
  232. wxASSERT(!m_bPureVirtual || (m_bPureVirtual && m_bVirtual));
  233. for (unsigned int i=0; i<m_args.GetCount(); i++)
  234. if (!m_args[i].IsOk()) {
  235. wxLogError("'%s' method has invalid %d-th argument type: %s",
  236. m_strName, i+1, m_args[i].GetAsString());
  237. return false;
  238. }
  239. // NB: the default value of the arguments can contain pretty much everything
  240. // (think to e.g. wxPoint(3+4/2,0) or *wxBLACK or someClass<type>)
  241. // so we don't do any test on their contents
  242. if (m_args.GetCount()>0)
  243. {
  244. bool previousArgHasDefault = m_args[0].HasDefaultValue();
  245. for (unsigned int i=1; i<m_args.GetCount(); i++)
  246. {
  247. if (previousArgHasDefault && !m_args[i].HasDefaultValue()) {
  248. wxLogError("'%s' method has %d-th argument which has no default value "
  249. "(while the previous one had one!)",
  250. m_strName, i+1);
  251. return false;
  252. }
  253. previousArgHasDefault = m_args[i].HasDefaultValue();
  254. }
  255. }
  256. return true;
  257. }
  258. bool wxMethod::MatchesExceptForAttributes(const wxMethod& m) const
  259. {
  260. if (GetReturnType() != m.GetReturnType() ||
  261. GetName() != m.GetName())
  262. {
  263. if (g_verbose)
  264. {
  265. wxLogMessage("The method '%s' does not match method '%s'; different names/rettype", GetName(), m.GetName());
  266. }
  267. return false;
  268. }
  269. if (m_args.GetCount()!=m.m_args.GetCount()) {
  270. if (g_verbose)
  271. {
  272. wxLogMessage("Method '%s' has %d arguments while '%s' has %d arguments",
  273. m_strName, m_args.GetCount(), m_strName, m.m_args.GetCount());
  274. }
  275. return false;
  276. }
  277. // compare argument types
  278. for (unsigned int i=0; i<m_args.GetCount(); i++)
  279. if (m_args[i] != m.m_args[i])
  280. return false;
  281. return true;
  282. }
  283. bool wxMethod::ActsAsDefaultCtor() const
  284. {
  285. if (!IsCtor())
  286. return false;
  287. for (unsigned int i=0; i<m_args.GetCount(); i++)
  288. if (!m_args[i].HasDefaultValue())
  289. return false;
  290. return true;
  291. }
  292. bool wxMethod::operator==(const wxMethod& m) const
  293. {
  294. // check attributes
  295. if (IsConst() != m.IsConst() ||
  296. IsStatic() != m.IsStatic() ||
  297. IsVirtual() != m.IsVirtual() ||
  298. IsPureVirtual() != m.IsPureVirtual() ||
  299. IsDeprecated() != m.IsDeprecated() ||
  300. GetAccessSpecifier() != m.GetAccessSpecifier())
  301. {
  302. if (g_verbose)
  303. {
  304. wxLogMessage("The method '%s' does not match method '%s'; different attributes", GetName(), m.GetName());
  305. }
  306. return false;
  307. }
  308. // check everything else
  309. return MatchesExceptForAttributes(m);
  310. }
  311. wxString wxMethod::GetAsString(bool bWithArgumentNames, bool bCleanDefaultValues,
  312. bool bDeprecated, bool bAccessSpec) const
  313. {
  314. wxString ret;
  315. // NOTE: for return and argument types, never use wxType::GetAsCleanString
  316. // since in that way we'd miss important decorators like &,*,const etc
  317. if (m_retType!=wxEmptyType)
  318. ret += m_retType.GetAsString() + " ";
  319. //else; this is a ctor or dtor
  320. ret += m_strName + "(";
  321. for (unsigned int i=0; i<m_args.GetCount(); i++)
  322. {
  323. ret += m_args[i].GetAsString();
  324. const wxString& name = m_args[i].GetArgumentName();
  325. if (bWithArgumentNames && !name.IsEmpty())
  326. ret += " " + name;
  327. const wxString& def = bCleanDefaultValues ?
  328. m_args[i].GetDefaultCleanValue() : m_args[i].GetDefaultValue();
  329. if (!def.IsEmpty())
  330. ret += " = " + def;
  331. ret += ", ";
  332. }
  333. if (m_args.GetCount()>0)
  334. ret = ret.Left(ret.Len()-2);
  335. ret += ")";
  336. if (m_bConst)
  337. ret += " const";
  338. if (m_bStatic)
  339. ret = "static " + ret;
  340. if (m_bVirtual || m_bPureVirtual)
  341. ret = "virtual " + ret;
  342. if (m_bPureVirtual)
  343. ret += " = 0";
  344. if (m_bDeprecated && bDeprecated)
  345. ret += " [deprecated]";
  346. if (bAccessSpec)
  347. {
  348. switch (m_access)
  349. {
  350. case wxMAS_PUBLIC:
  351. ret += " [public]";
  352. break;
  353. case wxMAS_PROTECTED:
  354. ret += " [protected]";
  355. break;
  356. case wxMAS_PRIVATE:
  357. ret += " [private]";
  358. break;
  359. }
  360. }
  361. return ret;
  362. }
  363. void wxMethod::Dump(wxTextOutputStream& stream) const
  364. {
  365. stream << "[" + m_retType.GetAsString() + "]";
  366. stream << "[" + m_strName + "]";
  367. for (unsigned int i=0; i<m_args.GetCount(); i++)
  368. stream << "[" + m_args[i].GetAsString() + " " + m_args[i].GetArgumentName() +
  369. "=" + m_args[i].GetDefaultValue() + "]";
  370. if (IsConst())
  371. stream << " CONST";
  372. if (IsStatic())
  373. stream << " STATIC";
  374. if (IsVirtual())
  375. stream << " VIRTUAL";
  376. if (IsPureVirtual())
  377. stream << " PURE-VIRTUAL";
  378. if (IsDeprecated())
  379. stream << " DEPRECATED";
  380. // no final newline
  381. }
  382. // ----------------------------------------------------------------------------
  383. // wxClass
  384. // ----------------------------------------------------------------------------
  385. wxString wxClass::GetNameWithoutTemplate() const
  386. {
  387. // NB: I'm not sure this is the right terminology for this function!
  388. if (m_strName.Contains("<"))
  389. return m_strName.Left(m_strName.Find("<"));
  390. return m_strName;
  391. }
  392. bool wxClass::IsValidCtorForThisClass(const wxMethod& m) const
  393. {
  394. // remember that e.g. the ctor for wxWritableCharTypeBuffer<wchar_t> is
  395. // named wxWritableCharTypeBuffer, without the <...> part!
  396. if (m.IsCtor() && m.GetName() == GetNameWithoutTemplate())
  397. return true;
  398. return false;
  399. }
  400. bool wxClass::IsValidDtorForThisClass(const wxMethod& m) const
  401. {
  402. if (m.IsDtor() && m.GetName() == "~" + GetNameWithoutTemplate())
  403. return true;
  404. return false;
  405. }
  406. void wxClass::Dump(wxTextOutputStream& out) const
  407. {
  408. out << m_strName + "\n";
  409. for (unsigned int i=0; i<m_methods.GetCount(); i++) {
  410. // dump all our methods
  411. out << "|- ";
  412. m_methods[i].Dump(out);
  413. out << "\n";
  414. }
  415. out << "\n";
  416. }
  417. bool wxClass::CheckConsistency() const
  418. {
  419. for (unsigned int i=0; i<m_methods.GetCount(); i++)
  420. for (unsigned int j=0; j<m_methods.GetCount(); j++)
  421. if (i!=j && m_methods[i] == m_methods[j])
  422. {
  423. wxLogError("class %s has two methods with the same prototype: '%s'",
  424. m_strName, m_methods[i].GetAsString());
  425. return false;
  426. // fix the problem?
  427. //((wxClass*)this)->m_methods.RemoveAt(j);
  428. //j--;
  429. }
  430. return true;
  431. }
  432. const wxMethod* wxClass::FindMethod(const wxMethod& m) const
  433. {
  434. for (unsigned int i=0; i<m_methods.GetCount(); i++)
  435. if (m_methods[i] == m)
  436. return &m_methods[i];
  437. return NULL;
  438. }
  439. const wxMethod* wxClass::RecursiveUpwardFindMethod(const wxMethod& m,
  440. const wxXmlInterface* allclasses) const
  441. {
  442. // first, search into *this
  443. const wxMethod* ret = FindMethod(m);
  444. if (ret)
  445. return ret;
  446. // then, search into its parents
  447. for (unsigned int i=0; i<m_parents.GetCount(); i++)
  448. {
  449. // ignore non-wx-classes parents
  450. // AD-HOC FIX: discard wxScrolledT_Helper parent as it always gives errors
  451. if (m_parents[i].StartsWith("wx") && m_parents[i] != "wxScrolledT_Helper")
  452. {
  453. const wxClass *parent = allclasses->FindClass(m_parents[i]);
  454. if (!parent) {
  455. wxLogError("Could not find parent '%s' of class '%s'...",
  456. m_parents[i], GetName());
  457. return false;
  458. }
  459. const wxMethod *parentMethod = parent->RecursiveUpwardFindMethod(m, allclasses);
  460. if (parentMethod)
  461. return parentMethod;
  462. }
  463. }
  464. // could not find anything even in parent classes...
  465. return NULL;
  466. }
  467. wxMethodPtrArray wxClass::FindMethodsNamed(const wxString& name) const
  468. {
  469. wxMethodPtrArray ret;
  470. for (unsigned int i=0; i<m_methods.GetCount(); i++)
  471. if (m_methods[i].GetName() == name)
  472. ret.Add(&m_methods[i]);
  473. return ret;
  474. }
  475. wxMethodPtrArray wxClass::RecursiveUpwardFindMethodsNamed(const wxString& name,
  476. const wxXmlInterface* allclasses) const
  477. {
  478. // first, search into *this
  479. wxMethodPtrArray ret = FindMethodsNamed(name);
  480. if (ret.GetCount()>0)
  481. return ret; // stop here, don't look upward in the parents
  482. // then, search into parents of this class
  483. for (unsigned int i=0; i<m_parents.GetCount(); i++)
  484. {
  485. // AD-HOC FIX: discard wxScrolledT_Helper parent as it always gives errors
  486. if (m_parents[i].StartsWith("wx") && m_parents[i] != "wxScrolledT_Helper")
  487. {
  488. const wxClass *parent = allclasses->FindClass(m_parents[i]);
  489. if (!parent) {
  490. wxLogError("Could not find parent '%s' of class '%s'...",
  491. m_parents[i], GetName());
  492. return false;
  493. }
  494. wxMethodPtrArray temp = parent->RecursiveUpwardFindMethodsNamed(name, allclasses);
  495. WX_APPEND_ARRAY(ret, temp);
  496. }
  497. }
  498. return ret;
  499. }
  500. // ----------------------------------------------------------------------------
  501. // wxXmlInterface
  502. // ----------------------------------------------------------------------------
  503. WX_DEFINE_SORTED_ARRAY(wxClass*, wxSortedClassArray);
  504. int CompareWxClassObjects(wxClass *item1, wxClass *item2)
  505. {
  506. // sort alphabetically
  507. return item1->GetName().Cmp(item2->GetName());
  508. }
  509. void wxXmlInterface::Dump(const wxString& filename)
  510. {
  511. wxFFileOutputStream apioutput( filename );
  512. wxTextOutputStream apiout( apioutput );
  513. // dump the classes in alphabetical order
  514. wxSortedClassArray sorted(CompareWxClassObjects);
  515. sorted.Alloc(m_classes.GetCount());
  516. unsigned i;
  517. for (i=0; i<m_classes.GetCount(); i++)
  518. sorted.Add(&m_classes[i]);
  519. // now they have been sorted
  520. for (i=0; i<sorted.GetCount(); i++)
  521. sorted[i]->Dump(apiout);
  522. }
  523. bool wxXmlInterface::CheckConsistency() const
  524. {
  525. // this check can be quite slow, so do it only for debug releases:
  526. //#ifdef __WXDEBUG__
  527. for (unsigned int i=0; i<m_classes.GetCount(); i++)
  528. {
  529. if (!m_classes[i].CheckConsistency())
  530. return false;
  531. for (unsigned int j=0; j<m_classes.GetCount(); j++)
  532. if (i!=j && m_classes[i].GetName() == m_classes[j].GetName())
  533. {
  534. wxLogError("two classes have the same name: %s",
  535. m_classes[i].GetName());
  536. return false;
  537. }
  538. }
  539. //#endif
  540. return true;
  541. }
  542. wxClassPtrArray wxXmlInterface::FindClassesDefinedIn(const wxString& headerfile) const
  543. {
  544. wxClassPtrArray ret;
  545. for (unsigned int i=0; i<m_classes.GetCount(); i++)
  546. if (m_classes[i].GetHeader() == headerfile)
  547. ret.Add(&m_classes[i]);
  548. return ret;
  549. }
  550. // ----------------------------------------------------------------------------
  551. // wxXmlGccInterface helper declarations
  552. // ----------------------------------------------------------------------------
  553. // or-able flags for a toResolveTypeItem->attrib:
  554. #define ATTRIB_CONST 1
  555. #define ATTRIB_REFERENCE 2
  556. #define ATTRIB_POINTER 4
  557. #define ATTRIB_ARRAY 8
  558. // it may sound strange but gccxml, in order to produce shorter ID names
  559. // uses (after the underscore) characters in range 0-9 and a-z in the ID names;
  560. // in order to be able to translate such strings into numbers using strtoul()
  561. // we use as base 10 (possible digits) + 25 (possible characters) = 35
  562. #define GCCXML_BASE 35
  563. class toResolveTypeItem
  564. {
  565. public:
  566. toResolveTypeItem() { attribs=0; }
  567. toResolveTypeItem(unsigned int refID, unsigned int attribint)
  568. : ref(refID), attribs(attribint) {}
  569. unsigned long ref, // the referenced type's ID
  570. attribs; // the attributes of this reference
  571. };
  572. #if 1
  573. // for wxToResolveTypeHashMap, keys == gccXML IDs and values == toResolveTypeItem
  574. WX_DECLARE_HASH_MAP( unsigned long, toResolveTypeItem,
  575. wxIntegerHash, wxIntegerEqual,
  576. wxToResolveTypeHashMap );
  577. // for wxClassMemberIdHashMap, keys == gccXML IDs and values == wxClass which owns that member ID
  578. WX_DECLARE_HASH_MAP( unsigned long, wxClass*,
  579. wxIntegerHash, wxIntegerEqual,
  580. wxClassMemberIdHashMap );
  581. #else
  582. #include <map>
  583. typedef std::map<unsigned long, toResolveTypeItem> wxToResolveTypeHashMap;
  584. #endif
  585. // utility to parse gccXML ID values;
  586. // this function is equivalent to wxString(str).Mid(1).ToULong(&id, GCCXML_BASE)
  587. // but is a little bit faster
  588. bool getID(unsigned long *id, const wxString& str)
  589. {
  590. const wxStringCharType * const start = str.wx_str()+1;
  591. wxStringCharType *end;
  592. #if wxUSE_UNICODE_WCHAR
  593. unsigned long val = wcstoul(start, &end, GCCXML_BASE);
  594. #else
  595. unsigned long val = strtoul(start, &end, GCCXML_BASE);
  596. #endif
  597. // return true only if scan was stopped by the terminating NUL and
  598. // if the string was not empty to start with and no under/overflow
  599. // occurred:
  600. if ( *end != '\0' || end == start || errno == ERANGE || errno == EINVAL )
  601. return false;
  602. *id = val;
  603. return true;
  604. }
  605. // utility specialized to parse efficiently the gccXML list of IDs which occur
  606. // in nodes like <Class> ones... i.e. numeric values separated by " _" token
  607. bool getMemberIDs(wxClassMemberIdHashMap* map, wxClass* p, const wxString& str)
  608. {
  609. const wxStringCharType * const start = str.wx_str();
  610. #if wxUSE_UNICODE_WCHAR
  611. size_t len = wcslen(start);
  612. #else
  613. size_t len = strlen(start);
  614. #endif
  615. if (len == 0 || start[0] != '_')
  616. return false;
  617. const wxStringCharType *curpos = start,
  618. *end = start + len;
  619. wxStringCharType *nexttoken;
  620. while (curpos < end)
  621. {
  622. // curpos always points to the underscore of the next token to parse:
  623. #if wxUSE_UNICODE_WCHAR
  624. unsigned long id = wcstoul(curpos+1, &nexttoken, GCCXML_BASE);
  625. #else
  626. unsigned long id = strtoul(curpos+1, &nexttoken, GCCXML_BASE);
  627. #endif
  628. if ( *nexttoken != ' ' || errno == ERANGE || errno == EINVAL )
  629. return false;
  630. // advance current position
  631. curpos = nexttoken + 1;
  632. // add this ID to the hashmap
  633. wxClassMemberIdHashMap::value_type v(id, p);
  634. map->insert(v);
  635. }
  636. return true;
  637. }
  638. // ----------------------------------------------------------------------------
  639. // wxXmlGccInterface
  640. // ----------------------------------------------------------------------------
  641. bool wxXmlGccInterface::Parse(const wxString& filename)
  642. {
  643. wxXmlDocument doc;
  644. wxXmlNode *child;
  645. int nodes = 0;
  646. wxLogMessage("Parsing %s...", filename);
  647. if (!doc.Load(filename)) {
  648. wxLogError("can't load %s", filename);
  649. return false;
  650. }
  651. // start processing the XML file
  652. if (doc.GetRoot()->GetName() != "GCC_XML") {
  653. wxLogError("invalid root node for %s", filename);
  654. return false;
  655. }
  656. wxString version = doc.GetRoot()->GetAttribute("cvs_revision");
  657. bool old = false;
  658. #define MIN_REVISION 120
  659. if (!version.StartsWith("1."))
  660. old = true;
  661. if (!old)
  662. {
  663. unsigned long rev = 0;
  664. if (!version.Mid(2).ToULong(&rev))
  665. old = true;
  666. else
  667. if (rev < MIN_REVISION)
  668. old = true;
  669. }
  670. if (old)
  671. {
  672. wxLogError("The version of GCC-XML used for the creation of %s is too old; "
  673. "the cvs_revision attribute of the root node reports '%s', "
  674. "minimal required is 1.%d.", filename, version, MIN_REVISION);
  675. return false;
  676. }
  677. wxToResolveTypeHashMap toResolveTypes;
  678. wxClassMemberIdHashMap members;
  679. wxTypeIdHashMap types;
  680. wxTypeIdHashMap files;
  681. wxTypeIdHashMap typedefs;
  682. // prealloc quite a lot of memory!
  683. m_classes.Alloc(ESTIMATED_NUM_CLASSES);
  684. // build a list of wx classes and in general of all existent types
  685. child = doc.GetRoot()->GetChildren();
  686. while (child)
  687. {
  688. const wxString& n = child->GetName();
  689. unsigned long id = 0;
  690. if (!getID(&id, child->GetAttribute("id")) || (id == 0 && n != "File")) {
  691. // NOTE: <File> nodes can have an id == "f0"...
  692. wxLogError("Invalid id for node %s: %s", n, child->GetAttribute("id"));
  693. return false;
  694. }
  695. if (n == "Class")
  696. {
  697. wxString cname = child->GetAttribute("name");
  698. if (cname.IsEmpty()) {
  699. wxLogError("Invalid empty name for '%s' node", n);
  700. return false;
  701. }
  702. // only register wx classes (do remember also the IDs of their members)
  703. if (cname.StartsWith("wx"))
  704. {
  705. // NB: "file" attribute contains an ID value that we'll resolve later
  706. m_classes.Add(wxClass(cname, child->GetAttribute("file")));
  707. // the just-inserted class:
  708. wxClass *newClass = &m_classes.Last();
  709. // now get a list of the base classes:
  710. wxXmlNode *baseNode = child->GetChildren();
  711. while (baseNode)
  712. {
  713. // for now we store as "parents" only the parent IDs...
  714. // later we will resolve them into full class names
  715. if (baseNode->GetName() == "Base")
  716. newClass->AddParent(baseNode->GetAttribute("type"));
  717. baseNode = baseNode->GetNext();
  718. }
  719. const wxString& ids = child->GetAttribute("members");
  720. if (ids.IsEmpty())
  721. {
  722. if (child->GetAttribute("incomplete") != "1") {
  723. wxLogError("Invalid member IDs for '%s' class node: %s",
  724. cname, child->GetAttribute("id"));
  725. return false;
  726. }
  727. //else: don't warn the user; it looks like "incomplete" classes
  728. // never have any member...
  729. }
  730. else
  731. {
  732. // decode the non-empty list of IDs:
  733. if (!getMemberIDs(&members, newClass, ids)) {
  734. wxLogError("Invalid member IDs for '%s' class node: %s",
  735. cname, child->GetAttribute("id"));
  736. return false;
  737. }
  738. }
  739. }
  740. // register this class also as possible return/argument type:
  741. types[id] = cname;
  742. }
  743. else if (n == "Typedef")
  744. {
  745. unsigned long typeId = 0;
  746. if (!getID(&typeId, child->GetAttribute("type"))) {
  747. wxLogError("Invalid type for node %s: %s", n, child->GetAttribute("type"));
  748. return false;
  749. }
  750. // this typedef node tell us that every type referenced with the
  751. // "typeId" ID should be called with another name:
  752. wxString name = child->GetAttribute("name");
  753. // save this typedef in a separate hashmap...
  754. typedefs[typeId] = name;
  755. types[id] = name;
  756. }
  757. else if (n == "PointerType" || n == "ReferenceType" ||
  758. n == "CvQualifiedType" || n == "ArrayType")
  759. {
  760. unsigned long type = 0;
  761. if (!getID(&type, child->GetAttribute("type")) || type == 0) {
  762. wxLogError("Invalid type for node %s: %s", n, child->GetAttribute("type"));
  763. return false;
  764. }
  765. unsigned long attr = 0;
  766. if (n == "PointerType")
  767. attr = ATTRIB_POINTER;
  768. else if (n == "ReferenceType")
  769. attr = ATTRIB_REFERENCE;
  770. else if (n == "CvQualifiedType" && child->GetAttribute("const") == "1")
  771. attr = ATTRIB_CONST;
  772. else if (n == "ArrayType")
  773. attr = ATTRIB_ARRAY;
  774. // these nodes make reference to other types... we'll resolve them later
  775. toResolveTypes[id] = toResolveTypeItem(type, attr);
  776. }
  777. else if (n == "FunctionType" || n == "MethodType")
  778. {
  779. /*
  780. TODO: parsing FunctionType and MethodType nodes is not as easy
  781. as for other "simple" types.
  782. */
  783. wxString argstr;
  784. wxXmlNode *arg = child->GetChildren();
  785. while (arg)
  786. {
  787. if (arg->GetName() == "Argument")
  788. argstr += arg->GetAttribute("type") + ", ";
  789. arg = arg->GetNext();
  790. }
  791. if (argstr.Len() > 0)
  792. argstr = argstr.Left(argstr.Len()-2); // remove final comma
  793. // these nodes make reference to other types... we'll resolve them later
  794. //toResolveTypes[id] = toResolveTypeItem(ret, 0);
  795. //types[id] = child->GetAttribute("returns") + "(" + argstr + ")";
  796. types[id] = "TOFIX"; // typically this type will be "fixed" thanks
  797. // to a typedef later...
  798. }
  799. else if (n == "File")
  800. {
  801. if (!child->GetAttribute("id").StartsWith("f")) {
  802. wxLogError("Unexpected file ID: %s", child->GetAttribute("id"));
  803. return false;
  804. }
  805. // just ignore this node... all file IDs/names were already parsed
  806. files[id] = child->GetAttribute("name");
  807. }
  808. else
  809. {
  810. // we register everything else as a possible return/argument type:
  811. const wxString& name = child->GetAttribute("name");
  812. if (!name.IsEmpty())
  813. {
  814. //typeIds.Add(id);
  815. //typeNames.Add(name);
  816. types[id] = name;
  817. }
  818. else
  819. {
  820. // this may happen with unnamed structs/union, special ctors,
  821. // or other exotic things which we are not interested to, since
  822. // they're never used as return/argument types by wxWidgets methods
  823. if (g_verbose)
  824. {
  825. wxLogWarning("Type node '%s' with ID '%s' does not have name attribute",
  826. n, child->GetAttribute("id"));
  827. }
  828. types[id] = "TOFIX";
  829. }
  830. }
  831. child = child->GetNext();
  832. // give feedback to the user about the progress...
  833. if ((++nodes%PROGRESS_RATE)==0) ShowProgress();
  834. }
  835. // some nodes with IDs referenced by methods as return/argument types, do reference
  836. // in turn other nodes (see PointerType, ReferenceType and CvQualifierType above);
  837. // thus we need to resolve their name iteratively:
  838. while (toResolveTypes.size()>0)
  839. {
  840. if (g_verbose)
  841. {
  842. wxLogMessage("%d types were collected; %d types need yet to be resolved...",
  843. types.size(), toResolveTypes.size());
  844. }
  845. for (wxToResolveTypeHashMap::iterator i = toResolveTypes.begin();
  846. i != toResolveTypes.end();)
  847. {
  848. unsigned long id = i->first;
  849. unsigned long referenced = i->second.ref;
  850. wxTypeIdHashMap::iterator primary = types.find(referenced);
  851. if (primary != types.end())
  852. {
  853. // this to-resolve-type references a "primary" type
  854. wxString newtype = primary->second;
  855. int attribs = i->second.attribs;
  856. // attribs may contain a combination of ATTRIB_* flags:
  857. if (attribs & ATTRIB_CONST)
  858. newtype = "const " + newtype;
  859. if (attribs & ATTRIB_REFERENCE)
  860. newtype = newtype + "&";
  861. if (attribs & ATTRIB_POINTER)
  862. newtype = newtype + "*";
  863. if (attribs & ATTRIB_ARRAY)
  864. newtype = newtype + "[]";
  865. // add the resolved type to the list of "primary" types
  866. if (newtype.Contains("TOFIX") && typedefs[id] != "")
  867. types[id] = typedefs[id]; // better use a typedef for this type!
  868. else
  869. types[id] = newtype;
  870. // this one has been resolved; erase it through its iterator!
  871. toResolveTypes.erase(i);
  872. // now iterator i is invalid; assign it again to the beginning
  873. i = toResolveTypes.begin();
  874. }
  875. else
  876. {
  877. // then search in the referenced types themselves:
  878. wxToResolveTypeHashMap::iterator idx2 = toResolveTypes.find(referenced);
  879. if (idx2 != toResolveTypes.end())
  880. {
  881. // merge this to-resolve-type with the idx2->second type
  882. i->second.ref = idx2->second.ref;
  883. i->second.attribs |= idx2->second.attribs;
  884. // this type will eventually be solved in the next while() iteration
  885. i++;
  886. }
  887. else
  888. {
  889. wxLogError("Cannot solve '%d' reference type!", referenced);
  890. return false;
  891. }
  892. }
  893. }
  894. }
  895. // resolve header names
  896. unsigned i;
  897. for (i=0; i<m_classes.GetCount(); i++)
  898. {
  899. unsigned long fileID = 0;
  900. if (!getID(&fileID, m_classes[i].GetHeader()) || fileID == 0) {
  901. wxLogError("invalid header id: %s", m_classes[i].GetHeader());
  902. return false;
  903. }
  904. // search this file
  905. wxTypeIdHashMap::const_iterator idx = files.find(fileID);
  906. if (idx == files.end())
  907. {
  908. // this is an error!
  909. wxLogError("couldn't find file ID '%s'", m_classes[i].GetHeader());
  910. }
  911. else
  912. m_classes[i].SetHeader(idx->second);
  913. }
  914. // resolve parent names
  915. for (i=0; i<m_classes.GetCount(); i++)
  916. {
  917. for (unsigned int k=0; k<m_classes[i].GetParentCount(); k++)
  918. {
  919. unsigned long id;
  920. if (!getID(&id, m_classes[i].GetParent(k))) {
  921. wxLogError("invalid parent class ID for '%s'", m_classes[i].GetName());
  922. return false;
  923. }
  924. wxTypeIdHashMap::const_iterator idx = types.find(id);
  925. if (idx == types.end())
  926. {
  927. // this is an error!
  928. wxLogError("couldn't find parent class ID '%d'", id);
  929. }
  930. else
  931. // replace k-th parent with its true name:
  932. m_classes[i].SetParent(k, idx->second);
  933. }
  934. }
  935. // build the list of the wx methods
  936. child = doc.GetRoot()->GetChildren();
  937. while (child)
  938. {
  939. wxString n = child->GetName(), acc = child->GetAttribute("access");
  940. // only register public&protected methods
  941. if ((acc == "public" || acc == "protected") &&
  942. (n == "Method" || n == "Constructor" || n == "Destructor" || n == "OperatorMethod"))
  943. {
  944. unsigned long id = 0;
  945. if (!getID(&id, child->GetAttribute("id"))) {
  946. wxLogError("invalid ID for node '%s' with ID '%s'", n, child->GetAttribute("id"));
  947. return false;
  948. }
  949. wxClassMemberIdHashMap::const_iterator it = members.find(id);
  950. if (it != members.end())
  951. {
  952. wxClass *p = it->second;
  953. // this <Method> node is a method of the i-th class!
  954. wxMethod newfunc;
  955. if (!ParseMethod(child, types, newfunc)) {
  956. wxLogError("The method '%s' could not be added to class '%s'",
  957. child->GetAttribute("demangled"), p->GetName());
  958. return false;
  959. }
  960. // do some additional check that we can do only here:
  961. if (newfunc.IsCtor() && !p->IsValidCtorForThisClass(newfunc)) {
  962. wxLogError("The method '%s' does not seem to be a ctor for '%s'",
  963. newfunc.GetName(), p->GetName());
  964. return false;
  965. }
  966. if (newfunc.IsDtor() && !p->IsValidDtorForThisClass(newfunc)) {
  967. wxLogError("The method '%s' does not seem to be a dtor for '%s'",
  968. newfunc.GetName(), p->GetName());
  969. return false;
  970. }
  971. p->AddMethod(newfunc);
  972. }
  973. }
  974. child = child->GetNext();
  975. // give feedback to the user about the progress...
  976. if ((++nodes%PROGRESS_RATE)==0) ShowProgress();
  977. }
  978. if (!CheckConsistency())
  979. return false; // the check failed
  980. return true;
  981. }
  982. bool wxXmlGccInterface::ParseMethod(const wxXmlNode *p,
  983. const wxTypeIdHashMap& types,
  984. wxMethod& m)
  985. {
  986. // get the real name
  987. wxString name = p->GetAttribute("name").Strip(wxString::both);
  988. if (p->GetName() == "Destructor")
  989. name = "~" + name;
  990. else if (p->GetName() == "OperatorMethod")
  991. name = "operator" + name;
  992. // resolve return type
  993. wxType ret;
  994. unsigned long retid = 0;
  995. if (!getID(&retid, p->GetAttribute("returns")) || retid == 0)
  996. {
  997. if (p->GetName() != "Destructor" && p->GetName() != "Constructor") {
  998. wxLogError("Empty return ID for method '%s', with ID '%s'",
  999. name, p->GetAttribute("id"));
  1000. return false;
  1001. }
  1002. }
  1003. else
  1004. {
  1005. wxTypeIdHashMap::const_iterator retidx = types.find(retid);
  1006. if (retidx == types.end()) {
  1007. wxLogError("Could not find return type ID '%s'", retid);
  1008. return false;
  1009. }
  1010. ret = wxType(retidx->second);
  1011. if (!ret.IsOk()) {
  1012. wxLogError("Invalid return type '%s' for method '%s', with ID '%s'",
  1013. retidx->second, name, p->GetAttribute("id"));
  1014. return false;
  1015. }
  1016. }
  1017. // resolve argument types
  1018. wxArgumentTypeArray argtypes;
  1019. wxXmlNode *arg = p->GetChildren();
  1020. while (arg)
  1021. {
  1022. if (arg->GetName() == "Argument")
  1023. {
  1024. unsigned long id = 0;
  1025. if (!getID(&id, arg->GetAttribute("type")) || id == 0) {
  1026. wxLogError("Invalid argument type ID '%s' for method '%s' with ID %s",
  1027. arg->GetAttribute("type"), name, p->GetAttribute("id"));
  1028. return false;
  1029. }
  1030. wxTypeIdHashMap::const_iterator idx = types.find(id);
  1031. if (idx == types.end()) {
  1032. wxLogError("Could not find argument type ID '%s'", id);
  1033. return false;
  1034. }
  1035. argtypes.Add(wxArgumentType(idx->second,
  1036. arg->GetAttribute("default"),
  1037. arg->GetAttribute("name")));
  1038. }
  1039. arg = arg->GetNext();
  1040. }
  1041. m.SetReturnType(ret);
  1042. m.SetName(name);
  1043. m.SetArgumentTypes(argtypes);
  1044. m.SetConst(p->GetAttribute("const") == "1");
  1045. m.SetStatic(p->GetAttribute("static") == "1");
  1046. // NOTE: gccxml is smart enough to mark as virtual those functions
  1047. // which are declared virtual in base classes but don't have
  1048. // the "virtual" keyword explicitly indicated in the derived
  1049. // classes... so we don't need any further logic for virtuals
  1050. m.SetVirtual(p->GetAttribute("virtual") == "1");
  1051. m.SetPureVirtual(p->GetAttribute("pure_virtual") == "1");
  1052. m.SetDeprecated(p->GetAttribute("attributes") == "deprecated");
  1053. // decode access specifier
  1054. if (p->GetAttribute("access") == "public")
  1055. m.SetAccessSpecifier(wxMAS_PUBLIC);
  1056. else if (p->GetAttribute("access") == "protected")
  1057. m.SetAccessSpecifier(wxMAS_PROTECTED);
  1058. else if (p->GetAttribute("access") == "private")
  1059. m.SetAccessSpecifier(wxMAS_PRIVATE);
  1060. if (!m.IsOk()) {
  1061. wxLogError("The prototype '%s' is not valid!", m.GetAsString());
  1062. return false;
  1063. }
  1064. return true;
  1065. }
  1066. // ----------------------------------------------------------------------------
  1067. // wxXmlDoxygenInterface global helpers
  1068. // ----------------------------------------------------------------------------
  1069. static wxString GetTextFromChildren(const wxXmlNode *n)
  1070. {
  1071. wxString text;
  1072. // consider the tree
  1073. //
  1074. // <a><b>this</b> is a <b>string</b></a>
  1075. //
  1076. // <a>
  1077. // |- <b>
  1078. // | |- this
  1079. // |- is a
  1080. // |- <b>
  1081. // |- string
  1082. //
  1083. // unlike wxXmlNode::GetNodeContent() which would return " is a "
  1084. // this function returns "this is a string"
  1085. wxXmlNode *ref = n->GetChildren();
  1086. while (ref) {
  1087. if (ref->GetType() == wxXML_ELEMENT_NODE)
  1088. text += ref->GetNodeContent();
  1089. else if (ref->GetType() == wxXML_TEXT_NODE)
  1090. text += ref->GetContent();
  1091. else
  1092. wxLogWarning("Unexpected node type while getting text from '%s' node", n->GetName());
  1093. ref = ref->GetNext();
  1094. }
  1095. return text;
  1096. }
  1097. static bool HasTextNodeContaining(const wxXmlNode *parent, const wxString& name)
  1098. {
  1099. if (!parent)
  1100. return false;
  1101. wxXmlNode *p = parent->GetChildren();
  1102. while (p)
  1103. {
  1104. switch (p->GetType())
  1105. {
  1106. case wxXML_TEXT_NODE:
  1107. if (p->GetContent() == name)
  1108. return true;
  1109. break;
  1110. case wxXML_ELEMENT_NODE:
  1111. // recurse into this node...
  1112. if (HasTextNodeContaining(p, name))
  1113. return true;
  1114. break;
  1115. default:
  1116. // skip it
  1117. break;
  1118. }
  1119. p = p->GetNext();
  1120. }
  1121. return false;
  1122. }
  1123. static const wxXmlNode* FindNodeNamed(const wxXmlNode* parent, const wxString& name)
  1124. {
  1125. if (!parent)
  1126. return NULL;
  1127. const wxXmlNode *p = parent->GetChildren();
  1128. while (p)
  1129. {
  1130. if (p->GetName() == name)
  1131. return p; // found!
  1132. // search recursively in the children of this node
  1133. const wxXmlNode *ret = FindNodeNamed(p, name);
  1134. if (ret)
  1135. return ret;
  1136. p = p->GetNext();
  1137. }
  1138. return NULL;
  1139. }
  1140. int GetAvailabilityFor(const wxXmlNode *node)
  1141. {
  1142. // identify <onlyfor> custom XML tags
  1143. const wxXmlNode* onlyfor = FindNodeNamed(node, "onlyfor");
  1144. if (!onlyfor)
  1145. return wxPORT_UNKNOWN;
  1146. wxArrayString ports = wxSplit(onlyfor->GetNodeContent(), ',');
  1147. int nAvail = wxPORT_UNKNOWN;
  1148. for (unsigned int i=0; i < ports.GetCount(); i++)
  1149. {
  1150. if (!ports[i].StartsWith("wx")) {
  1151. wxLogError("unexpected port ID '%s'", ports[i]);
  1152. return false;
  1153. }
  1154. nAvail |= wxPlatformInfo::GetPortId(ports[i].Mid(2));
  1155. }
  1156. return nAvail;
  1157. }
  1158. // ----------------------------------------------------------------------------
  1159. // wxXmlDoxygenInterface
  1160. // ----------------------------------------------------------------------------
  1161. bool wxXmlDoxygenInterface::Parse(const wxString& filename)
  1162. {
  1163. wxXmlDocument index;
  1164. wxXmlNode *compound;
  1165. wxLogMessage("Parsing %s...", filename);
  1166. if (!index.Load(filename)) {
  1167. wxLogError("can't load %s", filename);
  1168. return false;
  1169. }
  1170. // start processing the index:
  1171. if (index.GetRoot()->GetName() != "doxygenindex") {
  1172. wxLogError("invalid root node for %s", filename);
  1173. return false;
  1174. }
  1175. /*
  1176. NB: we may need in future to do a version-check here if the
  1177. format of the XML generated by doxygen changes.
  1178. For now (doxygen version 1.5.5), this check is not required
  1179. since AFAIK the XML format never changed since it was introduced.
  1180. */
  1181. m_classes.Alloc(ESTIMATED_NUM_CLASSES);
  1182. // process files referenced by this index file
  1183. compound = index.GetRoot()->GetChildren();
  1184. while (compound)
  1185. {
  1186. if (compound->GetName() == "compound" &&
  1187. compound->GetAttribute("kind") == "class")
  1188. {
  1189. wxString refid = compound->GetAttribute("refid");
  1190. wxFileName fn(filename);
  1191. if (!ParseCompoundDefinition(fn.GetPath(wxPATH_GET_SEPARATOR) + refid + ".xml"))
  1192. return false;
  1193. }
  1194. compound = compound->GetNext();
  1195. }
  1196. //wxPrint("\n");
  1197. if (!CheckConsistency())
  1198. return false; // the check failed
  1199. return true;
  1200. }
  1201. bool wxXmlDoxygenInterface::ParseCompoundDefinition(const wxString& filename)
  1202. {
  1203. wxClassMemberIdHashMap parents;
  1204. wxXmlDocument doc;
  1205. wxXmlNode *child;
  1206. int nodes = 0;
  1207. if (g_verbose)
  1208. {
  1209. wxLogMessage("Parsing %s...", filename);
  1210. }
  1211. if (!doc.Load(filename)) {
  1212. wxLogError("can't load %s", filename);
  1213. return false;
  1214. }
  1215. // start processing this compound definition XML
  1216. if (doc.GetRoot()->GetName() != "doxygen") {
  1217. wxLogError("invalid root node for %s", filename);
  1218. return false;
  1219. }
  1220. // build a list of wx classes
  1221. child = doc.GetRoot()->GetChildren();
  1222. while (child)
  1223. {
  1224. if (child->GetName() == "compounddef" &&
  1225. child->GetAttribute("kind") == "class")
  1226. {
  1227. // parse this class
  1228. wxClass klass;
  1229. wxString absoluteFile, header;
  1230. wxXmlNode *subchild = child->GetChildren();
  1231. while (subchild)
  1232. {
  1233. // NOTE: when documenting functions using the //@{ and //@}
  1234. // tags to create function groups, doxygen puts the
  1235. // contained methods into a "user-defined" section
  1236. // so we _must_ use the "prot" attribute to distinguish
  1237. // public/protected methods from private ones and cannot
  1238. // rely on the kind="public" attribute of <sectiondef>
  1239. if (subchild->GetName() == "sectiondef")
  1240. {
  1241. wxXmlNode *membernode = subchild->GetChildren();
  1242. while (membernode)
  1243. {
  1244. const wxString& accessSpec = membernode->GetAttribute("prot");
  1245. // parse only public&protected functions:
  1246. if (membernode->GetName() == "memberdef" &&
  1247. membernode->GetAttribute("kind") == "function" &&
  1248. (accessSpec == "public" || accessSpec == "protected"))
  1249. {
  1250. wxMethod m;
  1251. if (!ParseMethod(membernode, m, header)) {
  1252. wxLogError("The method '%s' could not be added to class '%s'",
  1253. m.GetName(), klass.GetName());
  1254. return false;
  1255. }
  1256. if (accessSpec == "public")

Large files files are truncated, but you can click here to view the full file