scripts/library: add human_to_size

This is a bash wrapper around an awk function that parses human readable
sizes and returns their representative values in bytes, as a string. A
small test harness is added to validate the functionality.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
This commit is contained in:
Dave Reisner 2012-04-25 22:27:19 -04:00 committed by Dan McGee
parent e183522e31
commit b58489d29a
6 changed files with 140 additions and 2 deletions

View File

@ -41,6 +41,8 @@ test-vercmp: test/util src/util
test-parseopts: test/scripts scripts
$(BASH_SHELL) $(top_srcdir)/test/scripts/parseopts_test.sh \
$(top_srcdir)/scripts/library/parseopts.sh
$(BASH_SHELL) $(top_srcdir)/test/scripts/human_to_size_test.sh \
$(top_srcdir)/scripts/library/human_to_size.sh
# create the pacman DB and cache directories upon install
install-data-local:

View File

@ -27,7 +27,8 @@ EXTRA_DIST = \
LIBRARY = \
library/output_format.sh \
library/parseopts.sh
library/parseopts.sh \
library/human_to_size.sh
# Files that should be removed, but which Automake does not know.
MOSTLYCLEANFILES = $(bin_SCRIPTS)

View File

@ -27,3 +27,11 @@ Reccommended Usage:
Returns:
0: parse success
1: parse failure (error message supplied)
human_to_size.sh:
A function to convert human readable sizes (such as "5.3 GiB") to raw byte
equivalents. base10 and base2 suffixes are supported, case sensitively. If
successful, the converted byte value is written to stdout and the function
returns 0. If an error occurs, nothing in written and the function returns 1.
Results may be inaccurate when using a broken implementation of awk, such
as mawk or busybox awk.

View File

@ -0,0 +1,51 @@
human_to_size() {
awk -v human="$1" '
function trim(s) {
gsub(/^[[:space:]]+|[[:space:]]+$/, "", s)
return s
}
function parse_units(units) {
if (!units || units == "B")
return 1
if (match(units, /^.iB$/))
return 1024
if (match(units, /^.B$/))
return 1000
if (length(units) == 1)
return 1024
# parse failure: invalid base
return -1
}
function parse_scale(s) {
return index("BKMGTPE", s) - 1
}
function isnumeric(string) {
return match(string, /^[-+]?[[:digit:]]*(\.[[:digit:]]*)?/)
}
BEGIN {
# peel off the leading number as the size, fail on invalid number
human = trim(human)
if (isnumeric(human))
size = substr(human, RSTART, RLENGTH)
else
exit 1
# the trimmed remainder is assumed to be the units
units = trim(substr(human, RLENGTH + 1))
base = parse_units(units)
if (base < 0)
exit 1
scale = parse_scale(substr(units, 1, 1))
if (scale < 0)
exit 1
printf "%d\n", size * base^scale + (size + 0 > 0 ? 0.5 : -0.5)
}'
}

View File

@ -1,5 +1,6 @@
check_SCRIPTS = \
parseopts_test.sh
parseopts_test.sh \
human_to_size_test.sh
noinst_SCRIPTS = $(check_SCRIPTS)

View File

@ -0,0 +1,75 @@
#!/bin/bash
# source the library function
if [[ -z $1 || ! -f $1 ]]; then
printf "error: path to human_to_size library not provided or does not exist\n"
exit 1
fi
. "$1"
if ! type -t human_to_size >/dev/null; then
printf 'human_to_size function not found\n'
exit 1
fi
parse_hts() {
local input=$1 expected=$2 result
(( ++testcount ))
result=$(human_to_size "$1")
if [[ $result = "$expected" ]]; then
(( ++pass ))
else
(( ++fail ))
printf '[TEST %3s]: FAIL\n' "$testcount"
printf ' input: %s\n' "$input"
printf ' output: %s\n' "$result"
printf ' expected: %s\n' "$expected"
fi
}
summarize() {
if (( !fail )); then
printf 'All %s tests successful\n' "$testcount"
exit 0
else
printf '%s of %s tests failed\n' "$fail" "$testcount"
exit 1
fi
}
trap 'summarize' EXIT
printf 'Beginning human_to_size tests\n'
# parse_hts <input> <expected output>
parse_hts '1MiB' 1048576
parse_hts '10XiB' ''
parse_hts '10 MiB' 10485760
parse_hts '10 XiB' ''
parse_hts '.1 TiB' 109951162778
parse_hts ' -3 KiB ' -3072
parse_hts 'foo3KiB' ''
parse_hts '3KiBfoo' ''
parse_hts '3kib' ''
parse_hts '+1KiB' 1024
parse_hts '+1.0 KiB' 1024
parse_hts '1MB' 1000000
parse_hts '1M' 1048576
parse_hts ' 1 G ' 1073741824
parse_hts '1Q' ''