22"""Generic baseN functions.
33
44"""
5+ from argparse import ArgumentParser , RawTextHelpFormatter
56from math import log
67from six import integer_types , string_types
78from string import ascii_lowercase as lower , ascii_uppercase as upper , digits , printable
8- from types import FunctionType
9+ from textwrap import wrap
10+ from types import FunctionType , MethodType
911
1012from ..__common__ import *
13+ from ..__info__ import __version__
1114
1215
1316class BaseError (ValueError ):
@@ -86,9 +89,7 @@ def base_encode(input, charset, errors="strict", exc=BaseEncodeError):
8689 :param errors: errors handling marker
8790 :param exc: exception to be raised in case of error
8891 """
89- i = input if isinstance (input , integer_types ) else s2i (input )
90- n = len (charset )
91- r = ""
92+ i , n , r = input if isinstance (input , integer_types ) else s2i (input ), len (charset ), ""
9293 while i > 0 :
9394 i , c = divmod (i , n )
9495 r = charset [c ] + r
@@ -103,13 +104,13 @@ def base_decode(input, charset, errors="strict", exc=BaseDecodeError):
103104 :param errors: errors handling marker
104105 :param exc: exception to be raised in case of error
105106 """
106- i , n = 0 , len (charset )
107+ i , n , dec = 0 , len (charset ), lambda n : base_encode ( n , [ chr ( x ) for x in range ( 256 )], errors , exc )
107108 for k , c in enumerate (input ):
108109 try :
109110 i = i * n + charset .index (c )
110111 except ValueError :
111- handle_error ("base" , errors , exc , decode = True )(c , k )
112- return base_encode ( i , [ chr ( j ) for j in range ( 256 )], errors , exc )
112+ handle_error ("base" , errors , exc , decode = True )(c , k , dec ( i ) )
113+ return dec ( i )
113114
114115
115116# base codec factory functions
@@ -162,3 +163,55 @@ def _decode(input, errors="strict"):
162163 guess = ["base%d-generic" % i for i in range (2 , 255 )], entropy = lambda e , n : log (int (n .split ("-" )[0 ][4 :]), 2 ),
163164 len_charset = lambda n : int (n .split ("-" )[0 ][4 :]), printables_rate = 1. , category = "base-generic" , penalty = .4 )
164165
166+
167+ def main (n , ref = None , alt = None ):
168+ base = str (n ) + ("-" + alt .lstrip ("-" ) if alt else "" )
169+ src = "The data are encoded as described for the base%(base)s alphabet in %(reference)s.\n " % \
170+ {'base' : base , 'reference' : "\n " + ref if len (ref ) > 10 else ref } if ref else ""
171+ descr = """Usage: base%(base)s [OPTION]... [FILE]
172+ Base%(base)s encode or decode FILE, or standard input, to standard output.
173+
174+ With no FILE, or when FILE is -, read standard input.
175+
176+ Mandatory arguments to long options are mandatory for short options too.
177+ -d, --decode decode data
178+ -i, --ignore-garbage when decoding, ignore non-alphabet characters
179+ -I, --invert invert charsets from the base alphabet (e.g. lower- and uppercase)
180+ -w, --wrap=COLS wrap encoded lines after COLS character (default 76).
181+ Use 0 to disable line wrapping
182+
183+ --help display this help and exit
184+ --version output version information and exit
185+
186+ %(source)sWhen decoding, the input may contain newlines in addition to the bytes of
187+ the formal base%(base)s alphabet. Use --ignore-garbage to attempt to recover
188+ from any other non-alphabet bytes in the encoded stream.
189+
190+ Report base%(base)s translation bugs to <https://github.com/dhondta/python-codext/issues/new>
191+ Full documentation at: <https://python-codext.readthedocs.io/en/latest/enc/base.html>
192+ """ % {'base' : base , 'source' : src }
193+
194+ def _main ():
195+ parser = ArgumentParser (description = descr , formatter_class = RawTextHelpFormatter , add_help = False )
196+ parser .format_help = MethodType (lambda s : s .description , parser )
197+ parser .add_argument ("file" , nargs = "?" )
198+ parser .add_argument ("-d" , "--decode" , action = "store_true" )
199+ parser .add_argument ("-i" , "--ignore-garbage" , action = "store_true" )
200+ parser .add_argument ("-I" , "--invert" , action = "store_true" )
201+ parser .add_argument ("-w" , "--wrap" , type = int , default = 76 )
202+ parser .add_argument ("--help" , action = "help" )
203+ parser .add_argument ("--version" , action = "version" )
204+ parser .version = "CodExt " + __version__
205+ args = parser .parse_args ()
206+ c , f = _input (args .file ), [encode , decode ][args .decode ]
207+ c = c .rstrip ("\r \n " ) if isinstance (c , str ) else c .rstrip (b"\r \n " )
208+ try :
209+ c = f (c , "base" + base + ["" , "-inv" ][args .invert ], ["strict" , "ignore" ][args .ignore_garbage ])
210+ except Exception as err :
211+ print ("%sbase%d: invalid input" % (err .output , n ))
212+ return 1
213+ for l in wrap (ensure_str (c ), args .wrap ):
214+ print (l )
215+ return 0
216+ return _main
217+
0 commit comments