Skip to content

Commit 4050234

Browse files
committed
chore: Initial commit
0 parents  commit 4050234

File tree

7 files changed

+127
-0
lines changed

7 files changed

+127
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.basalt/

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# bash-algo
2+
3+
Common algorithms implemented in pure Bash
4+
5+
All algorithms use _only_ builtins and create _no subshells_
6+
7+
## Algorithms
8+
9+
- [x] base64 encode
10+
- [ ] base64 decode
11+
- [ ] md5
12+
- [ ] sha1
13+
- [ ] sha256

basalt.toml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = 'bash-algo'
3+
slug = 'balgo'
4+
version = ''
5+
authors = ['Edwin Kofler <[email protected]>']
6+
description = 'Common algorithms implemented in pure Bash'
7+
8+
[run]
9+
dependencies = ['https://github.com/hyperupcall/[email protected]']
10+
sourceDirs = ['pkg/lib/public']
11+
builtinDirs = []
12+
binDirs = []
13+
completionDirs = []
14+
manDirs = []
15+
16+
[run.shellEnvironment]
17+
18+
[run.setOptions]
19+
20+
[run.shoptOptions]

pkg/lib/public/bash-algo.sh

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# shellcheck shell=bash
2+
3+
algo.base64encode() {
4+
unset REPLY; REPLY=
5+
local input="$1"
6+
7+
local char_str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
8+
local has_{second,third}_byte=
9+
local {first,second,third}_{byte,char}=
10+
for ((i=0; i<${#input}; i=i+3)); do
11+
has_second_byte=
12+
has_third_byte=
13+
14+
# These branches execute if the string's length isn't divisible by 3. i.e., it
15+
# is divisible by 2 or only 1 (has lengths of 4, or 5). The i+1 is skipped because
16+
# it will always be true due to the condition in the for loop
17+
printf -v first_byte '%d' "'${input:$i:1}"
18+
19+
# TODO: can simplify if empty string results in 0
20+
if ((i+2 > ${#input})); then
21+
second_byte=$((2#00000000))
22+
else
23+
has_second_byte=yes
24+
printf -v second_byte '%d' "'${input:$i+1:1}"
25+
fi
26+
27+
if ((i+3 > ${#input})); then
28+
third_byte=$((2#00000000))
29+
else
30+
has_third_byte=yes
31+
printf -v third_byte '%d' "'${input:$i+2:1}"
32+
fi
33+
34+
new_first_bits=$(( (first_byte >> 2) & 2#00111111 ))
35+
new_second_bits=$(( ((first_byte & 2#00000011) << 4) | ((second_byte & 2#11110000) >> 4 & 2#00001111) ))
36+
new_third_bits=$(( (second_byte & 2#00001111) << 2 | third_byte >> 6 & 2#00000011 ))
37+
new_fourth_bits=$(( third_byte & 2#00111111 ))
38+
39+
first_char="${char_str:$new_first_bits:1}"
40+
second_char="${char_str:$new_second_bits:1}"
41+
42+
if [ "$has_second_byte" = yes ]; then
43+
third_char="${char_str:$new_third_bits:1}"
44+
else
45+
third_char='='
46+
fi
47+
if [ "$has_third_byte" = yes ]; then
48+
fourth_char="${char_str:$new_fourth_bits:1}"
49+
else
50+
fourth_char='='
51+
fi
52+
53+
REPLY+="$first_char$second_char$third_char$fourth_char"
54+
done
55+
}

tests/all.bats

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
load './util/init.sh'
4+
5+
@test "base64encode" {
6+
algo.base64encode "paraguay-uruguay"
7+
assert [ "$REPLY" = 'cGFyYWd1YXktdXJ1Z3VheQ==' ]
8+
9+
test_util.base64encode 'A'
10+
test_util.base64encode 'AB'
11+
test_util.base64encode 'ABC'
12+
test_util.base64encode 'ABCD'
13+
test_util.base64encode 'WOOF'
14+
test_util.base64encode 'kafka38quebec'
15+
test_util.base64encode 'EcHo##8(0}}'
16+
}

tests/util/init.sh

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# shellcheck shell=bash
2+
3+
eval "$(basalt-package-init)"
4+
basalt.package-init
5+
basalt.package-load
6+
basalt.load 'github.com/hyperupcall/bats-common-utils' 'load.bash'
7+
8+
load './util/test_util.sh'
9+
10+
setup() {
11+
cd "$BATS_TEST_TMPDIR"
12+
}
13+
14+
teardown() {
15+
cd "$BATS_SUITE_TMPDIR"
16+
}

tests/util/test_util.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# shellcheck shell=bash
2+
3+
test_util.base64encode() {
4+
algo.base64encode "$1"
5+
assert [ "$REPLY" = "$(printf '%s' "$1" | base64)" ]
6+
}

0 commit comments

Comments
 (0)