Beispiel #1
0
def check_opts(usr_opts):  # Returns false if any check fails
    def opt_splits(val, sep, n, desc):
        sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else "'{}'".format(
            sep)
        try:
            l = val.split(sep)
        except:
            msg("'{}': invalid {} (not {}-separated list)".format(
                val, desc, sepword))
            return False

        if len(l) == n: return True
        else:
            msg("'{}': invalid {} ({} {}-separated items required)".format(
                val, desc, n, sepword))
            return False

    def opt_compares(val, op_str, target, desc, what=''):
        import operator as o
        op_f = {
            '<': o.lt,
            '<=': o.le,
            '>': o.gt,
            '>=': o.ge,
            '=': o.eq
        }[op_str]
        if what: what += ' '
        if not op_f(val, target):
            msg('{}: invalid {} ({}not {} {})'.format(val, desc, what, op_str,
                                                      target))
            return False
        return True

    def opt_is_int(val, desc):
        try:
            int(val)
        except:
            msg("'{}': invalid {} (not an integer)".format(val, desc))
            return False
        return True

    def opt_is_float(val, desc):
        try:
            float(val)
        except:
            msg("'{}': invalid {} (not a floating-point number)".format(
                val, desc))
            return False
        return True

    def opt_is_in_list(val, lst, desc):
        if val not in lst:
            q, sep = (('', ','), ("'", "','"))[type(lst[0]) == str]
            fs = '{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'
            msg(
                fs.format(v=val,
                          w=desc,
                          q=q,
                          o=sep.join(map(str, sorted(lst)))))
            return False
        return True

    def opt_unrecognized(key, val, desc):
        msg("'{}': unrecognized {} for option '{}'".format(
            val, desc, fmt_opt(key)))
        return False

    def opt_display(key, val='', beg='For selected', end=':\n'):
        s = '{}={}'.format(fmt_opt(key), val) if val else fmt_opt(key)
        msg_r("{} option '{}'{}".format(beg, s, end))

    global opt
    for key, val in [(k, getattr(opt, k)) for k in usr_opts]:

        desc = "parameter for '{}' option".format(fmt_opt(key))

        from mmgen.util import check_infile, check_outfile, check_outdir
        # Check for file existence and readability
        if key in ('keys_from_file', 'mmgen_keys_from_file', 'passwd_file',
                   'keysforaddrs', 'comment_file'):
            check_infile(val)  # exits on error
            continue

        if key == 'outdir':
            check_outdir(val)  # exits on error
# 		# NEW
        elif key in ('in_fmt', 'out_fmt'):
            from mmgen.seed import SeedSource, IncogWallet, Brainwallet, IncogWalletHidden
            sstype = SeedSource.fmt_code_to_type(val)
            if not sstype:
                return opt_unrecognized(key, val, 'format code')
            if key == 'out_fmt':
                p = 'hidden_incog_output_params'
                if sstype == IncogWalletHidden and not getattr(opt, p):
                    m1 = 'Hidden incog format output requested.  '
                    m2 = "You must supply a file and offset with the '{}' option"
                    die(1, m1 + m2.format(fmt_opt(p)))
                if issubclass(sstype, IncogWallet) and opt.old_incog_fmt:
                    opt_display(key, val, beg='Selected', end=' ')
                    opt_display('old_incog_fmt',
                                beg='conflicts with',
                                end=':\n')
                    die(1, 'Export to old incog wallet format unsupported')
                elif issubclass(sstype, Brainwallet):
                    die(1, 'Output to brainwallet format unsupported')
        elif key in ('hidden_incog_input_params',
                     'hidden_incog_output_params'):
            a = val.split(',')
            if len(a) < 2:
                opt_display(key, val)
                msg('Option requires two comma-separated arguments')
                return False
            fn, ofs = ','.join(a[:-1]), a[-1]  # permit comma in filename
            if not opt_is_int(ofs, desc): return False
            if key == 'hidden_incog_input_params':
                check_infile(fn, blkdev_ok=True)
                key2 = 'in_fmt'
            else:
                try:
                    os.stat(fn)
                except:
                    b = os.path.dirname(fn)
                    if b: check_outdir(b)
                else: check_outfile(fn, blkdev_ok=True)
                key2 = 'out_fmt'
            if hasattr(opt, key2):
                val2 = getattr(opt, key2)
                from mmgen.seed import IncogWalletHidden
                if val2 and val2 not in IncogWalletHidden.fmt_codes:
                    fs = 'Option conflict:\n  {}, with\n  {}={}'
                    die(1, fs.format(fmt_opt(key), fmt_opt(key2), val2))
        elif key == 'seed_len':
            if not opt_is_int(val, desc): return False
            if not opt_is_in_list(int(val), g.seed_lens, desc): return False
        elif key == 'hash_preset':
            if not opt_is_in_list(val, g.hash_presets.keys(), desc):
                return False
        elif key == 'brain_params':
            a = val.split(',')
            if len(a) != 2:
                opt_display(key, val)
                msg('Option requires two comma-separated arguments')
                return False
            d = 'seed length ' + desc
            if not opt_is_int(a[0], d): return False
            if not opt_is_in_list(int(a[0]), g.seed_lens, d): return False
            d = 'hash preset ' + desc
            if not opt_is_in_list(a[1], g.hash_presets.keys(), d): return False
        elif key == 'usr_randchars':
            if val == 0: continue
            if not opt_is_int(val, desc): return False
            if not opt_compares(val, '>=', g.min_urandchars, desc):
                return False
            if not opt_compares(val, '<=', g.max_urandchars, desc):
                return False
        elif key == 'tx_fee':
            if not opt_is_tx_fee(val, desc): return False
        elif key == 'tx_confs':
            if not opt_is_int(val, desc): return False
            if not opt_compares(val, '>=', 1, desc): return False
        elif key == 'vsize_adj':
            if not opt_is_float(val, desc): return False
            ymsg('Adjusting transaction vsize by a factor of {:1.2f}'.format(
                float(val)))
        elif key == 'key_generator':
            if not opt_compares(val, '<=', len(g.key_generators), desc):
                return False
            if not opt_compares(val, '>', 0, desc): return False
        elif key == 'coin':
            from mmgen.protocol import CoinProtocol
            if not opt_is_in_list(val.lower(), CoinProtocol.coins.keys(),
                                  'coin'):
                return False
        elif key == 'rbf':
            if not g.proto.cap('rbf'):
                die(
                    1,
                    '--rbf requested, but {} does not support replace-by-fee transactions'
                    .format(g.coin))
        elif key in ('bob', 'alice'):
            from mmgen.regtest import daemon_dir
            m = "Regtest (Bob and Alice) mode not set up yet.  Run '{}-regtest setup' to initialize."
            try:
                os.stat(daemon_dir)
            except:
                die(1, m.format(g.proj_name.lower()))
        elif key == 'locktime':
            if not opt_is_int(val, desc): return False
            if not opt_compares(val, '>', 0, desc): return False
        else:
            if g.debug: Msg("check_opts(): No test for opt '{}'".format(key))

    return True
Beispiel #2
0
def check_opts(usr_opts):       # Returns false if any check fails

	def opt_splits(val,sep,n,desc):
		sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else "'%s'" % sep
		try: l = val.split(sep)
		except:
			msg("'%s': invalid %s (not %s-separated list)" % (val,desc,sepword))
			return False

		if len(l) == n: return True
		else:
			msg("'%s': invalid %s (%s %s-separated items required)" %
					(val,desc,n,sepword))
			return False

	def opt_compares(val,op,target,desc,what=''):
		if what: what += ' '
		if not eval('%s %s %s' % (val, op, target)):
			msg('%s: invalid %s (%snot %s %s)' % (val,desc,what,op,target))
			return False
		return True

	def opt_is_int(val,desc):
		try: int(val)
		except:
			msg("'%s': invalid %s (not an integer)" % (val,desc))
			return False
		return True

	def opt_is_in_list(val,lst,desc):
		if val not in lst:
			q,sep = (('',','),("'","','"))[type(lst[0]) == str]
			msg('{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format(
					v=val,w=desc,q=q,
					o=sep.join([str(i) for i in sorted(lst)])
				))
			return False
		return True

	def opt_unrecognized(key,val,desc):
		msg("'%s': unrecognized %s for option '%s'"
				% (val,desc,fmt_opt(key)))
		return False

	def opt_display(key,val='',beg='For selected',end=':\n'):
		s = '%s=%s' % (fmt_opt(key),val) if val else fmt_opt(key)
		msg_r("%s option '%s'%s" % (beg,s,end))

	global opt
	for key,val in [(k,getattr(opt,k)) for k in usr_opts]:

		desc = "parameter for '%s' option" % fmt_opt(key)

		from mmgen.util import check_infile,check_outfile,check_outdir
		# Check for file existence and readability
		if key in ('keys_from_file','mmgen_keys_from_file',
				'passwd_file','keysforaddrs','comment_file'):
			check_infile(val)  # exits on error
			continue

		if key == 'outdir':
			check_outdir(val)  # exits on error
# 		# NEW
		elif key in ('in_fmt','out_fmt'):
			from mmgen.seed import SeedSource,IncogWallet,Brainwallet,IncogWalletHidden
			sstype = SeedSource.fmt_code_to_type(val)
			if not sstype:
				return opt_unrecognized(key,val,'format code')
			if key == 'out_fmt':
				p = 'hidden_incog_output_params'
				if sstype == IncogWalletHidden and not getattr(opt,p):
						die(1,'Hidden incog format output requested. You must supply'
						+ " a file and offset with the '%s' option" % fmt_opt(p))
				if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
					opt_display(key,val,beg='Selected',end=' ')
					opt_display('old_incog_fmt',beg='conflicts with',end=':\n')
					die(1,'Export to old incog wallet format unsupported')
				elif issubclass(sstype,Brainwallet):
					die(1,'Output to brainwallet format unsupported')
		elif key in ('hidden_incog_input_params','hidden_incog_output_params'):
			a = val.split(',')
			if len(a) < 2:
				opt_display(key,val)
				msg('Option requires two comma-separated arguments')
				return False
			fn,ofs = ','.join(a[:-1]),a[-1] # permit comma in filename
			if not opt_is_int(ofs,desc): return False
			if key == 'hidden_incog_input_params':
				check_infile(fn,blkdev_ok=True)
				key2 = 'in_fmt'
			else:
				try: os.stat(fn)
				except:
					b = os.path.dirname(fn)
					if b: check_outdir(b)
				else: check_outfile(fn,blkdev_ok=True)
				key2 = 'out_fmt'
			if hasattr(opt,key2):
				val2 = getattr(opt,key2)
				from mmgen.seed import IncogWalletHidden
				if val2 and val2 not in IncogWalletHidden.fmt_codes:
					die(1,
						'Option conflict:\n  %s, with\n  %s=%s' % (
						fmt_opt(key),fmt_opt(key2),val2
					))
		elif key == 'seed_len':
			if not opt_is_int(val,desc): return False
			if not opt_is_in_list(int(val),g.seed_lens,desc): return False
		elif key == 'hash_preset':
			if not opt_is_in_list(val,g.hash_presets.keys(),desc): return False
		elif key == 'brain_params':
			a = val.split(',')
			if len(a) != 2:
				opt_display(key,val)
				msg('Option requires two comma-separated arguments')
				return False
			d = 'seed length ' + desc
			if not opt_is_int(a[0],d): return False
			if not opt_is_in_list(int(a[0]),g.seed_lens,d): return False
			d = 'hash preset ' + desc
			if not opt_is_in_list(a[1],g.hash_presets.keys(),d): return False
		elif key == 'usr_randchars':
			if val == 0: continue
			if not opt_is_int(val,desc): return False
			if not opt_compares(val,'>=',g.min_urandchars,desc): return False
			if not opt_compares(val,'<=',g.max_urandchars,desc): return False
		elif key == 'tx_fee':
			if not opt_is_tx_fee(val,desc): return False
		elif key == 'tx_confs':
			if not opt_is_int(val,desc): return False
			if not opt_compares(val,'>=',1,desc): return False
		elif key == 'key_generator':
			if not opt_compares(val,'<=',len(g.key_generators),desc): return False
			if not opt_compares(val,'>',0,desc): return False
		elif key == 'coin':
			from mmgen.protocol import CoinProtocol
			if not opt_is_in_list(val.lower(),CoinProtocol.coins.keys(),'coin'): return False
		elif key == 'rbf':
			if not g.proto.cap('rbf'):
				die(1,'--rbf requested, but {} does not support replace-by-fee transactions'.format(g.coin))
		elif key in ('bob','alice'):
			from mmgen.regtest import daemon_dir
			m = "Regtest (Bob and Alice) mode not set up yet.  Run '{}-regtest setup' to initialize."
			try: os.stat(daemon_dir)
			except: die(1,m.format(g.proj_name.lower()))
		elif key == 'locktime':
			if not opt_is_int(val,desc): return False
			if not opt_compares(val,'>',0,desc): return False
		else:
			if g.debug: Msg("check_opts(): No test for opt '%s'" % key)

	return True
Beispiel #3
0
def check_opts(usr_opts):  # Returns false if any check fails
    def opt_splits(val, sep, n, desc):
        sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else "'%s'" % sep
        try:
            l = val.split(sep)
        except:
            msg("'%s': invalid %s (not %s-separated list)" %
                (val, desc, sepword))
            return False

        if len(l) == n: return True
        else:
            msg("'%s': invalid %s (%s %s-separated items required)" %
                (val, desc, n, sepword))
            return False

    def opt_compares(val, op, target, desc, what=''):
        if what: what += ' '
        if not eval('%s %s %s' % (val, op, target)):
            msg('%s: invalid %s (%snot %s %s)' % (val, desc, what, op, target))
            return False
        return True

    def opt_is_int(val, desc):
        try:
            int(val)
        except:
            msg("'%s': invalid %s (not an integer)" % (val, desc))
            return False
        return True

    def opt_is_tx_fee(val, desc):
        from mmgen.tx import MMGenTX
        ret = MMGenTX().convert_fee_spec(val, 224, on_fail='return')
        if ret == False:
            msg("'{}': invalid {} (not a {} amount or satoshis-per-byte specification)"
                .format(val, desc, g.coin.upper()))
        elif ret != None and ret > g.max_tx_fee:
            msg("'{}': invalid {} (> max_tx_fee ({} {}))".format(
                val, desc, g.max_tx_fee, g.coin.upper()))
        else:
            return True
        return False

    def opt_is_in_list(val, lst, desc):
        if val not in lst:
            q, sep = (('', ','), ("'", "','"))[type(lst[0]) == str]
            msg('{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format(
                v=val, w=desc, q=q, o=sep.join([str(i) for i in sorted(lst)])))
            return False
        return True

    def opt_unrecognized(key, val, desc):
        msg("'%s': unrecognized %s for option '%s'" %
            (val, desc, fmt_opt(key)))
        return False

    def opt_display(key, val='', beg='For selected', end=':\n'):
        s = '%s=%s' % (fmt_opt(key), val) if val else fmt_opt(key)
        msg_r("%s option '%s'%s" % (beg, s, end))

    global opt
    for key, val in [(k, getattr(opt, k)) for k in usr_opts]:

        desc = "parameter for '%s' option" % fmt_opt(key)

        from mmgen.util import check_infile, check_outfile, check_outdir
        # Check for file existence and readability
        if key in ('keys_from_file', 'mmgen_keys_from_file', 'passwd_file',
                   'keysforaddrs', 'comment_file'):
            check_infile(val)  # exits on error
            continue

        if key == 'outdir':
            check_outdir(val)  # exits on error
# 		# NEW
        elif key in ('in_fmt', 'out_fmt'):
            from mmgen.seed import SeedSource, IncogWallet, Brainwallet, IncogWalletHidden
            sstype = SeedSource.fmt_code_to_type(val)
            if not sstype:
                return opt_unrecognized(key, val, 'format code')
            if key == 'out_fmt':
                p = 'hidden_incog_output_params'
                if sstype == IncogWalletHidden and not getattr(opt, p):
                    die(
                        1,
                        'Hidden incog format output requested. You must supply'
                        +
                        " a file and offset with the '%s' option" % fmt_opt(p))
                if issubclass(sstype, IncogWallet) and opt.old_incog_fmt:
                    opt_display(key, val, beg='Selected', end=' ')
                    opt_display('old_incog_fmt',
                                beg='conflicts with',
                                end=':\n')
                    die(1, 'Export to old incog wallet format unsupported')
                elif issubclass(sstype, Brainwallet):
                    die(1, 'Output to brainwallet format unsupported')
        elif key in ('hidden_incog_input_params',
                     'hidden_incog_output_params'):
            a = val.split(',')
            if len(a) < 2:
                opt_display(key, val)
                msg('Option requires two comma-separated arguments')
                return False
            fn, ofs = ','.join(a[:-1]), a[-1]  # permit comma in filename
            if not opt_is_int(ofs, desc): return False
            if key == 'hidden_incog_input_params':
                check_infile(fn, blkdev_ok=True)
                key2 = 'in_fmt'
            else:
                try:
                    os.stat(fn)
                except:
                    b = os.path.dirname(fn)
                    if b: check_outdir(b)
                else: check_outfile(fn, blkdev_ok=True)
                key2 = 'out_fmt'
            if hasattr(opt, key2):
                val2 = getattr(opt, key2)
                from mmgen.seed import IncogWalletHidden
                if val2 and val2 not in IncogWalletHidden.fmt_codes:
                    die(
                        1, 'Option conflict:\n  %s, with\n  %s=%s' %
                        (fmt_opt(key), fmt_opt(key2), val2))
        elif key == 'seed_len':
            if not opt_is_int(val, desc): return False
            if not opt_is_in_list(int(val), g.seed_lens, desc): return False
        elif key == 'hash_preset':
            if not opt_is_in_list(val, g.hash_presets.keys(), desc):
                return False
        elif key == 'brain_params':
            a = val.split(',')
            if len(a) != 2:
                opt_display(key, val)
                msg('Option requires two comma-separated arguments')
                return False
            d = 'seed length ' + desc
            if not opt_is_int(a[0], d): return False
            if not opt_is_in_list(int(a[0]), g.seed_lens, d): return False
            d = 'hash preset ' + desc
            if not opt_is_in_list(a[1], g.hash_presets.keys(), d): return False
        elif key == 'usr_randchars':
            if val == 0: continue
            if not opt_is_int(val, desc): return False
            if not opt_compares(val, '>=', g.min_urandchars, desc):
                return False
            if not opt_compares(val, '<=', g.max_urandchars, desc):
                return False
        elif key == 'tx_fee':
            if not opt_is_tx_fee(val, desc): return False
        elif key == 'tx_confs':
            if not opt_is_int(val, desc): return False
            if not opt_compares(val, '>=', 1, desc): return False
        elif key == 'key_generator':
            if not opt_compares(val, '<=', len(g.key_generators), desc):
                return False
            if not opt_compares(val, '>', 0, desc): return False
        elif key == 'coin':
            if not opt_is_in_list(val.upper(), g.coins, 'coin'): return False
        else:
            if g.debug: Msg("check_opts(): No test for opt '%s'" % key)

    return True
Beispiel #4
0
def check_opts(usr_opts):       # Returns false if any check fails

	def opt_splits(val,sep,n,desc):
		sepword = "comma" if sep == "," else (
					"colon" if sep == ":" else ("'"+sep+"'"))
		try: l = val.split(sep)
		except:
			msg("'%s': invalid %s (not %s-separated list)" % (val,desc,sepword))
			return False

		if len(l) == n: return True
		else:
			msg("'%s': invalid %s (%s %s-separated items required)" %
					(val,desc,n,sepword))
			return False

	def opt_compares(val,op,target,desc,what=""):
		if what: what += " "
		if not eval("%s %s %s" % (val, op, target)):
			msg("%s: invalid %s (%snot %s %s)" % (val,desc,what,op,target))
			return False
		return True

	def opt_is_int(val,desc):
		try: int(val)
		except:
			msg("'%s': invalid %s (not an integer)" % (val,desc))
			return False
		return True

	def opt_is_in_list(val,lst,desc):
		if val not in lst:
			q,sep = ("'","','") if type(lst[0]) == str else ("",",")
			msg("{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}".format(
					v=val,w=desc,q=q,
					o=sep.join([str(i) for i in sorted(lst)])
				))
			return False
		return True

	def opt_unrecognized(key,val,desc):
		msg("'%s': unrecognized %s for option '%s'"
				% (val,desc,fmt_opt(key)))
		return False

	def opt_display(key,val='',beg="For selected",end=":\n"):
		s = "%s=%s" % (fmt_opt(key),val) if val else fmt_opt(key)
		msg_r("%s option '%s'%s" % (beg,s,end))

	global opt
	for key,val in [(k,getattr(opt,k)) for k in usr_opts]:

		desc = "parameter for '%s' option" % fmt_opt(key)

		from mmgen.util import check_infile,check_outfile,check_outdir
		# Check for file existence and readability
		if key in ('keys_from_file','mmgen_keys_from_file',
				'passwd_file','keysforaddrs','comment_file'):
			check_infile(val)  # exits on error
			continue

		if key == 'outdir':
			check_outdir(val)  # exits on error
		elif key == 'label':
			if not is_mmgen_wallet_label(val):
				msg("Illegal value for option '%s': '%s'" % (fmt_opt(key),val))
				return False
		# NEW
		elif key in ('in_fmt','out_fmt'):
			from mmgen.seed import SeedSource,IncogWallet,Brainwallet,IncogWalletHidden
			sstype = SeedSource.fmt_code_to_sstype(val)
			if not sstype:
				return opt_unrecognized(key,val,"format code")
			if key == 'out_fmt':
				p = 'hidden_incog_output_params'
				if sstype == IncogWalletHidden and not getattr(opt,p):
						die(1,"Hidden incog format output requested. You must supply"
						+ " a file and offset with the '%s' option" % fmt_opt(p))
				if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
					opt_display(key,val,beg="Selected",end=" ")
					opt_display('old_incog_fmt',beg="conflicts with",end=":\n")
					die(1,"Export to old incog wallet format unsupported")
				elif issubclass(sstype,Brainwallet):
					die(1,"Output to brainwallet format unsupported")
		elif key in ('hidden_incog_input_params','hidden_incog_output_params'):
			a = val.split(",")
			if len(a) != 2:
				opt_display(key,val)
				msg("Option requires two comma-separated arguments")
				return False
			if not opt_is_int(a[1],desc): return False
			if key == 'hidden_incog_input_params':
				check_infile(a[0],blkdev_ok=True)
				key2 = 'in_fmt'
			else:
				import os
				try: os.stat(a[0])
				except:
					b = os.path.dirname(a[0])
					if b: check_outdir(b)
				else: check_outfile(a[0],blkdev_ok=True)
				key2 = 'out_fmt'
			if hasattr(opt,key2):
				val2 = getattr(opt,key2)
				from mmgen.seed import IncogWalletHidden
				if val2 and val2 not in IncogWalletHidden.fmt_codes:
					die(1,
						"Option conflict:\n  %s, with\n  %s=%s" % (
						fmt_opt(key),fmt_opt(key2),val2
					))
		elif key == 'seed_len':
			if not opt_is_int(val,desc): return False
			if not opt_is_in_list(int(val),g.seed_lens,desc): return False
		elif key == 'hash_preset':
			if not opt_is_in_list(val,g.hash_presets.keys(),desc): return False
		elif key == 'brain_params':
			a = val.split(",")
			if len(a) != 2:
				opt_display(key,val)
				msg("Option requires two comma-separated arguments")
				return False
			d = "seed length " + desc
			if not opt_is_int(a[0],d): return False
			if not opt_is_in_list(int(a[0]),g.seed_lens,d): return False
			d = "hash preset " + desc
			if not opt_is_in_list(a[1],g.hash_presets.keys(),d): return False
		elif key == 'usr_randchars':
			if val == 0: continue
			if not opt_is_int(val,desc): return False
			if not opt_compares(val,">=",g.min_urandchars,desc): return False
			if not opt_compares(val,"<=",g.max_urandchars,desc): return False
		else:
			if g.debug: Msg("check_opts(): No test for opt '%s'" % key)

	return True
Beispiel #5
0
def check_opts(usr_opts):       # Returns false if any check fails

	def opt_splits(val,sep,n,desc):
		sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else "'{}'".format(sep)
		try: l = val.split(sep)
		except:
			msg("'{}': invalid {} (not {}-separated list)".format(val,desc,sepword))
			return False

		if len(l) == n: return True
		else:
			msg("'{}': invalid {} ({} {}-separated items required)".format(val,desc,n,sepword))
			return False

	def opt_compares(val,op_str,target,desc,what=''):
		import operator as o
		op_f = { '<':o.lt, '<=':o.le, '>':o.gt, '>=':o.ge, '=':o.eq }[op_str]
		if what: what += ' '
		if not op_f(val,target):
			msg('{}: invalid {} ({}not {} {})'.format(val,desc,what,op_str,target))
			return False
		return True

	def opt_is_int(val,desc):
		try: int(val)
		except:
			msg("'{}': invalid {} (not an integer)".format(val,desc))
			return False
		return True

	def opt_is_float(val,desc):
		try: float(val)
		except:
			msg("'{}': invalid {} (not a floating-point number)".format(val,desc))
			return False
		return True

	def opt_is_in_list(val,lst,desc):
		if val not in lst:
			q,sep = (('',','),("'","','"))[type(lst[0]) == str]
			fs = '{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'
			msg(fs.format(v=val,w=desc,q=q,o=sep.join(map(str,sorted(lst)))))
			return False
		return True

	def opt_unrecognized(key,val,desc):
		msg("'{}': unrecognized {} for option '{}'".format(val,desc,fmt_opt(key)))
		return False

	def opt_display(key,val='',beg='For selected',end=':\n'):
		s = '{}={}'.format(fmt_opt(key),val) if val else fmt_opt(key)
		msg_r("{} option '{}'{}".format(beg,s,end))

	global opt
	for key,val in [(k,getattr(opt,k)) for k in usr_opts]:

		desc = "parameter for '{}' option".format(fmt_opt(key))

		from mmgen.util import check_infile,check_outfile,check_outdir
		# Check for file existence and readability
		if key in ('keys_from_file','mmgen_keys_from_file',
				'passwd_file','keysforaddrs','comment_file'):
			check_infile(val)  # exits on error
			continue

		if key == 'outdir':
			check_outdir(val)  # exits on error
# 		# NEW
		elif key in ('in_fmt','out_fmt'):
			from mmgen.seed import SeedSource,IncogWallet,Brainwallet,IncogWalletHidden
			sstype = SeedSource.fmt_code_to_type(val)
			if not sstype:
				return opt_unrecognized(key,val,'format code')
			if key == 'out_fmt':
				p = 'hidden_incog_output_params'
				if sstype == IncogWalletHidden and not getattr(opt,p):
					m1 = 'Hidden incog format output requested.  '
					m2 = "You must supply a file and offset with the '{}' option"
					die(1,m1+m2.format(fmt_opt(p)))
				if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
					opt_display(key,val,beg='Selected',end=' ')
					opt_display('old_incog_fmt',beg='conflicts with',end=':\n')
					die(1,'Export to old incog wallet format unsupported')
				elif issubclass(sstype,Brainwallet):
					die(1,'Output to brainwallet format unsupported')
		elif key in ('hidden_incog_input_params','hidden_incog_output_params'):
			a = val.split(',')
			if len(a) < 2:
				opt_display(key,val)
				msg('Option requires two comma-separated arguments')
				return False
			fn,ofs = ','.join(a[:-1]),a[-1] # permit comma in filename
			if not opt_is_int(ofs,desc): return False
			if key == 'hidden_incog_input_params':
				check_infile(fn,blkdev_ok=True)
				key2 = 'in_fmt'
			else:
				try: os.stat(fn)
				except:
					b = os.path.dirname(fn)
					if b: check_outdir(b)
				else: check_outfile(fn,blkdev_ok=True)
				key2 = 'out_fmt'
			if hasattr(opt,key2):
				val2 = getattr(opt,key2)
				from mmgen.seed import IncogWalletHidden
				if val2 and val2 not in IncogWalletHidden.fmt_codes:
					fs = 'Option conflict:\n  {}, with\n  {}={}'
					die(1,fs.format(fmt_opt(key),fmt_opt(key2),val2))
		elif key == 'seed_len':
			if not opt_is_int(val,desc): return False
			if not opt_is_in_list(int(val),g.seed_lens,desc): return False
		elif key == 'hash_preset':
			if not opt_is_in_list(val,list(g.hash_presets.keys()),desc): return False
		elif key == 'brain_params':
			a = val.split(',')
			if len(a) != 2:
				opt_display(key,val)
				msg('Option requires two comma-separated arguments')
				return False
			d = 'seed length ' + desc
			if not opt_is_int(a[0],d): return False
			if not opt_is_in_list(int(a[0]),g.seed_lens,d): return False
			d = 'hash preset ' + desc
			if not opt_is_in_list(a[1],list(g.hash_presets.keys()),d): return False
		elif key == 'usr_randchars':
			if val == 0: continue
			if not opt_is_int(val,desc): return False
			if not opt_compares(val,'>=',g.min_urandchars,desc): return False
			if not opt_compares(val,'<=',g.max_urandchars,desc): return False
		elif key == 'tx_fee':
			if not opt_is_tx_fee(val,desc): return False
		elif key == 'tx_confs':
			if not opt_is_int(val,desc): return False
			if not opt_compares(val,'>=',1,desc): return False
		elif key == 'vsize_adj':
			if not opt_is_float(val,desc): return False
			ymsg('Adjusting transaction vsize by a factor of {:1.2f}'.format(float(val)))
		elif key == 'key_generator':
			if not opt_compares(val,'<=',len(g.key_generators),desc): return False
			if not opt_compares(val,'>',0,desc): return False
		elif key == 'coin':
			from mmgen.protocol import CoinProtocol
			if not opt_is_in_list(val.lower(),list(CoinProtocol.coins.keys()),'coin'): return False
		elif key == 'rbf':
			if not g.proto.cap('rbf'):
				msg('--rbf requested, but {} does not support replace-by-fee transactions'.format(g.coin))
				return False
		elif key in ('bob','alice'):
			from mmgen.regtest import daemon_dir
			m = "Regtest (Bob and Alice) mode not set up yet.  Run '{}-regtest setup' to initialize."
			try: os.stat(daemon_dir)
			except: die(1,m.format(g.proj_name.lower()))
		elif key == 'locktime':
			if not opt_is_int(val,desc): return False
			if not opt_compares(int(val),'>',0,desc): return False
		elif key == 'token':
			if not 'token' in g.proto.caps:
				msg("Coin '{}' does not support the --token option".format(g.coin))
				return False
			elif len(val) == 40 and is_hex_str(val):
				pass
			elif len(val) > 20 or not all(s.isalnum() for s in val):
				msg("u'{}: invalid parameter for --token option".format(val))
				return False
		elif key == 'contract_data':
			check_infile(val)
		else:
			if g.debug: Msg("check_opts(): No test for opt '{}'".format(key))

	return True