Browse Source

opts, help: contextual command options

The following invocations now display a different set of options:

    $ mmgen-txcreate --help
    $ mmgen-txcreate --help --coin=eth

This feature was formerly available only for global options
The MMGen Project 1 month ago
parent
commit
037c6bfb6f
8 changed files with 218 additions and 192 deletions
  1. 0 2
      mmgen/cfg.py
  2. 1 1
      mmgen/data/version
  3. 26 11
      mmgen/help/__init__.py
  4. 37 36
      mmgen/main_addrgen.py
  5. 36 35
      mmgen/main_txcreate.py
  6. 58 57
      mmgen/main_txdo.py
  7. 43 41
      mmgen/main_wallet.py
  8. 17 9
      mmgen/opts.py

+ 0 - 2
mmgen/cfg.py

@@ -433,7 +433,6 @@ class Config(Lockable):
 			cfg          = None,
 			opts_data    = None,
 			init_opts    = None,
-			opt_filter   = None,
 			parse_only   = False,
 			parsed_opts  = None,
 			need_proto   = True,
@@ -455,7 +454,6 @@ class Config(Lockable):
 				cfg          = self,
 				opts_data    = opts_data,
 				init_opts    = init_opts,
-				opt_filter   = opt_filter,
 				parsed_opts  = parsed_opts,
 				need_proto   = need_proto)
 			self._uopt_src = 'cmdline'

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-15.1.dev12
+15.1.dev13

+ 26 - 11
mmgen/help/__init__.py

@@ -118,23 +118,16 @@ class Help:
 
 		return nl.join(gen_output()) + '\n'
 
-class CmdHelp(Help):
+class CmdHelp_v1(Help):
 
 	help_type = 'options'
 	data_desc = 'opts_data'
 
 	def gen_text(self, opts):
-		opt_filter = opts.opt_filter
-		from ..opts import cmd_opts_pat
+		from ..opts import cmd_opts_v1_pat
 		skipping = False
 		for line in opts.opts_data['text']['options'].strip().splitlines():
-			if m := cmd_opts_pat.match(line):
-				if opt_filter:
-					if m[1] in opt_filter:
-						skipping = False
-					else:
-						skipping = True
-						continue
+			if m := cmd_opts_v1_pat.match(line):
 				yield '{} --{} {}'.format(
 					(f'-{m[1]},', '   ')[m[1] == '-'],
 					m[2],
@@ -142,6 +135,28 @@ class CmdHelp(Help):
 			elif not skipping:
 				yield line
 
+class CmdHelp_v2(CmdHelp_v1):
+
+	def gen_text(self, opts):
+		from ..opts import cmd_opts_v2_help_pat
+		skipping = False
+		coin_filter_codes = opts.global_filter_codes.coin
+		cmd_filter_codes = opts.opts_data['filter_codes']
+		for line in opts.opts_data['text']['options'][1:].rstrip().splitlines():
+			m = cmd_opts_v2_help_pat.match(line)
+			if m[1] == '+':
+				if not skipping:
+					yield line[6:]
+			elif m[1] in coin_filter_codes and m[2] in cmd_filter_codes:
+				yield '{} --{} {}'.format(
+					(f'-{m[3]},', '   ')[m[3] == '-'],
+					m[4],
+					m[6]
+				) if m[4] else m[6]
+				skipping = False
+			else:
+				skipping = True
+
 class GlobalHelp(Help):
 
 	help_type = 'global_options'
@@ -166,7 +181,7 @@ class GlobalHelp(Help):
 def print_help(cfg, opts):
 
 	if cfg.help:
-		help_cls = CmdHelp
+		help_cls = CmdHelp_v2 if 'filter_codes' in opts.opts_data else CmdHelp_v1
 	else:
 		help_cls = GlobalHelp
 

+ 37 - 36
mmgen/main_addrgen.py

@@ -30,16 +30,17 @@ if gc.prog_name == 'mmgen-keygen':
 	gen_what = 'keys'
 	gen_clsname = 'KeyAddrList'
 	gen_desc = 'secret keys'
-	opt_filter = None
+	filter_codes = ['-', 'k']
 	note_addrkey = 'By default, both addresses and secret keys are generated.\n\n'
 else:
 	gen_what = 'addresses'
 	gen_clsname = 'AddrList'
 	gen_desc = 'addresses'
-	opt_filter = 'hbcdeEiHOkKlpzPqrStUv-'
+	filter_codes = ['-']
 	note_addrkey = ''
 
 opts_data = {
+	'filter_codes': filter_codes,
 	'sets': [('print_checksum', True, 'quiet', True)],
 	'text': {
 		'desc': f"""
@@ -48,39 +49,39 @@ opts_data = {
 			  """,
 		'usage':'[opts] [seed source] <index list or range(s)>',
 		'options': """
--h, --help            Print this help message
---, --longhelp        Print help message for long (global) options
--A, --no-addresses    Print only secret keys, no addresses
--c, --print-checksum  Print address list checksum and exit
--d, --outdir=      d  Output files to directory 'd' instead of working dir
--e, --echo-passphrase Echo passphrase or mnemonic to screen upon entry
--i, --in-fmt=      f  Input is from wallet format 'f' (see FMT CODES below)
--H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
-                      'f' at offset 'o' (comma-separated)
--O, --old-incog-fmt   Specify old-format incognito input
--k, --use-internal-keccak-module Force use of the internal keccak module
--K, --keygen-backend=n Use backend 'n' for public key generation.  Options
-                      for {coin_id}: {kgs}
--l, --seed-len=    l  Specify wallet seed length of 'l' bits.  This option
-                      is required only for brainwallet and incognito inputs
-                      with non-standard (< {dsl}-bit) seed lengths.
--p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
-                      for password hashing (default: '{gc.dfl_hash_preset}')
--z, --show-hash-presets Show information on available hash presets
--P, --passwd-file= f  Get wallet passphrase from file 'f'
--q, --quiet           Produce quieter output; suppress some warnings
--r, --usr-randchars=n Get 'n' characters of additional randomness from user
-                      (min={cfg.min_urandchars}, max={cfg.max_urandchars}, default={cfg.usr_randchars})
--S, --stdout          Print {what} to stdout
--t, --type=t          Choose address type. Options: see ADDRESS TYPES below
-                      (default: {dmat})
--U, --subwallet=   U  Generate {what} for subwallet 'U' (see SUBWALLETS
-                      below)
--V, --viewkeys        Print viewkeys, omitting secret keys
--v, --verbose         Produce more verbose output
--x, --b16             Print secret keys in hexadecimal too
-""",
-	'notes': """
+			-- -h, --help            Print this help message
+			-- --, --longhelp        Print help message for long (global) options
+			-k -A, --no-addresses    Print only secret keys, no addresses
+			-- -c, --print-checksum  Print address list checksum and exit
+			-- -d, --outdir=      d  Output files to directory 'd' instead of working dir
+			-- -e, --echo-passphrase Echo passphrase or mnemonic to screen upon entry
+			-- -i, --in-fmt=      f  Input is from wallet format 'f' (see FMT CODES below)
+			-- -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
+			+                        'f' at offset 'o' (comma-separated)
+			-- -O, --old-incog-fmt   Specify old-format incognito input
+			-- -k, --use-internal-keccak-module Force use of the internal keccak module
+			-- -K, --keygen-backend=n Use backend 'n' for public key generation.  Options
+			+                        for {coin_id}: {kgs}
+			-- -l, --seed-len=    l  Specify wallet seed length of 'l' bits.  This option
+			+                        is required only for brainwallet and incognito inputs
+			+                        with non-standard (< {dsl}-bit) seed lengths.
+			-- -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
+			+                        for password hashing (default: '{gc.dfl_hash_preset}')
+			-- -z, --show-hash-presets Show information on available hash presets
+			-- -P, --passwd-file= f  Get wallet passphrase from file 'f'
+			-- -q, --quiet           Produce quieter output; suppress some warnings
+			-- -r, --usr-randchars=n Get 'n' characters of additional randomness from user
+			+                        (min={cfg.min_urandchars}, max={cfg.max_urandchars}, default={cfg.usr_randchars})
+			-- -S, --stdout          Print {what} to stdout
+			-- -t, --type=t          Choose address type. Options: see ADDRESS TYPES below
+			+                        (default: {dmat})
+			-- -U, --subwallet=   U  Generate {what} for subwallet 'U' (see SUBWALLETS
+			+                        below)
+			-k -V, --viewkeys        Print viewkeys, omitting secret keys
+			-- -v, --verbose         Produce more verbose output
+			-k -x, --b16             Print secret keys in hexadecimal too
+		""",
+		'notes': """
 
                            NOTES FOR THIS COMMAND
 
@@ -124,7 +125,7 @@ FMT CODES:
 	}
 }
 
-cfg = Config(opts_data=opts_data, opt_filter=opt_filter, need_amt=False)
+cfg = Config(opts_data=opts_data, need_amt=False)
 
 proto = cfg._proto
 

+ 36 - 35
mmgen/main_txcreate.py

@@ -25,46 +25,47 @@ from .cfg import gc, Config
 from .util import fmt_list, async_run
 
 opts_data = {
+	'filter_codes': ['-'],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 		'desc': f'Create a transaction with outputs to specified coin or {gc.proj_name} addresses',
 		'usage':   '[opts] {u_args} [addr file ...]',
 		'options': """
--h, --help            Print this help message
---, --longhelp        Print help message for long (global) options
--a, --autosign        Create a transaction for offline autosigning (see
-                      ‘mmgen-autosign’). The removable device is mounted and
-                      unmounted automatically
--A, --fee-adjust=  f  Adjust transaction fee by factor 'f' (see below)
--B, --no-blank        Don't blank screen before displaying {a_info}
--c, --comment-file=f  Source the transaction's comment from file 'f'
--C, --fee-estimate-confs=c Desired number of confirmations for fee estimation
-                      (default: {cfg.fee_estimate_confs})
--d, --outdir=      d  Specify an alternate directory 'd' for output
--D, --contract-data=D Path to hex-encoded contract data (ETH only)
--E, --fee-estimate-mode=M Specify the network fee estimate mode.  Choices:
-                      {fe_all}.  Default: {fe_dfl!r}
--f, --fee=         f  Transaction fee, as a decimal {cu} amount or as
-                      {fu} (an integer followed by {fl!r}).
-                      See FEE SPECIFICATION below.  If omitted, fee will be
-                      calculated using network fee estimation.
--g, --gas=         g  Specify start gas amount in Wei (ETH only)
--i, --info            Display {a_info} and exit
--I, --inputs=      i  Specify transaction inputs (comma-separated list of
-                      MMGen IDs or coin addresses).  Note that ALL unspent
-                      outputs associated with each address will be included.
--l, --locktime=    t  Lock time (block height or unix seconds) (default: 0)
--L, --autochg-ignore-labels Ignore labels when autoselecting change addresses
--m, --minconf=     n  Minimum number of confirmations required to spend
-                      outputs (default: 1)
--q, --quiet           Suppress warnings; overwrite files without prompting
--R, --no-rbf          Make transaction non-replaceable (non-replace-by-fee
-                      according to BIP 125)
--v, --verbose         Produce more verbose output
--V, --vsize-adj=   f  Adjust transaction's estimated vsize by factor 'f'
--y, --yes             Answer 'yes' to prompts, suppress non-essential output
--X, --cached-balances Use cached balances (Ethereum only)
-""",
+			-- -h, --help            Print this help message
+			-- --, --longhelp        Print help message for long (global) options
+			-- -a, --autosign        Create a transaction for offline autosigning (see
+			+                        ‘mmgen-autosign’). The removable device is mounted and
+			+                        unmounted automatically
+			-- -A, --fee-adjust=  f  Adjust transaction fee by factor 'f' (see below)
+			-- -B, --no-blank        Don't blank screen before displaying {a_info}
+			-- -c, --comment-file=f  Source the transaction's comment from file 'f'
+			b- -C, --fee-estimate-confs=c Desired number of confirmations for fee estimation
+			+                        (default: {cfg.fee_estimate_confs})
+			-- -d, --outdir=      d  Specify an alternate directory 'd' for output
+			e- -D, --contract-data=D Path to file containing hex-encoded contract data
+			b- -E, --fee-estimate-mode=M Specify the network fee estimate mode.  Choices:
+			+                        {fe_all}.  Default: {fe_dfl!r}
+			-- -f, --fee=         f  Transaction fee, as a decimal {cu} amount or as
+			+                        {fu} (an integer followed by {fl!r}).
+			+                        See FEE SPECIFICATION below.  If omitted, fee will be
+			+                        calculated using network fee estimation.
+			e- -g, --gas=         g  Specify start gas amount in Wei
+			-- -i, --info            Display {a_info} and exit
+			-- -I, --inputs=      i  Specify transaction inputs (comma-separated list of
+			+                        MMGen IDs or coin addresses).  Note that ALL unspent
+			+                        outputs associated with each address will be included.
+			b- -l, --locktime=    t  Lock time (block height or unix seconds) (default: 0)
+			b- -L, --autochg-ignore-labels Ignore labels when autoselecting change addresses
+			-- -m, --minconf=     n  Minimum number of confirmations required to spend
+			+                        outputs (default: 1)
+			-- -q, --quiet           Suppress warnings; overwrite files without prompting
+			b- -R, --no-rbf          Make transaction non-replaceable (non-replace-by-fee
+			+                        according to BIP 125)
+			-- -v, --verbose         Produce more verbose output
+			b- -V, --vsize-adj=   f  Adjust transaction's estimated vsize by factor 'f'
+			-- -y, --yes             Answer 'yes' to prompts, suppress non-essential output
+			e- -X, --cached-balances Use cached balances
+		""",
 		'notes': '\n{c}\n{F}\n{x}',
 	},
 	'code': {

+ 58 - 57
mmgen/main_txdo.py

@@ -25,68 +25,69 @@ from .util import die, fmt_list, async_run
 from .subseed import SubSeedIdxRange
 
 opts_data = {
+	'filter_codes': ['-'],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 		'desc': f'Create, sign and send an {gc.proj_name} transaction',
 		'usage':   '[opts] {u_args} [addr file ...] [seed source ...]',
 		'options': """
--h, --help             Print this help message
---, --longhelp         Print help message for long (global) options
--A, --fee-adjust=    f Adjust transaction fee by factor 'f' (see below)
--b, --brain-params=l,p Use seed length 'l' and hash preset 'p' for
-                       brainwallet input
--B, --no-blank         Don't blank screen before displaying {a_info}
--c, --comment-file=  f Source the transaction's comment from file 'f'
--C, --fee-estimate-confs=c Desired number of confirmations for fee estimation
-                       (default: {cfg.fee_estimate_confs})
--d, --outdir=        d Specify an alternate directory 'd' for output
--D, --contract-data= D Path to hex-encoded contract data (ETH only)
--e, --echo-passphrase  Print passphrase to screen when typing it
--E, --fee-estimate-mode=M Specify the network fee estimate mode.  Choices:
-                       {fe_all}.  Default: {fe_dfl!r}
--f, --fee=           f Transaction fee, as a decimal {cu} amount or as
-                       {fu} (an integer followed by {fl!r}).
-                       See FEE SPECIFICATION below.  If omitted, fee will be
-                       calculated using network fee estimation.
--g, --gas=           g Specify start gas amount in Wei (ETH only)
--H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
-                      'f' at offset 'o' (comma-separated)
--i, --in-fmt=        f Input is from wallet format 'f' (see FMT CODES below)
--I, --inputs=        i Specify transaction inputs (comma-separated list of
-                       MMGen IDs or coin addresses).  Note that ALL unspent
-                       outputs associated with each address will be included.
--l, --seed-len=      l Specify wallet seed length of 'l' bits. This option
-                       is required only for brainwallet and incognito inputs
-                       with non-standard (< {dsl}-bit) seed lengths.
--k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
--K, --keygen-backend=n Use backend 'n' for public key generation.  Options
-                       for {coin_id}: {kgs}
--l, --locktime=      t Lock time (block height or unix seconds) (default: 0)
--L, --autochg-ignore-labels Ignore labels when autoselecting change addresses
--m, --minconf=n        Minimum number of confirmations required to spend
-                       outputs (default: 1)
--M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key-
-                       address file (output of '{pnl}-keygen'). Permits
-                       online signing without an {pnm} seed source. The
-                       key-address file is also used to verify {pnm}-to-{cu}
-                       mappings, so the user should record its checksum.
--O, --old-incog-fmt    Specify old-format incognito input
--p, --hash-preset=   p Use the scrypt hash parameters defined by preset 'p'
-                       for password hashing (default: '{gc.dfl_hash_preset}')
--P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
--R, --no-rbf           Make transaction non-replaceable (non-replace-by-fee
-                       according to BIP 125)
--q, --quiet            Suppress warnings; overwrite files without prompting
--u, --subseeds=      n The number of subseed pairs to scan for (default: {ss},
-                       maximum: {ss_max}). Only the default or first supplied
-                       wallet is scanned for subseeds.
--v, --verbose          Produce more verbose output
--V, --vsize-adj=     f Adjust transaction's estimated vsize by factor 'f'
--X, --cached-balances  Use cached balances (Ethereum only)
--y, --yes              Answer 'yes' to prompts, suppress non-essential output
--z, --show-hash-presets Show information on available hash presets
-""",
-	'notes': """
+			-- -h, --help             Print this help message
+			-- --, --longhelp         Print help message for long (global) options
+			-- -A, --fee-adjust=    f Adjust transaction fee by factor 'f' (see below)
+			-- -b, --brain-params=l,p Use seed length 'l' and hash preset 'p' for
+			+                         brainwallet input
+			-- -B, --no-blank         Don't blank screen before displaying {a_info}
+			-- -c, --comment-file=  f Source the transaction's comment from file 'f'
+			b- -C, --fee-estimate-confs=c Desired number of confirmations for fee estimation
+			+                         (default: {cfg.fee_estimate_confs})
+			-- -d, --outdir=        d Specify an alternate directory 'd' for output
+			e- -D, --contract-data= D Path to file containing hex-encoded contract data
+			-- -e, --echo-passphrase  Print passphrase to screen when typing it
+			b- -E, --fee-estimate-mode=M Specify the network fee estimate mode.  Choices:
+			+                         {fe_all}.  Default: {fe_dfl!r}
+			-- -f, --fee=           f Transaction fee, as a decimal {cu} amount or as
+			+                         {fu} (an integer followed by {fl!r}).
+			+                         See FEE SPECIFICATION below.  If omitted, fee will be
+			+                         calculated using network fee estimation.
+			e- -g, --gas=           g Specify start gas amount in Wei
+			-- -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
+			+                        'f' at offset 'o' (comma-separated)
+			-- -i, --in-fmt=        f Input is from wallet format 'f' (see FMT CODES below)
+			-- -I, --inputs=        i Specify transaction inputs (comma-separated list of
+			+                         MMGen IDs or coin addresses).  Note that ALL unspent
+			+                         outputs associated with each address will be included.
+			-- -l, --seed-len=      l Specify wallet seed length of 'l' bits. This option
+			+                         is required only for brainwallet and incognito inputs
+			+                         with non-standard (< {dsl}-bit) seed lengths.
+			-- -k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
+			-- -K, --keygen-backend=n Use backend 'n' for public key generation.  Options
+			+                         for {coin_id}: {kgs}
+			b- -l, --locktime=      t Lock time (block height or unix seconds) (default: 0)
+			b- -L, --autochg-ignore-labels Ignore labels when autoselecting change addresses
+			-- -m, --minconf=n        Minimum number of confirmations required to spend
+			+                         outputs (default: 1)
+			-- -M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key-
+			+                         address file (output of '{pnl}-keygen'). Permits
+			+                         online signing without an {pnm} seed source. The
+			+                         key-address file is also used to verify {pnm}-to-{cu}
+			+                         mappings, so the user should record its checksum.
+			-- -O, --old-incog-fmt    Specify old-format incognito input
+			-- -p, --hash-preset=   p Use the scrypt hash parameters defined by preset 'p'
+			+                         for password hashing (default: '{gc.dfl_hash_preset}')
+			-- -P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
+			b- -R, --no-rbf           Make transaction non-replaceable (non-replace-by-fee
+			+                         according to BIP 125)
+			-- -q, --quiet            Suppress warnings; overwrite files without prompting
+			-- -u, --subseeds=      n The number of subseed pairs to scan for (default: {ss},
+			+                         maximum: {ss_max}). Only the default or first supplied
+			+                         wallet is scanned for subseeds.
+			-- -v, --verbose          Produce more verbose output
+			b- -V, --vsize-adj=     f Adjust transaction's estimated vsize by factor 'f'
+			e- -X, --cached-balances  Use cached balances
+			-- -y, --yes              Answer 'yes' to prompts, suppress non-essential output
+			-- -z, --show-hash-presets Show information on available hash presets
+		""",
+		'notes': """
 {c}\n{F}
 
                                  SIGNING NOTES

+ 43 - 41
mmgen/main_wallet.py

@@ -45,78 +45,80 @@ invoked_as = {
 
 dsw = f'the default or specified {gc.proj_name} wallet'
 
-# full: defhHiJkKlLmoOpPqrSvz-
 if invoked_as == 'gen':
 	desc = f'Generate an {gc.proj_name} wallet from a random seed'
-	opt_filter = 'ehdoJlLpPqrSvz-'
 	usage = '[opts]'
 	oaction = 'output'
 	nargs = 0
 elif invoked_as == 'conv':
 	desc = 'Convert ' + dsw + ' from one format to another'
-	opt_filter = 'dehHiJkKlLmNoOpPqrSvz-'
 elif invoked_as == 'chk':
 	desc = 'Check validity of ' + dsw
-	opt_filter = 'ehiHOlpPqrvz-'
 	iaction = 'input'
 elif invoked_as == 'passchg':
 	desc = 'Change the passphrase, hash preset or label of ' + dsw
-	opt_filter = 'efhdiHkKOlLmNpPqrSvz-'
 	iaction = 'input'
 	do_bw_note = False
 elif invoked_as == 'subgen':
 	desc = 'Generate a subwallet from ' + dsw
-	opt_filter = 'dehHiJkKlLmNoOpPqrSvz-' # omitted: f
 	usage = '[opts] [infile] <Subseed Index>'
 	iaction = 'input'
 	oaction = 'output'
 	do_sw_note = True
 elif invoked_as == 'seedsplit':
 	desc = 'Generate a seed share from ' + dsw
-	opt_filter = 'dehHiJlLMNIoOpPqrSvz-'
 	usage = '[opts] [infile] [<Split ID String>:]<index>:<share count>'
 	iaction = 'input'
 	oaction = 'output'
 	do_ss_note = True
 
 opts_data = {
+	'filter_codes': {
+		# Write  In-fmt  Out-fmt  Keep-pass  Force-update  Master-share  passwd-file-New-only
+		'chk':       ['-',      'i'],
+		'conv':      ['-', 'w', 'i', 'o', 'k',      'n'],
+		'gen':       ['-', 'w',      'o'],
+		'passchg':   ['-', 'w', 'i',      'k', 'f', 'n'],
+		'seedsplit': ['-', 'w', 'i', 'o',      'm', 'n'],
+		'subgen':    ['-', 'w', 'i', 'o', 'k',      'n'],
+	}[invoked_as],
 	'text': {
 		'desc': desc,
 		'usage': usage,
 		'options': """
--h, --help            Print this help message
---, --longhelp        Print help message for long (global) options
--d, --outdir=      d  Output files to directory 'd' instead of working dir
--e, --echo-passphrase Echo passphrases and other user input to screen
--f, --force-update    Force update of wallet even if nothing has changed
--i, --in-fmt=      f  {iaction} from wallet format 'f' (see FMT CODES below)
--o, --out-fmt=     f  {oaction} to wallet format 'f' (see FMT CODES below)
--H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
-                      'f' at offset 'o' (comma-separated)
--J, --hidden-incog-output-params=f,o  Write hidden incognito data to file
-                      'f' at offset 'o' (comma-separated). File 'f' will be
-                      created if necessary and filled with random data.
--O, --old-incog-fmt   Specify old-format incognito input
--k, --keep-passphrase Reuse passphrase of input wallet for output wallet
--K, --keep-hash-preset Reuse hash preset of input wallet for output wallet
--l, --seed-len=    l  Specify wallet seed length of 'l' bits.  This option
-                      is required only for brainwallet and incognito inputs
-                      with non-standard (< {dsl}-bit) seed lengths.
--L, --label=       l  Specify a label 'l' for output wallet
--m, --keep-label      Reuse label of input wallet for output wallet
--M, --master-share=i  Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
--p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
-                      for password hashing (default: '{gc.dfl_hash_preset}')
--z, --show-hash-presets Show information on available hash presets
--P, --passwd-file= f  Get wallet passphrase from file 'f'
--N, --passwd-file-new-only Use passwd file only for new, not existing, wallet
--q, --quiet           Produce quieter output; suppress some warnings
--r, --usr-randchars=n Get 'n' characters of additional randomness from user
-                      (min={cfg.min_urandchars}, max={cfg.max_urandchars}, default={cfg.usr_randchars})
--S, --stdout          Write wallet data to stdout instead of file
--v, --verbose         Produce more verbose output
-""",
-	'notes': """
+			-- -h, --help            Print this help message
+			-- --, --longhelp        Print help message for long (global) options
+			-w -d, --outdir=      d  Output files to directory 'd' instead of working dir
+			-- -e, --echo-passphrase Echo passphrases and other user input to screen
+			-f -f, --force-update    Force update of wallet even if nothing has changed
+			-i -i, --in-fmt=      f  {iaction} from wallet format 'f' (see FMT CODES below)
+			-o -o, --out-fmt=     f  {oaction} to wallet format 'f' (see FMT CODES below)
+			-i -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
+			+                        'f' at offset 'o' (comma-separated)
+			-o -J, --hidden-incog-output-params=f,o  Write hidden incognito data to file
+			+                        'f' at offset 'o' (comma-separated). File 'f' will be
+			+                        created if necessary and filled with random data.
+			-i -O, --old-incog-fmt   Specify old-format incognito input
+			-k -k, --keep-passphrase Reuse passphrase of input wallet for output wallet
+			-k -K, --keep-hash-preset Reuse hash preset of input wallet for output wallet
+			-- -l, --seed-len=    l  Specify wallet seed length of 'l' bits.  This option
+			+                        is required only for brainwallet and incognito inputs
+			+                        with non-standard (< {dsl}-bit) seed lengths.
+			-w -L, --label=       l  Specify a label 'l' for output wallet
+			-k -m, --keep-label      Reuse label of input wallet for output wallet
+			-m -M, --master-share=i  Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
+			-- -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
+			+                        for password hashing (default: '{gc.dfl_hash_preset}')
+			-- -z, --show-hash-presets Show information on available hash presets
+			-- -P, --passwd-file= f  Get wallet passphrase from file 'f'
+			-n -N, --passwd-file-new-only Use passwd file only for new, not existing, wallet
+			-- -q, --quiet           Produce quieter output; suppress some warnings
+			-- -r, --usr-randchars=n Get 'n' characters of additional randomness from user
+			+                        (min={cfg.min_urandchars}, max={cfg.max_urandchars}, default={cfg.usr_randchars})
+			-w -S, --stdout          Write wallet data to stdout instead of file
+			-- -v, --verbose         Produce more verbose output
+		""",
+		'notes': """
 
 {n_ss}{n_sw}{n_pw}{n_bw}
 
@@ -145,7 +147,7 @@ FMT CODES:
 	}
 }
 
-cfg = Config(opts_data=opts_data, opt_filter=opt_filter, need_proto=False)
+cfg = Config(opts_data=opts_data, need_proto=False)
 
 cmd_args = cfg._args
 

+ 17 - 9
mmgen/opts.py

@@ -150,30 +150,41 @@ def process_uopts(cfg, opts_data, opts, need_proto):
 
 	return uopts, uargs
 
-cmd_opts_pat         = re.compile(r'^-([a-zA-Z0-9-]), --([a-zA-Z0-9-]{2,64})(=| )(.+)')
+cmd_opts_v1_pat      = re.compile(r'^-([a-zA-Z0-9-]), --([a-zA-Z0-9-]{2,64})(=| )(.+)')
+
+cmd_opts_v2_pat      = re.compile(r'^\t\t\t(.)(.) -([a-zA-Z0-9-]), --([a-z0-9-]{2,64})(=| )(.+)')
+cmd_opts_v2_help_pat = re.compile(r'^\t\t\t(.)(.) (?:-([a-zA-Z0-9-]), --([a-z0-9-]{2,64})(=| ))?(.+)')
 
 global_opts_pat      = re.compile(r'^\t\t\t(.)(.) --([a-z0-9-]{2,64})(=| )(.+)')
 global_opts_help_pat = re.compile(r'^\t\t\t(.)(.) (?:--([{}a-zA-Z0-9-]{2,64})(=| ))?(.+)')
 
 opt_tuple = namedtuple('cmdline_option', ['name', 'has_parm'])
 
-def parse_opts(cfg, opts_data, opt_filter, global_opts_data, global_filter_codes, need_proto):
+def parse_opts(cfg, opts_data, global_opts_data, global_filter_codes, need_proto):
 
-	def parse_cmd():
+	def parse_v1():
 		for line in opts_data['text']['options'].strip().splitlines():
-			m = cmd_opts_pat.match(line)
-			if m and (not opt_filter or m[1] in opt_filter):
+			if m := cmd_opts_v1_pat.match(line):
 				ret = opt_tuple(m[2].replace('-', '_'), m[3] == '=')
 				yield (m[1], ret)
 				yield (m[2], ret)
 
+	def parse_v2():
+		cmd_filter_codes = opts_data['filter_codes']
+		for line in opts_data['text']['options'].splitlines():
+			m = cmd_opts_v2_pat.match(line)
+			if m and m[1] in global_filter_codes.coin and m[2] in cmd_filter_codes:
+				ret = opt_tuple(m[4].replace('-', '_'), m[5] == '=')
+				yield (m[3], ret)
+				yield (m[4], ret)
+
 	def parse_global():
 		for line in global_opts_data['text']['options'].splitlines():
 			m = global_opts_pat.match(line)
 			if m and m[1] in global_filter_codes.coin and m[2] in global_filter_codes.cmd:
 				yield (m[3], opt_tuple(m[3].replace('-', '_'), m[4] == '='))
 
-	opts = tuple(parse_cmd()) + tuple(parse_global())
+	opts = tuple((parse_v2 if 'filter_codes' in opts_data else parse_v1)()) + tuple(parse_global())
 
 	uopts, uargs = process_uopts(cfg, opts_data, dict(opts), need_proto)
 
@@ -229,7 +240,6 @@ class Opts:
 			cfg,
 			opts_data,
 			init_opts,    # dict containing opts to pre-initialize
-			opt_filter,   # whitelist of opt letters; all others are skipped
 			parsed_opts,
 			need_proto):
 
@@ -237,7 +247,6 @@ class Opts:
 			raise RuntimeError(f'{len(sys.argv) - 1}: too many command-line arguments')
 
 		opts_data = opts_data or opts_data_dfl
-		self.opt_filter = opt_filter
 
 		self.global_filter_codes = self.get_global_filter_codes(need_proto)
 		self.opts_data = opts_data
@@ -245,7 +254,6 @@ class Opts:
 		po = parsed_opts or parse_opts(
 			cfg,
 			opts_data,
-			opt_filter,
 			self.global_opts_data,
 			self.global_filter_codes,
 			need_proto)