From ba4425ab5227fd9597fccd368bffff6bf1032149 Mon Sep 17 00:00:00 2001 From: Luca Falavigna Date: Sat, 10 Sep 2011 11:25:53 +0200 Subject: Imported Upstream version 2.1.0 --- bin/scons-proc.py | 174 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 131 insertions(+), 43 deletions(-) (limited to 'bin/scons-proc.py') diff --git a/bin/scons-proc.py b/bin/scons-proc.py index 7cdb618..6d15816 100644 --- a/bin/scons-proc.py +++ b/bin/scons-proc.py @@ -10,10 +10,11 @@ # and/or .mod files contining the ENTITY definitions for each item, # or in man-page-formatted output. # -import os -import sys import getopt +import os import re +import string +import sys import xml.sax try: from io import StringIO @@ -153,9 +154,7 @@ class SCons_XML_to_XML(SCons_XML): for v in self.values: f.write('\n\n' % (v.prefix, v.idfunc())) - for term in v.termfunc(): - f.write('<%s>%s\n' % - (v.tag, term, v.tag)) + f.write('%s\n' % v.xml_term()) f.write('\n') for chunk in v.summary.body: f.write(str(chunk)) @@ -212,23 +211,41 @@ class SCons_XML_to_XML(SCons_XML): class SCons_XML_to_man(SCons_XML): def write(self, filename): + """ + Converts the contents of the specified filename from DocBook XML + to man page macros. + + This does not do an intelligent job. In particular, it doesn't + actually use the structured nature of XML to handle arbitrary + input. Instead, we're using text replacement and regular + expression substitutions to convert observed patterns into the + macros we want. To the extent that we're relatively consistent + with our input .xml, this works, but could easily break if handed + input that doesn't match these specific expectations. + """ if not filename: return f = self.fopen(filename) chunks = [] for v in self.values: - chunks.extend(v.mansep()) - chunks.extend(v.initial_chunks()) + chunks.extend(v.man_separator()) + chunks.extend(v.initial_man_chunks()) chunks.extend(list(map(str, v.summary.body))) body = ''.join(chunks) + + # Simple transformation of examples into our defined macros for those. body = body.replace('', '.ES') body = body.replace('', '.EE') + + # Replace groupings of tags and surrounding newlines + # with single blank lines. body = body.replace('\n\n\n', '\n\n') body = body.replace('\n', '') body = body.replace('', '\n') body = body.replace('\n', '') + # Convert and its child tags. body = body.replace('\n', '.RS 10\n') # Handling needs to be rationalized and made # consistent. Right now, the values map to arbitrary, @@ -240,35 +257,54 @@ class SCons_XML_to_man(SCons_XML): body = body.replace('\n', '') body = body.replace('\n', '.RE\n') + # Get rid of unnecessary .IP macros, and unnecessary blank lines + # in front of .IP macros. body = re.sub(r'\.EE\n\n+(?!\.IP)', '.EE\n.IP\n', body) + body = body.replace('\n.EE\n.IP\n.ES\n', '\n.EE\n\n.ES\n') body = body.replace('\n.IP\n\'\\"', '\n\n\'\\"') - body = re.sub('&(scons|SConstruct|SConscript|jar|Make|lambda);', r'\\fB\1\\fP', body) + + # Convert various named entities and tagged names to nroff + # in-line font conversions (\fB, \fI, \fP). + body = re.sub('&(scons|SConstruct|SConscript|Dir|jar|Make|lambda);', + r'\\fB\1\\fP', body) body = re.sub('&(TARGET|TARGETS|SOURCE|SOURCES);', r'\\fB$\1\\fP', body) - body = body.replace('&Dir;', r'\fBDir\fP') - body = body.replace('⌖', r'\fItarget\fP') - body = body.replace('&source;', r'\fIsource\fP') + body = re.sub('&(target|source);', r'\\fI\1\\fP', body) body = re.sub('&b(-link)?-([^;]*);', r'\\fB\2\\fP()', body) - body = re.sub('&cv(-link)?-([^;]*);', r'$\2', body) + body = re.sub('&cv(-link)?-([^;]*);', r'\\fB$\2\\fP', body) body = re.sub('&f(-link)?-env-([^;]*);', r'\\fBenv.\2\\fP()', body) body = re.sub('&f(-link)?-([^;]*);', r'\\fB\2\\fP()', body) body = re.sub(r'<(application|command|envar|filename|function|literal|option)>([^<]*)', r'\\fB\2\\fP', body) body = re.sub(r'<(classname|emphasis|varname)>([^<]*)', r'\\fI\2\\fP', body) + + # Convert groupings of font conversions (\fB, \fI, \fP) to + # man page .B, .BR, .I, .IR, .R, .RB and .RI macros. 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'.\1 \2', body) body = re.compile(r'^\\f([BI])(.*)\\fP(\S+)$', re.M).sub(r'.\1R \2 \3', body) + body = re.compile(r'^(\.B)( .*)\\fP(.*)\\fB(.*)$', re.M).sub(r'\1R\2 \3 \4', body) + body = re.compile(r'^(\.B)R?( .*)\\fP(.*)\\fI(.*)$', re.M).sub(r'\1I\2\3 \4', body) + body = re.compile(r'^(\.I)( .*)\\fP\\fB(.*)\\fP\\fI(.*)$', re.M).sub(r'\1R\2 \3 \4', body) body = re.compile(r'^(\S+)\\f([BI])(.*)\\fP$', re.M).sub(r'.R\2 \1 \3', body) body = re.compile(r'^(\S+)\\f([BI])(.*)\\fP([^\s\\]+)$', re.M).sub(r'.R\2 \1 \3 \4', body) body = re.compile(r'^(\.R[BI].*[\S])\s+$;', re.M).sub(r'\1', body) + + # Convert < and > entities to literal < and > characters. body = body.replace('<', '<') body = body.replace('>', '>') - body = re.sub(r'\\([^f])', r'\\\\\1', body) + + # Backslashes. Oh joy. + body = re.sub(r'\\(?=[^f])', r'\\\\', body) body = re.compile("^'\\\\\\\\", re.M).sub("'\\\\", body) + body = re.compile(r'^\.([BI]R?) ([^"]\S*\\\\\S+[^"])$', re.M).sub(r'.\1 "\2"', body) + + # Put backslashes in front of various hyphens that need + # to be long em-dashes. body = re.compile(r'^\.([BI]R?) --', re.M).sub(r'.\1 \-\-', 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) class Proxy(object): @@ -290,34 +326,91 @@ class Proxy(object): return cmp(self.__subject, other) return cmp(self.__dict__, other.__dict__) -class Builder(Proxy): +class SConsThing(Proxy): + def idfunc(self): + return self.name + def xml_term(self): + return '%s' % self.name + +class Builder(SConsThing): description = 'builder' prefix = 'b-' tag = 'function' - def idfunc(self): - return self.name - def termfunc(self): - return ['%s()' % self.name, 'env.%s()' % self.name] + def xml_term(self): + return ('<%s>%s()\n<%s>env.%s()' % + (self.tag, self.name, self.tag, self.tag, self.name, self.tag)) def entityfunc(self): return self.name - def mansep(self): + def man_separator(self): return ['\n', "'\\" + '"'*69 + '\n'] - def initial_chunks(self): - return [ '.IP %s\n' % t for t in self.termfunc() ] + def initial_man_chunks(self): + return [ '.IP %s()\n.IP env.%s()\n' % (self.name, self.name) ] -class Function(Proxy): +class Function(SConsThing): description = 'function' prefix = 'f-' tag = 'function' - def idfunc(self): - return self.name - def termfunc(self): - return ['%s()' % self.name, 'env.%s()' % self.name] + def args_to_xml(self, arg): + s = ''.join(arg.body).strip() + result = [] + for m in re.findall('([a-zA-Z/_]+=?|[^a-zA-Z/_]+)', s): + if m[0] in string.letters: + if m[-1] == '=': + result.append('%s=' % m[:-1]) + else: + result.append('%s' % m) + else: + result.append(m) + return ''.join(result) + def xml_term(self): + try: + arguments = self.arguments + except AttributeError: + arguments = ['()'] + result = [''] + for arg in arguments: + try: + signature = arg.signature + except AttributeError: + signature = "both" + s = self.args_to_xml(arg) + if signature in ('both', 'global'): + result.append('%s%s\n' % (self.name, s)) #
+ if signature in ('both', 'env'): + result.append('env.%s%s' % (self.name, s)) + result.append('
') + return ''.join(result) def entityfunc(self): return self.name - def mansep(self): + def man_separator(self): return ['\n', "'\\" + '"'*69 + '\n'] - def initial_chunks(self): + def args_to_man(self, arg): + """Converts the contents of an tag, which + specifies a function's calling signature, into a series + of tokens that alternate between literal tokens + (to be displayed in roman or bold face) and variable + names (to be displayed in italics). + + This is complicated by the presence of Python "keyword=var" + arguments, where "keyword=" should be displayed literally, + and "var" should be displayed in italics. We do this by + detecting the keyword= var portion and appending it to the + previous string, if any. + """ + s = ''.join(arg.body).strip() + result = [] + for m in re.findall('([a-zA-Z/_]+=?|[^a-zA-Z/_]+)', s): + if m[-1] == '=' and result: + if result[-1][-1] == '"': + result[-1] = result[-1][:-1] + m + '"' + else: + result[-1] += m + else: + if ' ' in m: + m = '"%s"' % m + result.append(m) + return ' '.join(result) + def initial_man_chunks(self): try: arguments = self.arguments except AttributeError: @@ -328,40 +421,35 @@ class Function(Proxy): signature = arg.signature except AttributeError: signature = "both" + s = self.args_to_man(arg) if signature in ('both', 'global'): - result.append('.TP\n.RI %s%s\n' % (self.name, arg)) + result.append('.TP\n.RI %s%s\n' % (self.name, s)) if signature in ('both', 'env'): - result.append('.TP\n.IR env .%s%s\n' % (self.name, arg)) + result.append('.TP\n.IR env .%s%s\n' % (self.name, s)) return result -class Tool(Proxy): +class Tool(SConsThing): description = 'tool' prefix = 't-' tag = 'literal' def idfunc(self): return self.name.replace('+', 'X') - def termfunc(self): - return [self.name] def entityfunc(self): return self.name - def mansep(self): + def man_separator(self): return ['\n'] - def initial_chunks(self): + def initial_man_chunks(self): return ['.IP %s\n' % self.name] -class Variable(Proxy): +class Variable(SConsThing): description = 'construction variable' prefix = 'cv-' tag = 'envar' - def idfunc(self): - return self.name - def termfunc(self): - return [self.name] def entityfunc(self): return '$' + self.name - def mansep(self): + def man_separator(self): return ['\n'] - def initial_chunks(self): + def initial_man_chunks(self): return ['.IP %s\n' % self.name] if output_type == '--man': -- cgit v1.2.3