summaryrefslogtreecommitdiffstats
path: root/options.py
blob: b40d6b4037c2b4b29b06f1df75abeb70cbc7cd2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import sys, textwrap, getopt, re

class OptDict:
    def __init__(self):
        self._opts = {}

    def __setitem__(self, k, v):
        self._opts[k] = v
        
    def __getitem__(self, k):
        return self._opts[k]

    def __getattr__(self, k):
        return self[k]


class Options:
    def __init__(self, exe, optspec, optfunc=getopt.gnu_getopt):
        self.exe = exe
        self.optspec = optspec
        self.optfunc = optfunc
        self._aliases = {}
        self._shortopts = 'h?'
        self._longopts = ['help']
        self._hasparms = {}
        self._usagestr = self._gen_usage()
        
    def _gen_usage(self):
        out = []
        lines = self.optspec.strip().split('\n')
        lines.reverse()
        first_syn = True
        while lines:
            l = lines.pop()
            if l == '--': break
            out.append('%s: %s\n' % (first_syn and 'usage' or '   or', l))
            first_syn = False
        out.append('\n')
        while lines:
            l = lines.pop()
            if l.startswith(' '):
                out.append('\n%s\n' % l.lstrip())
            elif l:
                (flags, extra) = l.split(' ', 1)
                extra = extra.strip()
                if flags.endswith('='):
                    flags = flags[:-1]
                    has_parm = 1
                else:
                    has_parm = 0
                flagl = flags.split(',')
                flagl_nice = []
                for f in flagl:
                    f_nice = re.sub(r'\W', '_', f)
                    self._aliases[f] = flagl[0]
                    self._aliases[f_nice] = flagl[0]
                    self._hasparms[f] = has_parm
                    if len(f) == 1:
                        self._shortopts += f + (has_parm and ':' or '')
                        flagl_nice.append('-' + f)
                    else:
                        assert(not f.startswith('no-')) # supported implicitly
                        self._longopts.append(f + (has_parm and '=' or ''))
                        self._longopts.append('no-' + f)
                        flagl_nice.append('--' + f)
                flags_nice = ', '.join(flagl_nice)
                if has_parm:
                    flags_nice += ' ...'
                prefix = '    %-20s  ' % flags_nice
                argtext = '\n'.join(textwrap.wrap(extra, width=70,
                                                initial_indent=prefix,
                                                subsequent_indent=' '*28))
                out.append(argtext + '\n')
            else:
                out.append('\n')
        return ''.join(out).rstrip() + '\n'
    
    def usage(self):
        sys.stderr.write(self._usagestr)
        sys.exit(97)

    def fatal(self, s):
        sys.stderr.write('error: %s\n' % s)
        return self.usage()
        
    def parse(self, args):
        try:
            (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
        except getopt.GetoptError, e:
            self.fatal(e)

        opt = OptDict()
        for f in self._aliases.values():
            opt[f] = None
        for (k,v) in flags:
            while k.startswith('-'):
                k = k[1:]
            if k in ['h', '?', 'help']:
                self.usage()
            if k.startswith('no-'):
                k = self._aliases[k[3:]]
                opt[k] = None
            else:
                k = self._aliases[k]
                if not self._hasparms[k]:
                    assert(v == '')
                    opt[k] = (opt._opts.get(k) or 0) + 1
                else:
                    try:
                        vv = int(v)
                        if str(vv) == v:
                            v = vv
                    except ValueError:
                        pass
                    opt[k] = v
        for (f1,f2) in self._aliases.items():
            opt[f1] = opt[f2]
        return (opt,flags,extra)