blob: 1c86ec5519b090caea4686fac110e9a940972402 [file] [log] [blame]
// doxml2qbk (developed in the context of Boost.Geometry documentation)
//
// Copyright (c) 2010 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
//
// Barend Gehrels, Aug 1, 2010
// In continuation of the QuickBook documentation of Boost.Geometry
//
// Converts XML files created by Doxygen to Quickbook
// Notes:
// - basically generic, but implemented with Boost.Geometry in mind
// - makes use of some specific XML elements, which can be created by Doxygen
// using /xmlonly
// currently this is the element <qbk.example> which will make a reference
// to an example.
// - currently still in draft
// Aug 14/15: added classes, defines, various enhancements.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/program_options.hpp>
#include <rapidxml.hpp>
#include <configuration.hpp>
#include <file_to_string.hpp>
#include <doxygen_elements.hpp>
#include <doxygen_xml_parser.hpp>
#include <parameter_predicates.hpp>
#include <quickbook_output.hpp>
#include <rapidxml_util.hpp>
int main(int argc, char** argv)
{
std::string filename;
try
{
configuration config;
std::string copyright_filename;
// Read/get configuration
{
namespace po = boost::program_options;
po::options_description description("=== doxml2qbk ===\nAllowed options");
std::string convenience_headers;
description.add_options()
("help", "Help message")
("xml", po::value<std::string>(&filename),
"Name of XML file written by Doxygen")
("start_include", po::value<std::string>(&config.start_include),
"Start include")
("convenience_header_path", po::value<std::string>(&config.convenience_header_path),
"Convenience header path")
("convenience_headers", po::value<std::string>(&convenience_headers),
"Convenience header(s) (comma-separated)")
("skip_namespace", po::value<std::string>(&config.skip_namespace),
"Namespace to skip (e.g. boost::mylib::")
("copyright", po::value<std::string>(&copyright_filename),
"Name of QBK file including (commented) copyright and license")
;
po::variables_map varmap;
if (argc == 2 && ! boost::starts_with(argv[1], "--"))
{
// (especially for debugging) options might go into an INI file
std::ifstream config_file (argv[1], std::ifstream::in);
po::store(po::parse_config_file(config_file, description), varmap);
}
else
{
po::store(po::parse_command_line(argc, argv, description), varmap);
}
po::notify(varmap);
if (varmap.count("help") || filename.empty())
{
std::cout << description << std::endl;
return 1;
}
// Split CSV with headerfile names into configuration
if (! convenience_headers.empty())
{
boost::split(config.convenience_headers, convenience_headers, boost::is_any_of(","));
}
}
// Read files into strings
std::string xml_string = file_to_string(filename);
std::string license = copyright_filename.empty()
? ""
: file_to_string(copyright_filename);
// Parse the XML outputted by Doxygen
xml_doc xml(xml_string.c_str());
documentation doc;
parse(xml.first_node(), config, doc);
// Check for duplicate function names
for (std::size_t i = 0; i < doc.functions.size(); i++)
{
function& f1 = doc.functions[i];
for (std::size_t j = i + 1; j < doc.functions.size(); j++)
{
function& f2 = doc.functions[j];
if (f1.name == f2.name)
{
// It is not a unique function, so e.g. an overload,
// so a description must distinguish them.
// Difference is either the number of parameters, or a const / non-const version
// Use the "\qbk{distinguish,with strategy}" in the source code to distinguish
f1.unique = false;
f2.unique = false;
}
}
}
// Write copyright/license (keep inspect silent)
if (! license.empty())
{
std::cout << license << std::endl;
}
// Write warning comment
std::cout
<< "[/ Generated by doxygen_xml2qbk, don't change, will be overwritten automatically]" << std::endl
<< "[/ Generated from " << filename << "]" << std::endl;
// Write the rest: functions, defines, classes or structs
BOOST_FOREACH(function const& f, doc.functions)
{
quickbook_output(f, config, std::cout);
}
BOOST_FOREACH(function const& f, doc.defines)
{
quickbook_output(f, config, std::cout);
}
BOOST_FOREACH(enumeration const& e, doc.enumerations)
{
quickbook_output(e, config, std::cout);
}
if (! doc.cos.name.empty())
{
std::sort(doc.cos.functions.begin(), doc.cos.functions.end(), sort_on_line<function>());
quickbook_output(doc.cos, config, std::cout);
}
}
catch(std::exception const& e)
{
std::cerr << "Exception in doxygen_xml2qbk: " << std::endl
<< " Message: " << e.what() << std::endl
<< " File: " << filename << std::endl
<< " Type: " << typeid(e).name() << std::endl
<< std::endl;
return 1;
}
catch(...)
{
std::cerr << "Unknown exception in doxygen_xml2qbk"
<< std::endl;
return 1;
}
return 0;
}