Merged revisions 2136-2200,2202-2290,2292-2301 via svnmerge from
[scons.git] / bin / scons-proc.py
index 809c3d04e1001a3934f7bc4285a4d5757b563f63..1de0caa96144c20db5e013520bb696f517c2c8d1 100644 (file)
@@ -2,10 +2,13 @@
 #
 # Process a list of Python and/or XML files containing SCons documentation.
 #
-# Depending on the options, this script creates DocBook-formatted lists
-# of the Builders, Tools or construction variables in generated SGML
-# files containing the summary text and/or .mod files contining the
-# ENTITY definitions for each item.
+# This script creates formatted lists of the Builders, Tools or
+# construction variables documented in the specified XML files.
+#
+# Dependening on the options, the lists are output in either
+# DocBook-formatted generated XML files containing the summary text
+# and/or .mod files contining the ENTITY definitions for each item,
+# or in man-page-formatted output.
 #
 import getopt
 import os.path
@@ -20,25 +23,39 @@ import SConsDoc
 base_sys_path = [os.getcwd() + '/build/test-tar-gz/lib/scons'] + sys.path
 
 helpstr = """\
-Usage: scons-varlist.py [-b .gen,.mod] [-t .gen,.mod] [-v .gen,.mod] [infile]
+Usage: scons-proc.py [--man|--xml]
+                     [-b file(s)] [-t file(s)] [-v file(s)] [infile ...]
 Options:
-  -m, --modfile               .mod file to hold Builder entities
+  -b file(s)        dump builder information to the specified file(s)
+  -t file(s)        dump tool information to the specified file(s)
+  -v file(s)        dump variable information to the specified file(s)
+  --man             print info in man page format, each -[btv] argument
+                    is a single file name
+  --xml             (default) print info in SML format, each -[btv] argument
+                    is a pair of comma-separated .gen,.mod file names
 """
 
 opts, args = getopt.getopt(sys.argv[1:],
-                           "b:t:v:",
-                           ['builders=', 'tools=', 'variables='])
+                           "b:ht:v:",
+                           ['builders=', 'help',
+                            'man', 'xml', 'tools=', 'variables='])
 
 buildersfiles = None
+output_type = '--xml'
 toolsfiles = None
 variablesfiles = None
 
 for o, a in opts:
-    if o == '-b' or o == '--builders':
+    if o in ['-b', '--builders']:
         buildersfiles = a
-    elif o == '-t' or o == '--tools':
+    elif o in ['-h', '--help']:
+        sys.stdout.write(helpstr)
+        sys.exit(0)
+    elif o in ['--man', '--xml']:
+        output_type = o
+    elif o in ['-t', '--tools']:
         toolsfiles = a
-    elif o == '-v' or o == '--variables':
+    elif o in ['-v', '--variables']:
         variablesfiles = a
 
 h = SConsDoc.SConsDocHandler()
@@ -46,12 +63,12 @@ saxparser = xml.sax.make_parser()
 saxparser.setContentHandler(h)
 saxparser.setErrorHandler(h)
 
-preamble = """\
+xml_preamble = """\
 <?xml version="1.0"?>
 <scons_doc>
 """
 
-postamble = """\
+xml_postamble = """\
 </scons_doc>
 """
 
@@ -62,7 +79,7 @@ for f in args:
         if dir:
             sys.path = [dir] + base_sys_path
         module = SConsDoc.importfile(f)
-        h.set_file_info(f, len(preamble.split('\n')))
+        h.set_file_info(f, len(xml_preamble.split('\n')))
         try:
             content = module.__scons_doc__
         except AttributeError:
@@ -70,11 +87,11 @@ for f in args:
         else:
             del module.__scons_doc__
     else:
-        h.set_file_info(f, len(preamble.split('\n')))
+        h.set_file_info(f, len(xml_preamble.split('\n')))
         content = open(f).read()
     if content:
         content = content.replace('&', '&amp;')
-        input = preamble + content + postamble
+        input = xml_preamble + content + xml_postamble
         try:
             saxparser.parse(StringIO.StringIO(input))
         except:
@@ -103,17 +120,27 @@ Link_Entities_Header = """\
 -->
 """
 
-class XXX:
+class SCons_XML:
     def __init__(self, entries, **kw):
         values = entries.values()
         values.sort()
         self.values = values
         for k, v in kw.items():
             setattr(self, k, v)
+    def fopen(self, name):
+        if name == '-':
+            return sys.stdout
+        return open(name, 'w')
+
+class SCons_XML_to_XML(SCons_XML):
+    def write(self, files):
+        gen, mod = string.split(files, ',')
+        g.write_gen(gen)
+        g.write_mod(mod)
     def write_gen(self, filename):
         if not filename:
             return
-        f = open(filename, 'w')
+        f = self.fopen(filename)
         for v in self.values:
             f.write('\n<varlistentry id="%s%s">\n' %
                         (self.prefix, self.idfunc(v.name)))
@@ -123,17 +150,22 @@ class XXX:
             f.write('<listitem>\n')
             for chunk in v.summary.body:
                 f.write(str(chunk))
-            #if v.uses:
-            #    u = map(lambda x, s: '&%slink-%s;' % (s.prefix, x), v.uses)
-            #    f.write('<para>\n')
-            #    f.write('Uses:  ' + ', '.join(u) + '.\n')
-            #    f.write('</para>\n')
+            if v.sets:
+                s = map(lambda x: '&cv-link-%s;' % x, v.sets)
+                f.write('<para>\n')
+                f.write('Sets:  ' + ', '.join(s) + '.\n')
+                f.write('</para>\n')
+            if v.uses:
+                u = map(lambda x: '&cv-link-%s;' % x, v.uses)
+                f.write('<para>\n')
+                f.write('Uses:  ' + ', '.join(u) + '.\n')
+                f.write('</para>\n')
             f.write('</listitem>\n')
             f.write('</varlistentry>\n')
     def write_mod(self, filename):
         if not filename:
             return
-        f = open(filename, 'w')
+        f = self.fopen(filename)
         f.write(Warning)
         f.write('\n')
         f.write(Regular_Entities_Header % self.description)
@@ -155,8 +187,59 @@ class XXX:
         f.write('\n')
         f.write(Warning)
 
+class SCons_XML_to_man(SCons_XML):
+    def mansep(self):
+        return ['\n']
+    def initial_chunks(self, name):
+        return [name]
+    def write(self, filename):
+        if not filename:
+            return
+        f = self.fopen(filename)
+        chunks = []
+        for v in self.values:
+            chunks.extend(self.mansep())
+            for n in self.initial_chunks(v.name):
+                chunks.append('.IP %s\n' % n)
+            chunks.extend(map(str, v.summary.body))
+
+        body = ''.join(chunks)
+        body = string.replace(body, '<programlisting>', '.ES')
+        body = string.replace(body, '</programlisting>', '.EE')
+        body = string.replace(body, '\n</para>\n<para>\n', '\n\n')
+        body = string.replace(body, '<para>\n', '')
+        body = string.replace(body, '<para>', '\n')
+        body = string.replace(body, '</para>\n', '')
+        body = re.sub('\.EE\n\n+(?!\.IP)', '.EE\n.IP\n', body)
+        body = re.sub('&(scons|SConstruct|SConscript|jar);', r'\\fB\1\\fP', body)
+        body = string.replace(body, '&Dir;', r'\fBDir\fP')
+        body = re.sub('&b(-link)?-([^;]*);', r'\\fB\2\\fP()', body)
+        body = re.sub('&cv(-link)?-([^;]*);', r'$\2', body)
+        body = re.sub(r'<(command|envar|filename|literal|option)>([^<]*)</\1>',
+                      r'\\fB\2\\fP', body)
+        body = re.sub(r'<(classname|emphasis|varname)>([^<]*)</\1>',
+                      r'\\fI\2\\fP', body)
+        body = re.compile(r'^\\f([BI])(.*)\\fP\s*$', re.M).sub(r'.\1 \2', body)
+        body = re.compile(r'^\\f([BI])(.*)\\fP(\S+)', re.M).sub(r'.\1R \2 \3', body)
+        body = string.replace(body, '&lt;', '<')
+        body = string.replace(body, '&gt;', '>')
+        body = re.sub(r'\\([^f])', r'\\\\\1', body)
+        body = re.compile("^'\\\\\\\\", re.M).sub("'\\\\", body)
+        body = re.compile(r'^\.([BI]R?) -', re.M).sub(r'.\1 \-', body)
+        body = re.compile(r'^\.([BI]R?) (\S+)\\\\(\S+)', re.M).sub(r'.\1 "\2\\\\\\\\\2"', body)
+        body = re.compile(r'\\f([BI])-', re.M).sub(r'\\f\1\-', body)
+        f.write(body)
+
+if output_type == '--man':
+    processor_class = SCons_XML_to_man
+elif output_type == '--xml':
+    processor_class = SCons_XML_to_XML
+else:
+    sys.stderr.write("Unknown output type '%s'\n" % output_type)
+    sys.exit(1)
+
 if buildersfiles:
-    g = XXX(h.builders,
+    g = processor_class(h.builders,
             description = 'builder',
             prefix = 'b-',
             tag = 'function',
@@ -164,12 +247,13 @@ if buildersfiles:
             termfunc = lambda x: [x+'()', 'env.'+x+'()'],
             entityfunc = lambda x: x)
 
-    gen, mod = string.split(buildersfiles, ',')
-    g.write_gen(gen)
-    g.write_mod(mod)
+    g.mansep = lambda: ['\n', "'\\" + '"'*69 + '\n']
+    g.initial_chunks = lambda n: [n+'()', 'env.'+n+'()']
+
+    g.write(buildersfiles)
 
 if toolsfiles:
-    g = XXX(h.tools,
+    g = processor_class(h.tools,
             description = 'tool',
             prefix = 't-',
             tag = 'literal',
@@ -177,12 +261,10 @@ if toolsfiles:
             termfunc = lambda x: [x],
             entityfunc = lambda x: x)
 
-    gen, mod = string.split(toolsfiles, ',')
-    g.write_gen(gen)
-    g.write_mod(mod)
+    g.write(toolsfiles)
 
 if variablesfiles:
-    g = XXX(h.cvars,
+    g = processor_class(h.cvars,
             description = 'construction variable',
             prefix = 'cv-',
             tag = 'envar',
@@ -190,6 +272,4 @@ if variablesfiles:
             termfunc = lambda x: [x],
             entityfunc = lambda x: '$'+x)
 
-    gen, mod = string.split(variablesfiles, ',')
-    g.write_gen(gen)
-    g.write_mod(mod)
+    g.write(variablesfiles)