From: Francis Dupont Date: Sat, 5 Sep 2015 17:30:52 +0000 (+0200) Subject: [3516] Addressed old comments X-Git-Tag: trac3874_base~8^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a0a929cc69f0dde530b8fac4efee67e5a8a68c32;p=thirdparty%2Fkea.git [3516] Addressed old comments --- diff --git a/tools/system_messages.cc b/tools/system_messages.cc index bb708486b0..d55fe85cff 100644 --- a/tools/system_messages.cc +++ b/tools/system_messages.cc @@ -24,6 +24,7 @@ // system_messages [-o ] // // If no output file is specified, output is written to stdout. +// The produced format is docbook XML. #include #include @@ -35,48 +36,50 @@ #include #include -#ifdef USE_BOOST_FILESYSTEM -#include -#endif #include -typedef std::vector lines_type; +typedef std::vector LinesType; -/// dictionary values +/// @brief dictionary values struct Details { std::string text; - lines_type description; + LinesType description; std::string sname; std::string filename; }; -/// Main dictionary holding all the messages. The messages are -/// accumulated here before being printed in alphabetical order. -typedef std::map dictionary_type; -dictionary_type dictionary; +/// @brief Main dictionary holding all the messages. +/// The messages are accumulated here before being printed in +/// alphabetical order. +typedef std::map dictionaryType; +dictionaryType dictionary; -// The structure of the output page is: +/// @brief The structure of the output page // -// header -// section header -// message -// separator -// message -// separator -// : -// separator -// message -// section trailer -// separator -// section header -// : -// section trailer -// trailer +/// header +/// section header +/// message +/// separator +/// message +/// separator +/// : +/// separator +/// message +/// section trailer +/// separator +/// section header +/// : +/// section trailer +/// trailer // -// (Indentation is not relevant - it has only been added to the above -// illustration to make the structure clearer.) The text of these section is: +/// (Indentation is not relevant - it has only been added to the above +/// illustration to make the structure clearer.) The text of these section is: -// Header - this is output before anything else. +/// @name Constants for the output page +//@{ + +/// @brief File header +/// this is output before anything else. const std::string FILE_HEADER = "\n\ Kea Messages Manual\n\ \n\ \n\ - 2011-2014Internet Systems Consortium, Inc.\n\ + 2011-2015Internet Systems Consortium, Inc.\n\ \n\ \n\ \n\ @@ -141,15 +144,17 @@ const std::string FILE_HEADER = \n\ Kea Log Messages\n"; -// This is output one for each module. $M substitution token is the name. +/// @brief Section header +/// This is output one for each module. $M substitution token is the name. const std::string SECTION_HEADER = "
\n\ $M Module\n\ \n\ \n"; -// 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. +/// @brief message ID +/// 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. const std::string ID_MESSAGE = "\n\ $I $T\n\ @@ -157,27 +162,35 @@ const std::string ID_MESSAGE = $D\n\ "; -// A description may contain blank lines intended to separate -// paragraphs. If so, each blank line is replaced by the following. +/// @brief Blank line +/// A description may contain blank lines intended to separate +/// paragraphs. If so, each blank line is replaced by the following. const std::string BLANK = ""; -// The separator is copied to the output verbatim after each message except -// the last. +/// @brief Separator +/// 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. +/// @brief Section trailer +/// The trailer is copied to the output verbatim after the last message. const std::string SECTION_TRAILER = " \n\ \n\
"; -// The trailier is copied to the output verbatim after the last section. +/// @brief File trailer +/// The trailier is copied to the output verbatim after the last section. const std::string FILE_TRAILER = "
\n\ "; +//@} + +/// @name Utility routines +//@{ -/// Report an error and exit +/// @brief Report an error and exit void reportError(const std::string& filename, const std::string& what) { std::cerr << "*** ERROR in " << filename << "\n"; @@ -186,7 +199,7 @@ void reportError(const std::string& filename, const std::string& what) exit(1); } - +/// @brief Replace tag /// Replaces the '<' and '>' in text about to be inserted into the template /// sections above with < and > to avoid problems with message text /// being interpreted as XML text. @@ -202,10 +215,20 @@ std::string replaceTag(const std::string& src) result.push_back(*it); } } - return result; + return (result); } -/// Replace $c in a string +/// @brief Replace shell +/// Replace $c in a string (or with other words performs macro expansion +/// with '$' for introducing a macro followed by a character selecting +/// a specific macro. +/// +/// @param src source string +/// @param c character selecting a macro when it follows '$' +/// @param val value which +/// +/// @return the source string where all occurrences of $c were +/// replaced by val std::string replaceShell(const std::string& src, char c, const std::string& val) { @@ -226,33 +249,40 @@ std::string replaceShell(const std::string& src, char c, result.push_back(*it); } } - return result; + return (result); } +/// @brief Replace blank lines /// Replaces blank lines in an array with the contents of the 'blank' section. -lines_type replaceBlankLines(const lines_type lines) +LinesType replaceBlankLines(const LinesType lines) { - lines_type result; - for (lines_type::const_iterator l = lines.begin(); l != lines.end(); ++l) { + LinesType result; + for (LinesType::const_iterator l = lines.begin(); l != lines.end(); ++l) { if (l->empty()) { result.push_back(BLANK); } else { result.push_back(*l); } } - return result; + return (result); } +//@} + +/// @name Printing functions +//@{ -/// Printing functions +/// @brief Print file header void printHeader() { std::cout << FILE_HEADER << "\n"; } +/// @brief Print separator void printSeparator() { std::cout << SEPARATOR << "\n"; } +/// @brief Print section header void printSectionHeader(const std::string& sname) { // In the section name, replace "<" and ">" with XML-safe versions and @@ -260,6 +290,7 @@ void printSectionHeader(const std::string& sname) std::cout << replaceShell(SECTION_HEADER, 'M', replaceTag(sname)); } +/// @brief print message id void printMessage(const std::string& msgid) { // In the message ID, replace "<" and ">" with XML-safe versions and @@ -274,17 +305,17 @@ void printMessage(const std::string& msgid) // Do the same for the description then replace blank lines with the // specified separator. (We do this in that order to avoid replacing // the "<" and ">" in the XML tags in the separator.) - lines_type desc0 = dictionary[msgid].description; - lines_type desc1; - for (lines_type::iterator l = desc0.begin(); l != desc0.end(); ++l) { + LinesType desc0 = dictionary[msgid].description; + LinesType desc1; + for (LinesType::iterator l = desc0.begin(); l != desc0.end(); ++l) { desc1.push_back(replaceTag(*l)); } - lines_type desc2 = replaceBlankLines(desc1); + LinesType desc2 = replaceBlankLines(desc1); // Join the lines together to form a single string and insert into // current text. std::string m3; - for (lines_type::iterator l = desc2.begin(); l != desc2.end(); ++l) { + for (LinesType::iterator l = desc2.begin(); l != desc2.end(); ++l) { m3.append(*l); m3.push_back('\n'); } @@ -292,42 +323,43 @@ void printMessage(const std::string& msgid) std::cout << replaceShell(m2, 'D', m3) << "\n"; } +/// @brief print section trailer void printSectionTrailer() { std::cout << SECTION_TRAILER << "\n"; } +/// @brief print file trailer void printTrailer() { std::cout << FILE_TRAILER << "\n"; } +//@} -/// Removes leading and trailing empty lines. +/// @brief Removes leading and trailing empty lines. /// /// A list of strings is passed as argument, some of which may be empty. /// This function removes from the start and end of list a contiguous /// sequence of empty lines and returns the result. Embedded sequence of /// empty lines are not touched. /// -/// Parameters: -/// lines List of strings to be modified. +/// @param lines List of strings to be modified. /// -/// Return: -/// Input list of strings with leading/trailing blank line sequences -/// removed. -lines_type removeEmptyLeadingTrailing(lines_type lines) +/// @return Input list of strings with leading/trailing blank line +/// sequences removed. +LinesType removeEmptyLeadingTrailing(const LinesType& lines) { - lines_type retlines = lines; + LinesType retlines = lines; // Dispose of degenerate case of empty array if (retlines.empty()) { - return retlines; + return (retlines); } // Search for first non-blank line for (;;) { - lines_type::iterator start = retlines.begin(); + LinesType::iterator start = retlines.begin(); if (start == retlines.end()) { - return retlines; + return (retlines); } if (start->empty()) { retlines.erase(start); @@ -338,9 +370,9 @@ lines_type removeEmptyLeadingTrailing(lines_type lines) // Search for last non-blank line for (;;) { - lines_type::reverse_iterator finish = retlines.rbegin(); + LinesType::reverse_iterator finish = retlines.rbegin(); if (finish == retlines.rend()) { - return retlines; + return (retlines); } if (finish->empty()) { retlines.erase(retlines.end() - 1); @@ -349,24 +381,25 @@ lines_type removeEmptyLeadingTrailing(lines_type lines) } } - return retlines; + 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. +/// @brief 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. /// -/// Parameters: -/// msgid Message ID -/// msgtext Message text -/// desc Message description -/// 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. +/// @param msgid Message ID +/// @param msgtext Message text +/// @param desc Message description +/// @param 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. void addToDictionary(const std::string& msgid, const std::string& msgtext, - const lines_type& desc, + const LinesType& desc, const std::string& filename) { // If the ID is in the dictionary, append a "(n)" to the name - this will @@ -397,22 +430,24 @@ void addToDictionary(const std::string& msgid, } -/// Processes file content. Messages and descriptions are identified and -/// added to a dictionary (keyed by message ID). If the key already exists, -/// a numeric suffix is added to it. +/// @brief Processes file content. +/// Messages and descriptions are identified and added to a dictionary +/// (keyed by message ID). If the key already exists, a numeric +/// suffix is added to it. + +/// The format of .mes files is fully described in src/lib/log/logging.dox /// -/// Parameters: -/// filename Name of the message file being processed -/// lines Lines read from the file +/// @param filename Name of the message file being processed +/// @param lines Lines read from the file void processFileContent(const std::string& filename, - const lines_type& lines) + const LinesType& lines) { std::string prefix; // Last prefix encountered std::string msgid; // Last message ID encountered std::string msgtext; // Text of the message - lines_type description; // Description + LinesType description; // Description - for (lines_type::const_iterator l = lines.begin(); l != lines.end(); ++l) { + for (LinesType::const_iterator l = lines.begin(); l != lines.end(); ++l) { if (l->empty()) { description.push_back(*l); } else if (l->at(0) == '$') { @@ -464,26 +499,30 @@ 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. +/// @brief Process a file +/// Read it in and strip out all comments and and directives. Leading +/// and trailing blank lines in the file are removed and the remainder +/// passed for message processing. /// -/// Parameters: -/// filename Name of the message file to process +/// @param filename Name of the message file to process void processFile(const std::string& filename) { std::ifstream cin; cin.open(filename, std::ios::in); - lines_type lines0; + if (!cin.is_open()) { + reportError(filename, "open for read failure"); + } + LinesType lines0; while (!cin.eof()) { std::string line; getline(cin, line); lines0.push_back(line); } + cin.close(); // Trim leading and trailing spaces from each line, and remove comments. - lines_type lines1; - for (lines_type::iterator l = lines0.begin(); l != lines0.end(); ++l) { + LinesType lines1; + for (LinesType::iterator l = lines0.begin(); l != lines0.end(); ++l) { std::string line = *l; if (line.empty()) { lines1.push_back(line); @@ -512,51 +551,22 @@ void processFile(const std::string& filename) } // Remove leading/trailing empty line sequences from the result - lines_type lines2 = removeEmptyLeadingTrailing(lines1); + LinesType lines2 = removeEmptyLeadingTrailing(lines1); // Interpret content processFileContent(filename, lines2); } -/// Iterates through all files in the tree starting at the given root and -/// calls processFile for all .mes files found. -/// -/// Parameters: -/// root Directory that is the root of the source tree -#ifdef USE_BOOST_FILESYSTEM -void processAllFiles(const boost::filesystem::path& root) -{ - boost::filesystem::directory_iterator endd; - for (boost::filesystem::directory_iterator file(root); - file != endd; - ++file) { - boost::filesystem::path path = file->path(); - if (boost::filesystem::is_directory(path)) { - processAllFiles(path); - } else if (boost::filesystem::is_regular_file(path)) { - boost::filesystem::path extension = path.extension(); - // Identify message files - if (extension == ".mes") { - processFile(path.native()); - } - } - } -} -#endif - +/// @brief Usage error routine void usage(char* progname) { -#ifdef USE_BOOST_FILESYSTEM - std::cerr << "Usage: " << progname << - " [--help | options] root|files\n"; -#else std::cerr << "Usage: " << progname << " [--help | options] files\n"; -#endif std::cerr << " options: --output file: " << "output file name (default to stdout)\n"; } +/// @brief Main (entry point) int main(int argc, char* argv[]) { char* progname = argv[0]; @@ -578,9 +588,13 @@ int main(int argc, char* argv[]) exit(-1); } fout.open(argv[0], std::ofstream::out | std::ofstream::trunc); + if (!fout.is_open()) { + reportError(argv[0], "open for write failure"); + } std::cout.rdbuf(fout.rdbuf()); --argc; ++argv; + break; } } @@ -588,30 +602,15 @@ int main(int argc, char* argv[]) usage(progname); exit(-1); } -#ifdef USE_BOOST_FILESYSTEM - if (argc > 1) { - for (int i = 0; i < argc; ++i) { - processFile(argv[i]); - } - } else { - boost::filesystem::path root(argv[0]); - if (boost::filesystem::is_directory(root)) { - processAllFiles(root); - } else { - processFile(argv[0]); - } - } -#else for (int i = 0; i < argc; ++i) { processFile(argv[i]); } -#endif // 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(); + for (dictionaryType::iterator it = dictionary.begin(); it != dictionary.end(); ++it) { if (sname.compare(it->second.sname) != 0) { diff --git a/tools/system_messages.py b/tools/system_messages.py deleted file mode 100644 index 20190c79d9..0000000000 --- a/tools/system_messages.py +++ /dev/null @@ -1,442 +0,0 @@ -# Copyright (C) 2011, 2015 Internet Systems Consortium, Inc. ("ISC") -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. - -# Produce System Messages Manual -# -# This tool reads all the .mes files in the directory tree whose root is given -# on the command line and interprets them as message files. It pulls -# all the messages and description out, sorts them by message ID, and writes -# them out as a single (formatted) file. -# -# Invocation: -# The code is invoked using the command line: -# -# python system_messages.py [-o ] | -# -# If no output file is specified, output is written to stdout. - -import re -import os -import sys -from optparse import OptionParser - -# Main dictionary holding all the messages. The messages are accumulated here -# before being printed in alphabetical order. -dictionary = {} - -# The structure of the output page is: -# -# header -# section header -# message -# separator -# message -# separator -# : -# separator -# message -# section trailer -# separator -# section header -# : -# section trailer -# trailer -# -# (Indentation is not relevant - it has only been added to the above -# illustration to make the structure clearer.) The text of these section is: - -# Header - this is output before anything else. -FILE_HEADER = """ - - -%version; -]> - - - - - - Kea Messages Manual - - - 2011-2014Internet Systems Consortium, Inc. - - - - - This is the messages manual for Kea version &__VERSION__;. - The most up-to-date version of this document, along with - other documents for Kea, can be found at - . - - - - This is the messages manual for Kea version - &__VERSION__;. - - - - Introduction - - This document lists each message that can be logged by the - programs in the Kea package. Each entry in this manual - is of the form: - IDENTIFICATION message-text - ... where "IDENTIFICATION" is the message identification included - in each message logged and "message-text" is the accompanying - message text. The "message-text" may include placeholders of the - form "%1", "%2" etc.; these parameters are replaced by relevant - values when the message is logged. - - - Each entry is also accompanied by a description giving more - information about the circumstances that result in the message - being logged. - - - For information on configuring and using Kea logging, - refer to the Kea Guide. - - - - - Kea Log Messages -""" - -# This is output one for each module. $M substitution token is the name. -SECTION_HEADER = """
- $M Module - - """ - -# 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. -ID_MESSAGE = """ -$I $T - -$D - -""" - -# A description may contain blank lines intended to separate -# paragraphs. If so, each blank line is replaced by the following. -BLANK = "" - -# The separator is copied to the output verbatim after each message or -# section except the last. -SEPARATOR = "" - -# The trailer is copied to the output verbatim after the last message. -SECTION_TRAILER = """ - -
""" - -# The trailer is copied to the output verbatim after the last section. -FILE_TRAILER = """
-
""" - - -def reportError(filename, what): - """Report an error and exit""" - print("*** ERROR in ", filename, file=sys.stderr) - print("*** REASON: ", what, file=sys.stderr) - print("*** System message generator terminating", file=sys.stderr) - sys.exit(1) - - -def replaceTag(string): - """Replaces the '<' and '>' in text about to be inserted into the template - sections above with < and > to avoid problems with message text - being interpreted as XML text. - """ - string1 = string.replace("<", "<") - string2 = string1.replace(">", ">") - return string2 - -def replaceBlankLines(lines): - """Replaces blank lines in an array with the contents of the 'blank' - section. - """ - result = [] - for l in lines: - if len(l) == 0: - result.append(BLANK) - else: - result.append(l) - - return result - - -# Printing functions -def printHeader(): - print(FILE_HEADER) - -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. - m1 = ID_MESSAGE.replace("$I", replaceTag(msgid)) - - # Do the same for the message text. - m2 = m1.replace("$T", replaceTag(dictionary[msgid]['text'])) - - # Do the same for the description then replace blank lines with the - # specified separator. (We do this in that order to avoid replacing - # the "<" and ">" in the XML tags in the separator.) - desc1 = [replaceTag(l) for l in dictionary[msgid]['description']] - desc2 = replaceBlankLines(desc1) - - # Join the lines together to form a single string and insert into - # current text. - m3 = m2.replace("$D", "\n".join(desc2)) - - print(m3) - -def printSectionTrailer(): - print(SECTION_TRAILER) - -def printTrailer(): - print(FILE_TRAILER) - - -def removeEmptyLeadingTrailing(lines): - """Removes leading and trailing empty lines. - - A list of strings is passed as argument, some of which may be empty. - This function removes from the start and end of list a contiguous - sequence of empty lines and returns the result. Embedded sequence of - empty lines are not touched. - - Parameters: - lines List of strings to be modified. - - Return: - Input list of strings with leading/trailing blank line sequences - removed. - """ - - retlines = [] - - # Dispose of degenerate case of empty array - if len(lines) == 0: - return retlines - - # Search for first non-blank line - start = 0 - while start < len(lines): - if len(lines[start]) > 0: - break - start = start + 1 - - # Handle case when entire list is empty - if start >= len(lines): - return retlines - - # Search for last non-blank line - finish = len(lines) - 1 - while finish >= 0: - if len(lines[finish]) > 0: - break - finish = finish - 1 - - retlines = lines[start:finish + 1] - 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 - suffixes of the form "(n)" to it until one is found that doesn't. - - Parameters: - 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. - """ - - # If the ID is in the dictionary, append a "(n)" to the name - this will - # flag that there are multiple instances. (However, this is an error - - # each ID should be unique in the code.) - if msgid in dictionary: - i = 1 - while msgid + " (" + str(i) + ")" in dictionary: - i = i + 1 - msgid = msgid + " (" + str(i) + ")" - - # Remove leading and trailing blank lines in the description, then - # 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, - a numeric suffix is added to it. - - Parameters: - filename Name of the message file being processed - lines Lines read from the file - """ - - prefix = "" # Last prefix encountered - msgid = "" # Last message ID encountered - msgtext = "" # Text of the message - description = [] # Description - - for l in lines: - if l.startswith("$"): - # Starts with "$". Ignore anything other than $PREFIX - words = re.split("\s+", l) - if words[0].upper() == "$PREFIX": - if len(words) == 1: - prefix = "" - else: - prefix = words[1] - - elif l.startswith("%"): - # Start of a message. Add the message we were processing to the - # dictionary and clear everything apart from the file name. - if msgid != "": - addToDictionary(msgid, msgtext, description, filename) - - msgid = "" - msgtext = "" - description = [] - - # Start of a message - l = l[1:].strip() # Remove "%" and trim leading spaces - if len(l) == 0: - printError(filename, "Line with single % found") - next - - # Split into words. The first word is the message ID - words = re.split("\s+", l) - msgid = (prefix + words[0]).upper() - msgtext = l[len(words[0]):].strip() - - else: - # Part of a description, so add to the current description array - description.append(l) - - # All done, add the last message to the global dictionaty. - if msgid != "": - 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 - and the remainder passed for message processing. - - Parameters: - filename Name of the message file to process - """ - lines = open(filename).readlines(); - - # Trim leading and trailing spaces from each line, and remove comments. - lines = [l.strip() for l in lines] - lines = [l for l in lines if not l.startswith("#")] - - # Remove leading/trailing empty line sequences from the result - lines = removeEmptyLeadingTrailing(lines) - - # Interpret content - 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. - - Parameters: - root Directory that is the root of the source tree - """ - for (path, dirs, files) in os.walk(root): - - # Identify message files - mes_files = [f for f in files if f.endswith(".mes")] - - # ... and process each file in the list - for m in mes_files: - processFile(path + os.sep + m) - - -# Main program -if __name__ == "__main__": - parser = OptionParser(usage="Usage: %prog [--help | options] root|files") - parser.add_option("-o", "--output", dest="output", default=None, - metavar="FILE", - help="output file name (default to stdout)") - (options, args) = parser.parse_args() - - if len(args) == 0: - parser.error("Must supply directory at which to begin search or files") - - # Redirect output if specified (errors are written to stderr) - if options.output is not None: - sys.stdout = open(options.output, 'w') - - # Read the files and load the data - if (len(args) > 1) or (not os.path.isdir(args[0])): - for file in args: - processFile(file) - else: - processAllFiles(args[0]) - - # Now just print out everything we've read (in alphabetical order). - 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()