-
Notifications
You must be signed in to change notification settings - Fork 2
/
radix
executable file
·132 lines (113 loc) · 3.76 KB
/
radix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/bin/bash
help() { cat <</help
Convert a number to any radix (arithmetic base) between 2 and 64 (inclusive)
Usage: $self [-][INPUT_RADIX#]NUMBER [OUTPUT_RADIX]
$self md5[:STRING] [OUTPUT_RADIX]
- The negative sign goes *before* the INPUT_RADIX, not after
INPUT_RADIX The input radix is any integer between 2 and 64 (default = 10)
NUMBER Any integer. Digits run 0-9 then a-z then A-Z then @ then _
Must be 64-bit (-$max to $max)
OUTPUT_RADIX The output radix is any integer between 2 and 64
If INPUT_RADIX is 10, default = 36. Otherwise default = 10.
md5 Use a truncated MD5 checksum of STRING (or else standard input)
STRING A string to checksum. No trailing linebreak is added.
Examples:
$self 123 # \`ya\` (defaults to input/output radices of 10/36)
$self -805854694382 32 # \`-negative\`
$self -32\\#negative # \`-805854694382\` (defaults to output radix 10)
$self "64#1F_@rS" 36 # \`testme\`
$self "md5:hey Joe" 64 # \`6ZGm5WN3VNv\` (THIS IS NOT A PASSWORD GENERATOR!)
/help
version
}
version() {
echo "Part of misc-scripts: https://github.com/adamhotep/misc-scripts"
echo "radix 0.1.20241124.0 copyright 2024+ by Adam Katz, GPL v3+"
exit
}
we_have() { command -v "$@" >/dev/null; } # true if the command exists
die() { echo "$self: $*" >&2; exit 2; } # report error and exit
isNaN() { ! [ "${1#-}" -le $max ] 2>/dev/null; } # cannot use [[ ... ]]
vet_radix() {
r="radix (arithmetic base) \`$1\`"
if isNaN "$1"; then
die "Invalid number for $r"
elif (( 2 > $1 || $1 > 64 )); then
die "Out of bounds $r is not 2-64"
fi
}
self="${0##*/}"
if [[ $1 == -- ]]; then
shift
elif [[ $# == 0 ]]; then
help |grep -A1 ^Usage
exit
fi
iradix=10 # input radix (updated later if specified in the number)
number="$1" # input number, which may specify an input radix
oradix="$2" # output radix
digits="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@_"
# -9223372036854775808 is 64-bit, but it had issues, so it is forbidden
max=9223372036854775807
out_of_bounds="Number must be between -$max and $max"
case $number in
( -h* | --help* | help ) help ;;
( -v* | -V | ver | version ) version ;;
( md5* )
if ! we_have md5sum; then
if we_have busybox && busybox |grep -Fwq md5sum; then
md5sum() { busybox md5sum "$@"; }
elif we_have md5; then
md5sum() { md5 "$@"; }
else
die "Cannot locate md5 checksummer"
fi
fi
case $number in
( md5 ) number="$(cat |md5sum)" ;;
( md5:* ) number="$(printf %s "${number#md5:}" |md5sum)" ;;
( * ) die 'MD5 must be invoked as either `md5` or `md5:STRING`' ;;
esac
tmp="${number#????????????????}"
number="16#${number%$tmp}"
;;
esac
if isNaN "$number"; then
: "NUMBER is not an integer. Determine its safety then convert to an integer"
if [[ $number != *\#* ]]; then
if [[ ${number#-} != *[^0-9]* ]]; then
die "$out_of_bounds"
else
die "Invalid number \`$1\` (no input radix specified? see \`--help\`)"
fi
fi
abs="${number#-}"
iradix="${abs%%#*}"
vet_radix "$iradix"
case ${abs#$iradix#} in
( '' | *[!0-9a-zA-Z@_]* ) die "Invalid number \`$number\`" ;;
esac
: "convert \`$number\` to an integer or else exit after bash arithmetic error"
(( (number += 0) || number == 0 )) || exit 2
: "number converted from <$1> to <$number>"
fi
case $iradix:$oradix in
( 10: ) oradix=36 ;;
( *: ) oradix=10 ;;
esac
vet_radix "$oradix"
if (( number < 0 )); then
sign='-'
number="${number#-}"
else
sign=''
fi
if isNaN "$number"; then
die "$out_of_bounds"
fi
out=""
while (( number != 0 )); do
out="${digits:(( number % oradix )):1}${out}"
(( number /= oradix ))
done
echo "$sign${out:-$number}"