util2.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
  4. # Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen
  9. # https://gitlab.com/mmgen/mmgen
  10. """
  11. util2: Less frequently-used variables, classes and utility functions for the MMGen suite
  12. """
  13. import re,time
  14. from .util import msg,suf,hexdigits
  15. def die_wait(delay,ev=0,s=''):
  16. assert isinstance(delay,int)
  17. assert isinstance(ev,int)
  18. if s:
  19. msg(s)
  20. time.sleep(delay)
  21. sys.exit(ev)
  22. def die_pause(ev=0,s=''):
  23. assert isinstance(ev,int)
  24. if s:
  25. msg(s)
  26. input('Press ENTER to exit')
  27. sys.exit(ev)
  28. def removeprefix(s,pfx): # workaround for pre-Python 3.9
  29. return s[len(pfx):] if s.startswith(pfx) else s
  30. def removesuffix(s,sfx): # workaround for pre-Python 3.9
  31. return s[:-len(sfx)] if s.endswith(sfx) else s
  32. # called with no arguments by pyethereum.utils:
  33. def get_keccak(cfg=None,cached_ret=[]):
  34. if not cached_ret:
  35. if cfg and cfg.use_internal_keccak_module:
  36. cfg._util.qmsg('Using internal keccak module by user request')
  37. from .contrib.keccak import keccak_256
  38. else:
  39. try:
  40. from sha3 import keccak_256
  41. except:
  42. from .contrib.keccak import keccak_256
  43. cached_ret.append(keccak_256)
  44. return cached_ret[0]
  45. # From 'man dd':
  46. # c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024,
  47. # GB=1000*1000*1000, G=1024*1024*1024, and so on for T, P, E, Z, Y.
  48. bytespec_map = (
  49. ('c', 1),
  50. ('w', 2),
  51. ('b', 512),
  52. ('kB', 1000),
  53. ('K', 1024),
  54. ('MB', 1000000),
  55. ('M', 1048576),
  56. ('GB', 1000000000),
  57. ('G', 1073741824),
  58. ('TB', 1000000000000),
  59. ('T', 1099511627776),
  60. ('PB', 1000000000000000),
  61. ('P', 1125899906842624),
  62. ('EB', 1000000000000000000),
  63. ('E', 1152921504606846976),
  64. )
  65. def int2bytespec(n,spec,fmt,print_sym=True,strip=False,add_space=False):
  66. def spec2int(spec):
  67. for k,v in bytespec_map:
  68. if k == spec:
  69. return v
  70. else:
  71. die('{spec}: unrecognized bytespec')
  72. if strip:
  73. ret = '{:{}f}'.format(n/spec2int(spec),fmt).rstrip('0')
  74. return ret + ('0' if ret.endswith('.') else '') + ((' ' if add_space else '') + spec if print_sym else '')
  75. else:
  76. return '{:{}f}'.format(n/spec2int(spec),fmt) + ((' ' if add_space else '') + spec if print_sym else '')
  77. def parse_bytespec(nbytes):
  78. m = re.match(r'([0123456789.]+)(.*)',nbytes)
  79. if m:
  80. if m.group(2):
  81. for k,v in bytespec_map:
  82. if k == m.group(2):
  83. from decimal import Decimal
  84. return int(Decimal(m.group(1)) * v)
  85. else:
  86. msg("Valid byte specifiers: '{}'".format("' '".join([i[0] for i in bytespec_map])))
  87. elif '.' in nbytes:
  88. raise ValueError('fractional bytes not allowed')
  89. else:
  90. return int(nbytes)
  91. die(1,f'{nbytes!r}: invalid byte specifier')
  92. def format_elapsed_hr(t,now=None,cached={}):
  93. e = int((now or time.time()) - t)
  94. if not e in cached:
  95. abs_e = abs(e)
  96. cached[e] = ' '.join(
  97. '{} {}{}'.format(n,desc,suf(n)) for desc,n in (
  98. ('day', abs_e // 86400),
  99. ('hour', abs_e // 3600 % 24),
  100. ('minute', abs_e // 60 % 60),
  101. ) if n
  102. ) + (' ago' if e > 0 else ' in the future') if abs_e // 60 else 'just now'
  103. return cached[e]
  104. def pretty_format(s,width=80,pfx=''):
  105. out = []
  106. while(s):
  107. if len(s) <= width:
  108. out.append(s)
  109. break
  110. i = s[:width].rfind(' ')
  111. out.append(s[:i])
  112. s = s[i+1:]
  113. return pfx + ('\n'+pfx).join(out)
  114. def block_format(data,gw=2,cols=8,line_nums=None,data_is_hex=False):
  115. assert line_nums in (None,'hex','dec'),"'line_nums' must be one of None, 'hex' or 'dec'"
  116. ln_fs = '{:06x}: ' if line_nums == 'hex' else '{:06}: '
  117. bytes_per_chunk = gw
  118. if data_is_hex:
  119. gw *= 2
  120. nchunks = len(data)//gw + bool(len(data)%gw)
  121. return ''.join(
  122. ('' if (line_nums == None or i % cols) else ln_fs.format(i*bytes_per_chunk))
  123. + data[i*gw:i*gw+gw]
  124. + (' ' if (not cols or (i+1) % cols) else '\n')
  125. for i in range(nchunks)
  126. ).rstrip() + '\n'
  127. def pretty_hexdump(data,gw=2,cols=8,line_nums=None):
  128. return block_format(data.hex(),gw,cols,line_nums,data_is_hex=True)
  129. def decode_pretty_hexdump(data):
  130. pat = re.compile(fr'^[{hexdigits}]+:\s+')
  131. lines = [pat.sub('',line) for line in data.splitlines()]
  132. try:
  133. return bytes.fromhex(''.join((''.join(lines).split())))
  134. except:
  135. msg('Data not in hexdump format')
  136. return False