/Src/Dependencies/Boost/libs/geometry/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml_parser.hpp

http://hadesmem.googlecode.com/ · C++ Header · 538 lines · 435 code · 49 blank · 54 comment · 194 complexity · 98b9bda834f5286f9fefd1775e09f83e MD5 · raw file

  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. //
  3. // Copyright (c) 2010-2011 Barend Gehrels, Amsterdam, the Netherlands.
  4. // Use, modification and distribution is subject to the Boost Software License,
  5. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. //
  9. #ifndef DOXYGEN_XML_PARSER_HPP
  10. #define DOXYGEN_XML_PARSER_HPP
  11. #include <string>
  12. #include <vector>
  13. #include <boost/algorithm/string.hpp>
  14. #include <rapidxml_util.hpp>
  15. #include <doxygen_elements.hpp>
  16. #include <parameter_predicates.hpp>
  17. #include <configuration.hpp>
  18. inline std::string keep_after(std::string const& input, std::string const& sig)
  19. {
  20. std::size_t pos = input.rfind(sig);
  21. if (pos != std::string::npos)
  22. {
  23. std::string copy = input.substr(pos + sig.length());
  24. return copy;
  25. }
  26. return input;
  27. }
  28. static inline void add_or_set(std::vector<parameter>& parameters, parameter const& p)
  29. {
  30. std::vector<parameter>::iterator it = std::find_if(parameters.begin(), parameters.end(), par_by_name(p.name));
  31. if (it != parameters.end())
  32. {
  33. if (it->brief_description.empty()) it->brief_description = p.brief_description;
  34. if (it->type.empty()) it->type = p.type;
  35. if (it->fulltype.empty()) it->fulltype = p.fulltype;
  36. if (it->default_value.empty()) it->default_value = p.default_value;
  37. }
  38. else
  39. {
  40. parameters.push_back(p);
  41. }
  42. }
  43. /// Parses a "para" element
  44. /*
  45. This is used for different purposes within Doxygen.
  46. - Either a detailed description, possibly containing several sections (para's)
  47. -> so parse next siblings
  48. - Or a detailed description also containing qbk records
  49. So we have to list explicitly either where to recurse, or where not to...
  50. */
  51. static void parse_para(rapidxml::xml_node<>* node, std::string& contents, bool& skip, bool first = true)
  52. {
  53. if (node != NULL)
  54. {
  55. if (node->type() == rapidxml::node_element)
  56. {
  57. //std::cout << "ELEMENT: " << node->name() << "=" << node->value() << std::endl;
  58. std::string name = node->name();
  59. if (boost::equals(name, "qbk.skip"))
  60. {
  61. skip = true;
  62. return;
  63. }
  64. else if (! (
  65. (boost::equals(name, "para") && first)
  66. || boost::equals(name, "ref")
  67. || boost::equals(name, "defval")
  68. || boost::equals(name, "verbatim")
  69. || boost::equals(name, "bold")
  70. || boost::equals(name, "emphasis")
  71. || boost::equals(name, "linebreak")
  72. ))
  73. {
  74. return;
  75. }
  76. }
  77. else if (node->type() == rapidxml::node_data)
  78. {
  79. contents += node->value();
  80. //std::cout << "DATA: " << node->name() << "=" << node->value() << std::endl;
  81. }
  82. else
  83. {
  84. //std::cout << "OTHER: " << node->name() << "=" << node->value() << std::endl;
  85. }
  86. parse_para(node->first_node(), contents, skip, false);
  87. parse_para(node->next_sibling(), contents, skip, false);
  88. }
  89. }
  90. static void parse_parameter(rapidxml::xml_node<>* node, parameter& p)
  91. {
  92. // #define: <param><defname>Point</defname></param>
  93. // template: <param><type>typename</type><declname>CoordinateType</declname><defname>CoordinateType</defname></param>
  94. // template with default: <param><type>typename</type><declname>CoordinateSystem</declname><defname>CoordinateSystem</defname><defval><ref ....>cs::cartesian</ref></defval></param>
  95. // with enum: <type><ref refid="group__enum_1ga7d33eca9a5389952bdf719972eb802b6" kindref="member">closure_selector</ref></type>
  96. if (node != NULL)
  97. {
  98. std::string name = node->name();
  99. if (name == "type")
  100. {
  101. get_contents(node->first_node(), p.fulltype);
  102. p.type = p.fulltype;
  103. boost::replace_all(p.type, " const", "");
  104. boost::trim(p.type);
  105. boost::replace_all(p.type, "&", "");
  106. boost::replace_all(p.type, "*", "");
  107. boost::trim(p.type);
  108. }
  109. else if (name == "declname") p.name = node->value();
  110. else if (name == "parametername") p.name = node->value();
  111. else if (name == "defname") p.name = node->value();
  112. else if (name == "defval")
  113. {
  114. parse_para(node, p.default_value, p.skip);
  115. }
  116. else if (name == "para")
  117. {
  118. parse_para(node, p.brief_description, p.skip);
  119. }
  120. parse_parameter(node->first_node(), p);
  121. parse_parameter(node->next_sibling(), p);
  122. }
  123. }
  124. static void parse_enumeration_value(rapidxml::xml_node<>* node, enumeration_value& value)
  125. {
  126. // <enumvalue><name>green</name><initializer> 2</initializer>
  127. // <briefdescription><para>...</para></briefdescription>
  128. // <detaileddescription><para>...</para></detaileddescription>
  129. // </enumvalue>
  130. if (node != NULL)
  131. {
  132. std::string node_name = node->name();
  133. if (node_name == "name") value.name = node->value();
  134. else if (node_name == "para")
  135. {
  136. // Parses both brief AND detailed into this description
  137. parse_para(node, value.brief_description, value.skip);
  138. }
  139. else if (node_name == "initializer")
  140. {
  141. value.initializer = node->value();
  142. }
  143. parse_enumeration_value(node->first_node(), value);
  144. parse_enumeration_value(node->next_sibling(), value);
  145. }
  146. }
  147. // Definition is a function or a class/struct
  148. template <typename Parameters>
  149. static void parse_parameter_list(rapidxml::xml_node<>* node, Parameters& parameters)
  150. {
  151. if (node != NULL)
  152. {
  153. std::string name = node->name();
  154. if (name == "parameteritem")
  155. {
  156. parameter p;
  157. parse_parameter(node->first_node(), p);
  158. if (! p.name.empty())
  159. {
  160. // Copy its description
  161. std::vector<parameter>::iterator it = std::find_if(parameters.begin(),
  162. parameters.end(), par_by_name(p.name));
  163. if (it != parameters.end())
  164. {
  165. it->brief_description = p.brief_description;
  166. }
  167. else
  168. {
  169. parameters.push_back(p);
  170. }
  171. }
  172. }
  173. else if (name == "param")
  174. {
  175. // Element of 'templateparamlist.param (.type,.declname,.defname)'
  176. parameter p;
  177. parse_parameter(node->first_node(), p);
  178. // Doxygen handles templateparamlist param's differently:
  179. //
  180. // Case 1:
  181. // <param><type>typename T</type></param>
  182. // -> no name, assign type to name, replace typename
  183. //
  184. // Case 2:
  185. // <type>typename</type><declname>T</declname><defname>T</defname>
  186. // -> set full type
  187. if (p.name.empty())
  188. {
  189. // Case 1
  190. p.name = p.type;
  191. boost::replace_all(p.name, "typename", "");
  192. boost::trim(p.name);
  193. }
  194. else
  195. {
  196. // Case 2
  197. p.fulltype = p.type + " " + p.name;
  198. }
  199. add_or_set(parameters, p);
  200. }
  201. parse_parameter_list(node->first_node(), parameters);
  202. parse_parameter_list(node->next_sibling(), parameters);
  203. }
  204. }
  205. template <typename Element>
  206. static void parse_element(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, Element& el)
  207. {
  208. if (node != NULL)
  209. {
  210. std::string name = node->name();
  211. std::string full = parent + "." + name;
  212. if (full == ".briefdescription.para")
  213. {
  214. parse_para(node, el.brief_description, el.skip);
  215. }
  216. else if (full == ".detaileddescription.para")
  217. {
  218. std::string para;
  219. parse_para(node, para, el.skip);
  220. if (!para.empty() && !el.detailed_description.empty())
  221. {
  222. el.detailed_description += "\n\n";
  223. }
  224. el.detailed_description += para;
  225. }
  226. else if (full == ".location")
  227. {
  228. std::string loc = get_attribute(node, "file");
  229. // Location of (header)file. It is a FULL path, so find the start
  230. // and strip the rest
  231. std::size_t pos = loc.rfind(config.start_include);
  232. if (pos != std::string::npos)
  233. {
  234. loc = loc.substr(pos);
  235. }
  236. el.location = loc;
  237. el.line = atol(get_attribute(node, "line").c_str());
  238. }
  239. else if (full == ".detaileddescription.para.qbk")
  240. {
  241. el.qbk_markup.push_back(markup(node->value()));
  242. }
  243. else if (full == ".detaileddescription.para.qbk.after.synopsis")
  244. {
  245. el.qbk_markup.push_back(markup(markup_after, markup_synopsis, node->value()));
  246. }
  247. else if (full == ".detaileddescription.para.qbk.before.synopsis")
  248. {
  249. el.qbk_markup.push_back(markup(markup_before, markup_synopsis, node->value()));
  250. }
  251. else if (full == ".detaileddescription.para.qbk.distinguish")
  252. {
  253. el.additional_description = node->value();
  254. boost::trim(el.additional_description);
  255. }
  256. else if (full == ".templateparamlist")
  257. {
  258. parse_parameter_list(node->first_node(), el.template_parameters);
  259. }
  260. else if (full == ".detaileddescription.para.parameterlist")
  261. {
  262. std::string kind = get_attribute(node, "kind");
  263. if (kind == "param")
  264. {
  265. parse_parameter_list(node->first_node(), el.parameters);
  266. }
  267. else if (kind == "templateparam")
  268. {
  269. parse_parameter_list(node->first_node(), el.template_parameters);
  270. }
  271. }
  272. parse_element(node->first_node(), config, full, el);
  273. parse_element(node->next_sibling(), config, parent, el);
  274. }
  275. }
  276. static void parse_function(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, function& f)
  277. {
  278. if (node != NULL)
  279. {
  280. std::string name = node->name();
  281. std::string full = parent + "." + name;
  282. if (full == ".name") f.name = node->value();
  283. else if (full == ".argsstring") f.argsstring = node->value();
  284. else if (full == ".definition")
  285. {
  286. f.definition = node->value();
  287. if (! config.skip_namespace.empty())
  288. {
  289. boost::replace_all(f.definition, config.skip_namespace, "");
  290. }
  291. }
  292. else if (full == ".param")
  293. {
  294. parameter p;
  295. parse_parameter(node->first_node(), p);
  296. add_or_set(f.parameters, p);
  297. }
  298. else if (full == ".type")
  299. {
  300. get_contents(node->first_node(), f.return_type);
  301. }
  302. else if (full == ".detaileddescription.para.simplesect")
  303. {
  304. std::string kind = get_attribute(node, "kind");
  305. if (kind == "return")
  306. {
  307. get_contents(node->first_node(), f.return_description);
  308. }
  309. /*else if (kind == "param")
  310. {
  311. get_contents(node->first_node(), f.paragraphs);
  312. }*/
  313. }
  314. else if (full == ".detaileddescription.para.image")
  315. {
  316. }
  317. parse_function(node->first_node(), config, full, f);
  318. parse_function(node->next_sibling(), config, parent, f);
  319. }
  320. }
  321. static void parse_enumeration(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, enumeration& e)
  322. {
  323. if (node != NULL)
  324. {
  325. std::string name = node->name();
  326. std::string full = parent + "." + name;
  327. if (full == ".name") e.name = node->value();
  328. else if (full == ".enumvalue")
  329. {
  330. enumeration_value value;
  331. parse_enumeration_value(node->first_node(), value);
  332. e.enumeration_values.push_back(value);
  333. }
  334. parse_enumeration(node->first_node(), config, full, e);
  335. parse_enumeration(node->next_sibling(), config, parent, e);
  336. }
  337. }
  338. static std::string parse_named_node(rapidxml::xml_node<>* node, std::string const& look_for_name)
  339. {
  340. if (node != NULL)
  341. {
  342. std::string node_name = node->name();
  343. std::string contents;
  344. if (boost::equals(node_name, look_for_name))
  345. {
  346. contents = node->value();
  347. }
  348. return contents
  349. + parse_named_node(node->first_node(), look_for_name)
  350. + parse_named_node(node->next_sibling(), look_for_name);
  351. }
  352. return "";
  353. }
  354. static void parse(rapidxml::xml_node<>* node, configuration const& config, documentation& doc, bool member = false)
  355. {
  356. if (node != NULL)
  357. {
  358. bool recurse = false;
  359. bool is_member = member;
  360. std::string nodename = node->name();
  361. if (nodename == "doxygen")
  362. {
  363. recurse = true;
  364. }
  365. else if (nodename == "sectiondef")
  366. {
  367. std::string kind = get_attribute(node, "kind");
  368. if (kind == "func"
  369. || kind == "define"
  370. || kind == "enum"
  371. )
  372. {
  373. recurse = true;
  374. }
  375. else if (boost::starts_with(kind, "public"))
  376. {
  377. recurse = true;
  378. is_member = true;
  379. }
  380. }
  381. else if (nodename == "compounddef")
  382. {
  383. std::string kind = get_attribute(node, "kind");
  384. if (kind == "group")
  385. {
  386. recurse = true;
  387. }
  388. else if (kind == "struct")
  389. {
  390. recurse = true;
  391. doc.cos.is_class = false;
  392. parse_element(node->first_node(), config, "", doc.cos);
  393. }
  394. else if (kind == "class")
  395. {
  396. recurse = true;
  397. doc.cos.is_class = true;
  398. parse_element(node->first_node(), config, "", doc.cos);
  399. }
  400. }
  401. else if (nodename == "memberdef")
  402. {
  403. std::string kind = get_attribute(node, "kind");
  404. if (kind == "function")
  405. {
  406. function f;
  407. parse_element(node->first_node(), config, "", f);
  408. parse_function(node->first_node(), config, "", f);
  409. if (member)
  410. {
  411. f.type = boost::equals(f.name, doc.cos.name)
  412. ? function_constructor
  413. : function_member;
  414. doc.cos.functions.push_back(f);
  415. }
  416. else
  417. {
  418. f.type = function_free;
  419. doc.functions.push_back(f);
  420. }
  421. }
  422. else if (kind == "define")
  423. {
  424. function f;
  425. f.type = function_define;
  426. parse_element(node->first_node(), config, "", f);
  427. parse_function(node->first_node(), config, "", f);
  428. doc.functions.push_back(f);
  429. }
  430. else if (kind == "enum")
  431. {
  432. enumeration e;
  433. parse_element(node->first_node(), config, "", e);
  434. parse_enumeration(node->first_node(), config, "", e);
  435. doc.enumerations.push_back(e);
  436. }
  437. else if (kind == "typedef")
  438. {
  439. if (boost::equals(get_attribute(node, "prot"), "public"))
  440. {
  441. std::string name = parse_named_node(node->first_node(), "name");
  442. doc.cos.typedefs.push_back(base_element(name));
  443. }
  444. }
  445. else if (kind == "variable")
  446. {
  447. if (boost::equals(get_attribute(node, "static"), "yes")
  448. && boost::equals(get_attribute(node, "mutable"), "no")
  449. && boost::equals(get_attribute(node, "prot"), "public"))
  450. {
  451. std::string name = parse_named_node(node->first_node(), "name");
  452. doc.cos.variables.push_back(base_element(name));
  453. }
  454. }
  455. }
  456. else if (nodename == "compoundname")
  457. {
  458. std::string name = node->value();
  459. if (name.find("::") != std::string::npos)
  460. {
  461. doc.cos.fullname = name;
  462. // For a class, it should have "boost::something::" before
  463. // set its name without namespace
  464. doc.cos.name = keep_after(name, "::");
  465. }
  466. }
  467. else if (nodename == "basecompoundref")
  468. {
  469. base_class bc;
  470. bc.name = node->value();
  471. bc.derivation = get_attribute(node, "prot");
  472. bc.virtuality = get_attribute(node, "virt");
  473. doc.cos.base_classes.push_back(bc);
  474. }
  475. else
  476. {
  477. //std::cout << nodename << " ignored." << std::endl;
  478. }
  479. if (recurse)
  480. {
  481. // First recurse into childnodes, then handle next siblings
  482. parse(node->first_node(), config, doc, is_member);
  483. }
  484. parse(node->next_sibling(), config, doc, is_member);
  485. }
  486. }
  487. #endif // DOXYGEN_XML_PARSER_HPP