1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 //
3 // Copyright (c) 2010-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2012-2015 Adam Wulkiewicz, Lodz, Poland.
5 
6 // This file was modified by Oracle on 2014, 2015.
7 // Modifications copyright (c) 2014-2015, Oracle and/or its affiliates.
8 
9 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
10 
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
14 //
15 //
16 #ifndef QUICKBOOK_OUTPUT_HPP
17 #define QUICKBOOK_OUTPUT_HPP
18 
19 
20 #include <string>
21 #include <vector>
22 
23 #include <boost/algorithm/string.hpp>
24 
25 #include <doxygen_elements.hpp>
26 #include <parameter_predicates.hpp>
27 
qbk_escaped(std::string const & s)28 std::string qbk_escaped(std::string const& s)
29 {
30     // Replace _ by unicode to avoid accidental quickbook underlining.
31     // 1) do NOT do this in quickbook markup, so not within []
32     // (e.g. to avoid [include get_point.qbk] having unicoded)
33     // 2) \[ and \] should not count as []
34     std::size_t const len = s.length();
35     int counter = 0;
36     std::string result = "";
37     for (std::size_t i = 0; i < len; i++)
38     {
39         switch(s[i])
40         {
41             case '[' : counter++; break;
42             case ']' : counter--; break;
43             case '\\' :
44                 {
45                     result += s[i];
46                     if (i + 1 < len)
47                     {
48                         result += s[i + 1];
49                     }
50                     i++;
51                     continue;
52                 }
53             case '_' :
54                 if (counter == 0)
55                 {
56                     result += "\\u005f";
57                     continue;
58                 }
59         }
60         result += s[i];
61     }
62 
63     return result;
64 }
65 
66 
next_item(std::string const & first,std::string const & indent,std::size_t items_per_line,std::size_t & index,std::ostream & out)67 inline void next_item(std::string const& first, std::string const& indent,
68                 std::size_t items_per_line,
69                 std::size_t& index, std::ostream& out)
70 {
71     if (index > 0)
72     {
73         if (index % items_per_line == 0)
74         {
75             out << "," << std::endl << indent;
76         }
77         else
78         {
79             out << ", ";
80         }
81     }
82     else
83     {
84         std::cout << first;
85     }
86     index++;
87 }
88 
quickbook_template_parameter_list(std::vector<parameter> const & parameters,std::string const & related_name,std::ostream & out)89 void quickbook_template_parameter_list(std::vector<parameter> const& parameters,
90                 std::string const& related_name,
91                 std::ostream& out)
92 {
93     if (!parameters.empty())
94     {
95         std::string const header = "template<";
96         std::size_t index = 0;
97         std::string const indent(header.length(), ' ');
98         out << header;
99         BOOST_FOREACH(parameter const& p, parameters)
100         {
101             if (p.fulltype.empty())
102             {
103                 std::cerr << "Warning: template parameter " << p.name << " has no type in " << related_name << std::endl;
104             }
105 
106             next_item("", indent, 4, index, out);
107             out << p.fulltype;
108         }
109         out << ">" << std::endl;
110     }
111 }
112 
113 
quickbook_synopsis(function const & f,std::ostream & out)114 void quickbook_synopsis(function const& f, std::ostream& out)
115 {
116     out << "``";
117     quickbook_template_parameter_list(f.template_parameters, f.name, out);
118 
119     switch(f.type)
120     {
121         case function_constructor_destructor :
122             out << f.name;
123             break;
124         case function_member :
125             out << f.return_type << " " << f.name;
126             break;
127         case function_free :
128             out << f.definition;
129             break;
130         case function_define :
131             out << "#define " << f.name;
132             break;
133         case function_unknown :
134             // do nothing
135             break;
136     }
137 
138     // Output the parameters
139     // Because we want to be able to skip, we cannot use the argstring
140     {
141         std::size_t index = 0;
142         std::string const indent(f.name.length() + f.return_type.length() + 2, ' ');
143         BOOST_FOREACH(parameter const& p, f.parameters)
144         {
145             if (! p.skip)
146             {
147                 next_item("(", indent, 3, index, out);
148 
149                 out << p.fulltype << (p.fulltype.empty() ? "" : " ")
150                     << p.name
151                     << (p.default_value.empty() ? "" : " = ")
152                     << p.default_value;
153             }
154         }
155         if (index > 0)
156         {
157             out << ")";
158         }
159         else if (f.type != function_define)
160         {
161             out << "()";
162         }
163     }
164 
165     out << "``"
166         << std::endl
167         << std::endl;
168 }
169 
170 
quickbook_synopsis(enumeration const & e,std::ostream & out)171 void quickbook_synopsis(enumeration const& e, std::ostream& out)
172 {
173     out << "``enum " << e.name;
174     bool first = true;
175 
176     bool has_many_values = e.enumeration_values.size() > 4;
177 
178     BOOST_FOREACH(enumeration_value const& value, e.enumeration_values)
179     {
180         if (has_many_values)
181         {
182             if (first)
183             {
184                 out << std::endl << "{";
185             }
186             else
187             {
188                 out << ",";
189             }
190             out << std::endl << "    " << value.name;
191         }
192         else
193         {
194             out << (first ? " {" : ", ") << value.name;
195         }
196         if (! value.initializer.empty())
197         {
198             // Doxygen 1.6 does not include "=" in the <initializer> tag, Doxygen 1.8 does.
199             // We just remove the "=" to have consistent output
200             out << " = " << boost::trim_copy(boost::replace_all_copy(value.initializer, "=", ""));
201         }
202         first = false;
203     }
204     if (! first)
205     {
206         if (has_many_values)
207         {
208             out << std::endl;
209         }
210         out << "};";
211     }
212     out << "``"
213         << std::endl
214         << std::endl;
215 }
216 
includes(std::string const & filename,std::string const & header)217 inline bool includes(std::string const& filename, std::string const& header)
218 {
219     std::string result;
220 
221     std::ifstream cpp_file(filename.c_str());
222     if (cpp_file.is_open())
223     {
224         while (! cpp_file.eof() )
225         {
226             std::string line;
227             std::getline(cpp_file, line);
228             boost::trim(line);
229             if (boost::starts_with(line, "#include")
230                 && boost::contains(line, header))
231             {
232                 return true;
233             }
234         }
235     }
236     return false;
237 }
238 
239 
fix_location(std::string const & raw_location)240 std::string fix_location(std::string const& raw_location)
241 {
242     if ( raw_location.find("detail/") == std::string::npos
243          || raw_location.find("/interface.hpp") == std::string::npos )
244     {
245         return raw_location;
246     }
247 
248     std::string fixed_location(raw_location);
249 
250     fixed_location.erase(fixed_location.find("detail/"), 7u);
251     fixed_location.erase(fixed_location.find("/interface"), 10u);
252 
253     return fixed_location;
254 }
255 
256 
fix_include_header(std::string const & header)257 std::string fix_include_header(std::string const& header)
258 {
259     if ( header.find("geometry/geometry.hpp") == std::string::npos )
260     {
261         return header;
262     }
263 
264     std::string fixed_header(header);
265 
266     fixed_header.erase(fixed_header.find("geometry/"), 9u);
267 
268     return fixed_header;
269 }
270 
271 
quickbook_header(std::string const & raw_location,configuration const & config,std::ostream & out)272 void quickbook_header(std::string const& raw_location,
273     configuration const& config,
274     std::ostream& out)
275 {
276     std::string location = fix_location(raw_location);
277 
278     if (! location.empty())
279     {
280         std::vector<std::string> including_headers;
281 
282         // Select headerfiles containing to this location
283         BOOST_FOREACH(std::string const& header, config.convenience_headers)
284         {
285             if (includes(config.convenience_header_path + header, location))
286             {
287                 including_headers.push_back(header);
288             }
289         }
290 
291         out << "[heading Header]" << std::endl;
292         if (! including_headers.empty())
293         {
294             out << "Either"
295                 << (including_headers.size() > 1 ? " one of" : "")
296                 << std::endl << std::endl;
297             BOOST_FOREACH(std::string const& header, including_headers)
298             {
299                 out << "`#include <" << fix_include_header(config.start_include + header) << ">`" << std::endl << std::endl;
300             }
301 
302             out << std::endl << "Or" << std::endl << std::endl;
303         }
304         out << "`#include <" << location << ">`" << std::endl;
305         out << std::endl;
306     }
307 }
308 
309 
quickbook_markup(std::vector<markup> const & qbk_markup,markup_order_type order,markup_type type,std::ostream & out)310 void quickbook_markup(std::vector<markup> const& qbk_markup,
311             markup_order_type order, markup_type type,
312             std::ostream& out)
313 {
314     bool has_output = false;
315     BOOST_FOREACH(markup const& inc, qbk_markup)
316     {
317         if (inc.type == type && inc.order == order)
318         {
319             out << inc.value << std::endl;
320             has_output = true;
321         }
322     }
323     if (has_output)
324     {
325         out << std::endl;
326     }
327 }
328 
329 
330 
quickbook_string_with_heading_if_present(std::string const & heading,std::string const & contents,std::ostream & out)331 void quickbook_string_with_heading_if_present(std::string const& heading,
332             std::string const& contents, std::ostream& out)
333 {
334     if (! contents.empty())
335     {
336         out << "[heading " << heading << "]" << std::endl
337             << qbk_escaped(contents) << std::endl
338             << std::endl;
339     }
340 }
341 
to_section_name(std::string const & name)342 inline std::string to_section_name(std::string const& name)
343 {
344     // Make section-name lowercase and remove :: because these are filenames
345     return boost::to_lower_copy(boost::replace_all_copy(name, "::", "_"));
346 }
347 
quickbook_output_function_parameters(function const & f,std::ostream & out)348 void quickbook_output_function_parameters(function const& f, std::ostream& out)
349 {
350     BOOST_FOREACH(parameter const& p, f.parameters)
351     {
352         if (! p.skip)
353         {
354             out << "[* " << p.fulltype << "]: ['" << p.name << "]:  " << p.brief_description << std::endl << std::endl;
355         }
356     }
357     out << std::endl;
358     out << std::endl;
359 }
360 
quickbook_output_function_return(function const & f,std::ostream & out)361 void quickbook_output_function_return(function const& f, std::ostream& out)
362 {
363     if (! f.return_description.empty())
364     {
365         out << f.return_description << std::endl;
366     }
367 
368     out << std::endl;
369 }
370 
namespace_skipped(std::string const & name,configuration const & config)371 inline std::string namespace_skipped(std::string const& name, configuration const& config)
372 {
373     return config.skip_namespace.empty()
374         ? name
375         : boost::replace_all_copy(name, config.skip_namespace, "")
376         ;
377 }
378 
output_if_different(std::string const & s,std::string const & s2)379 inline std::string output_if_different(std::string const& s, std::string const& s2)
380 {
381     return boost::equals(s, s2)
382         ? ""
383         : s + " "
384         ;
385 }
386 
quickbook_output_indexterm(std::string const & term,std::ostream & out)387 inline void quickbook_output_indexterm(std::string const& term, std::ostream& out
388             //, std::string const& secondary = ""
389             )
390 {
391     out << "'''";
392     if (boost::contains(term, "::"))
393     {
394         // "Unnamespace" it and add all terms (also namespaces)
395         std::vector<std::string> splitted;
396         std::string for_split = boost::replace_all_copy(term, "::", ":");
397         boost::split(splitted, for_split, boost::is_any_of(":"), boost::token_compress_on);
398         BOOST_FOREACH(std::string const& part, splitted)
399         {
400             out << "<indexterm><primary>" << part << "</primary></indexterm>";
401         }
402     }
403     else
404     {
405         out << "<indexterm><primary>" << term;
406         /*if (! secondary.empty())
407         {
408             out << "<secondary>" << secondary << "</secondary>";
409         }*/
410         out << "</primary></indexterm>";
411     }
412     out << "'''" << std::endl;
413 }
414 
quickbook_output(function const & f,configuration const & config,std::ostream & out)415 void quickbook_output(function const& f, configuration const& config, std::ostream& out)
416 {
417     // Write the parsed function
418     int arity = (int)f.parameters.size();
419 
420     std::string additional_description;
421 
422     if (! f.additional_description.empty())
423     {
424         additional_description = " (";
425         additional_description += f.additional_description;
426         additional_description += ")";
427     }
428 
429     out << "[section:" << to_section_name(f.name);
430     // Make section name unique if necessary by arity and additional description
431     if (! f.unique)
432     {
433         out << "_" << arity;
434         if (! f.additional_description.empty())
435         {
436             out << "_" << boost::to_lower_copy(boost::replace_all_copy(f.additional_description, " ", "_"));
437         }
438     }
439     out << " " << f.name
440         << additional_description
441         << "]" << std::endl
442         << std::endl;
443 
444     quickbook_output_indexterm(f.name, out);
445 
446     out << qbk_escaped(f.brief_description) << std::endl;
447     out << std::endl;
448 
449     quickbook_string_with_heading_if_present("Description", f.detailed_description, out);
450 
451     // Synopsis
452     quickbook_markup(f.qbk_markup, markup_before, markup_synopsis, out);
453     out << "[heading Synopsis]" << std::endl;
454     quickbook_synopsis(f, out);
455     quickbook_markup(f.qbk_markup, markup_after, markup_synopsis, out);
456 
457 
458     out << "[heading Parameters]" << std::endl
459         << std::endl;
460 
461     out << "[table" << std::endl << "[";
462     if (f.type != function_define)
463     {
464         out << "[Type] [Concept] ";
465     }
466     out << "[Name] [Description] ]" << std::endl;
467 
468     // First: output any template parameter which is NOT used in the normal parameter list
469     BOOST_FOREACH(parameter const& tp, f.template_parameters)
470     {
471         if (! tp.skip)
472         {
473             std::vector<parameter>::const_iterator it = std::find_if(f.parameters.begin(), f.parameters.end(), par_by_type(tp.name));
474 
475             if (it == f.parameters.end())
476             {
477                 out << "[[" << tp.name << "] [" << tp.brief_description << "] [ - ] [Must be specified]]" << std::endl;
478             }
479         }
480     }
481 
482     BOOST_FOREACH(parameter const& p, f.parameters)
483     {
484         if (! p.skip)
485         {
486             out << "[";
487             std::vector<parameter>::const_iterator it = std::find_if(f.template_parameters.begin(),
488                 f.template_parameters.end(), par_by_name(p.type));
489 
490             if (f.type != function_define)
491             {
492                 out << "[" << p.fulltype
493                     << "] [" << (it == f.template_parameters.end() ? "" : it->brief_description)
494                     << "] ";
495             }
496             out << "[" << p.name
497                 << "] [" << p.brief_description
498                 << "]]"
499                 << std::endl;
500         }
501     }
502     out << "]" << std::endl
503         << std::endl
504         << std::endl;
505 
506     quickbook_string_with_heading_if_present("Returns", f.return_description, out);
507 
508     quickbook_header(f.location, config, out);
509     quickbook_markup(f.qbk_markup, markup_any, markup_default, out);
510 
511     out << std::endl;
512     out << "[endsect]" << std::endl;
513     out << std::endl;
514 }
515 
quickbook_output(enumeration const & e,configuration const & config,std::ostream & out)516 void quickbook_output(enumeration const& e, configuration const& config, std::ostream& out)
517 {
518     out << "[section:" << to_section_name(e.name);
519     out << " " << e.name
520         << "]" << std::endl
521         << std::endl;
522 
523     quickbook_output_indexterm(e.name, out);
524     BOOST_FOREACH(enumeration_value const& value, e.enumeration_values)
525     {
526         quickbook_output_indexterm(value.name, out);
527     }
528 
529     out << e.brief_description << std::endl;
530     out << std::endl;
531 
532     quickbook_string_with_heading_if_present("Description", e.detailed_description, out);
533 
534     // Synopsis
535     quickbook_markup(e.qbk_markup, markup_before, markup_synopsis, out);
536     out << "[heading Synopsis]" << std::endl;
537     quickbook_synopsis(e, out);
538     quickbook_markup(e.qbk_markup, markup_after, markup_synopsis, out);
539 
540 
541     out << "[heading Values]" << std::endl
542         << std::endl;
543 
544     out << "[table" << std::endl << "[";
545     out << "[Value] [Description] ]" << std::endl;
546 
547     BOOST_FOREACH(enumeration_value const& value, e.enumeration_values)
548     {
549         out << "[[" << value.name
550             << "] [" << value.brief_description
551             << "]]"
552             << std::endl;
553     }
554     out << "]" << std::endl
555         << std::endl
556         << std::endl;
557 
558     quickbook_header(e.location, config, out);
559     quickbook_markup(e.qbk_markup, markup_any, markup_default, out);
560 
561     out << std::endl;
562     out << "[endsect]" << std::endl;
563     out << std::endl;
564 }
565 
quickbook_output_function(std::vector<function> const & functions,function_type type,std::string const & title,configuration const &,std::ostream & out)566 void quickbook_output_function(std::vector<function> const& functions,
567                                 function_type type,
568                                 std::string const& title,
569                                 configuration const& , std::ostream& out)
570 {
571     std::string returns = type == function_constructor_destructor ? "" : " [Returns]";
572     out << "[heading " << title << "(s)]" << std::endl
573         << "[table" << std::endl
574         << "[[Function] [Description] [Parameters] " << returns << "]" << std::endl;
575 
576     BOOST_FOREACH(function const& f, functions)
577     {
578         if (f.type == type)
579         {
580             out << "[[";
581             quickbook_synopsis(f, out);
582             out << "] [" << f.brief_description << "] [";
583             quickbook_output_function_parameters(f, out);
584             out << "]";
585             if ( type != function_constructor_destructor )
586             {
587                 out << "[" << std::endl;
588                 quickbook_output_function_return(f, out);
589                 out << "]" << std::endl;
590             }
591             out << "]" << std::endl;
592         }
593     }
594     out << "]" << std::endl
595         << std::endl;
596 }
597 
quickbook_output(class_or_struct const & cos,configuration const & config,std::ostream & out)598 void quickbook_output(class_or_struct const& cos, configuration const& config, std::ostream& out)
599 {
600     // Skip namespace
601     std::string short_name = namespace_skipped(cos.fullname, config);
602 
603     // Write the parsed function
604     out << "[section:" << to_section_name(short_name) << " " << short_name << "]" << std::endl
605         << std::endl;
606 
607     quickbook_output_indexterm(short_name, out);
608 
609     out << cos.brief_description << std::endl;
610     out << std::endl;
611 
612     quickbook_string_with_heading_if_present("Description", cos.detailed_description, out);
613 
614     quickbook_markup(cos.qbk_markup, markup_before, markup_synopsis, out);
615     out << "[heading Synopsis]" << std::endl
616         << "``";
617     quickbook_template_parameter_list(cos.template_parameters, cos.name, out);
618     out << (cos.is_class ? "class" : "struct")
619         << " " << short_name << std::endl;
620 
621     if (! cos.base_classes.empty())
622     {
623         out << "      : ";
624         bool first = true;
625         BOOST_FOREACH(base_class const& bc, cos.base_classes)
626         {
627             if (! first)
628             {
629                 out << std::endl << "      , ";
630             }
631             out << output_if_different(bc.derivation, "private")
632                 << output_if_different(bc.virtuality, "non-virtual")
633                 << namespace_skipped(bc.name, config);
634             first = false;
635         }
636         out << std::endl;
637     }
638 
639     out << "{" << std::endl;
640     if (! cos.variables.empty() && config.output_member_variables)
641     {
642         size_t maxlength = 0;
643         BOOST_FOREACH(parameter const& p, cos.variables)
644         {
645             if (! p.skip)
646             {
647                 size_t length = 6 + p.fulltype.size() + p.name.size();
648                 if (length > maxlength) maxlength = length;
649             }
650         }
651         BOOST_FOREACH(parameter const& p, cos.variables)
652         {
653             if (! p.skip)
654             {
655                 size_t length = 4 + p.fulltype.size() + p.name.size();
656                 out << "  " << p.fulltype << " " << p.name << ";";
657                 if (! p.brief_description.empty())
658                 {
659                     while(length++ < maxlength) out << " ";
660                     out << "// " << p.brief_description;
661                 }
662                 out << std::endl;
663             }
664         }
665     }
666     else
667     {
668         out << "  // ..." << std::endl;
669     }
670     out << "};" << std::endl
671         << "``" << std::endl << std::endl;
672     quickbook_markup(cos.qbk_markup, markup_after, markup_synopsis, out);
673 
674 
675 
676     if (! cos.template_parameters.empty())
677     {
678         bool has_default = false;
679         BOOST_FOREACH(parameter const& p, cos.template_parameters)
680         {
681             if (! p.default_value.empty())
682             {
683                 has_default = true;
684             }
685         }
686 
687         out << "[heading Template parameter(s)]" << std::endl
688             << "[table" << std::endl
689             << "[[Parameter]";
690         if (has_default)
691         {
692             out << " [Default]";
693         }
694         out << " [Description]]" << std::endl;
695 
696         BOOST_FOREACH(parameter const& p, cos.template_parameters)
697         {
698             out << "[[" << p.fulltype;
699             if (has_default)
700             {
701                 out << "] [" << p.default_value;
702             }
703             out << "] [" << p.brief_description << "]]" << std::endl;
704         }
705         out << "]" << std::endl
706             << std::endl;
707     }
708 
709 
710     std::map<function_type, int> counts;
711     BOOST_FOREACH(function const& f, cos.functions)
712     {
713         counts[f.type]++;
714     }
715 
716     if (counts[function_constructor_destructor] > 0)
717     {
718         quickbook_output_function(cos.functions, function_constructor_destructor, "Constructor", config, out);
719     }
720 
721     if (counts[function_member] > 0)
722     {
723         quickbook_output_function(cos.functions, function_member, "Member Function", config, out);
724     }
725 
726     quickbook_header(cos.location, config, out);
727     quickbook_markup(cos.qbk_markup, markup_any, markup_default, out);
728 
729     out << "[endsect]" << std::endl
730         << std::endl;
731 }
732 
733 
734 // ----------------------------------------------------------------------------------------------- //
735 // ALT
736 // ----------------------------------------------------------------------------------------------- //
737 
remove_template_parameters(std::string const & name)738 std::string remove_template_parameters(std::string const& name)
739 {
740     std::string res;
741     std::string::size_type prev_i = 0, i = 0;
742     int blocks_counter = 0;
743     for ( ;; )
744     {
745         std::string::size_type next_begin = name.find('<', i);
746         std::string::size_type next_end = name.find('>', i);
747 
748         if ( next_begin == next_end )
749         {
750             res += name.substr(prev_i, next_begin - prev_i);
751             break;
752         }
753         else if ( next_begin < next_end )
754         {
755             i = next_begin + 1;
756             if ( blocks_counter == 0 )
757                 res += name.substr(prev_i, next_begin - prev_i) + "<...>";
758             blocks_counter++;
759         }
760         else
761         {
762             i = next_end + 1;
763             blocks_counter--;
764             if ( blocks_counter == 0 )
765                 prev_i = i;
766         }
767     }
768 
769     return res;
770 }
771 
replace_brackets(std::string const & str)772 std::string replace_brackets(std::string const& str)
773 {
774     return boost::replace_all_copy(boost::replace_all_copy(str, "[", "\\["), "]", "\\]");
775 }
776 
quickbook_output_enumerations(std::vector<enumeration> const & enumerations,configuration const &,std::ostream & out)777 void quickbook_output_enumerations(std::vector<enumeration> const& enumerations,
778                                   configuration const& ,
779                                   std::ostream& out)
780 {
781     out << "[table" << std::endl
782         << "[[Enumeration][Description]]" << std::endl;
783 
784     for ( size_t i = 0 ; i < enumerations.size() ; ++i )
785     {
786         enumeration const& e = enumerations[i];
787 
788         out << "[[[link " << e.id << " `";
789         out << e.name;
790         out << "`]][" << e.brief_description << "]]" << std::endl;
791     }
792     out << "]" << std::endl
793         << std::endl;
794 }
795 
quickbook_synopsis_short(function const & f,std::ostream & out)796 void quickbook_synopsis_short(function const& f, std::ostream& out)
797 {
798     if ( f.type != function_unknown )
799         out << f.name;
800 
801     bool first = true;
802     BOOST_FOREACH(parameter const& p, f.parameters)
803     {
804         if ( !p.skip && p.default_value.empty() )
805         {
806             out << (first ? "(" : ", ") << remove_template_parameters(p.fulltype_without_links);
807             first = false;
808         }
809     }
810 
811 
812     if (! first)
813         out << ")";
814     else if (f.type != function_define)
815         out << "()";
816 }
817 
quickbook_output_functions(std::vector<function> const & functions,function_type type,configuration const &,std::ostream & out,bool display_all=false,std::string const & ColTitle="Function")818 void quickbook_output_functions(std::vector<function> const& functions,
819                                 function_type type,
820                                 configuration const& ,
821                                 std::ostream& out,
822                                 bool display_all = false,
823                                 std::string const& ColTitle = "Function")
824 {
825     bool show_modifiers = false;
826     BOOST_FOREACH(function const& f, functions)
827     {
828         if ( (display_all || f.type == type) && (f.is_const || f.is_static) && !f.brief_description.empty() )
829             show_modifiers = true;
830     }
831 
832     out << "[table\n"
833         << "[";
834     if ( show_modifiers )
835         out << "[Modifier]";
836     out << "[" << ColTitle << "]";
837     out << "[Description]";
838     out << "]" << std::endl;
839 
840     for ( size_t i = 0 ; i < functions.size() ; ++i )
841     {
842         function const& f = functions[i];
843 
844         if ( f.brief_description.empty() )
845             continue;
846 
847         if (display_all || f.type == type)
848         {
849             out << "[";
850             if ( show_modifiers )
851             {
852                 out << "[";
853                 out << (f.is_static ? "`static`" : "");
854                 out << (f.is_const ? " `const`" : "");
855                 out << "]";
856             }
857             out << "[[link " << f.id << " `";
858             quickbook_synopsis_short(f, out);
859             out << "`]]";
860             out << "[" << f.brief_description << "]";
861             out << "]" << std::endl;
862         }
863     }
864     out << "]" << std::endl
865         << std::endl;
866 }
867 
output_paragraphs_note_warning(element const & el,std::ostream & out)868 void output_paragraphs_note_warning(element const& el, std::ostream & out)
869 {
870     // Additional paragraphs
871     if ( !el.paragraphs.empty() )
872     {
873         BOOST_FOREACH(paragraph const& p, el.paragraphs)
874         {
875             if ( !p.title.empty() )
876                 out << "[heading " << p.title << "]" << std::endl;
877             else
878                 out << "\n\n" << std::endl;
879             out << p.text << std::endl;
880             out << std::endl;
881         }
882     }
883 
884     // Note
885     if ( !el.note.empty() )
886     {
887         out << "[note " << el.note << "]" << std::endl;
888         out << std::endl;
889     }
890 
891     // Warning
892     if ( !el.warning.empty() )
893     {
894         out << "[warning " << el.warning << "]" << std::endl;
895         out << std::endl;
896     }
897 }
898 
inline_str_with_links(std::string const & str,std::ostream & out)899 void inline_str_with_links(std::string const& str, std::ostream & out)
900 {
901     typedef std::string::size_type ST;
902 
903     bool link_started = false;
904     bool first = true;
905     for ( ST i = 0 ; i < str.size() ; ++i )
906     {
907         if ( !link_started )
908         {
909             if ( str[i] == '[' && str.substr(i, 6) == "[link " )
910             {
911                 if ( !first )
912                 {
913                     out << "`";
914                     first = true;
915                 }
916                 link_started = true;
917                 out << "[^[link ";
918                 i += 5; // (+ 6 - 1)
919             }
920             else
921             {
922                 if ( first )
923                 {
924                     out << "`";
925                     first = false;
926                 }
927                 out << str[i];
928             }
929         }
930         else
931         {
932             if ( str[i] == '\\' )
933             {
934                 out << str[i];
935                 ++i;
936                 if ( i < str.size() )
937                     out << str[i];
938             }
939             else if ( str[i] == ']' )
940             {
941                 out << "]]";
942                 link_started = false;
943             }
944             else
945                 out << str[i];
946         }
947     }
948 
949     if ( !first )
950         out << "`";
951     if ( link_started )
952         out << "]]";
953 }
954 
quickbook_template_parameter_list_alt(std::vector<parameter> const & parameters,std::ostream & out)955 void quickbook_template_parameter_list_alt(std::vector<parameter> const& parameters, std::ostream& out)
956 {
957     std::string next_param;
958 
959     if ( 2 < parameters.size() )
960         next_param = std::string("`,`\n") + "         ";
961     else
962         next_param = "`,` ";
963 
964     if (!parameters.empty())
965     {
966         out << "`template<`" ;
967         bool first = true;
968         BOOST_FOREACH(parameter const& p, parameters)
969         {
970             out << (first ? "" : next_param.c_str());
971             inline_str_with_links(p.fulltype, out);
972 
973             if ( !p.default_value.empty() )
974             {
975                 out << " = ";
976                 // don't display default values from details
977                 if ( p.default_value.find("detail") != std::string::npos )
978                     out << "/default/";
979                 else
980                     inline_str_with_links(p.default_value, out);
981             }
982 
983             first = false;
984         }
985         out << "`>`";
986     }
987 }
988 
quickbook_synopsis_alt(function const & f,std::ostream & out)989 void quickbook_synopsis_alt(function const& f, std::ostream& out)
990 {
991     out << "[pre\n";
992     quickbook_template_parameter_list_alt(f.template_parameters, out);
993     out << "\n";
994 
995     std::size_t offset = 1; // '('
996     switch(f.type)
997     {
998         case function_constructor_destructor :
999             out << "`" << f.name << "`";
1000             offset += f.name.size();
1001             break;
1002         case function_member :
1003         case function_free :
1004             // don't display return types from details
1005             if ( f.return_type.find("detail") != std::string::npos )
1006             {
1007                 out << "/unspecified/";
1008                 offset += 11;
1009             }
1010             else
1011             {
1012                 inline_str_with_links(f.return_type, out);
1013                 offset += f.return_type_without_links.size();
1014             }
1015             out << " `" << f.name << "`";
1016             offset += 1 + f.name.size();
1017             break;
1018         case function_define :
1019             out << "`#define " << f.name << "`";
1020             offset += 8 + f.name.size();
1021             break;
1022         case function_unknown :
1023             // do nothing
1024             break;
1025     }
1026 
1027     std::string par_end("`,` ");
1028     if ( 2 < f.parameters.size() )
1029         par_end = std::string("`,`\n") + std::string(offset, ' ');
1030 
1031     // Output the parameters
1032     // Because we want to be able to skip, we cannot use the argstring
1033     {
1034         bool first = true;
1035         BOOST_FOREACH(parameter const& p, f.parameters)
1036         {
1037             if (! p.skip)
1038             {
1039                 out << (first ? "`(`" : par_end);
1040                 if ( !p.fulltype.empty() )
1041                 {
1042                     inline_str_with_links(p.fulltype, out);
1043                     out << " ";
1044                 }
1045                 if ( !p.name.empty() )
1046                     out << "`" << p.name << "`";
1047                 if ( !p.default_value.empty() )
1048                 {
1049                     out << " = ";
1050                     // don't display default values from details
1051                     if ( p.default_value.find("detail") != std::string::npos )
1052                         out << "/default/";
1053                     else
1054                         inline_str_with_links(p.default_value, out);
1055                 }
1056                 first = false;
1057             }
1058         }
1059 
1060         if (! first)
1061             out << "`)`\n";
1062         else if (f.type != function_define)
1063             out << "`()`\n";
1064     }
1065 
1066     out << "]"
1067         << std::endl
1068         << std::endl;
1069 }
1070 
quickbook_synopsis_alt(class_or_struct const & cos,configuration const & config,std::ostream & out)1071 void quickbook_synopsis_alt(class_or_struct const& cos, configuration const& config, std::ostream & out)
1072 {
1073     std::string short_name = namespace_skipped(cos.fullname, config);
1074 
1075     out << "[pre\n";
1076 
1077     quickbook_template_parameter_list_alt(cos.template_parameters, out);
1078     out << "\n";
1079 
1080     out << (cos.is_class ? "`class " : "`struct ");
1081     {
1082         std::string::size_type last_scope = std::string::npos;
1083         std::string::size_type i = short_name.find("<");
1084         for(std::string::size_type j = short_name.find("::") ; j < i ; j = short_name.find("::", j+1))
1085             last_scope = j;
1086         if ( last_scope == std::string::npos )
1087             out << short_name << "`" << std::endl;
1088         else
1089             out << short_name.substr(last_scope + 2) << "`" << std::endl;
1090     }
1091 
1092     if (! cos.base_classes.empty())
1093     {
1094         bool first = true;
1095         BOOST_FOREACH(base_class const& bc, cos.base_classes)
1096         {
1097             // don't display base classes from details
1098             if ( bc.name.find("detail") != std::string::npos )
1099                 continue;
1100 
1101             if (first)
1102                 out << "`      : ";
1103             else
1104                 out << std::endl << "      , ";
1105             out << output_if_different(bc.derivation, "private")
1106                 << output_if_different(bc.virtuality, "non-virtual")
1107                 << namespace_skipped(bc.name, config);
1108             first = false;
1109         }
1110         if (!first)
1111             out << "`" << std::endl;
1112     }
1113 
1114     out << "`{`" << std::endl
1115         << "`  // ...`" << std::endl
1116         << "`};`" << std::endl
1117         << "]" << std::endl << std::endl;
1118 }
1119 
quickbook_synopsis_alt(enumeration const & e,std::ostream & out)1120 void quickbook_synopsis_alt(enumeration const& e, std::ostream& out)
1121 {
1122     std::string values_separator =
1123         e.enumeration_values.size() <= 2 ?
1124             std::string(", ") :
1125             ( std::string(",\n") + std::string(e.name.size() + 7, ' ') );
1126 
1127     out << "``enum " << e.name << " ";
1128     bool first = true;
1129     BOOST_FOREACH(enumeration_value const& value, e.enumeration_values)
1130     {
1131         out << (first ? "{" : values_separator.c_str());
1132         out << value.name;
1133         if ( !value.initializer.empty() )
1134         {
1135             out << " = " << boost::trim_copy(boost::replace_all_copy(value.initializer, "=", ""));
1136         }
1137         first = false;
1138     }
1139     if (! first)
1140     {
1141         out << "};";
1142     }
1143     out << "``"
1144         << std::endl
1145         << std::endl;
1146 }
1147 
1148 template <typename Range>
has_brief_description(Range const & rng)1149 bool has_brief_description(Range const& rng)
1150 {
1151     typedef typename Range::value_type V;
1152     BOOST_FOREACH(V const& bc, rng)
1153     {
1154         if ( !bc.brief_description.empty() )
1155             return true;
1156     }
1157     return false;
1158 }
1159 
1160 template <typename Range>
has_brief_description(Range const & rng,function_type t)1161 bool has_brief_description(Range const& rng, function_type t)
1162 {
1163     typedef typename Range::value_type V;
1164     BOOST_FOREACH(V const& bc, rng)
1165     {
1166         if ( bc.type == t && !bc.brief_description.empty() )
1167             return true;
1168     }
1169     return false;
1170 }
1171 
quickbook_output_functions_details(std::vector<function> const & functions,function_type type,configuration const &,std::ostream & out,bool display_all=false)1172 void quickbook_output_functions_details(std::vector<function> const& functions,
1173                                         function_type type,
1174                                         configuration const& ,
1175                                         std::ostream& out,
1176                                         bool display_all = false)
1177 {
1178     for ( size_t i = 0 ; i < functions.size() ; ++i )
1179     {
1180         function const& f = functions[i];
1181 
1182         if ( f.brief_description.empty() )
1183             continue;
1184 
1185         if ( display_all || f.type == type )
1186         {
1187             // Section
1188             std::stringstream ss;
1189             quickbook_synopsis_short(f, ss);
1190             out << "[#" << f.id << "]" << std::endl;
1191             out << "[section " << replace_brackets(ss.str()) << "]" << std::endl;
1192 
1193             quickbook_output_indexterm(f.name, out);
1194 
1195             // Brief description
1196             out << f.brief_description << std::endl;
1197             out << std::endl;
1198 
1199             // Detail description
1200             if ( !f.detailed_description.empty() )
1201             {
1202                 out << "[heading Description]" << std::endl;
1203                 out << f.detailed_description;
1204             }
1205 
1206             // Synopsis
1207             quickbook_markup(f.qbk_markup, markup_before, markup_synopsis, out);
1208             out << "[heading Synopsis]" << std::endl;
1209             quickbook_synopsis_alt(f, out);
1210             quickbook_markup(f.qbk_markup, markup_after, markup_synopsis, out);
1211 
1212             if ( f.is_static || f.is_virtual || f.is_explicit || f.is_const )
1213             {
1214                 out << "[heading Modifier(s)]" << std::endl;
1215                 out << "``"
1216                     << (f.is_static ? "static " : "")
1217                     << (f.is_virtual ? "virtual " : "")
1218                     << (f.is_explicit ? "explicit " : "")
1219                     << (f.is_const ? "const " : "")
1220                     << "``";
1221             }
1222 
1223             // Template parameters
1224             if ( !f.template_parameters.empty() && has_brief_description(f.template_parameters) )
1225             {
1226                 out << "[heading Template parameter(s)]" << std::endl
1227                     << "[table" << std::endl
1228                     << "[[Parameter] [Description]]" << std::endl;
1229 
1230                 BOOST_FOREACH(parameter const& p, f.template_parameters)
1231                 {
1232                     if ( p.brief_description.empty() )
1233                         continue;
1234 
1235                     out << "[[`";
1236                     if ( p.fulltype.find("typename ") == 0 )
1237                         out << p.fulltype.substr(9);
1238                     else if ( p.fulltype.find("class ") == 0 )
1239                         out << p.fulltype.substr(6);
1240                     else
1241                         out << p.fulltype;
1242                     out << "`][" << p.brief_description << "]]" << std::endl;
1243                 }
1244                 out << "]" << std::endl
1245                     << std::endl;
1246             }
1247 
1248             // Parameters
1249             if ( !f.parameters.empty() && has_brief_description(f.parameters) )
1250             {
1251                 out << "[heading Parameter(s)]" << std::endl;
1252                 out << "[table " << std::endl;
1253                 out << "[";
1254                 if ( f.type != function_define )
1255                     out << "[Type]";
1256                 out << "[Name][Description]]" << std::endl;
1257                 BOOST_FOREACH(parameter const& p, f.parameters)
1258                 {
1259                     if (!p.skip)
1260                     {
1261                         out << "[";
1262                         if ( f.type != function_define )
1263                         {
1264                             out << "[";
1265                             inline_str_with_links(p.fulltype, out);
1266                             out << "]";
1267                         }
1268                         out << "[ `" << p.name << "` ][" << p.brief_description << "]]"<< std::endl;
1269                     }
1270                 }
1271                 out << "]" << std::endl;
1272             }
1273 
1274             // Precondition
1275             if ( !f.precondition.empty() )
1276             {
1277                 out << "[heading Precondition(s)]" << std::endl;
1278                 out << f.precondition << std::endl;
1279                 out << std::endl;
1280             }
1281 
1282             // Return
1283             if ( !f.return_description.empty() )
1284             {
1285                 out << "[heading Returns]" << std::endl;
1286                 out << f.return_description << std::endl;
1287             }
1288 
1289             // Additional paragraphs, note, warning
1290             output_paragraphs_note_warning(f, out);
1291 
1292             // QBK markup
1293             quickbook_markup(f.qbk_markup, markup_any, markup_default, out);
1294 
1295             // Section end
1296             out << "[endsect]" << std::endl
1297                 //<< "[br]" << std::endl
1298                 << std::endl;
1299         }
1300     }
1301 }
1302 
quickbook_output_enumeration_details(enumeration const & e,configuration const &,std::ostream & out)1303 void quickbook_output_enumeration_details(enumeration const& e, configuration const& , std::ostream& out)
1304 {
1305     out << "[#" << e.id << "]\n";
1306     out << "[section " << e.name << "]" << std::endl
1307         << std::endl;
1308 
1309     quickbook_output_indexterm(e.name, out);
1310     BOOST_FOREACH(enumeration_value const& value, e.enumeration_values)
1311     {
1312         quickbook_output_indexterm(value.name, out);
1313     }
1314 
1315     out << e.brief_description << std::endl;
1316     out << std::endl;
1317 
1318     if ( !e.detailed_description.empty() )
1319     {
1320         out << "[heading Description]\n\n";
1321         out << e.detailed_description << "\n\n";
1322     }
1323 
1324     // Additional paragraphs, note, warning
1325     output_paragraphs_note_warning(e, out);
1326 
1327     quickbook_markup(e.qbk_markup, markup_any, markup_default, out);
1328 
1329     // Synopsis
1330     quickbook_markup(e.qbk_markup, markup_before, markup_synopsis, out);
1331     out << "[heading Synopsis]" << std::endl;
1332     quickbook_synopsis_alt(e, out);
1333     quickbook_markup(e.qbk_markup, markup_after, markup_synopsis, out);
1334 
1335 
1336     out << "[heading Values]" << std::endl
1337         << std::endl;
1338 
1339     out << "[table" << std::endl << "[";
1340     out << "[Value] [Description] ]" << std::endl;
1341 
1342     BOOST_FOREACH(enumeration_value const& value, e.enumeration_values)
1343     {
1344         out << "[[" << value.name << "] [" << value.brief_description << "]]\n";
1345     }
1346     out << "]\n\n\n";
1347 
1348     out << std::endl;
1349     out << "[endsect]" << std::endl;
1350     out << std::endl;
1351 }
1352 
quickbook_output_alt(documentation const & doc,configuration const & config,std::ostream & out)1353 void quickbook_output_alt(documentation const& doc, configuration const& config, std::ostream& out)
1354 {
1355     if ( !doc.group_id.empty() )
1356     {
1357         std::cout << "[section:" << doc.group_id << " " << doc.group_title << "]" << std::endl;
1358     }
1359 
1360     if ( !doc.enumerations.empty() )
1361     {
1362         std::cout << "[heading Enumerations]\n";
1363         quickbook_output_enumerations(doc.enumerations, config, out);
1364     }
1365 
1366     if ( !doc.defines.empty() )
1367     {
1368         std::cout << "[heading Defines]\n";
1369         quickbook_output_functions(doc.defines, function_unknown, config, out, true, "Define");
1370     }
1371 
1372     if ( !doc.functions.empty() )
1373     {
1374         std::cout << "[heading Functions]\n";
1375         quickbook_output_functions(doc.functions, function_unknown, config, out, true, "Function");
1376     }
1377 
1378     BOOST_FOREACH(enumeration const& e, doc.enumerations)
1379     {
1380         quickbook_output_enumeration_details(e, config, out);
1381     }
1382 
1383     quickbook_output_functions_details(doc.defines, function_unknown, config, out, true);
1384     quickbook_output_functions_details(doc.functions, function_unknown, config, out, true);
1385 
1386     if ( !doc.group_id.empty() )
1387     {
1388         out << "[endsect]" << std::endl
1389             << std::endl;
1390     }
1391 }
1392 
quickbook_output_alt(class_or_struct const & cos,configuration const & config,std::ostream & out)1393 void quickbook_output_alt(class_or_struct const& cos, configuration const& config, std::ostream& out)
1394 {
1395     // Skip namespace
1396     std::string short_name = namespace_skipped(cos.fullname, config);
1397 
1398     BOOST_ASSERT(configuration::alt == config.output_style);
1399 
1400     if ( !cos.id.empty() )
1401         out << "[#" << cos.id << "]" << std::endl;
1402     out << "[section " << short_name << "]" << std::endl << std::endl;
1403 
1404     // WARNING! Can't be used in the case of specializations
1405     quickbook_output_indexterm(short_name, out);
1406 
1407     // Brief
1408 
1409     out << cos.brief_description << std::endl;
1410     out << std::endl;
1411 
1412     // Description
1413 
1414     quickbook_string_with_heading_if_present("Description", cos.detailed_description, out);
1415 
1416     // Additional paragraphs, note, warning
1417     output_paragraphs_note_warning(cos, out);
1418 
1419     // Markup
1420     quickbook_markup(cos.qbk_markup, markup_any, markup_default, out);
1421 
1422     // Header
1423 
1424     quickbook_header(cos.location, config, out);
1425 
1426     // Class synposis
1427 
1428     quickbook_markup(cos.qbk_markup, markup_before, markup_synopsis, out);
1429     out << "[heading Synopsis]" << std::endl;
1430     quickbook_synopsis_alt(cos, config, out);
1431     quickbook_markup(cos.qbk_markup, markup_after, markup_synopsis, out);
1432 
1433     // Template parameters
1434 
1435     if (! cos.template_parameters.empty())
1436     {
1437         if ( has_brief_description(cos.template_parameters) )
1438         {
1439             out << "[heading Template parameter(s)]" << std::endl
1440                 << "[table" << std::endl
1441                 << "[[Parameter] [Description]]" << std::endl;
1442 
1443             BOOST_FOREACH(parameter const& p, cos.template_parameters)
1444             {
1445                 if ( p.brief_description.empty() )
1446                     continue;
1447 
1448                 out << "[[`";
1449                 if ( p.fulltype.find("typename ") == 0 )
1450                     out << p.fulltype.substr(9);
1451                 else if ( p.fulltype.find("class ") == 0 )
1452                     out << p.fulltype.substr(6);
1453                 else
1454                     out << p.fulltype;
1455                 out << "`][" << p.brief_description << "]]" << std::endl;
1456             }
1457             out << "]" << std::endl
1458                 << std::endl;
1459         }
1460     }
1461 
1462     // Typedefs
1463 
1464     if ( !cos.typedefs.empty() )
1465     {
1466         if ( has_brief_description(cos.typedefs) )
1467         {
1468             out << "[heading Typedef(s)]" << std::endl
1469                 << "[table" << std::endl
1470                 << "[[Type]";
1471             out << " [Description]]" << std::endl;
1472 
1473             BOOST_FOREACH(base_element const& e, cos.typedefs)
1474             {
1475                 if ( e.brief_description.empty() )
1476                     continue;
1477 
1478                 out << "[[";
1479                 if ( !e.id.empty() )
1480                     out << "[#" << e.id << "]" << " ";
1481                 out << "`" << e.name << "`";
1482                 out << "][" << e.brief_description << "]]" << std::endl;
1483             }
1484             out << "]" << std::endl
1485                 << std::endl;
1486         }
1487     }
1488 
1489     // Members
1490 
1491     bool display_ctors = has_brief_description(cos.functions, function_constructor_destructor);
1492     bool display_members = has_brief_description(cos.functions, function_member);
1493 
1494     std::map<function_type, int> counts;
1495     BOOST_FOREACH(function const& f, cos.functions)
1496     {
1497         counts[f.type]++;
1498     }
1499 
1500     if (display_ctors && counts[function_constructor_destructor] > 0)
1501     {
1502         out << "[heading Constructor(s) and destructor]" << std::endl;
1503         quickbook_output_functions(cos.functions, function_constructor_destructor, config, out);
1504     }
1505 
1506     if (display_members && counts[function_member] > 0)
1507     {
1508         out << "[heading Member(s)]" << std::endl;
1509         quickbook_output_functions(cos.functions, function_member, config, out);
1510     }
1511 
1512     // Details start
1513 
1514     //if ( display_ctors || display_members )
1515     //    out << "[br]" << std::endl;
1516 
1517     if (display_ctors && counts[function_constructor_destructor] > 0)
1518         quickbook_output_functions_details(cos.functions, function_constructor_destructor, config, out);
1519 
1520     if (display_members && counts[function_member] > 0)
1521         quickbook_output_functions_details(cos.functions, function_member, config, out);
1522 
1523     // Details end
1524 
1525     out << "[endsect]" << std::endl
1526         << std::endl;
1527 }
1528 
1529 #endif // QUICKBOOK_OUTPUT_HPP
1530