From: Tomek Mrugalski Date: Tue, 2 Oct 2018 13:16:22 +0000 (+0200) Subject: [#10,!3] Docgen sources are now documented. X-Git-Tag: 176-update-to-sysrepo-0-7-6-release_base~168 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=66a390fe09164b406e125c35eecd347589a42e9d;p=thirdparty%2Fkea.git [#10,!3] Docgen sources are now documented. --- diff --git a/doc/docgen/kea_docgen.cc b/doc/docgen/kea_docgen.cc index 41da9f9bab..88386c7c1b 100644 --- a/doc/docgen/kea_docgen.cc +++ b/doc/docgen/kea_docgen.cc @@ -1,3 +1,9 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + #include #include #include @@ -13,14 +19,19 @@ using namespace isc; using namespace isc::data; - +/// @brief API documentation generator class DocGen { public: + /// Output location of a file. const string OUTPUT = "guide/api.xml"; + /// Controls whether to print out extra information. bool verbose = false; + /// @brief Load JSON files that each contain description of an API command + /// + /// @param files a vector with names of files. void loadFiles(const vector& files) { map commands; @@ -61,42 +72,57 @@ public: << " file(s)" << endl; } - + /// @brief checks if mandatory string parameter is specified + /// + /// @param x a map that is being checked + /// @param name name of the string element expected to be there + /// @param fname name of the file (used in error reporting) + /// @throw Unexpected if missing, different type or empty void requireString(const ElementPtr& x, const string& name, const string& fname) { if (!x->contains(name)) { isc_throw(Unexpected, "Mandatory '" + name + " field missing while " "processing file " + fname); } if (x->get(name)->getType() != Element::string) { - isc_throw(BadValue, "'" + name + " field is present, but is not a string" + isc_throw(Unexpected, "'" + name + " field is present, but is not a string" " in file " + fname); } if (x->get(name)->stringValue().empty()) { - isc_throw(BadValue, "'" + name + " field is present, is a string, but is " + isc_throw(Unexpected, "'" + name + " field is present, is a string, but is " "empty in file " + fname); } } + /// @brief checks if mandatory list parameter is specified + /// + /// @param x a map that is being checked + /// @param name name of the list element expected to be there + /// @param fname name of the file (used in error reporting) + /// @throw Unexpected if missing, different type or empty void requireList(const ElementPtr& x, const string& name, const string& fname) { if (!x->contains(name)) { isc_throw(Unexpected, "Mandatory '" + name + " field missing while " "processing file " + fname); } if (x->get(name)->getType() != Element::list) { - isc_throw(BadValue, "'" + name + " field is present, but is not a list " + isc_throw(Unexpected, "'" + name + " field is present, but is not a list " "in file " + fname); } ConstElementPtr l = x->get(name); if (l->size() == 0) { - isc_throw(BadValue, "'" + name + " field is a list, but is empty in file " + isc_throw(Unexpected, "'" + name + " field is a list, but is empty in file " + fname); } // todo: check that every element is a string } + /// @brief Checks that the essential parameters for each command are defined + /// + /// @param fname name of the file the data was read from (printed if error is detected) + /// @param x a JSON map that contains content of the file void sanityCheck(const string& fname, const ElementPtr& x) { requireString(x, "name", fname); requireString(x, "brief", fname); @@ -111,6 +137,9 @@ public: //requireString(x, "resp-comment", fname); } + /// @brief Writes ISC copyright note to the stream + /// + /// @param f stream to write copyrights to void generateCopyright(stringstream& f) { f << "" << endl; } + /// @brief generates a link to command + /// + /// @param f stream to write the generated link to + /// @param cmd name of the command void generateCmdLink(stringstream& f, const string& cmd) { - f << "" << cmd << "" << endl; + f << "" << cmd + << "" << endl; } + /// @brief generates lists of all commands. + /// + /// Currently there are several lists (or rather lists of lists). They all enumerate + /// commands, but each list serving a different purpose: + /// - list of commands supported by a daemon + /// - list of commands provided by a hook + /// + /// @param f stream to write the generated lists to void generateLists(stringstream& f) { // Generate a list of all commands f << " Kea currently supports " << cmds_.size() << " commands:" << endl; @@ -163,8 +205,8 @@ public: } } - cout << "### " << all_daemons.size() << " daemon(s) detected." << endl; - cout << "### " << all_hooks.size() << " hook lib(s) detected." << endl; + cout << all_daemons.size() << " daemon(s) detected." << endl; + cout << all_hooks.size() << " hook lib(s) detected." << endl; for (auto daemon : all_daemons) { f << "" @@ -214,6 +256,7 @@ public: } + /// @brief generates the whole API documentation void generateOutput() { stringstream f; @@ -244,6 +287,9 @@ public: cout << "Output written to " << OUTPUT << endl; } + /// @brief generate sections for all commands + /// + /// @param f stream to write the commands to void generateCommands(stringstream& f){ for (auto cmd : cmds_) { @@ -257,118 +303,139 @@ public: } } -void replaceAll(std::string& str, const std::string& from, const std::string& to) { - if(from.empty()) - return; - size_t start_pos = 0; - while((start_pos = str.find(from, start_pos)) != std::string::npos) { - str.replace(start_pos, from.length(), to); - start_pos += to.length(); + /// @brief replace all strings + /// + /// @param str [in,out] this string will have some replacements + /// @param from what to replace + /// @param to what to replace with + void replaceAll(std::string& str, const std::string& from, const std::string& to) { + if(from.empty()) + return; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } } -} - -string escapeString(string txt) { - - replaceAll(txt, "<", "<"); - replaceAll(txt, ">", ">"); - return (txt); -} -string standardResponseSyntax() { - stringstream t; + /// @brief escapes string to be safe for XML (docbook) + /// + /// @param txt string to be escaped + /// @return escaped string + string escapeString(string txt) { - t << "{" << endl - << " \"result\": ," << endl - << " \"text\": " << endl - << "}" << endl; - return (t.str()); -} + replaceAll(txt, "<", "<"); + replaceAll(txt, ">", ">"); + return (txt); + } -string standardResponseComment() { - stringstream t; - - t << "Result is an integer representation of the status. Currently supported" - << " statuses are:" << endl - << "" << endl - << " 0 - success" << endl - << " 1 - error" << endl - << " 2 - unsupported" << endl - << " 3 - empty (command was completed successfully, but " - << "no data was affected or returned)" - << "" << endl - << "" << endl; - return (t.str()); -} + /// @brief generates standard description of command's response + /// + /// If a command doesn't have response syntax specified, we will + /// assume it follows the usual syntax and provide the default description. + string standardResponseSyntax() { + stringstream t; + + t << "{" << endl + << " \"result\": ," << endl + << " \"text\": " << endl + << "}" << endl; + return (t.str()); + } -void generateCommand(stringstream& f, const ElementPtr& cmd) { + /// @brief generates standard description of command's comment + /// + /// If a command doesn't have response syntax comment specified, we will + /// assume it follows the usual syntax and provide the default description. + string standardResponseComment() { + stringstream t; + + t << "Result is an integer representation of the status. Currently supported" + << " statuses are:" << endl + << "" << endl + << " 0 - success" << endl + << " 1 - error" << endl + << " 2 - unsupported" << endl + << " 3 - empty (command was completed successfully, but " + << "no data was affected or returned)" + << "" << endl + << "" << endl; + return (t.str()); + } - // command overview - f << "get("name")->stringValue() << "\">" - << cmd->get("name")->stringValue() << " - " - << cmd->get("brief")->stringValue() << "" << endl << endl; + /// @brief generates command description + /// + /// @param f stream to write the description to + /// @param cmd pointer to JSON structure that describes the command + void generateCommand(stringstream& f, const ElementPtr& cmd) { + + // command overview + f << "get("name")->stringValue() << "\">" + << cmd->get("name")->stringValue() << " - " + << cmd->get("brief")->stringValue() << "" << endl << endl; + + // command can be issued to the following daemons + f << "Supported by: "; + ConstElementPtr daemons = cmd->get("support"); + for (int i = 0; i < daemons->size(); i++) { + if (i) { + f << ", "; + } - // command can be issued to the following daemons - f << "Supported by: "; - ConstElementPtr daemons = cmd->get("support"); - for (int i = 0; i < daemons->size(); i++) { - if (i) { - f << ", "; + f << "get(i)->stringValue() + << "\">" << daemons->get(i)->stringValue() << ""; + } + f << "" << endl << endl; + + // availability + f << "Availability: " << cmd->get("avail")->stringValue(); + auto hook = cmd->get("hook"); + if (hook) { + f << " (stringValue() << "-lib\">" + << hook->stringValue() << ")"; + } else { + f << " (built-in)"; } - f << "get(i)->stringValue() - << "\">" << daemons->get(i)->stringValue() << ""; - } - f << "" << endl << endl; - - // availability - f << "Availability: " << cmd->get("avail")->stringValue(); - auto hook = cmd->get("hook"); - if (hook) { - f << " (stringValue() << "-lib\">" - << hook->stringValue() << ")"; - } else { - f << " (built-in)"; - } - - f << "" << endl << endl; - - // description and examples - f << "Description and examples: See get("name")->stringValue() << "\"/>" << endl << endl; - - // Command syntax: - f << "Command syntax:" << endl; - if (cmd->contains("cmd-syntax")) { - f << " " << escapeString(cmd->get("cmd-syntax")->stringValue()) - << "" << endl; - } else { - f << " {" << endl - << " \"command\": \"" << cmd->get("name")->stringValue() << "\"" << endl - << "}" << endl; - } - if (cmd->contains("cmd-comment")) { - f << cmd->get("cmd-comment")->stringValue(); - } - f << "" << endl << endl; + f << "" << endl << endl; + + // description and examples + f << "Description and examples: See get("name")->stringValue() << "\"/>" << endl << endl; + + // Command syntax: + f << "Command syntax:" << endl; + if (cmd->contains("cmd-syntax")) { + f << " " << escapeString(cmd->get("cmd-syntax")->stringValue()) + << "" << endl; + } else { + f << " {" << endl + << " \"command\": \"" << cmd->get("name")->stringValue() << "\"" << endl + << "}" << endl; + } + if (cmd->contains("cmd-comment")) { + f << cmd->get("cmd-comment")->stringValue(); + } + f << "" << endl << endl; - // Response syntax - f << "Response syntax:" << endl - << " "; + // Response syntax + f << "Response syntax:" << endl + << " "; - if (cmd->contains("resp-syntax")) { - f << escapeString(cmd->get("resp-syntax")->stringValue()); - } else { - f << escapeString(standardResponseSyntax()); - } - f << "" << endl; + if (cmd->contains("resp-syntax")) { + f << escapeString(cmd->get("resp-syntax")->stringValue()); + } else { + f << escapeString(standardResponseSyntax()); + } + f << "" << endl; - if (cmd->contains("resp-comment")) { - f << cmd->get("resp-comment")->stringValue(); - } else { - f << standardResponseComment(); + if (cmd->contains("resp-comment")) { + f << cmd->get("resp-comment")->stringValue(); + } else { + f << standardResponseComment(); + } + f << "" << endl << endl; } - f << "" << endl << endl; -} map cmds_; };