Synopsis - Cross-Reference

File: /scripts/synopsis
  1#!/usr/bin/env python
  2#
  3# Copyright (C) 2003 Stefan Seefeld
  4# All rights reserved.
  5# Licensed to the public under the terms of the GNU LGPL (>= 2),
  6# see the file COPYING for details.
  7#
  8
  9from Synopsis import config
 10from Synopsis.getoptions import get_options
 11from Synopsis import IR
 12from Synopsis.Processor import Processor, Composite, Error
 13from Synopsis.Processors import *
 14
 15import sys, os, os.path, getopt
 16
 17def error(msg):
 18    """Write an error message and exit."""
 19    sys.stderr.write('Error: %s\n'%msg)
 20    sys.exit(-1)
 21
 22def __import__(name, verbose):
 23    """Import a named processor. Instead of returning the module, this
 24    reimplementation returns the processor itself. Exits on error."""
 25
 26    from Synopsis.import_processor import import_processor
 27    try:
 28        return import_processor(name)
 29
 30    except ImportError, msg:
 31        if verbose:
 32            print 'Unable to import %s'%name
 33            print 'Reason :', msg
 34        else:
 35            print 'Error : no processor \'%s\''%'.'.join(name.split('.')[-2:])
 36        sys.exit(-1)
 37
 38def usage():
 39    """Print a little usage text"""
 40
 41    print 'Usage : %s [options] <input files>'%'synopsis'
 42    print """
 43List of options:
 44  -h, --help                  Display usage summary.
 45  -V, --version               Display version information.
 46  -v  --verbose               Operate verbosely.
 47  -d  --debug                 Operate in debug mode.
 48  -o <file>, --output=<file>  Write output to <file>.
 49  -p <lang>, --parser=<lang>  Select a parser for <lang>.
 50  -Wp,<arg>[,<arg>...]        Send <args> to the parser.
 51  -t [<markup>]
 52    --translate[=<markup>]    Translate comments to doc-strings, processing it as
 53                                <markup> (typical values are 'javadoc' or 'rst').
 54  --cfilter=<filter>          Specify a comment filter.
 55  --cprocessor=<processor>    Specify a comment processor.
 56  -Wc,<arg>[,<arg>...]        Send <args> to the comment translator.
 57  -l                          Run the linker.
 58  -Wl,<arg>[,<arg>...]        Send <args> to the linker.
 59  --linker=<processor>        Link, and invoke <processor>.
 60  -f <type>,
 61    --formatter=<type>        Select a formatter for <type>.
 62  -Wf,<arg>[,<arg>...]        Send <args> to the formatter.
 63  -I <path>                   Add <path> to list of include paths.
 64  -D <macro>                  Add <macro> to list of predefined macros.
 65  -s <directory>,
 66    --sxr=<directory>         Specify sxr directory. If given, process source cross-references.
 67  --probe                     Probe the specified processor.
 68"""
 69   
 70def make_processor(argv):
 71    """Parse command line options and translate them to
 72    processor commands and arguments."""
 73    parser = None
 74    parser_opts = {}
 75    translator_opts = {}
 76    cfilters = {'ss': Comments.SSFilter,
 77                'sss': Comments.SSSFilter,
 78                'ssd': Comments.SSDFilter,
 79                'c': Comments.CFilter,
 80                'qt': Comments.QtFilter,
 81                'java': Comments.JavaFilter}
 82    cprocessors = {'previous': Comments.Previous,
 83                   'grouper': Comments.Grouper}
 84    linker = None
 85    linker_opts = {'processors':[]}
 86    formatter = None
 87    formatter_opts = {}
 88    options = {}
 89    help = False
 90    probe = False
 91
 92    opts, args = getopt.getopt(argv,
 93                               'o:p:t:lf:s:I:D:W:jvhVdP',
 94                               ['output=',
 95                                'parser=', 'translate=', 'cfilter=', 'cprocessor=',
 96                                'linker=', 'formatter=', 'sxr=',
 97                                'version', 'help', 'verbose', 'debug', 'profile',
 98                                'probe'])
 99    
100    for o, a in opts:
101        if o in ['-V', '--version']:
102            print 'synopsis version %s (revision %s)'%(config.version, config.revision)
103            sys.exit(0)
104         
105        if o in ['-v', '--verbose']: options['verbose'] = True
106        elif o in ['-d', '--debug']: options['debug'] = True
107        elif o in ['-P', '--profile']: options['profile'] = True
108        elif o in ['-o', '--output']: options['output'] = a
109
110        elif o in ['-p', '--parser']:
111            if parser:
112                error('Multiple parsers specified.')
113            parser = __import__('Synopsis.Parsers.%s.Parser'%a,
114                                'verbose' in options)
115
116        elif o in ['-t', '--translate']:
117            if 'markup' in translator_opts:
118                error('Multiple translators specified.')
119            translator_opts['markup'] = a or ''
120
121        elif o == '--cfilter':
122            if a not in cfilters:
123                error('%s is not a known comment filter.\n'
124                      '\t possible values are : %s'
125                      %(a, ', '.join([f for f in cfilters])))
126            translator_opts['filter'] = cfilters[a]()
127
128        elif o == '--cprocessor':
129            if a not in cprocessors:
130                error('%s is not a known comment processor.\n'
131                      '\t possible values are : %s'
132                      %(a, ', '.join([p for p in cprocessors])))
133            if not translator_opts.get('processor'): translator_opts['processor'] = []
134            translator_opts['processor'].append(cprocessors[a]())
135
136        elif o == '-l':
137            if not linker:
138                linker = __import__('Synopsis.Processors.Linker',
139                                    'verbose' in options)
140
141        elif o == '--linker':
142            if not linker:
143                linker = __import__('Synopsis.Processors.Linker',
144                                    'verbose' in options)
145            linker_opts['processors'].extend([__import__('Synopsis.Processors.%s'%x,
146                                                         'verbose' in options)()
147                                              for x in a.split(',')])
148
149        elif o in ['-f', '--formatter']:
150            if formatter:
151                error('Multiple formatters specified.')
152            formatter = __import__('Synopsis.Formatters.%s.Formatter'%a,
153                                   'verbose' in options)
154
155        elif o == '-I':
156            if not parser_opts.get('cppflags'): parser_opts['cppflags'] = []
157            parser_opts['cppflags'].append('-I%s'%a)
158
159        elif o == '-D':
160            if not parser_opts.get('cppflags'): parser_opts['cppflags'] = []
161            parser_opts['cppflags'].append('-D%s'%a)
162
163        elif o == '-W':
164            if a[0] == "p":
165                for o,a in get_options(a[2:].split(','), expect_non_options = False):
166                    parser_opts[o.replace('-', '_')] = a
167            elif a[0] == "l":
168                for o,a in get_options(a[2:].split(','), expect_non_options = False):
169                    linker_opts[o.replace('-', '_')] = a
170            elif a[0] == "f":
171                for o,a in get_options(a[2:].split(','), expect_non_options = False):
172                    formatter_opts[o.replace('-', '_')] = a
173
174        elif o in ['-s', '--sxr']:
175            parser_opts['sxr_prefix'] = a
176            linker_opts['sxr_prefix'] = a
177            formatter_opts['sxr_prefix'] = a
178
179        elif o in ['-h', '--help']:
180            help = True
181        elif o == '--probe':
182            probe = True
183
184    if help:
185        for p in parser, linker, formatter:
186            if not p: continue
187            processor = p()
188            print "Parameters for processor '%s':"%p.__module__
189            parameters = processor.get_parameters()
190            tab = max(map(lambda x:len(x), parameters.keys()))
191            for p in parameters:
192                print "   %-*s     %s"%(tab, p, parameters[p].doc)
193        if not (parser or linker or formatter):
194            usage()
195        sys.exit(0)
196
197    # quick hack: if the parser is Cpp, rename the 'cppflags'
198    # options to just 'flags'
199    if parser and parser.__module__ == 'Synopsis.Parsers.Cpp':
200        if parser_opts.has_key('cppflags'):
201            parser_opts['flags'] = parser_opts['cppflags']
202            del parser_opts['cppflags']
203
204    if probe:
205	if parser and parser.__module__ == 'Synopsis.Parsers.Cpp':
206            cpp = parser(**parser_opts)
207            info = cpp.probe()
208            if not info:
209                print 'Error: no compiler found'
210            else:
211                print 'Compiler:', info.compiler
212                print 'Flags:', ', '.join(info.flags)
213                print 'Language:', info.language
214                print 'Header search path:\n  %s\n'%'\n  '.join(info.include_paths)
215	        macros = [k + (v and '=%s'%v or '') for (k,v) in info.macros]
216
217                print 'Macro definitions:\n  %s\n'%'\n  '.join(macros)
218	else:
219            print 'Only the Cpp processor supports probing at this time.'
220	sys.exit(0)
221
222    if not args:
223        usage()
224	sys.exit(0)
225
226    if translator_opts.has_key('processor'):
227	processor = translator_opts['processor']
228
229    options['input'] = args
230
231    #now instantiate the processor
232    processors = []
233    if parser:
234        processors.append(parser(**parser_opts))
235    if translator_opts:
236        processors.append(Comments.Translator(**translator_opts))
237    if linker:
238        processors.append(linker(**linker_opts))
239    if formatter:
240        processors.append(formatter(**formatter_opts))
241
242    return Composite(*processors, **options)
243
244def main():
245    processor = make_processor(sys.argv[1:])
246    processor.process(IR.IR())
247
248if __name__ == '__main__':
249
250    try:
251        main()
252    except getopt.GetoptError, e:
253        error(str(e))
254    except Error, e:
255        error(str(e))
256    except KeyboardInterrupt, e:
257        print 'KeyboardInterrupt'
258    except IOError, e:
259        error(str(e))