]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/geometry/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml_parser.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / geometry / doc / src / docutils / tools / doxygen_xml2qbk / doxygen_xml_parser.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 //
3 // Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland.
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 //
10 #ifndef DOXYGEN_XML_PARSER_HPP
11 #define DOXYGEN_XML_PARSER_HPP
12
13
14 #include <string>
15 #include <vector>
16
17 #include <boost/algorithm/string.hpp>
18
19 #include <rapidxml_util.hpp>
20 #include <doxygen_elements.hpp>
21 #include <parameter_predicates.hpp>
22 #include <configuration.hpp>
23
24
25 inline std::string keep_after(std::string const& input, std::string const& sig)
26 {
27 std::size_t pos = input.rfind(sig);
28 if (pos != std::string::npos)
29 {
30 std::string copy = input.substr(pos + sig.length());
31 return copy;
32 }
33 return input;
34 }
35
36
37 static inline void add_or_set(std::vector<parameter>& parameters, parameter const& p)
38 {
39 std::vector<parameter>::iterator it = std::find_if(parameters.begin(), parameters.end(), par_by_name(p.name));
40 if (it != parameters.end())
41 {
42 if (it->brief_description.empty()) it->brief_description = p.brief_description;
43 if (it->type.empty()) it->type = p.type;
44 if (it->fulltype.empty()) it->fulltype = p.fulltype;
45 if (it->default_value.empty()) it->default_value = p.default_value;
46 }
47 else
48 {
49 parameters.push_back(p);
50 }
51 }
52
53
54
55
56 /// Parses a "para" element
57 /*
58 This is used for different purposes within Doxygen.
59 - Either a detailed description, possibly containing several sections (para's)
60 -> so parse next siblings
61 - Or a detailed description also containing qbk records
62
63 So we have to list explicitly either where to recurse, or where not to...
64
65 */
66
67 // Type used to store parsing state. It indicates if QBK formatting block was opened - [*...], [^...], etc.
68 enum text_block
69 {
70 not_in_block,
71 in_code_block,
72 in_block
73 };
74
75 static void parse_para(rapidxml::xml_node<>* node, configuration const& config, std::string& contents, bool& skip, bool first = true, text_block tb = not_in_block)
76 {
77 if (node != NULL)
78 {
79 if (node->type() == rapidxml::node_element)
80 {
81 //std::cout << "ELEMENT: " << node->name() << "=" << node->value() << std::endl;
82 std::string name = node->name();
83 if ( boost::equals(name, "itemizedlist") )
84 {
85 contents += "\n\n";
86 parse_para(node->first_node(), config, contents, skip, true, tb);
87 contents += "\n";
88 parse_para(node->next_sibling(), config, contents, skip, true, tb);
89 return;
90 }
91 else if ( boost::equals(name, "listitem") )
92 {
93 contents += "* ";
94 parse_para(node->first_node(), config, contents, skip, true, tb);
95 contents += "\n";
96 parse_para(node->next_sibling(), config, contents, skip, true, tb);
97 return;
98 }
99 else if ( boost::equals(name, "verbatim") )
100 {
101 contents += "\n``\n";
102 parse_para(node->first_node(), config, contents, skip, false, tb);
103 contents += "``\n";
104 parse_para(node->next_sibling(), config, contents, skip, false, tb);
105 return;
106 }
107 else if ( boost::equals(name, "bold") )
108 {
109 contents += "[*";
110 parse_para(node->first_node(), config, contents, skip, false, in_block);
111 contents += "]";
112 parse_para(node->next_sibling(), config, contents, skip, false, tb);
113 return;
114 }
115 else if ( boost::equals(name, "emphasis") )
116 {
117 contents += "['";
118 parse_para(node->first_node(), config, contents, skip, false, in_block);
119 contents += "]";
120 parse_para(node->next_sibling(), config, contents, skip, false, tb);
121 return;
122 }
123 else if ( boost::equals(name, "computeroutput") )
124 {
125 contents += "[^";
126 parse_para(node->first_node(), config, contents, skip, false, tb == in_block ? in_block : in_code_block);
127 contents += "]";
128 parse_para(node->next_sibling(), config, contents, skip, false, tb);
129 return;
130 }
131 else if ( boost::equals(name, "ref") )
132 {
133 // If alternative output is used - insert links
134 if ( configuration::alt == config.output_style )
135 {
136 std::string refid = node->first_attribute("refid")->value();
137 if ( !refid.empty() )
138 {
139 contents += std::string("[link ") + refid + " ";
140 parse_para(node->first_node(), config, contents, skip, false, in_block);
141 contents += "]";
142 parse_para(node->next_sibling(), config, contents, skip, false, tb);
143 return;
144 }
145 }
146 }
147 else if (! (
148 (boost::equals(name, "para") && first)
149 || boost::equals(name, "defval")
150 || boost::equals(name, "linebreak")
151 ))
152 {
153 return;
154 }
155 }
156 else if (node->type() == rapidxml::node_data)
157 {
158 std::string str = node->value();
159 if ( tb == in_block )
160 {
161 boost::replace_all(str, "\\", "\\\\");
162 boost::replace_all(str, "[", "\\[");
163 boost::replace_all(str, "]", "\\]");
164 }
165 else if ( tb == in_code_block )
166 {
167 if ( str.find('`') == std::string::npos )
168 str = std::string("`") + str + "`";
169 }
170 contents += str;
171 //std::cout << "DATA: " << node->name() << "=" << node->value() << std::endl;
172 }
173 else
174 {
175 //std::cout << "OTHER: " << node->name() << "=" << node->value() << std::endl;
176 }
177
178 parse_para(node->first_node(), config, contents, skip, false, tb);
179 parse_para(node->next_sibling(), config, contents, skip, false, tb);
180 }
181 }
182
183
184 static void parse_parameter(rapidxml::xml_node<>* node, configuration const& config, parameter& p)
185 {
186 // #define: <param><defname>Point</defname></param>
187 // template: <param><type>typename</type><declname>CoordinateType</declname><defname>CoordinateType</defname></param>
188 // template with default: <param><type>typename</type><declname>CoordinateSystem</declname><defname>CoordinateSystem</defname><defval><ref ....>cs::cartesian</ref></defval></param>
189 // with enum: <type><ref refid="group__enum_1ga7d33eca9a5389952bdf719972eb802b6" kindref="member">closure_selector</ref></type>
190 if (node != NULL)
191 {
192 std::string name = node->name();
193 if (name == "type")
194 {
195 get_contents(node->first_node(), p.fulltype);
196 p.type = p.fulltype;
197 boost::replace_all(p.type, " const", "");
198 boost::trim(p.type);
199 boost::replace_all(p.type, "&", "");
200 boost::replace_all(p.type, "*", "");
201 boost::trim(p.type);
202
203 // If alt output is used retrieve type with QBK links
204 if ( configuration::alt == config.output_style )
205 {
206 p.fulltype_without_links = p.fulltype;
207 p.fulltype.clear();
208 parse_para(node->first_node(), config, p.fulltype, p.skip);
209 }
210 }
211 else if (name == "declname") p.name = node->value();
212 else if (name == "parametername") p.name = node->value();
213 else if (name == "defname") p.name = node->value();
214 else if (name == "defval")
215 {
216 parse_para(node, config, p.default_value, p.skip);
217 }
218 else if (name == "para")
219 {
220 parse_para(node, config, p.brief_description, p.skip);
221 }
222
223 parse_parameter(node->first_node(), config, p);
224 parse_parameter(node->next_sibling(), config, p);
225 }
226 }
227
228 static void parse_enumeration_value(rapidxml::xml_node<>* node, configuration const& config, enumeration_value& value)
229 {
230 // <enumvalue><name>green</name><initializer> 2</initializer>
231 // <briefdescription><para>...</para></briefdescription>
232 // <detaileddescription><para>...</para></detaileddescription>
233 // </enumvalue>
234 if (node != NULL)
235 {
236 std::string node_name = node->name();
237
238 if (node_name == "name") value.name = node->value();
239 else if (node_name == "para")
240 {
241 // Parses both brief AND detailed into this description
242 parse_para(node, config, value.brief_description, value.skip);
243 }
244 else if (node_name == "initializer")
245 {
246 value.initializer = node->value();
247 }
248
249 parse_enumeration_value(node->first_node(), config, value);
250 parse_enumeration_value(node->next_sibling(), config, value);
251 }
252 }
253
254 // Definition is a function or a class/struct
255 template <typename Parameters>
256 static void parse_parameter_list(rapidxml::xml_node<>* node, configuration const& config, Parameters& parameters)
257 {
258 if (node != NULL)
259 {
260 std::string name = node->name();
261
262 if (name == "parameteritem")
263 {
264 parameter p;
265 parse_parameter(node->first_node(), config, p);
266 if (! p.name.empty())
267 {
268 // Copy its description
269 std::vector<parameter>::iterator it = std::find_if(parameters.begin(),
270 parameters.end(), par_by_name(p.name));
271 if (it != parameters.end())
272 {
273 it->brief_description = p.brief_description;
274 }
275 else
276 {
277 parameters.push_back(p);
278 }
279 }
280 }
281 else if (name == "param")
282 {
283 // Element of 'templateparamlist.param (.type,.declname,.defname)'
284 parameter p;
285 parse_parameter(node->first_node(), config, p);
286
287 // Doxygen handles templateparamlist param's differently:
288 //
289 // Case 1:
290 // <param><type>typename T</type></param>
291 // -> no name, assign type to name, replace typename
292 //
293 // Case 2:
294 // <type>typename</type><declname>T</declname><defname>T</defname>
295 // -> set full type
296 if (p.name.empty())
297 {
298 // Case 1
299 p.name = p.type;
300 boost::replace_all(p.name, "typename", "");
301 boost::trim(p.name);
302 }
303 else
304 {
305 // Case 2
306 p.fulltype = p.type + " " + p.name;
307 }
308
309 add_or_set(parameters, p);
310 }
311
312 parse_parameter_list(node->first_node(), config, parameters);
313 parse_parameter_list(node->next_sibling(), config, parameters);
314 }
315 }
316
317 static void copy_string_property(std::string const& source, std::string& target)
318 {
319 if (target.empty())
320 {
321 target = source;
322 }
323 }
324
325
326 template <typename Parameters>
327 static void copy_parameter_properties(parameter const& source, Parameters& target)
328 {
329 BOOST_FOREACH(parameter& t, target)
330 {
331 if (source.name == t.name)
332 {
333 t.skip = source.skip;
334 copy_string_property(source.brief_description, t.brief_description);
335 copy_string_property(source.type, t.type);
336 copy_string_property(source.default_value, t.default_value);
337 copy_string_property(source.fulltype, t.fulltype);
338
339 return;
340 }
341 }
342 // If not found, write a warning
343 std::cerr << "Parameter not found: " << source.name << std::endl;
344 }
345
346
347 template <typename Parameters>
348 static void copy_parameters_properties(Parameters const& source, Parameters& target)
349 {
350 BOOST_FOREACH(parameter const& s, source)
351 {
352 copy_parameter_properties(s, target);
353 }
354 }
355
356
357
358 template <typename Element>
359 static void parse_element(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, Element& el)
360 {
361 if (node != NULL)
362 {
363 std::string name = node->name();
364 std::string full = parent + "." + name;
365
366 if (full == ".briefdescription.para")
367 {
368 parse_para(node, config, el.brief_description, el.skip);
369 }
370 else if (full == ".detaileddescription.para")
371 {
372 std::string para;
373 parse_para(node, config, para, el.skip);
374 if (!para.empty() && !el.detailed_description.empty())
375 {
376 el.detailed_description += "\n\n";
377 }
378 el.detailed_description += para;
379 }
380 else if (full == ".location")
381 {
382 std::string loc = get_attribute(node, "file");
383 // Location of (header)file. It is a FULL path, so find the start
384 // and strip the rest
385 std::size_t pos = loc.rfind(config.start_include);
386 if (pos != std::string::npos)
387 {
388 loc = loc.substr(pos);
389 }
390 el.location = loc;
391 el.line = atol(get_attribute(node, "line").c_str());
392 }
393 else if (full == ".detaileddescription.para.qbk")
394 {
395 el.qbk_markup.push_back(markup(node->value()));
396 }
397 else if (full == ".detaileddescription.para.qbk.after.synopsis")
398 {
399 el.qbk_markup.push_back(markup(markup_after, markup_synopsis, node->value()));
400 }
401 else if (full == ".detaileddescription.para.qbk.before.synopsis")
402 {
403 el.qbk_markup.push_back(markup(markup_before, markup_synopsis, node->value()));
404 }
405 else if (full == ".detaileddescription.para.qbk.distinguish")
406 {
407 el.additional_description = node->value();
408 boost::trim(el.additional_description);
409 }
410 else if (full == ".templateparamlist")
411 {
412 parse_parameter_list(node->first_node(), config, el.template_parameters);
413 }
414 else if (full == ".detaileddescription.para.parameterlist")
415 {
416 std::string kind = get_attribute(node, "kind");
417 if (kind == "param")
418 {
419 // Parse parameters and their descriptions.
420 // NOTE: they are listed here, but the order might not be the order in the function call
421 std::vector<parameter> parameters;
422 parse_parameter_list(node->first_node(), config, parameters);
423 copy_parameters_properties(parameters, el.parameters);
424 }
425 else if (kind == "templateparam")
426 {
427 parse_parameter_list(node->first_node(), config, el.template_parameters);
428 }
429 }
430 else if (full == ".detaileddescription.para.simplesect")
431 {
432 std::string kind = get_attribute(node, "kind");
433 if (kind == "par")
434 {
435 paragraph p;
436
437 rapidxml::xml_node<> * title_node = node->first_node("title");
438 if ( title_node )
439 p.title = title_node->value();
440
441 parse_para(node->first_node("para"), config, p.text, el.skip);
442
443 el.paragraphs.push_back(p);
444 }
445 else if (kind == "warning")
446 {
447 parse_para(node->first_node("para"), config, el.warning, el.skip);
448 }
449 else if (kind == "note")
450 {
451 parse_para(node->first_node("para"), config, el.note, el.skip);
452 }
453 }
454 else if (full == ".param")
455 {
456 // Parse one parameter, and add it to el.parameters
457 parameter p;
458 parse_parameter(node->first_node(), config, p);
459 el.parameters.push_back(p);
460 }
461
462
463 parse_element(node->first_node(), config, full, el);
464 parse_element(node->next_sibling(), config, parent, el);
465 }
466 }
467
468 static void parse_function(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, function& f)
469 {
470 if (node != NULL)
471 {
472 std::string name = node->name();
473 std::string full = parent + "." + name;
474
475 if (full == ".name") f.name = node->value();
476 else if (full == ".argsstring") f.argsstring = node->value();
477 else if (full == ".definition")
478 {
479 f.definition = node->value();
480 if (! config.skip_namespace.empty())
481 {
482 boost::replace_all(f.definition, config.skip_namespace, "");
483 }
484 }
485 else if (full == ".param")
486 {
487 parameter p;
488 parse_parameter(node->first_node(), config, p);
489 add_or_set(f.parameters, p);
490 }
491 else if (full == ".type")
492 {
493 get_contents(node->first_node(), f.return_type);
494
495 // If alt output is used, retrieve return type with links
496 if ( configuration::alt == config.output_style )
497 {
498 f.return_type_without_links = f.return_type;
499 bool dummy_skip;
500 f.return_type.clear();
501 parse_para(node->first_node(), config, f.return_type, dummy_skip);
502 }
503 }
504 else if (full == ".detaileddescription.para.simplesect")
505 {
506 std::string kind = get_attribute(node, "kind");
507 if (kind == "return")
508 {
509 parse_para(node->first_node(), config, f.return_description, f.skip);
510 }
511 /*else if (kind == "param")
512 {
513 get_contents(node->first_node(), f.paragraphs);
514 }*/
515 else if (kind == "pre")
516 {
517 parse_para(node->first_node(), config, f.precondition, f.skip);
518 }
519 }
520 else if (full == ".detaileddescription.para.image")
521 {
522 }
523
524 parse_function(node->first_node(), config, full, f);
525 parse_function(node->next_sibling(), config, parent, f);
526 }
527 }
528
529 static void parse_enumeration(rapidxml::xml_node<>* node, configuration const& config, std::string const& parent, enumeration& e)
530 {
531 if (node != NULL)
532 {
533 std::string name = node->name();
534 std::string full = parent + "." + name;
535
536 if (full == ".name") e.name = node->value();
537 else if (full == ".enumvalue")
538 {
539 enumeration_value value;
540 parse_enumeration_value(node->first_node(), config, value);
541 e.enumeration_values.push_back(value);
542 }
543
544 parse_enumeration(node->first_node(), config, full, e);
545 parse_enumeration(node->next_sibling(), config, parent, e);
546 }
547 }
548
549
550 static std::string parse_named_node(rapidxml::xml_node<>* node, std::string const& look_for_name)
551 {
552 if (node != NULL)
553 {
554 std::string node_name = node->name();
555 std::string contents;
556
557 if (boost::equals(node_name, look_for_name))
558 {
559 contents = node->value();
560 }
561
562 return contents
563 + parse_named_node(node->first_node(), look_for_name)
564 + parse_named_node(node->next_sibling(), look_for_name);
565 }
566 return "";
567 }
568
569
570
571
572 static void parse(rapidxml::xml_node<>* node, configuration const& config, documentation& doc, bool member = false)
573 {
574 if (node != NULL)
575 {
576 bool recurse = false;
577 bool is_member = member;
578
579 std::string nodename = node->name();
580
581 if (nodename == "doxygen")
582 {
583 recurse = true;
584 }
585 else if (nodename == "sectiondef")
586 {
587 std::string kind = get_attribute(node, "kind");
588
589 if (kind == "func"
590 || kind == "define"
591 || kind == "enum"
592 )
593 {
594 recurse = true;
595 }
596 else if (boost::starts_with(kind, "public"))
597 {
598 recurse = true;
599 is_member = true;
600 }
601 }
602 else if (nodename == "compounddef")
603 {
604 std::string kind = get_attribute(node, "kind");
605 std::string id = get_attribute(node, "id");
606 if (kind == "group")
607 {
608 recurse = true;
609 doc.group_id = id;
610 rapidxml::xml_node<> * n = node->first_node("title");
611 if ( n )
612 doc.group_title = n->value();
613 }
614 else if (kind == "struct")
615 {
616 recurse = true;
617 doc.cos.is_class = false;
618 doc.cos.id = id;
619 parse_element(node->first_node(), config, "", doc.cos);
620 }
621 else if (kind == "class")
622 {
623 recurse = true;
624 doc.cos.is_class = true;
625 doc.cos.id = id;
626 parse_element(node->first_node(), config, "", doc.cos);
627 }
628 }
629 else if (nodename == "memberdef")
630 {
631 std::string kind = get_attribute(node, "kind");
632 std::string id = get_attribute(node, "id");
633
634 if (kind == "function")
635 {
636 function f;
637 f.id = id;
638 f.is_static = get_attribute(node, "static") == "yes" ? true : false;
639 f.is_const = get_attribute(node, "const") == "yes" ? true : false;
640 f.is_explicit = get_attribute(node, "explicit") == "yes" ? true : false;
641 f.is_virtual = get_attribute(node, "virt") == "virtual" ? true : false;
642
643 parse_element(node->first_node(), config, "", f);
644 parse_function(node->first_node(), config, "", f);
645
646 if (member)
647 {
648 bool c_or_d = boost::equals(f.name, doc.cos.name) ||
649 boost::equals(f.name, std::string("~") + doc.cos.name);
650
651 f.type = c_or_d
652 ? function_constructor_destructor
653 : function_member;
654 doc.cos.functions.push_back(f);
655 }
656 else
657 {
658 f.type = function_free;
659 doc.functions.push_back(f);
660 }
661 }
662 else if (kind == "define")
663 {
664 function f;
665 f.id = id;
666 f.type = function_define;
667 parse_element(node->first_node(), config, "", f);
668 parse_function(node->first_node(), config, "", f);
669 doc.defines.push_back(f);
670 }
671 else if (kind == "enum")
672 {
673 enumeration e;
674 e.id = id;
675 parse_element(node->first_node(), config, "", e);
676 parse_enumeration(node->first_node(), config, "", e);
677 doc.enumerations.push_back(e);
678 }
679 else if (kind == "typedef")
680 {
681 if (boost::equals(get_attribute(node, "prot"), "public"))
682 {
683 std::string name = parse_named_node(node->first_node(), "name");
684 doc.cos.typedefs.push_back(base_element(name));
685 doc.cos.typedefs.back().id = id;
686
687 element dummy;
688 parse_element(node->first_node(), config, "", dummy);
689 doc.cos.typedefs.back().brief_description = dummy.brief_description;
690 }
691 }
692 else if (kind == "variable")
693 {
694 if (boost::equals(get_attribute(node, "prot"), "public"))
695 {
696 parameter p;
697 p.id = id;
698 for(rapidxml::xml_node<>* var_node = node->first_node(); var_node; var_node=var_node->next_sibling())
699 {
700 if(boost::equals(var_node->name(), "name"))
701 {
702 p.name = var_node->value();
703 }
704 else if(boost::equals(var_node->name(), "type"))
705 {
706 get_contents(var_node->first_node(), p.fulltype);
707 p.type = p.fulltype;
708 //boost::replace_all(p.type, " const", "");
709 //boost::trim(p.type);
710 //boost::replace_all(p.type, "&", "");
711 //boost::replace_all(p.type, "*", "");
712 boost::trim(p.type);
713
714 // If alt output is used retrieve type with QBK links
715 if ( configuration::alt == config.output_style )
716 {
717 p.fulltype_without_links = p.fulltype;
718 p.fulltype.clear();
719 parse_para(var_node->first_node(), config, p.fulltype, p.skip);
720 }
721 }
722 else if(boost::equals(var_node->name(), "briefdescription"))
723 {
724 parse_para(var_node->first_node(), config, p.brief_description, p.skip);
725 }
726 else if(p.brief_description.empty() && boost::equals(var_node->name(), "detaileddescription"))
727 {
728 parse_para(var_node->first_node(), config, p.brief_description, p.skip);
729 }
730 }
731 doc.cos.variables.push_back(p);
732 }
733 }
734
735 }
736 else if (nodename == "compoundname")
737 {
738 std::string name = node->value();
739 if (name.find("::") != std::string::npos)
740 {
741 doc.cos.fullname = name;
742
743 // For a class, it should have "boost::something::" before
744 // set its name without namespace
745 doc.cos.name = keep_after(name, "::");
746 }
747 }
748 else if (nodename == "basecompoundref")
749 {
750 base_class bc;
751 bc.name = node->value();
752 bc.derivation = get_attribute(node, "prot");
753 bc.virtuality = get_attribute(node, "virt");
754 doc.cos.base_classes.push_back(bc);
755 }
756 else
757 {
758 //std::cout << nodename << " ignored." << std::endl;
759 }
760
761
762 if (recurse)
763 {
764 // First recurse into childnodes, then handle next siblings
765 parse(node->first_node(), config, doc, is_member);
766 }
767 parse(node->next_sibling(), config, doc, is_member);
768 }
769 }
770
771 #endif // DOXYGEN_XML_PARSER_HPP