]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#10,!3] Docgen sources are now documented.
authorTomek Mrugalski <tomasz@isc.org>
Tue, 2 Oct 2018 13:16:22 +0000 (15:16 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Tue, 29 Oct 2019 17:57:13 +0000 (18:57 +0100)
doc/docgen/kea_docgen.cc

index 41da9f9bab62ef3d46b13faf8321aee50780dc5c..88386c7c1b093bd848322f7e1fd2495e86c34518 100644 (file)
@@ -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 <iostream>
 #include <fstream>
 #include <sstream>
@@ -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<string>& files) {
 
         map <string, ElementPtr> 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;
         f << " - Copyright (C) 2018 Internet Systems Consortium, Inc. (\"ISC\")" << endl;
@@ -123,10 +152,23 @@ public:
         f << "<!-- autogenerated using cmd_docgen. Do not edit by hand! -->" << 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 << "<command><link linkend=\"ref-" << cmd << "\">" << cmd << "</link></command>" << endl;
+        f << "<command><link linkend=\"ref-" << cmd << "\">" << cmd
+          << "</link></command>" << 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 << "  <para>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 << "<para xml:id=\"commands-" << daemon << "\">"
@@ -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, "<", "&lt;");
-    replaceAll(txt, ">", "&gt;");
-    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\": <integer>," << endl
-      << "    \"text\": <string>" << endl
-      << "}" << endl;
-    return (t.str());
-}
+        replaceAll(txt, "<", "&lt;");
+        replaceAll(txt, ">", "&gt;");
+        return (txt);
+    }
 
-string standardResponseComment() {
-    stringstream t;
-
-    t << "Result is an integer representation of the status. Currently supported"
-      << " statuses are:" << endl
-      << "<itemizedlist>" << endl
-      << "  <listitem><para>0 - success</para></listitem>" << endl
-      << "  <listitem><para>1 - error</para></listitem>" << endl
-      << "  <listitem><para>2 - unsupported</para></listitem>" << endl
-      << "  <listitem><para>3 - empty (command was completed successfully, but "
-      <<                        "no data was affected or returned)</para>"
-      <<                        "</listitem>" << endl
-      << "</itemizedlist>" << 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\": <integer>," << endl
+          << "    \"text\": <string>" << 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
+          << "<itemizedlist>" << endl
+          << "  <listitem><para>0 - success</para></listitem>" << endl
+          << "  <listitem><para>1 - error</para></listitem>" << endl
+          << "  <listitem><para>2 - unsupported</para></listitem>" << endl
+          << "  <listitem><para>3 - empty (command was completed successfully, but "
+          <<                        "no data was affected or returned)</para>"
+          <<                        "</listitem>" << endl
+          << "</itemizedlist>" << endl;
+        return (t.str());
+    }
 
-    // command overview
-    f << "<para xml:id=\"ref-" << cmd->get("name")->stringValue() << "\"><command>"
-      << cmd->get("name")->stringValue() << "</command> - "
-      << cmd->get("brief")->stringValue() << "</para>" << 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 << "<para xml:id=\"ref-" << cmd->get("name")->stringValue() << "\"><command>"
+          << cmd->get("name")->stringValue() << "</command> - "
+          << cmd->get("brief")->stringValue() << "</para>" << endl << endl;
+
+        // command can be issued to the following daemons
+        f << "<para>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 << "<para>Supported by: ";
-    ConstElementPtr daemons = cmd->get("support");
-    for (int i = 0; i < daemons->size(); i++) {
-        if (i) {
-            f << ", ";
+            f << "<command><link linkend=\"commands-" << daemons->get(i)->stringValue()
+              << "\">" << daemons->get(i)->stringValue() << "</link></command>";
+        }
+        f << "</para>" << endl << endl;
+
+        // availability
+        f << "<para>Availability: " << cmd->get("avail")->stringValue();
+        auto hook = cmd->get("hook");
+        if (hook) {
+            f << " (<link linkend=\"commands-" << hook->stringValue() << "-lib\">"
+              << hook->stringValue() << "</link>)";
+        } else {
+            f << " (built-in)";
         }
 
-        f << "<command><link linkend=\"commands-" << daemons->get(i)->stringValue()
-          << "\">" << daemons->get(i)->stringValue() << "</link></command>";
-    }
-    f << "</para>" << endl << endl;
-
-    // availability
-    f << "<para>Availability: " << cmd->get("avail")->stringValue();
-    auto hook = cmd->get("hook");
-    if (hook) {
-        f << " (<link linkend=\"commands-" << hook->stringValue() << "-lib\">"
-          << hook->stringValue() << "</link>)";
-    } else {
-        f << " (built-in)";
-    }
-
-    f << "</para>" << endl << endl;
-
-    // description and examples
-    f << "<para>Description and examples: See <xref linkend=\"command-"
-      << cmd->get("name")->stringValue() << "\"/></para>" << endl << endl;
-
-    // Command syntax:
-    f << "<para>Command syntax:" << endl;
-    if (cmd->contains("cmd-syntax")) {
-        f << "  <screen>" << escapeString(cmd->get("cmd-syntax")->stringValue())
-          << "</screen>" << endl;
-    } else {
-        f << "  <screen>{" << endl
-          << "    \"command\": \"" << cmd->get("name")->stringValue() << "\"" << endl
-          << "}</screen>" << endl;
-    }
-    if (cmd->contains("cmd-comment")) {
-        f << cmd->get("cmd-comment")->stringValue();
-    }
-    f << "</para>" << endl << endl;
+        f << "</para>" << endl << endl;
+
+        // description and examples
+        f << "<para>Description and examples: See <xref linkend=\"command-"
+          << cmd->get("name")->stringValue() << "\"/></para>" << endl << endl;
+
+        // Command syntax:
+        f << "<para>Command syntax:" << endl;
+        if (cmd->contains("cmd-syntax")) {
+            f << "  <screen>" << escapeString(cmd->get("cmd-syntax")->stringValue())
+              << "</screen>" << endl;
+        } else {
+            f << "  <screen>{" << endl
+              << "    \"command\": \"" << cmd->get("name")->stringValue() << "\"" << endl
+              << "}</screen>" << endl;
+        }
+        if (cmd->contains("cmd-comment")) {
+            f << cmd->get("cmd-comment")->stringValue();
+        }
+        f << "</para>" << endl << endl;
 
-    // Response syntax
-    f << "<para>Response syntax:" << endl
-      << "  <screen>";
+        // Response syntax
+        f << "<para>Response syntax:" << endl
+          << "  <screen>";
 
-    if (cmd->contains("resp-syntax")) {
-        f << escapeString(cmd->get("resp-syntax")->stringValue());
-    } else {
-        f << escapeString(standardResponseSyntax());
-    }
-    f << "</screen>" << endl;
+        if (cmd->contains("resp-syntax")) {
+            f << escapeString(cmd->get("resp-syntax")->stringValue());
+        } else {
+            f << escapeString(standardResponseSyntax());
+        }
+        f << "</screen>" << 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 << "</para>" << endl << endl;
     }
-    f << "</para>" << endl << endl;
-}
 
     map<string, ElementPtr> cmds_;
 };