1ab2043b8SDevin Teskeif [ ! "$_STRINGS_SUBR" ]; then _STRINGS_SUBR=1 2ab2043b8SDevin Teske# 30cb8bea7SDevin Teske# Copyright (c) 2006-2016 Devin Teske 4f8ea072aSDevin Teske# All rights reserved. 5ab2043b8SDevin Teske# 6ab2043b8SDevin Teske# Redistribution and use in source and binary forms, with or without 7ab2043b8SDevin Teske# modification, are permitted provided that the following conditions 8ab2043b8SDevin Teske# are met: 9ab2043b8SDevin Teske# 1. Redistributions of source code must retain the above copyright 10ab2043b8SDevin Teske# notice, this list of conditions and the following disclaimer. 11ab2043b8SDevin Teske# 2. Redistributions in binary form must reproduce the above copyright 12ab2043b8SDevin Teske# notice, this list of conditions and the following disclaimer in the 13ab2043b8SDevin Teske# documentation and/or other materials provided with the distribution. 14ab2043b8SDevin Teske# 15ab2043b8SDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 168e37a7c8SDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17ab2043b8SDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18ab2043b8SDevin Teske# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19ab2043b8SDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 208e37a7c8SDevin Teske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21ab2043b8SDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22ab2043b8SDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23ab2043b8SDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24ab2043b8SDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25ab2043b8SDevin Teske# SUCH DAMAGE. 26ab2043b8SDevin Teske# 27d3a0f918SDevin Teske# 28fcaed0c1SDevin Teske############################################################ INCLUDES 29fcaed0c1SDevin Teske 30fcaed0c1SDevin TeskeBSDCFG_SHARE="/usr/share/bsdconfig" 31fcaed0c1SDevin Teske. $BSDCFG_SHARE/common.subr || exit 1 32fcaed0c1SDevin Teske 33d3a0f918SDevin Teske############################################################ GLOBALS 34d3a0f918SDevin Teske 35d3a0f918SDevin Teske# 3605a0a04aSDevin Teske# A Literal newline (for use with f_replace_all(), or IFS, or whatever) 3705a0a04aSDevin Teske# 3805a0a04aSDevin TeskeNL=" 3905a0a04aSDevin Teske" # END-QUOTE 4005a0a04aSDevin Teske 4105a0a04aSDevin Teske# 42d3a0f918SDevin Teske# Valid characters that can appear in an sh(1) variable name 43d3a0f918SDevin Teske# 44d3a0f918SDevin Teske# Please note that the character ranges A-Z and a-z should be avoided because 45d3a0f918SDevin Teske# these can include accent characters (which are not valid in a variable name). 46d3a0f918SDevin Teske# For example, A-Z matches any character that sorts after A but before Z, 47d3a0f918SDevin Teske# including A and Z. Although ASCII order would make more sense, that is not 48d3a0f918SDevin Teske# how it works. 49d3a0f918SDevin Teske# 50d3a0f918SDevin TeskeVALID_VARNAME_CHARS="0-9ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_" 51d3a0f918SDevin Teske 52d3a0f918SDevin Teske############################################################ FUNCTIONS 53ab2043b8SDevin Teske 5492db3842SDevin Teske# f_isinteger $arg 5592db3842SDevin Teske# 5692db3842SDevin Teske# Returns true if argument is a positive/negative whole integer. 5792db3842SDevin Teske# 5892db3842SDevin Teskef_isinteger() 5992db3842SDevin Teske{ 6092db3842SDevin Teske local arg="${1#-}" 6192db3842SDevin Teske [ "${arg:-x}" = "${arg%[!0-9]*}" ] 6292db3842SDevin Teske} 6392db3842SDevin Teske 640cb8bea7SDevin Teske# f_substr [-v $var_to_set] $string $start [$length] 65ab2043b8SDevin Teske# 660cb8bea7SDevin Teske# Similar to awk(1)'s substr(), return length substring of string that begins 670cb8bea7SDevin Teske# at start position counted from 1. 68ab2043b8SDevin Teske# 69*437455deSDevin Teskecase "$BASH_VERSION" in 70*437455deSDevin Teske*?*) 71*437455deSDevin Teske f_substr() 72*437455deSDevin Teske { 73*437455deSDevin Teske local __var_to_set= 74*437455deSDevin Teske case "$1" in 75*437455deSDevin Teske -v) __var_to_set="$2"; shift 2 ;; 76*437455deSDevin Teske -v?*) __var_to_set="${2#-v}"; shift 1 ;; 77*437455deSDevin Teske esac 78*437455deSDevin Teske local __tmp="$1" __start="${2:-1}" __len="$3" 79*437455deSDevin Teske [ "$__start" -gt 0 ] 2> /dev/null && 80*437455deSDevin Teske __start=$(( $__start - 1 )) 81*437455deSDevin Teske if [ ! "$__var_to_set" ]; then 82*437455deSDevin Teske eval echo \"\${__tmp:\$__start${__len:+:\$__len}}\" 83*437455deSDevin Teske return $? 84*437455deSDevin Teske fi 85*437455deSDevin Teske if [ "$__len" ]; then 86*437455deSDevin Teske eval $__var_to_set=\"\${__tmp:\$__start:\$__len}\" 87*437455deSDevin Teske else 88*437455deSDevin Teske eval $__var_to_set=\"\${__tmp:\$__start}\" 89*437455deSDevin Teske fi 90*437455deSDevin Teske } 91*437455deSDevin Teske ;; 92*437455deSDevin Teske*) 93*437455deSDevin Teske # NB: On FreeBSD, sh(1) runs this faster than bash(1) runs the above 94ab2043b8SDevin Teske f_substr() 95ab2043b8SDevin Teske { 960cb8bea7SDevin Teske local OPTIND=1 OPTARG __flag __var_to_set= 970cb8bea7SDevin Teske while getopts v: __flag; do 980cb8bea7SDevin Teske case "$__flag" in 990cb8bea7SDevin Teske v) __var_to_set="$OPTARG" ;; 1000cb8bea7SDevin Teske esac 1010cb8bea7SDevin Teske done 1020cb8bea7SDevin Teske shift $(( $OPTIND - 1 )) 103ab2043b8SDevin Teske 1040cb8bea7SDevin Teske local __tmp="$1" __start="${2:-1}" __size="$3" 1050cb8bea7SDevin Teske local __tbuf __tbuf_len __trim __trimq 1060f913ed5SDevin Teske 1070cb8bea7SDevin Teske if [ ! "$__tmp" ]; then 1080cb8bea7SDevin Teske [ "$__var_to_set" ] && setvar "$__var_to_set" "" 1090f913ed5SDevin Teske return ${SUCCESS:-0} 1100cb8bea7SDevin Teske fi 1110cb8bea7SDevin Teske [ "$__start" -ge 1 ] 2> /dev/null || __start=1 1120cb8bea7SDevin Teske if ! [ "${__size:-1}" -ge 1 ] 2> /dev/null; then 1130cb8bea7SDevin Teske [ "$__var_to_set" ] && setvar "$__var_to_set" "" 1140f913ed5SDevin Teske return ${FAILURE:-1} 1150f913ed5SDevin Teske fi 1160f913ed5SDevin Teske 1170cb8bea7SDevin Teske __trim=$(( $__start - 1 )) 1180cb8bea7SDevin Teske while [ $__trim -gt 0 ]; do 1190cb8bea7SDevin Teske __tbuf="?" 1200cb8bea7SDevin Teske __tbuf_len=1 121*437455deSDevin Teske while [ $__tbuf_len -lt $(( $__trim / $__tbuf_len )) ] 122*437455deSDevin Teske do 1230cb8bea7SDevin Teske __tbuf="$__tbuf?" 1240cb8bea7SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1250cb8bea7SDevin Teske done 1260cb8bea7SDevin Teske __trimq=$(( $__trim / $__tbuf_len )) 1270cb8bea7SDevin Teske __trim=$(( $__trim - $__tbuf_len * $__trimq )) 1280cb8bea7SDevin Teske while [ $__trimq -gt 0 ]; do 1290cb8bea7SDevin Teske __tmp="${__tmp#$__tbuf}" 1300cb8bea7SDevin Teske __trimq=$(( $__trimq - 1 )) 1310cb8bea7SDevin Teske done 1320cb8bea7SDevin Teske done 1330f913ed5SDevin Teske 1340cb8bea7SDevin Teske local __tmp_size=${#__tmp} 1350f913ed5SDevin Teske local __mask __mask_len 1360cb8bea7SDevin Teske __trim=$(( $__tmp_size - ${__size:-$__tmp_size} )) 1370f913ed5SDevin Teske while [ $__trim -gt 0 ]; do 1380f913ed5SDevin Teske __tbuf="?" 1390f913ed5SDevin Teske __tbuf_len=1 1400f913ed5SDevin Teske if [ $__trim -le $__size ]; then 141*437455deSDevin Teske while [ $__tbuf_len -lt $(( 142*437455deSDevin Teske $__trim / $__tbuf_len 143*437455deSDevin Teske )) ]; do 1440f913ed5SDevin Teske __tbuf="$__tbuf?" 1450f913ed5SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1460f913ed5SDevin Teske done 1470f913ed5SDevin Teske __trimq=$(( $__trim / $__tbuf_len )) 1480f913ed5SDevin Teske __trim=$(( $__trim - $__tbuf_len * $__trimq )) 1490f913ed5SDevin Teske while [ $__trimq -gt 0 ]; do 1500cb8bea7SDevin Teske __tmp="${__tmp%$__tbuf}" 1510f913ed5SDevin Teske __trimq=$(( $__trimq - 1 )) 1520f913ed5SDevin Teske done 1530f913ed5SDevin Teske else 1540cb8bea7SDevin Teske __mask="$__tmp" 155*437455deSDevin Teske while [ $__tbuf_len -lt $(( 156*437455deSDevin Teske $__size / $__tbuf_len 157*437455deSDevin Teske )) ]; do 1580f913ed5SDevin Teske __tbuf="$__tbuf?" 1590f913ed5SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1600f913ed5SDevin Teske done 1610f913ed5SDevin Teske __trimq=$(( $__size / $__tbuf_len )) 162*437455deSDevin Teske if [ $__size -ne $(( 163*437455deSDevin Teske $__trimq * $__tbuf_len 164*437455deSDevin Teske )) ]; then 1650f913ed5SDevin Teske __tbuf="$__tbuf?" 1660f913ed5SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1670f913ed5SDevin Teske fi 168*437455deSDevin Teske __mask_len=$(( 169*437455deSDevin Teske $__tmp_size - $__tbuf_len * $__trimq 170*437455deSDevin Teske )) 171*437455deSDevin Teske __trim=$(( 172*437455deSDevin Teske $__tmp_size - $__mask_len - $__size 173*437455deSDevin Teske )) 1740f913ed5SDevin Teske while [ $__trimq -gt 0 ]; do 1750f913ed5SDevin Teske __mask="${__mask#$__tbuf}" 1760f913ed5SDevin Teske __trimq=$(( $__trimq - 1 )) 1770f913ed5SDevin Teske done 1780cb8bea7SDevin Teske __tmp="${__tmp%"$__mask"}" 1790f913ed5SDevin Teske fi 1800f913ed5SDevin Teske done 1810cb8bea7SDevin Teske 1829e81c4fbSDevin Teske if [ "$__var_to_set" ]; then 1830cb8bea7SDevin Teske setvar "$__var_to_set" "$__tmp" 1849e81c4fbSDevin Teske else 1859e81c4fbSDevin Teske echo "$__tmp" 1869e81c4fbSDevin Teske fi 1870cb8bea7SDevin Teske } 188*437455deSDevin Teskeesac 1890cb8bea7SDevin Teske 1900efb8b7aSDevin Teske# f_sprintf $var_to_set $format [$arguments ...] 1910efb8b7aSDevin Teske# 1920efb8b7aSDevin Teske# Similar to sprintf(3), write a string into $var_to_set using printf(1) syntax 1930efb8b7aSDevin Teske# (`$format [$arguments ...]'). 1940efb8b7aSDevin Teske# 1957883f920SDevin Teskecase "$BASH_VERSION" in 1967883f920SDevin Teske3.1*|4.*) 1977883f920SDevin Teske f_sprintf() 1987883f920SDevin Teske { 1997883f920SDevin Teske local __var_to_set="$1" __tmp 2007883f920SDevin Teske shift 1 # var_to_set 2017883f920SDevin Teske printf -v __tmp "$@" 2027883f920SDevin Teske eval "$__var_to_set"=\"\${__tmp%\$NL}\" 2037883f920SDevin Teske } 2047883f920SDevin Teske ;; 2057883f920SDevin Teske*) 2067883f920SDevin Teske # NB: On FreeBSD, sh(1) runs this faster than bash(1) runs the above 2070efb8b7aSDevin Teske f_sprintf() 2080efb8b7aSDevin Teske { 2090efb8b7aSDevin Teske local __var_to_set="$1" 2100efb8b7aSDevin Teske shift 1 # var_to_set 2117883f920SDevin Teske eval "$__var_to_set"=\$\( printf -- \"\$@\" \) 2120efb8b7aSDevin Teske } 2137883f920SDevin Teskeesac 2140efb8b7aSDevin Teske 215e4f08d49SDevin Teske# f_vsprintf $var_to_set $format $format_args 216e4f08d49SDevin Teske# 217e4f08d49SDevin Teske# Similar to vsprintf(3), write a string into $var_to_set using printf(1) 218e4f08d49SDevin Teske# syntax (`$format $format_args'). 219e4f08d49SDevin Teske# 220e4f08d49SDevin Teskef_vsprintf() 221e4f08d49SDevin Teske{ 222e4f08d49SDevin Teske eval f_sprintf \"\$1\" \"\$2\" $3 223e4f08d49SDevin Teske} 224e4f08d49SDevin Teske 2253c8cd13bSDevin Teske# f_snprintf $var_to_set $size $format [$arguments ...] 2263c8cd13bSDevin Teske# 2273c8cd13bSDevin Teske# Similar to snprintf(3), write at most $size number of bytes into $var_to_set 2283c8cd13bSDevin Teske# using printf(1) syntax (`$format [$arguments ...]'). 2293c8cd13bSDevin Teske# 2303c8cd13bSDevin Teskef_snprintf() 2313c8cd13bSDevin Teske{ 2323c8cd13bSDevin Teske local __var_to_set="$1" __size="$2" 2333c8cd13bSDevin Teske shift 2 # var_to_set size 2343c8cd13bSDevin Teske 2353c8cd13bSDevin Teske local __f_snprintf_tmp 2363c8cd13bSDevin Teske f_sprintf __f_snprintf_tmp "$@" 2373c8cd13bSDevin Teske f_substr "$__var_to_set" "$__f_snprintf_tmp" 1 "$__size" 2383c8cd13bSDevin Teske} 2393c8cd13bSDevin Teske 240dd5cc066SDevin Teske# f_vsnprintf $var_to_set $size $format $format_args 241dd5cc066SDevin Teske# 242dd5cc066SDevin Teske# Similar to vsnprintf(3), write at most $size number of bytes into $var_to_set 243dd5cc066SDevin Teske# using printf(1) syntax (`$format $format_args'). The value of $var_to_set is 244dd5cc066SDevin Teske# NULL unless at-least one byte is stored from the output. 245dd5cc066SDevin Teske# 246dd5cc066SDevin Teske# Example 1: 247dd5cc066SDevin Teske# 248dd5cc066SDevin Teske# limit=7 format="%s" 249dd5cc066SDevin Teske# format_args="'abc 123'" # 3-spaces between abc and 123 250dd5cc066SDevin Teske# f_vsnprintf foo $limit "$format" "$format_args" # foo=[abc 1] 251dd5cc066SDevin Teske# 252dd5cc066SDevin Teske# Example 2: 253dd5cc066SDevin Teske# 254dd5cc066SDevin Teske# limit=12 format="%s %s" 25533291485SDevin Teske# format_args=" 'doghouse' 'fox' " 256dd5cc066SDevin Teske# # even more spaces added to illustrate escape-method 257dd5cc066SDevin Teske# f_vsnprintf foo $limit "$format" "$format_args" # foo=[doghouse fox] 258dd5cc066SDevin Teske# 259dd5cc066SDevin Teske# Example 3: 260dd5cc066SDevin Teske# 261dd5cc066SDevin Teske# limit=13 format="%s %s" 262dd5cc066SDevin Teske# f_shell_escape arg1 'aaa"aaa' # arg1=[aaa"aaa] (no change) 263dd5cc066SDevin Teske# f_shell_escape arg2 "aaa'aaa" # arg2=[aaa'\''aaa] (escaped s-quote) 264dd5cc066SDevin Teske# format_args="'$arg1' '$arg2'" # use single-quotes to surround args 265dd5cc066SDevin Teske# f_vsnprintf foo $limit "$format" "$format_args" # foo=[aaa"aaa aaa'a] 266dd5cc066SDevin Teske# 267dd5cc066SDevin Teske# In all of the above examples, the call to f_vsnprintf() does not change. Only 268dd5cc066SDevin Teske# the contents of $limit, $format, and $format_args changes in each example. 269dd5cc066SDevin Teske# 270dd5cc066SDevin Teskef_vsnprintf() 271dd5cc066SDevin Teske{ 272dd5cc066SDevin Teske eval f_snprintf \"\$1\" \"\$2\" \"\$3\" $4 273dd5cc066SDevin Teske} 274dd5cc066SDevin Teske 275d3a0f918SDevin Teske# f_replaceall $string $find $replace [$var_to_set] 276d3a0f918SDevin Teske# 277f82ca17bSDevin Teske# Replace all occurrences of $find in $string with $replace. If $var_to_set is 278d3a0f918SDevin Teske# either missing or NULL, the variable name is produced on standard out for 279d3a0f918SDevin Teske# capturing in a sub-shell (which is less recommended due to performance 280d3a0f918SDevin Teske# degradation). 281d3a0f918SDevin Teske# 28233db33a7SDevin Teske# To replace newlines or a sequence containing the newline character, use $NL 28333db33a7SDevin Teske# as `\n' is not supported. 28433db33a7SDevin Teske# 285d3a0f918SDevin Teskef_replaceall() 286d3a0f918SDevin Teske{ 287d3a0f918SDevin Teske local __left="" __right="$1" 288d3a0f918SDevin Teske local __find="$2" __replace="$3" __var_to_set="$4" 289d3a0f918SDevin Teske while :; do 290d3a0f918SDevin Teske case "$__right" in *$__find*) 291d3a0f918SDevin Teske __left="$__left${__right%%$__find*}$__replace" 292d3a0f918SDevin Teske __right="${__right#*$__find}" 293d3a0f918SDevin Teske continue 294d3a0f918SDevin Teske esac 295d3a0f918SDevin Teske break 296d3a0f918SDevin Teske done 297d3a0f918SDevin Teske __left="$__left${__right#*$__find}" 298d3a0f918SDevin Teske if [ "$__var_to_set" ]; then 299d3a0f918SDevin Teske setvar "$__var_to_set" "$__left" 300d3a0f918SDevin Teske else 301d3a0f918SDevin Teske echo "$__left" 302d3a0f918SDevin Teske fi 303d3a0f918SDevin Teske} 304d3a0f918SDevin Teske 305d3a0f918SDevin Teske# f_str2varname $string [$var_to_set] 306d3a0f918SDevin Teske# 307d3a0f918SDevin Teske# Convert a string into a suitable value to be used as a variable name 308d3a0f918SDevin Teske# by converting unsuitable characters into the underscrore [_]. If $var_to_set 309d3a0f918SDevin Teske# is either missing or NULL, the variable name is produced on standard out for 310d3a0f918SDevin Teske# capturing in a sub-shell (which is less recommended due to performance 311d3a0f918SDevin Teske# degradation). 312d3a0f918SDevin Teske# 313d3a0f918SDevin Teskef_str2varname() 314d3a0f918SDevin Teske{ 315d3a0f918SDevin Teske local __string="$1" __var_to_set="$2" 316d3a0f918SDevin Teske f_replaceall "$__string" "[!$VALID_VARNAME_CHARS]" "_" "$__var_to_set" 317d3a0f918SDevin Teske} 318d3a0f918SDevin Teske 319d3a0f918SDevin Teske# f_shell_escape $string [$var_to_set] 320d3a0f918SDevin Teske# 321d3a0f918SDevin Teske# Escape $string for shell eval statement(s) by replacing all single-quotes 322d3a0f918SDevin Teske# with a special sequence that creates a compound string when interpolated 323d3a0f918SDevin Teske# by eval with surrounding single-quotes. 324d3a0f918SDevin Teske# 325d3a0f918SDevin Teske# For example: 326d3a0f918SDevin Teske# 327d3a0f918SDevin Teske# foo="abc'123" 328d3a0f918SDevin Teske# f_shell_escape "$foo" bar # bar=[abc'\''123] 32910908a6fSDevin Teske# eval echo \'$bar\' # produces abc'123 330d3a0f918SDevin Teske# 331d3a0f918SDevin Teske# This is helpful when processing an argument list that has to retain its 332d3a0f918SDevin Teske# escaped structure for later evaluations. 333d3a0f918SDevin Teske# 334d3a0f918SDevin Teske# WARNING: Surrounding single-quotes are not added; this is the responsibility 335d3a0f918SDevin Teske# of the code passing the escaped values to eval (which also aids readability). 336d3a0f918SDevin Teske# 337d3a0f918SDevin Teskef_shell_escape() 338d3a0f918SDevin Teske{ 339d3a0f918SDevin Teske local __string="$1" __var_to_set="$2" 340d3a0f918SDevin Teske f_replaceall "$__string" "'" "'\\''" "$__var_to_set" 341d3a0f918SDevin Teske} 342d3a0f918SDevin Teske 343d3a0f918SDevin Teske# f_shell_unescape $string [$var_to_set] 344d3a0f918SDevin Teske# 345d3a0f918SDevin Teske# The antithesis of f_shell_escape(), this function takes an escaped $string 346d3a0f918SDevin Teske# and expands it. 347d3a0f918SDevin Teske# 348d3a0f918SDevin Teske# For example: 349d3a0f918SDevin Teske# 350d3a0f918SDevin Teske# foo="abc'123" 351d3a0f918SDevin Teske# f_shell_escape "$foo" bar # bar=[abc'\''123] 352d3a0f918SDevin Teske# f_shell_unescape "$bar" # produces abc'123 353d3a0f918SDevin Teske# 354d3a0f918SDevin Teskef_shell_unescape() 355d3a0f918SDevin Teske{ 356d3a0f918SDevin Teske local __string="$1" __var_to_set="$2" 357d3a0f918SDevin Teske f_replaceall "$__string" "'\\''" "'" "$__var_to_set" 358d3a0f918SDevin Teske} 359d3a0f918SDevin Teske 360a96ea66fSDevin Teske# f_expand_number $string [$var_to_set] 361a96ea66fSDevin Teske# 362a96ea66fSDevin Teske# Unformat $string into a number, optionally to be stored in $var_to_set. This 363a96ea66fSDevin Teske# function follows the SI power of two convention. 364a96ea66fSDevin Teske# 365a96ea66fSDevin Teske# The prefixes are: 366a96ea66fSDevin Teske# 367a96ea66fSDevin Teske# Prefix Description Multiplier 368a96ea66fSDevin Teske# k kilo 1024 369a96ea66fSDevin Teske# M mega 1048576 370a96ea66fSDevin Teske# G giga 1073741824 371a96ea66fSDevin Teske# T tera 1099511627776 372a96ea66fSDevin Teske# P peta 1125899906842624 373a96ea66fSDevin Teske# E exa 1152921504606846976 374a96ea66fSDevin Teske# 375a96ea66fSDevin Teske# NOTE: Prefixes are case-insensitive. 376a96ea66fSDevin Teske# 3779acbeddcSDevin Teske# Upon successful completion, success status is returned; otherwise the number 3789acbeddcSDevin Teske# -1 is produced ($var_to_set set to -1 or if $var_to_set is NULL or missing) 3799acbeddcSDevin Teske# on standard output. In the case of failure, the error status will be one of: 380a96ea66fSDevin Teske# 3819acbeddcSDevin Teske# Status Reason 3829acbeddcSDevin Teske# 1 Given $string contains no digits 3839acbeddcSDevin Teske# 2 An unrecognized prefix was given 3849acbeddcSDevin Teske# 3 Result too large to calculate 385a96ea66fSDevin Teske# 386a96ea66fSDevin Teskef_expand_number() 387a96ea66fSDevin Teske{ 388a96ea66fSDevin Teske local __string="$1" __var_to_set="$2" 38905a0a04aSDevin Teske local __cp __num __bshift __maxinput 390a96ea66fSDevin Teske 39105a0a04aSDevin Teske # Remove any leading non-digits 392ae978c36SDevin Teske __string="${__string#${__string%%[0-9]*}}" 39305a0a04aSDevin Teske 39405a0a04aSDevin Teske # Store the numbers (no trailing suffix) 39505a0a04aSDevin Teske __num="${__string%%[!0-9]*}" 396a96ea66fSDevin Teske 3979acbeddcSDevin Teske # Produce `-1' if string didn't contain any digits 39805a0a04aSDevin Teske if [ ! "$__num" ]; then 399a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 400a96ea66fSDevin Teske setvar "$__var_to_set" -1 401a96ea66fSDevin Teske else 402a96ea66fSDevin Teske echo -1 403a96ea66fSDevin Teske fi 4049acbeddcSDevin Teske return 1 # 1 = "Given $string contains no digits" 405a96ea66fSDevin Teske fi 406a96ea66fSDevin Teske 407a96ea66fSDevin Teske # Remove all the leading numbers from the string to get at the prefix 40805a0a04aSDevin Teske __string="${__string#"$__num"}" 409a96ea66fSDevin Teske 4109acbeddcSDevin Teske # 4119acbeddcSDevin Teske # Test for invalid prefix (and determine bitshift length) 4129acbeddcSDevin Teske # 413a96ea66fSDevin Teske case "$__string" in 4149acbeddcSDevin Teske ""|[[:space:]]*) # Shortcut 4159acbeddcSDevin Teske if [ "$__var_to_set" ]; then 41605a0a04aSDevin Teske setvar "$__var_to_set" $__num 4179acbeddcSDevin Teske else 41805a0a04aSDevin Teske echo $__num 4199acbeddcSDevin Teske fi 4209acbeddcSDevin Teske return $SUCCESS ;; 4219acbeddcSDevin Teske [Kk]*) __bshift=10 ;; 4229acbeddcSDevin Teske [Mm]*) __bshift=20 ;; 4239acbeddcSDevin Teske [Gg]*) __bshift=30 ;; 4249acbeddcSDevin Teske [Tt]*) __bshift=40 ;; 4259acbeddcSDevin Teske [Pp]*) __bshift=50 ;; 4269acbeddcSDevin Teske [Ee]*) __bshift=60 ;; 427a96ea66fSDevin Teske *) 428a96ea66fSDevin Teske # Unknown prefix 429a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 430a96ea66fSDevin Teske setvar "$__var_to_set" -1 431a96ea66fSDevin Teske else 432a96ea66fSDevin Teske echo -1 433a96ea66fSDevin Teske fi 4349acbeddcSDevin Teske return 2 # 2 = "An unrecognized prefix was given" 435a96ea66fSDevin Teske esac 436a96ea66fSDevin Teske 4379acbeddcSDevin Teske # Determine if the wheels fall off 4389acbeddcSDevin Teske __maxinput=$(( 0x7fffffffffffffff >> $__bshift )) 43905a0a04aSDevin Teske if [ $__num -gt $__maxinput ]; then 4409acbeddcSDevin Teske # Input (before expanding) would exceed 64-bit signed int 441a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 442a96ea66fSDevin Teske setvar "$__var_to_set" -1 443a96ea66fSDevin Teske else 444a96ea66fSDevin Teske echo -1 445a96ea66fSDevin Teske fi 4469acbeddcSDevin Teske return 3 # 3 = "Result too large to calculate" 447a96ea66fSDevin Teske fi 448a96ea66fSDevin Teske 4499acbeddcSDevin Teske # Shift the number out and produce it 45005a0a04aSDevin Teske __num=$(( $__num << $__bshift )) 451a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 45205a0a04aSDevin Teske setvar "$__var_to_set" $__num 453a96ea66fSDevin Teske else 45405a0a04aSDevin Teske echo $__num 455a96ea66fSDevin Teske fi 456a96ea66fSDevin Teske} 457a96ea66fSDevin Teske 4580f9fec9dSDevin Teske# f_longest_line_length 4590f9fec9dSDevin Teske# 4600f9fec9dSDevin Teske# Simple wrapper to an awk(1) script to print the length of the longest line of 4610f9fec9dSDevin Teske# input (read from stdin). Supports the newline escape-sequence `\n' for 4620f9fec9dSDevin Teske# splitting a single line into multiple lines. 4630f9fec9dSDevin Teske# 4640f9fec9dSDevin Teskef_longest_line_length_awk=' 4650f9fec9dSDevin TeskeBEGIN { longest = 0 } 4660f9fec9dSDevin Teske{ 4670f9fec9dSDevin Teske if (split($0, lines, /\\n/) > 1) 4680f9fec9dSDevin Teske { 4690f9fec9dSDevin Teske for (n in lines) 4700f9fec9dSDevin Teske { 4710f9fec9dSDevin Teske len = length(lines[n]) 4720f9fec9dSDevin Teske longest = ( len > longest ? len : longest ) 4730f9fec9dSDevin Teske } 4740f9fec9dSDevin Teske } 4750f9fec9dSDevin Teske else 4760f9fec9dSDevin Teske { 4770f9fec9dSDevin Teske len = length($0) 4780f9fec9dSDevin Teske longest = ( len > longest ? len : longest ) 4790f9fec9dSDevin Teske } 4800f9fec9dSDevin Teske} 4810f9fec9dSDevin TeskeEND { print longest } 4820f9fec9dSDevin Teske' 4830f9fec9dSDevin Teskef_longest_line_length() 4840f9fec9dSDevin Teske{ 4850f9fec9dSDevin Teske awk "$f_longest_line_length_awk" 4860f9fec9dSDevin Teske} 4870f9fec9dSDevin Teske 4880f9fec9dSDevin Teske# f_number_of_lines 4890f9fec9dSDevin Teske# 4900f9fec9dSDevin Teske# Simple wrapper to an awk(1) script to print the number of lines read from 4910f9fec9dSDevin Teske# stdin. Supports newline escape-sequence `\n' for splitting a single line into 4920f9fec9dSDevin Teske# multiple lines. 4930f9fec9dSDevin Teske# 4940f9fec9dSDevin Teskef_number_of_lines_awk=' 4950f9fec9dSDevin TeskeBEGIN { num_lines = 0 } 4960f9fec9dSDevin Teske{ 4970f9fec9dSDevin Teske num_lines += split(" "$0, unused, /\\n/) 4980f9fec9dSDevin Teske} 4990f9fec9dSDevin TeskeEND { print num_lines } 5000f9fec9dSDevin Teske' 5010f9fec9dSDevin Teskef_number_of_lines() 5020f9fec9dSDevin Teske{ 5030f9fec9dSDevin Teske awk "$f_number_of_lines_awk" 5040f9fec9dSDevin Teske} 5050f9fec9dSDevin Teske 5060f9fec9dSDevin Teske# f_uriencode [$text] 5070f9fec9dSDevin Teske# 5080f9fec9dSDevin Teske# Encode $text for the purpose of embedding safely into a URL. Non-alphanumeric 5090f9fec9dSDevin Teske# characters are converted to `%XX' sequence where XX represents the hexa- 5100f9fec9dSDevin Teske# decimal ordinal of the non-alphanumeric character. If $text is missing, data 5110f9fec9dSDevin Teske# is instead read from standard input. 5120f9fec9dSDevin Teske# 5130f9fec9dSDevin Teskef_uriencode_awk=' 5140f9fec9dSDevin TeskeBEGIN { 5150f9fec9dSDevin Teske output = "" 5160f9fec9dSDevin Teske for (n = 0; n < 256; n++) pack[sprintf("%c", n)] = sprintf("%%%02x", n) 5170f9fec9dSDevin Teske} 5180f9fec9dSDevin Teske{ 5190f9fec9dSDevin Teske sline = "" 5200f9fec9dSDevin Teske slen = length($0) 5210f9fec9dSDevin Teske for (n = 1; n <= slen; n++) { 5220f9fec9dSDevin Teske char = substr($0, n, 1) 5230f9fec9dSDevin Teske if ( char !~ /^[[:alnum:]_]$/ ) char = pack[char] 5240f9fec9dSDevin Teske sline = sline char 5250f9fec9dSDevin Teske } 5260f9fec9dSDevin Teske output = output ( output ? "%0a" : "" ) sline 5270f9fec9dSDevin Teske} 5280f9fec9dSDevin TeskeEND { print output } 5290f9fec9dSDevin Teske' 5300f9fec9dSDevin Teskef_uriencode() 5310f9fec9dSDevin Teske{ 5320f9fec9dSDevin Teske if [ $# -gt 0 ]; then 5330f9fec9dSDevin Teske echo "$1" | awk "$f_uriencode_awk" 5340f9fec9dSDevin Teske else 5350f9fec9dSDevin Teske awk "$f_uriencode_awk" 5360f9fec9dSDevin Teske fi 5370f9fec9dSDevin Teske} 5380f9fec9dSDevin Teske 5390f9fec9dSDevin Teske# f_uridecode [$text] 5400f9fec9dSDevin Teske# 5410f9fec9dSDevin Teske# Decode $text from a URI. Encoded characters are converted from their `%XX' 5420f9fec9dSDevin Teske# sequence into original unencoded ASCII sequences. If $text is missing, data 5430f9fec9dSDevin Teske# is instead read from standard input. 5440f9fec9dSDevin Teske# 5450f9fec9dSDevin Teskef_uridecode_awk=' 5460f9fec9dSDevin TeskeBEGIN { for (n = 0; n < 256; n++) chr[n] = sprintf("%c", n) } 5470f9fec9dSDevin Teske{ 5480f9fec9dSDevin Teske sline = "" 5490f9fec9dSDevin Teske slen = length($0) 5500f9fec9dSDevin Teske for (n = 1; n <= slen; n++) 5510f9fec9dSDevin Teske { 5520f9fec9dSDevin Teske seq = substr($0, n, 3) 5530f9fec9dSDevin Teske if ( seq ~ /^%[[:xdigit:]][[:xdigit:]]$/ ) { 5540f9fec9dSDevin Teske hex = substr(seq, 2, 2) 5550f9fec9dSDevin Teske sline = sline chr[sprintf("%u", "0x"hex)] 5560f9fec9dSDevin Teske n += 2 5570f9fec9dSDevin Teske } else 5580f9fec9dSDevin Teske sline = sline substr(seq, 1, 1) 5590f9fec9dSDevin Teske } 5600f9fec9dSDevin Teske print sline 5610f9fec9dSDevin Teske} 5620f9fec9dSDevin Teske' 5630f9fec9dSDevin Teskef_uridecode() 5640f9fec9dSDevin Teske{ 5650f9fec9dSDevin Teske if [ $# -gt 0 ]; then 5660f9fec9dSDevin Teske echo "$1" | awk "$f_uridecode_awk" 5670f9fec9dSDevin Teske else 5680f9fec9dSDevin Teske awk "$f_uridecode_awk" 5690f9fec9dSDevin Teske fi 5700f9fec9dSDevin Teske} 5710f9fec9dSDevin Teske 572d3a0f918SDevin Teske############################################################ MAIN 573d3a0f918SDevin Teske 57456961fd7SDevin Teskef_dprintf "%s: Successfully loaded." strings.subr 57556961fd7SDevin Teske 576ab2043b8SDevin Teskefi # ! $_STRINGS_SUBR 577