sshuttle/options.py

119 lines
3.9 KiB
Python
Raw Normal View History

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)