BOOST_FOREACH(value_consumer copyright, copyrights) { while(copyright.check()) { tmp << "\n" << " <copyright>\n"; while(copyright.check(doc_info_tags::copyright_year)) { value year_start_value = copyright.consume(); int year_start = year_start_value.get_int(); int year_end = copyright.check(doc_info_tags::copyright_year_end) ? copyright.consume().get_int() : year_start; if (year_end < year_start) { ++state.error_count; detail::outerr(state.current_file, copyright.begin()->get_position()) << "Invalid year range: " << year_start << "-" << year_end << "." << std::endl; } for(; year_start <= year_end; ++year_start) tmp << " <year>" << year_start << "</year>\n"; } tmp << " <holder>" << doc_info_output(copyright.consume(doc_info_tags::copyright_name), 106) << "</holder>\n" << " </copyright>\n" << "\n" ; } }
std::string pre(quickbook::state& state, parse_iterator pos, value include_doc_id, bool nested_file) { // The doc_info in the file has been parsed. Here's what we'll do // *before* anything else. // // If there isn't a doc info block, then values will be empty, so most // of the following code won't actually do anything. value_consumer values = state.values.release(); // Skip over invalid attributes while (values.check(value::default_tag)) values.consume(); bool use_doc_info = false; std::string doc_type; value doc_title; if (values.check(doc_info_tags::type)) { doc_type = detail::to_s(values.consume(doc_info_tags::type).get_quickbook()); doc_title = values.consume(doc_info_tags::title); use_doc_info = !nested_file || qbk_version_n >= 106u; } else { if (!nested_file) { detail::outerr(state.current_file, pos.base()) << "No doc_info block." << std::endl; ++state.error_count; // Create a fake document info block in order to continue. doc_type = "article"; doc_title = qbk_value(state.current_file, pos.base(), pos.base(), doc_info_tags::type); use_doc_info = true; } } std::vector<std::string> duplicates; std::vector<value> escaped_attributes = consume_multiple_values(values, doc_info_tags::escaped_attribute); value qbk_version = consume_list(values, doc_attributes::qbk_version, &duplicates); value compatibility_mode = consume_list(values, doc_attributes::compatibility_mode, &duplicates); consume_multiple_values(values, doc_attributes::source_mode); value id = consume_value_in_list(values, doc_info_attributes::id, &duplicates); value dirname = consume_value_in_list(values, doc_info_attributes::dirname, &duplicates); value last_revision = consume_value_in_list(values, doc_info_attributes::last_revision, &duplicates); value purpose = consume_value_in_list(values, doc_info_attributes::purpose, &duplicates); std::vector<value> categories = consume_multiple_values(values, doc_info_attributes::category); value lang = consume_value_in_list(values, doc_info_attributes::lang, &duplicates); value version = consume_value_in_list(values, doc_info_attributes::version, &duplicates); std::vector<value> authors = consume_multiple_values(values, doc_info_attributes::authors); std::vector<value> copyrights = consume_multiple_values(values, doc_info_attributes::copyright); value license = consume_value_in_list(values, doc_info_attributes::license, &duplicates); std::vector<value> biblioids = consume_multiple_values(values, doc_info_attributes::biblioid); value xmlbase = consume_value_in_list(values, doc_info_attributes::xmlbase, &duplicates); values.finish(); if(!duplicates.empty()) { detail::outwarn(state.current_file->path) << (duplicates.size() > 1 ? "Duplicate attributes" : "Duplicate attribute") << ":" << boost::algorithm::join(duplicates, ", ") << "\n" ; } std::string include_doc_id_, id_; if (!include_doc_id.empty()) include_doc_id_ = detail::to_s(include_doc_id.get_quickbook()); if (!id.empty()) id_ = detail::to_s(id.get_quickbook()); // Quickbook version unsigned new_version = get_version(state, use_doc_info, qbk_version); if (new_version != qbk_version_n) { if (new_version >= 107u) { detail::outwarn(state.current_file->path) << "Quickbook " << (new_version / 100) << "." << (new_version % 100) << " is still under development and is " "likely to change in the future." << std::endl; } } if (new_version) { qbk_version_n = new_version; } else if (use_doc_info) { // hard code quickbook version to v1.1 qbk_version_n = 101; detail::outwarn(state.current_file, pos.base()) << "Quickbook version undefined. " "Version 1.1 is assumed" << std::endl; } state.current_file->version(qbk_version_n); // Compatibility Version unsigned compatibility_version = get_version(state, use_doc_info, compatibility_mode); if (!compatibility_version) { compatibility_version = use_doc_info ? qbk_version_n : state.document.compatibility_version(); } // Start file, finish here if not generating document info. if (!use_doc_info) { state.document.start_file(compatibility_version, include_doc_id_, id_, doc_title); return ""; } std::string id_placeholder = state.document.start_file_with_docinfo( compatibility_version, include_doc_id_, id_, doc_title); // Make sure we really did have a document info block. assert(doc_title.check() && !doc_type.empty()); // Set xmlbase std::string xmlbase_value; if (!xmlbase.empty()) { xinclude_path x = calculate_xinclude_path(xmlbase, state); if (!fs::is_directory(x.path)) { detail::outerr(xmlbase.get_file(), xmlbase.get_position()) << "xmlbase \"" << xmlbase.get_quickbook() << "\" isn't a directory." << std::endl; ++state.error_count; } else { xmlbase_value = x.uri; state.xinclude_base = x.path; } } // Warn about invalid fields if (doc_type != "library") { std::vector<std::string> invalid_attributes; if (!purpose.empty()) invalid_attributes.push_back("purpose"); if (!categories.empty()) invalid_attributes.push_back("category"); if (!dirname.empty()) invalid_attributes.push_back("dirname"); if(!invalid_attributes.empty()) { detail::outwarn(state.current_file->path) << (invalid_attributes.size() > 1 ? "Invalid attributes" : "Invalid attribute") << " for '" << doc_type << " document info': " << boost::algorithm::join(invalid_attributes, ", ") << "\n" ; } } // Write out header if (!nested_file) { state.out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" << "<!DOCTYPE " << doc_type << " PUBLIC \"-//Boost//DTD BoostBook XML V1.0//EN\"\n" << " \"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd\">\n" ; } state.out << '<' << doc_type << "\n" << " id=\"" << id_placeholder << "\"\n"; if(!lang.empty()) { state.out << " lang=\"" << doc_info_output(lang, 106) << "\"\n"; } if(doc_type == "library" && !doc_title.empty()) { state.out << " name=\"" << doc_info_output(doc_title, 106) << "\"\n"; } // Set defaults for dirname + last_revision if (!dirname.empty() || doc_type == "library") { state.out << " dirname=\""; if (!dirname.empty()) { state.out << doc_info_output(dirname, 106); } else if (!id_.empty()) { state.out << id_; } else if (!include_doc_id_.empty()) { state.out << include_doc_id_; } else if (!doc_title.empty()) { state.out << detail::make_identifier(doc_title.get_quickbook()); } else { state.out << "library"; } state.out << "\"\n"; } state.out << " last-revision=\""; if (!last_revision.empty()) { state.out << doc_info_output(last_revision, 106); } else { // default value for last-revision is now char strdate[64]; strftime( strdate, sizeof(strdate), (debug_mode ? "DEBUG MODE Date: %Y/%m/%d %H:%M:%S $" : "$" /* prevent CVS substitution */ "Date: %Y/%m/%d %H:%M:%S $"), current_gm_time ); state.out << strdate; } state.out << "\" \n"; if (!xmlbase.empty()) { state.out << " xml:base=\"" << xmlbase_value << "\"\n"; } state.out << " xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n"; std::ostringstream tmp; if(!authors.empty()) { tmp << " <authorgroup>\n"; BOOST_FOREACH(value_consumer author_values, authors) { while (author_values.check()) { value surname = author_values.consume(doc_info_tags::author_surname); value first = author_values.consume(doc_info_tags::author_first); tmp << " <author>\n" << " <firstname>" << doc_info_output(first, 106) << "</firstname>\n" << " <surname>" << doc_info_output(surname, 106) << "</surname>\n" << " </author>\n"; } } tmp << " </authorgroup>\n"; }
void pre(collector& out, quickbook::actions& actions, bool ignore_docinfo) { // The doc_info in the file has been parsed. Here's what we'll do // *before* anything else. value_consumer values = actions.values.release(); // Skip over invalid attributes while (values.check(value::default_tag)) values.consume(); value qbk_version = values.optional_consume(doc_info_tags::qbk_version); value doc_title; if (values.check()) { actions.doc_type = values.consume(doc_info_tags::type).get_quickbook(); doc_title = values.consume(doc_info_tags::title); actions.doc_title_qbk = doc_title.get_quickbook(); } std::vector<std::string> duplicates; value id = consume_last_single(values, doc_info_attributes::id, &duplicates); value dirname = consume_last_single(values, doc_info_attributes::dirname, &duplicates); value last_revision = consume_last_single(values, doc_info_attributes::last_revision, &duplicates); value purpose = consume_last_single(values, doc_info_attributes::purpose, &duplicates); std::vector<value> categories = consume_multiple(values, doc_info_attributes::category); value lang = consume_last_single(values, doc_info_attributes::lang, &duplicates); value version = consume_last_single(values, doc_info_attributes::version, &duplicates); std::vector<value> authors = consume_multiple(values, doc_info_attributes::authors); std::vector<value> copyrights = consume_multiple(values, doc_info_attributes::copyright); value license = consume_last_single(values, doc_info_attributes::license, &duplicates); std::vector<value> biblioids = consume_multiple(values, doc_info_attributes::biblioid); // Skip over source-mode tags (already dealt with) while (values.check(doc_info_attributes::source_mode)) values.consume(); values.finish(); if(!duplicates.empty()) { detail::outwarn(actions.filename,1) << (duplicates.size() > 1 ? "Duplicate attributes" : "Duplicate attribute") << ":" << detail::utf8(boost::algorithm::join(duplicates, ", ")) << "\n" ; } bool generated_id = false; if (!id.empty()) actions.doc_id = id.get_quickbook(); if (actions.doc_id.empty()) { actions.doc_id = detail::make_identifier(actions.doc_title_qbk); generated_id = true; } if (dirname.empty() && actions.doc_type == "library") { if (!id.empty()) { dirname = id; } else { dirname = qbk_bbk_value(actions.doc_id, doc_info_attributes::dirname); } } if (last_revision.empty()) { // default value for last-revision is now char strdate[64]; strftime( strdate, sizeof(strdate), (debug_mode ? "DEBUG MODE Date: %Y/%m/%d %H:%M:%S $" : "$" /* prevent CVS substitution */ "Date: %Y/%m/%d %H:%M:%S $"), current_gm_time ); last_revision = qbk_bbk_value(strdate, doc_info_attributes::last_revision); } // if we're ignoring the document info, we're done. if (ignore_docinfo) { return; } // Quickbook version int qbk_major_version, qbk_minor_version; if (qbk_version.empty()) { // hard code quickbook version to v1.1 qbk_major_version = 1; qbk_minor_version = 1; detail::outwarn(actions.filename,1) << "Warning: Quickbook version undefined. " "Version 1.1 is assumed" << std::endl; } else { value_consumer qbk_version_values(qbk_version); qbk_major_version = qbk_version_values.consume().get_int(); qbk_minor_version = qbk_version_values.consume().get_int(); qbk_version_values.finish(); } qbk_version_n = ((unsigned) qbk_major_version * 100) + (unsigned) qbk_minor_version; if (qbk_version_n == 106) { detail::outwarn(actions.filename,1) << "Quickbook 1.6 is still under development and is " "likely to change in the future." << std::endl; } else if(qbk_version_n < 100 || qbk_version_n > 106) { detail::outerr(actions.filename,1) << "Unknown version of quickbook: quickbook " << qbk_major_version << "." << qbk_minor_version << std::endl; ++actions.error_count; } // Warn about invalid fields if (actions.doc_type != "library") { std::vector<std::string> invalid_attributes; if (!purpose.empty()) invalid_attributes.push_back("purpose"); if (!categories.empty()) invalid_attributes.push_back("category"); if (!dirname.empty()) invalid_attributes.push_back("dirname"); if(!invalid_attributes.empty()) { detail::outwarn(actions.filename,1) << (invalid_attributes.size() > 1 ? "Invalid attributes" : "Invalid attribute") << " for '" << detail::utf8(actions.doc_type) << " document info': " << detail::utf8(boost::algorithm::join(invalid_attributes, ", ")) << "\n" ; } } // Write out header out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" << "<!DOCTYPE " << actions.doc_type << " PUBLIC \"-//Boost//DTD BoostBook XML V1.0//EN\"\n" << " \"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd\">\n" << '<' << actions.doc_type << "\n" << " id=\"" << actions.ids.add(actions.doc_id, generated_id ? id_generator::generated_doc : id_generator::explicit_id) << "\"\n"; if(!lang.empty()) { out << " lang=\"" << doc_info_output(lang, 106) << "\"\n"; } if(actions.doc_type == "library") { out << " name=\"" << doc_info_output(doc_title, 106) << "\"\n"; } if(!dirname.empty()) { out << " dirname=\"" << doc_info_output(dirname, 106) << "\"\n"; } out << " last-revision=\"" << doc_info_output(last_revision, 106) << "\" \n" << " xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n"; std::ostringstream tmp; if(!authors.empty()) { tmp << " <authorgroup>\n"; BOOST_FOREACH(value_consumer author_values, authors) { while (author_values.check()) { value surname = author_values.consume(doc_info_tags::author_surname); value first = author_values.consume(doc_info_tags::author_first); tmp << " <author>\n" << " <firstname>" << doc_info_output(first, 106) << "</firstname>\n" << " <surname>" << doc_info_output(surname, 106) << "</surname>\n" << " </author>\n"; } } tmp << " </authorgroup>\n"; }