|
@@ -0,0 +1,334 @@
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+import re
|
|
|
+import os
|
|
|
+import sys
|
|
|
+from optparse import OptionParser
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+dictionary = {}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+SEC_HEADER = """<html>
|
|
|
+<head>
|
|
|
+<title>BIND 10 System Messages</title>
|
|
|
+<link rel="stylesheet" href="./bind10-guide.css" type="text/css">
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+<h1>BIND 10 System Messages</h1>
|
|
|
+<p/>
|
|
|
+"""
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+SEC_MESSAGE = """<b><a name="$I">$I</a></b>, $T<br/>
|
|
|
+$D"""
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+SEC_BLANK = "<p/>"
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+SEC_SEPARATOR = "<p/>"
|
|
|
+
|
|
|
+
|
|
|
+SEC_TRAILER = """</body>
|
|
|
+</html>"""
|
|
|
+
|
|
|
+
|
|
|
+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 printHeader():
|
|
|
+ print(SEC_HEADER)
|
|
|
+
|
|
|
+def printSeparator():
|
|
|
+ print(SEC_SEPARATOR)
|
|
|
+
|
|
|
+def printMessage(msgid):
|
|
|
+ m1 = SEC_MESSAGE.replace("$I", msgid)
|
|
|
+ m2 = m1.replace("$T", dictionary[msgid]['text'])
|
|
|
+ m3 = m2.replace("$D", dictionary[msgid]['description'])
|
|
|
+ print(m3)
|
|
|
+
|
|
|
+def printTrailer():
|
|
|
+ print(SEC_TRAILER)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+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(SEC_BLANK)
|
|
|
+ else:
|
|
|
+ result.append(l)
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+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 = []
|
|
|
+
|
|
|
+
|
|
|
+ if len(lines) == 0:
|
|
|
+ return retlines
|
|
|
+
|
|
|
+
|
|
|
+ start = 0
|
|
|
+ while start < len(lines):
|
|
|
+ if len(lines[start]) > 0:
|
|
|
+ break
|
|
|
+ start = start + 1
|
|
|
+
|
|
|
+
|
|
|
+ if start >= len(lines):
|
|
|
+ return retlines
|
|
|
+
|
|
|
+
|
|
|
+ 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
|
|
|
+ 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 msgid in dictionary:
|
|
|
+ i = 1
|
|
|
+ while msgid + " (" + str(i) + ")" in dictionary:
|
|
|
+ i = i + 1
|
|
|
+ msgid = msgid + " (" + str(i) + ")"
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ modified_desc = replaceBlankLines(removeEmptyLeadingTrailing(desc))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ details = {}
|
|
|
+ details['text'] = msgtext
|
|
|
+ details['description'] = "\n".join(modified_desc)
|
|
|
+ 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 = ""
|
|
|
+ msgid = ""
|
|
|
+ msgtext = ""
|
|
|
+ description = []
|
|
|
+
|
|
|
+ for l in lines:
|
|
|
+ if l.startswith("$"):
|
|
|
+
|
|
|
+ words = re.split("\s+", l)
|
|
|
+ if words[0].upper() == "$PREFIX":
|
|
|
+ if len(words) == 1:
|
|
|
+ prefix = ""
|
|
|
+ else:
|
|
|
+ prefix = words[1]
|
|
|
+
|
|
|
+ elif l.startswith("%"):
|
|
|
+
|
|
|
+
|
|
|
+ if msgid != "":
|
|
|
+ addToDictionary(msgid, msgtext, description, filename)
|
|
|
+
|
|
|
+ msgid = ""
|
|
|
+ msgtext = ""
|
|
|
+ description = []
|
|
|
+
|
|
|
+
|
|
|
+ l = l[1:].strip()
|
|
|
+ if len(l) == 0:
|
|
|
+ printError(filename, "Line with single % found")
|
|
|
+ next
|
|
|
+
|
|
|
+
|
|
|
+ words = re.split("\s+", l)
|
|
|
+ msgid = (prefix + words[0]).upper()
|
|
|
+ msgtext = l[len(words[0]):].strip()
|
|
|
+
|
|
|
+ else:
|
|
|
+
|
|
|
+ description.append(l)
|
|
|
+
|
|
|
+
|
|
|
+ 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();
|
|
|
+
|
|
|
+
|
|
|
+ lines = [l.strip() for l in lines]
|
|
|
+ lines = [l for l in lines if not l.startswith("#")]
|
|
|
+
|
|
|
+
|
|
|
+ lines = removeEmptyLeadingTrailing(lines)
|
|
|
+
|
|
|
+
|
|
|
+ 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 BIND-10 source tree
|
|
|
+ """
|
|
|
+ for (path, dirs, files) in os.walk(root):
|
|
|
+
|
|
|
+
|
|
|
+ mes_files = [f for f in files if f.endswith(".mes")]
|
|
|
+
|
|
|
+
|
|
|
+ for m in mes_files:
|
|
|
+ processFile(path + os.sep + m)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ parser = OptionParser(usage="Usage: %prog [--help | options] root")
|
|
|
+ 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")
|
|
|
+ elif len(args) > 1:
|
|
|
+ parser.error("Only a single root directory can be given")
|
|
|
+
|
|
|
+
|
|
|
+ if options.output is not None:
|
|
|
+ sys.stdout = open(options.output, 'w')
|
|
|
+
|
|
|
+
|
|
|
+ processAllFiles(args[0])
|
|
|
+
|
|
|
+
|
|
|
+ count = 1
|
|
|
+ printHeader()
|
|
|
+ for msgid in sorted(dictionary):
|
|
|
+ if count > 1:
|
|
|
+ printSeparator()
|
|
|
+ count = count + 1
|
|
|
+ printMessage(msgid)
|
|
|
+ printTrailer()
|