Browse Source

tool: add 'to_bytespec' command; minor changes

The MMGen Project 4 years ago
parent
commit
a4ef9ba4ac
4 changed files with 72 additions and 19 deletions
  1. 2 0
      mmgen/exception.py
  2. 8 0
      mmgen/tool.py
  3. 38 13
      mmgen/util.py
  4. 24 6
      test/tooltest2.py

+ 2 - 0
mmgen/exception.py

@@ -34,6 +34,8 @@ class InvalidPasswdFormat(Exception):     mmcode = 1
 class CfgFileParseError(Exception):       mmcode = 1
 class UserOptError(Exception):            mmcode = 1
 class NoLEDSupport(Exception):            mmcode = 1
+class NotAnInteger(Exception):            mmcode = 1
+class IntegerOutOfRange(Exception):       mmcode = 1
 
 # 2: yellow hl, message only
 class InvalidTokenAddress(Exception):     mmcode = 2

+ 8 - 0
mmgen/tool.py

@@ -310,6 +310,14 @@ class MMGenToolCmdUtil(MMGenToolCmds):
 		"convert a byte specifier such as '1GB' into an integer"
 		return parse_bytespec(dd_style_byte_specifier)
 
+	def to_bytespec(self,
+			n: int,
+			dd_style_byte_specifier: str,
+			fmt = '0.2',
+			print_sym = True ):
+		"convert an integer to a byte specifier such as '1GB'"
+		return int2bytespec(n,dd_style_byte_specifier,fmt,print_sym)
+
 	def randhex(self,nbytes='32'):
 		"print 'n' bytes (default 32) of random data in hex format"
 		return get_random(int(nbytes)).hex()

+ 38 - 13
mmgen/util.py

@@ -173,29 +173,44 @@ def set_for_type(val,refval,desc,invert_bool=False,src=None):
 # From 'man dd':
 # c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024,
 # GB=1000*1000*1000, G=1024*1024*1024, and so on for T, P, E, Z, Y.
+bytespec_map = (
+	('c',  1),
+	('w',  2),
+	('b',  512),
+	('kB', 1000),
+	('K',  1024),
+	('MB', 1000000),
+	('M',  1048576),
+	('GB', 1000000000),
+	('G',  1073741824),
+	('TB', 1000000000000),
+	('T',  1099511627776),
+	('PB', 1000000000000000),
+	('P',  1125899906842624),
+	('EB', 1000000000000000000),
+	('E',  1152921504606846976),
+)
+
+def int2bytespec(n,spec,fmt,print_sym=True):
+	def spec2int(spec):
+		for k,v in bytespec_map:
+			if k == spec:
+				return v
+		else:
+			die('{spec}: unrecognized bytespec')
+	return '{:{}f}{}'.format( n / spec2int(spec), fmt, spec if print_sym else '' )
 
 def parse_bytespec(nbytes):
-	smap = (('c',   1),
-			('w',   2),
-			('b',   512),
-			('kB',  1000),
-			('K',   1024),
-			('MB',  1000*1000),
-			('M',   1024*1024),
-			('GB',  1000*1000*1000),
-			('G',   1024*1024*1024),
-			('TB',  1000*1000*1000*1000),
-			('T',   1024*1024*1024*1024))
 	import re
 	m = re.match(r'([0123456789.]+)(.*)',nbytes)
 	if m:
 		if m.group(2):
-			for k,v in smap:
+			for k,v in bytespec_map:
 				if k == m.group(2):
 					from decimal import Decimal
 					return int(Decimal(m.group(1)) * v)
 			else:
-				msg("Valid byte specifiers: '{}'".format("' '".join([i[0] for i in smap])))
+				msg("Valid byte specifiers: '{}'".format("' '".join([i[0] for i in bytespec_map])))
 		elif '.' in nbytes:
 			raise ValueError('fractional bytes not allowed')
 		else:
@@ -347,6 +362,16 @@ def is_ascii(s,enc='ascii'):
 	except: return False
 	else:   return True
 
+def check_int_between(n,lo,hi,desc='value'):
+	import re
+	m = re.match(r'-{0,1}[0-9]+',str(n))
+	if m == None:
+		raise NotAnInteger(f'{n}: {desc} must be an integer')
+	n = int(n)
+	if n < lo or n > hi:
+		raise IntegerOutOfRange(f'{n}: {desc} must be between {lo} and {hi}')
+	return n
+
 def match_ext(addr,ext):
 	return addr.split('.')[-1] == ext
 

+ 24 - 6
test/tooltest2.py

@@ -277,13 +277,31 @@ tests = {
 			( ['111111115Q','pad=2'], 'ff' ),
 		],
 		'bytespec': [
-			( ['1G'], str(1024*1024*1024) ),
-			( ['1234G'], str(1234*1024*1024*1024) ),
-			( ['1GB'], str(1000*1000*1000) ),
-			( ['1234GB'], str(1234*1000*1000*1000) ),
-			( ['1.234MB'], str(1234*1000) ),
+			( ['1G'],        str(1024*1024*1024) ),
+			( ['1GB'],       str(1000*1000*1000) ),
+			( ['1234GB'],    str(1234*1000*1000*1000) ),
+			( ['1234G'],     str(1234*1024*1024*1024) ),
+			( ['1234TB'],    str(1234*1000*1000*1000*1000) ),
+			( ['1234T'],     str(1234*1024*1024*1024*1024) ),
+			( ['1234PB'],    str(1234*1000*1000*1000*1000*1000) ),
+			( ['1234P'],     str(1234*1024*1024*1024*1024*1024) ),
+			( ['1234EB'],    str(1234*1000*1000*1000*1000*1000*1000) ),
+			( ['1234E'],     str(1234*1024*1024*1024*1024*1024*1024) ),
+			( ['1.234MB'],   str(1234*1000) ),
 			( ['1.234567M'], str(int(Decimal('1.234567')*1024*1024)) ),
-			( ['1234'], str(1234) ),
+			( ['1234'],      str(1234) ),
+		],
+		'to_bytespec': [
+			( [str(1024*1024*1024),'G'],                               '1.00G' ),
+			( [str(1024*1024*1024),'G','fmt=0.0'],                     '1G' ),
+			( [str(1024*1024*1024),'G','fmt=08.5'],                    '01.00000G' ),
+			( [str(1234*1000*1000*1000),'GB'],                         '1234.00GB' ),
+			( [str(1234*1024*1024*1024),'G'],                          '1234.00G', ),
+			( [str(1000*1000*1000*1000*1000),'PB'],                    '1.00PB' ),
+			( [str(1024*1024*1024*1024*1024),'P'],                     '1.00P' ),
+			( [str(1024*1024*1024*1024*1024*1024),'E'],                '1.00E' ),
+			( [str(int(Decimal('1.234567')*1024*1024)),'M','fmt=0.6'], '1.234567M' ),
+			( ['1234','c','fmt=0.0','print_sym=false'],                '1234' ),
 		],
 		'hash160': [ # TODO: check that hextob58chk(hash160) = pubhex2addr
 			( ['deadbeef'], 'f04df4c4b30d2b7ac6e1ed2445aeb12a9cb4d2ec' ),