3 # Process a list of Python and/or XML files containing SCons documentation.
5 # This script creates formatted lists of the Builders, functions, Tools
6 # or construction variables documented in the specified XML files.
8 # Dependening on the options, the lists are output in either
9 # DocBook-formatted generated XML files containing the summary text
10 # and/or .mod files contining the ENTITY definitions for each item,
11 # or in man-page-formatted output.
22 base_sys_path = [os.getcwd() + '/build/test-tar-gz/lib/scons'] + sys.path
25 Usage: scons-proc.py [--man|--xml]
26 [-b file(s)] [-f file(s)] [-t file(s)] [-v file(s)]
29 -b file(s) dump builder information to the specified file(s)
30 -f file(s) dump function information to the specified file(s)
31 -t file(s) dump tool information to the specified file(s)
32 -v file(s) dump variable information to the specified file(s)
33 --man print info in man page format, each -[btv] argument
35 --xml (default) print info in SML format, each -[btv] argument
36 is a pair of comma-separated .gen,.mod file names
39 opts, args = getopt.getopt(sys.argv[1:],
42 'man', 'xml', 'tools=', 'variables='])
51 if o in ['-b', '--builders']:
53 elif o in ['-f', '--functions']:
55 elif o in ['-h', '--help']:
56 sys.stdout.write(helpstr)
58 elif o in ['--man', '--xml']:
60 elif o in ['-t', '--tools']:
62 elif o in ['-v', '--variables']:
65 h = SConsDoc.SConsDocHandler()
66 saxparser = xml.sax.make_parser()
67 saxparser.setContentHandler(h)
68 saxparser.setErrorHandler(h)
80 _, ext = os.path.splitext(f)
82 dir, _ = os.path.split(f)
84 sys.path = [dir] + base_sys_path
85 module = SConsDoc.importfile(f)
86 h.set_file_info(f, len(xml_preamble.split('\n')))
88 content = module.__scons_doc__
89 except AttributeError:
92 del module.__scons_doc__
94 h.set_file_info(f, len(xml_preamble.split('\n')))
95 content = open(f).read()
97 content = content.replace('&', '&')
98 # Strip newlines after comments so they don't turn into
99 # spurious paragraph separators.
100 content = content.replace('-->\n', '-->')
101 input = xml_preamble + content + xml_postamble
103 saxparser.parse(StringIO.StringIO(input))
105 sys.stderr.write("error in %s\n" % f)
110 THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
114 Regular_Entities_Header = """\
122 Link_Entities_Header = """\
125 Entities that are links to the %s entries in the appendix.
131 def __init__(self, entries, **kw):
132 self.values = entries
133 for k, v in kw.items():
135 def fopen(self, name):
138 return open(name, 'w')
140 class SCons_XML_to_XML(SCons_XML):
141 def write(self, files):
142 gen, mod = files.split(',')
145 def write_gen(self, filename):
148 f = self.fopen(filename)
149 for v in self.values:
150 f.write('\n<varlistentry id="%s%s">\n' %
151 (v.prefix, v.idfunc()))
152 for term in v.termfunc():
153 f.write('<term><%s>%s</%s></term>\n' %
154 (v.tag, term, v.tag))
155 f.write('<listitem>\n')
156 for chunk in v.summary.body:
159 s = ['&cv-link-%s;' % x for x in v.sets]
161 f.write('Sets: ' + ', '.join(s) + '.\n')
164 u = ['&cv-link-%s;' % x for x in v.uses]
166 f.write('Uses: ' + ', '.join(u) + '.\n')
168 f.write('</listitem>\n')
169 f.write('</varlistentry>\n')
170 def write_mod(self, filename):
171 description = self.values[0].description
174 f = self.fopen(filename)
177 f.write(Regular_Entities_Header % description)
179 for v in self.values:
180 f.write('<!ENTITY %s%s "<%s>%s</%s>">\n' %
181 (v.prefix, v.idfunc(),
182 v.tag, v.entityfunc(), v.tag))
183 if self.env_signatures:
185 for v in self.values:
186 f.write('<!ENTITY %senv-%s "<%s>env.%s</%s>">\n' %
187 (v.prefix, v.idfunc(),
188 v.tag, v.entityfunc(), v.tag))
192 f.write(Link_Entities_Header % description)
194 for v in self.values:
195 f.write('<!ENTITY %slink-%s \'<link linkend="%s%s"><%s>%s</%s></link>\'>\n' %
196 (v.prefix, v.idfunc(),
197 v.prefix, v.idfunc(),
198 v.tag, v.entityfunc(), v.tag))
199 if self.env_signatures:
201 for v in self.values:
202 f.write('<!ENTITY %slink-env-%s \'<link linkend="%s%s"><%s>env.%s</%s></link>\'>\n' %
203 (v.prefix, v.idfunc(),
204 v.prefix, v.idfunc(),
205 v.tag, v.entityfunc(), v.tag))
209 class SCons_XML_to_man(SCons_XML):
210 def write(self, filename):
213 f = self.fopen(filename)
215 for v in self.values:
216 chunks.extend(v.mansep())
217 chunks.extend(v.initial_chunks())
218 chunks.extend(list(map(str, v.summary.body)))
220 body = ''.join(chunks)
221 body = body.replace('<programlisting>', '.ES')
222 body = body.replace('</programlisting>', '.EE')
223 body = body.replace('\n</para>\n<para>\n', '\n\n')
224 body = body.replace('<para>\n', '')
225 body = body.replace('<para>', '\n')
226 body = body.replace('</para>\n', '')
228 body = string.replace(body, '<variablelist>\n', '.RS 10\n')
229 # Handling <varlistentry> needs to be rationalized and made
230 # consistent. Right now, the <term> values map to arbitrary,
231 # ad-hoc idioms in the current man page.
232 body = re.compile(r'<varlistentry>\n<term><literal>([^<]*)</literal></term>\n<listitem>\n').sub(r'.TP 6\n.B \1\n', body)
233 body = re.compile(r'<varlistentry>\n<term><parameter>([^<]*)</parameter></term>\n<listitem>\n').sub(r'.IP \1\n', body)
234 body = re.compile(r'<varlistentry>\n<term>([^<]*)</term>\n<listitem>\n').sub(r'.HP 6\n.B \1\n', body)
235 body = string.replace(body, '</listitem>\n', '')
236 body = string.replace(body, '</varlistentry>\n', '')
237 body = string.replace(body, '</variablelist>\n', '.RE\n')
239 body = re.sub(r'\.EE\n\n+(?!\.IP)', '.EE\n.IP\n', body)
240 body = string.replace(body, '\n.IP\n\'\\"', '\n\n\'\\"')
241 body = re.sub('&(scons|SConstruct|SConscript|jar|Make|lambda);', r'\\fB\1\\fP', body)
242 body = re.sub('&(TARGET|TARGETS|SOURCE|SOURCES);', r'\\fB$\1\\fP', body)
243 body = body.replace('&Dir;', r'\fBDir\fP')
244 body = body.replace('⌖', r'\fItarget\fP')
245 body = body.replace('&source;', r'\fIsource\fP')
246 body = re.sub('&b(-link)?-([^;]*);', r'\\fB\2\\fP()', body)
247 body = re.sub('&cv(-link)?-([^;]*);', r'$\2', body)
248 body = re.sub('&f(-link)?-env-([^;]*);', r'\\fBenv.\2\\fP()', body)
249 body = re.sub('&f(-link)?-([^;]*);', r'\\fB\2\\fP()', body)
250 body = re.sub(r'<(application|command|envar|filename|function|literal|option)>([^<]*)</\1>',
252 body = re.sub(r'<(classname|emphasis|varname)>([^<]*)</\1>',
254 body = re.compile(r'^\\f([BI])([^\\]* [^\\]*)\\fP\s*$', re.M).sub(r'.\1 "\2"', body)
255 body = re.compile(r'^\\f([BI])(.*)\\fP\s*$', re.M).sub(r'.\1 \2', body)
256 body = re.compile(r'^\\f([BI])(.*)\\fP(\S+)$', re.M).sub(r'.\1R \2 \3', body)
257 body = re.compile(r'^(\S+)\\f([BI])(.*)\\fP$', re.M).sub(r'.R\2 \1 \3', body)
258 body = re.compile(r'^(\S+)\\f([BI])(.*)\\fP([^\s\\]+)$', re.M).sub(r'.R\2 \1 \3 \4', body)
259 body = re.compile(r'^(\.R[BI].*[\S])\s+$;', re.M).sub(r'\1', body)
260 body = body.replace('<', '<')
261 body = body.replace('>', '>')
262 body = re.sub(r'\\([^f])', r'\\\\\1', body)
263 body = re.compile("^'\\\\\\\\", re.M).sub("'\\\\", body)
264 body = re.compile(r'^\.([BI]R?) --', re.M).sub(r'.\1 \-\-', body)
265 body = re.compile(r'^\.([BI]R?) -', re.M).sub(r'.\1 \-', body)
266 body = re.compile(r'^\.([BI]R?) (\S+)\\\\(\S+)$', re.M).sub(r'.\1 "\2\\\\\\\\\2"', body)
267 body = re.compile(r'\\f([BI])-', re.M).sub(r'\\f\1\-', body)
271 def __init__(self, subject):
272 """Wrap an object as a Proxy object"""
273 self.__subject = subject
275 def __getattr__(self, name):
276 """Retrieve an attribute from the wrapped object. If the named
277 attribute doesn't exist, AttributeError is raised"""
278 return getattr(self.__subject, name)
281 """Retrieve the entire wrapped object"""
282 return self.__subject
284 def __cmp__(self, other):
285 if issubclass(other.__class__, self.__subject.__class__):
286 return cmp(self.__subject, other)
287 return cmp(self.__dict__, other.__dict__)
289 class Builder(Proxy):
290 description = 'builder'
296 return ['%s()' % self.name, 'env.%s()' % self.name]
297 def entityfunc(self):
300 return ['\n', "'\\" + '"'*69 + '\n']
301 def initial_chunks(self):
302 return [ '.IP %s\n' % t for t in self.termfunc() ]
304 class Function(Proxy):
305 description = 'function'
311 return ['%s()' % self.name, 'env.%s()' % self.name]
312 def entityfunc(self):
315 return ['\n', "'\\" + '"'*69 + '\n']
316 def initial_chunks(self):
318 arguments = self.arguments
319 except AttributeError:
322 for arg in arguments:
324 signature = arg.signature
325 except AttributeError:
327 if signature in ('both', 'global'):
328 result.append('.TP\n.RI %s%s\n' % (self.name, arg))
329 if signature in ('both', 'env'):
330 result.append('.TP\n.IR env .%s%s\n' % (self.name, arg))
338 return string.replace(self.name, '+', 'X')
341 def entityfunc(self):
345 def initial_chunks(self):
346 return ['.IP %s\n' % self.name]
348 class Variable(Proxy):
349 description = 'construction variable'
356 def entityfunc(self):
357 return '$' + self.name
360 def initial_chunks(self):
361 return ['.IP %s\n' % self.name]
363 if output_type == '--man':
364 processor_class = SCons_XML_to_man
365 elif output_type == '--xml':
366 processor_class = SCons_XML_to_XML
368 sys.stderr.write("Unknown output type '%s'\n" % output_type)
372 g = processor_class([ Builder(b) for b in sorted(h.builders.values()) ],
374 g.write(buildersfiles)
377 g = processor_class([ Function(b) for b in sorted(h.functions.values()) ],
379 g.write(functionsfiles)
382 g = processor_class([ Tool(t) for t in sorted(h.tools.values()) ],
383 env_signatures=False)
387 g = processor_class([ Variable(v) for v in sorted(h.cvars.values()) ],
388 env_signatures=False)
389 g.write(variablesfiles)
393 # indent-tabs-mode:nil
395 # vim: set expandtab tabstop=4 shiftwidth=4: