Browse Source

[3516] Added sectioning in both python and c++ system messages tools

Francis Dupont 10 years ago
parent
commit
f2b1aad25d
2 changed files with 93 additions and 34 deletions
  1. 51 12
      tools/system_messages.cc
  2. 42 22
      tools/system_messages.py

+ 51 - 12
tools/system_messages.cc

@@ -45,6 +45,7 @@ typedef std::vector<std::string> lines_type;
 struct Details {
     std::string text;
     lines_type description;
+    std::string sname;
     std::string filename;
 };
 
@@ -137,7 +138,11 @@ const std::string FILE_HEADER =
   </chapter>\n\
 \n\
   <chapter id=\"messages\">\n\
-    <title>Kea Log Messages</title>\n\
+    <title>Kea Log Messages</title>\n";
+
+// This is output one for each module. $M substitution token is the name.
+const std::string SECTION_HEADER = "  <section id=\"$M\">\n\
+    <title>$M Module</title>\n\
     <para>\n\
       <variablelist>\n";
 
@@ -153,19 +158,24 @@ $D</para></listitem>\n\
 
 // A description may contain blank lines intended to separate
 // paragraphs.  If so, each blank line is replaced by the following.
-const std::string SEC_BLANK = "</para><para>";
+const std::string BLANK = "</para><para>";
 
 // The separator is copied to the output verbatim after each message except
 // the last.
 const std::string SEPARATOR = "";
 
 // The trailier is copied to the output verbatim after the last message.
-const std::string FILE_TRAILER =
+const std::string SECTION_TRAILER =
 "      </variablelist>\n\
     </para>\n\
-  </chapter>\n\
+  </section>";
+
+// The trailier is copied to the output verbatim after the last section.
+const std::string FILE_TRAILER =
+"  </chapter>\n\
 </book>";
 
+
 /// Report an error and exit
 void reportError(const std::string& filename, const std::string& what)
 {
@@ -224,7 +234,7 @@ lines_type replaceBlankLines(const lines_type lines)
     lines_type result;
     for (lines_type::const_iterator l = lines.begin(); l != lines.end(); ++l) {
         if (l->empty()) {
-            result.push_back(SEC_BLANK);
+            result.push_back(BLANK);
         } else {
             result.push_back(*l);
         }
@@ -242,9 +252,16 @@ void printSeparator() {
     std::cout << SEPARATOR << "\n";
 }
 
+void printSectionHeader(const std::string& sname)
+{
+    // In the section name, replace "<" and ">" with XML-safe versions and
+    // substitute into the data.
+    std::cout << replaceShell(SECTION_HEADER, 'M', replaceTag(sname));
+}
+
 void printMessage(const std::string& msgid)
 {
-    //In the message ID, replace "<" and ">" with XML-safe versions and
+    // In the message ID, replace "<" and ">" with XML-safe versions and
     // substitute into the data.
     const std::string m0 = ID_MESSAGE;
     const std::string m1 = replaceShell(m0, 'I', replaceTag(msgid));
@@ -274,6 +291,10 @@ void printMessage(const std::string& msgid)
     std::cout << replaceShell(m2, 'D', m3) << "\n";
 }
 
+void printSectionTrailer() {
+    std::cout << SECTION_TRAILER << "\n";
+}
+
 void printTrailer() {
     std::cout << FILE_TRAILER << "\n";
 }
@@ -330,6 +351,7 @@ lines_type removeEmptyLeadingTrailing(lines_type lines)
     return retlines;
 }
 
+
 /// Add the current message ID and associated information to the global
 /// dictionary.  If a message with that ID already exists, loop appending
 /// suffixes of the form "(n)" to it until one is found that doesn't.
@@ -367,6 +389,8 @@ void addToDictionary(const std::string& msgid,
     Details details;
     details.text = msgtext;
     details.description = removeEmptyLeadingTrailing(desc);
+    size_t underscore = msgid.find_first_of('_');
+    details.sname = msgid.substr(0, underscore);
     details.filename = filename;
     dictionary.insert(std::pair<const std::string, Details>(key, details));
 }
@@ -439,7 +463,6 @@ void processFileContent(const std::string& filename,
     }
 }
 
-
 /// Processes a file by reading it in and stripping out all comments and
 /// and directives.  Leading and trailing blank lines in the file are removed
 /// and the remainder passed for message processing.
@@ -518,6 +541,7 @@ void processAllFiles(const boost::filesystem::path& root)
     }
 }
 
+
 void usage(char* progname)
 {
     std::cerr << "Usage: " << progname <<
@@ -548,6 +572,8 @@ int main(int argc, char* argv[])
             }
             fout.open(argv[0], std::ofstream::out | std::ofstream::trunc);
             std::cout.rdbuf(fout.rdbuf());
+            --argc;
+            ++argv;
         }
     }
 
@@ -570,15 +596,28 @@ int main(int argc, char* argv[])
 
     // Now just print out everything we've read (in alphabetical order).
     bool first = true;
+    std::string sname;
     printHeader();
     for (dictionary_type::iterator it = dictionary.begin();
          it != dictionary.end();
          ++it) {
-         if (!first) {
-             printSeparator();
-         }
-         first = false;
-         printMessage(it->first);
+        if (sname.compare(it->second.sname) != 0) {
+            if (!sname.empty()) {
+                printSectionTrailer();
+                printSeparator();
+            }
+            sname = it->second.sname;
+            printSectionHeader(sname);
+            first = true;
+        }
+        if (!first) {
+            printSeparator();
+        }
+        first = false;
+        printMessage(it->first);
+    }
+    if (!sname.empty()) {
+        printSectionTrailer();
     }
     printTrailer();
     exit(0);

+ 42 - 22
tools/system_messages.py

@@ -57,7 +57,7 @@ dictionary = {}
 # illustration to make the structure clearer.)  The text of these section is:
 
 # Header - this is output before anything else.
-FILE_HEADER="""<?xml version="1.0" encoding="UTF-8"?>
+FILE_HEADER = """<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY mdash  "&#x2014;" >
@@ -119,10 +119,14 @@ FILE_HEADER="""<?xml version="1.0" encoding="UTF-8"?>
 
   <chapter id="messages">
     <title>Kea Log Messages</title>
-    <para>
-      <variablelist>
 """
 
+# This is output one for each module. $M substitution token is the name.
+SECTION_HEADER = """  <section id="$M">
+    <title>$M Module</title>
+    <para>
+      <variablelist>"""
+
 # This is output once for each message.  The string contains substitution
 # tokens: $I is replaced by the message identification, $T by the message text,
 # and $D by the message description.
@@ -133,18 +137,21 @@ $D
 </para></listitem>
 </varlistentry>"""
 
-# A description may contain blank lines intended to separate paragraphs.  If so,
-# each blank line is replaced by the following.
-SEC_BLANK = "</para><para>"
+# A description may contain blank lines intended to separate
+# paragraphs.  If so, each blank line is replaced by the following.
+BLANK = "</para><para>"
 
-# The separator is copied to the output verbatim after each message except
-# the last.
+# The separator is copied to the output verbatim after each message or
+# section except the last.
 SEPARATOR = ""
 
-# The trailier is copied to the output verbatim after the last message.
-FILE_TRAILER = """      </variablelist>
+# The trailer is copied to the output verbatim after the last message.
+SECTION_TRAILER = """      </variablelist>
     </para>
-  </chapter>
+  </section>"""
+
+# The trailer is copied to the output verbatim after the last section.
+FILE_TRAILER = """  </chapter>
 </book>"""
 
 
@@ -156,7 +163,6 @@ def reportError(filename, what):
     sys.exit(1)
 
 
-
 def replaceTag(string):
     """Replaces the '<' and '>' in text about to be inserted into the template
        sections above with &lt; and &gt; to avoid problems with message text
@@ -166,8 +172,6 @@ def replaceTag(string):
     string2 = string1.replace(">", "&gt;")
     return string2
 
-
-
 def replaceBlankLines(lines):
     """Replaces blank lines in an array with the contents of the 'blank'
        section.
@@ -175,14 +179,13 @@ def replaceBlankLines(lines):
     result = []
     for l in lines:
         if len(l) == 0:
-            result.append(SEC_BLANK)
+            result.append(BLANK)
         else:
             result.append(l)
 
     return result
 
 
-
 # Printing functions
 def printHeader():
     print(FILE_HEADER)
@@ -190,6 +193,13 @@ def printHeader():
 def printSeparator():
     print(SEPARATOR)
 
+def printSectionHeader(sname):
+    # In the section name, replace "<" and ">" with XML-safe versions and
+    # substitute into the data.
+    m = SECTION_HEADER.replace("$M", replaceTag(sname));
+
+    print(m)
+
 def printMessage(msgid):
     # In the message ID, replace "<" and ">" with XML-safe versions and
     # substitute into the data.
@@ -210,11 +220,13 @@ def printMessage(msgid):
 
     print(m3)
 
+def printSectionTrailer():
+    print(SECTION_TRAILER)
+
 def printTrailer():
     print(FILE_TRAILER)
 
 
-
 def removeEmptyLeadingTrailing(lines):
     """Removes leading and trailing empty lines.
 
@@ -259,7 +271,6 @@ def removeEmptyLeadingTrailing(lines):
     return retlines
 
 
-
 def addToDictionary(msgid, msgtext, desc, filename):
     """Add the current message ID and associated information to the global
        dictionary.  If a message with that ID already exists, loop appending
@@ -269,6 +280,7 @@ def addToDictionary(msgid, msgtext, desc, filename):
        msgid        Message ID
        msgtext      Message text
        desc         Message description
+       sname        Section name (part before the first _ of the ID)
        filename     File from which the message came.  Currently this is
                     not used, but a future enhancement may wish to include the
                     name of the message file in the messages manual.
@@ -287,13 +299,14 @@ def addToDictionary(msgid, msgtext, desc, filename):
     # add everything into a subdictionary which is then added to the main
     # one.
     details = {}
+    words = re.split("_", msgid)
     details['text'] = msgtext
     details['description'] = removeEmptyLeadingTrailing(desc)
+    details['sname'] = words[0]
     details['filename'] = filename
     dictionary[msgid] = details
 
 
-
 def processFileContent(filename, lines):
     """Processes file content.  Messages and descriptions are identified and
        added to a dictionary (keyed by message ID).  If the key already exists,
@@ -349,7 +362,6 @@ def processFileContent(filename, lines):
         addToDictionary(msgid, msgtext, description, filename)
 
 
-
 def processFile(filename):
     """Processes a file by reading it in and stripping out all comments and
        and directives.  Leading and trailing blank lines in the file are removed
@@ -371,7 +383,6 @@ def processFile(filename):
     processFileContent(filename, lines)
 
 
-
 def processAllFiles(root):
     """Iterates through all files in the tree starting at the given root and
        calls processFile for all .mes files found.
@@ -410,11 +421,20 @@ if __name__ == "__main__":
     processAllFiles(args[0])
 
     # Now just print out everything we've read (in alphabetical order).
-    count = 1
+    sname = ""
     printHeader()
     for msgid in sorted(dictionary):
+        if dictionary[msgid]['sname'] != sname:
+            if sname != "":
+               printSectionTrailer()
+               printSeparator()
+            sname = dictionary[msgid]['sname']
+            printSectionHeader(sname)
+            count = 1
         if count > 1:
             printSeparator()
         count = count + 1
         printMessage(msgid)
+    if sname !="":
+        printSectionTrailer()
     printTrailer()