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# 27ab2043b8SDevin Teske# $FreeBSD$ 28d3a0f918SDevin Teske# 29fcaed0c1SDevin Teske############################################################ INCLUDES 30fcaed0c1SDevin Teske 31fcaed0c1SDevin TeskeBSDCFG_SHARE="/usr/share/bsdconfig" 32fcaed0c1SDevin Teske. $BSDCFG_SHARE/common.subr || exit 1 33fcaed0c1SDevin Teske 34d3a0f918SDevin Teske############################################################ GLOBALS 35d3a0f918SDevin Teske 36d3a0f918SDevin Teske# 3705a0a04aSDevin Teske# A Literal newline (for use with f_replace_all(), or IFS, or whatever) 3805a0a04aSDevin Teske# 3905a0a04aSDevin TeskeNL=" 4005a0a04aSDevin Teske" # END-QUOTE 4105a0a04aSDevin Teske 4205a0a04aSDevin Teske# 43d3a0f918SDevin Teske# Valid characters that can appear in an sh(1) variable name 44d3a0f918SDevin Teske# 45d3a0f918SDevin Teske# Please note that the character ranges A-Z and a-z should be avoided because 46d3a0f918SDevin Teske# these can include accent characters (which are not valid in a variable name). 47d3a0f918SDevin Teske# For example, A-Z matches any character that sorts after A but before Z, 48d3a0f918SDevin Teske# including A and Z. Although ASCII order would make more sense, that is not 49d3a0f918SDevin Teske# how it works. 50d3a0f918SDevin Teske# 51d3a0f918SDevin TeskeVALID_VARNAME_CHARS="0-9ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_" 52d3a0f918SDevin Teske 53d3a0f918SDevin Teske############################################################ FUNCTIONS 54ab2043b8SDevin Teske 5592db3842SDevin Teske# f_isinteger $arg 5692db3842SDevin Teske# 5792db3842SDevin Teske# Returns true if argument is a positive/negative whole integer. 5892db3842SDevin Teske# 5992db3842SDevin Teskef_isinteger() 6092db3842SDevin Teske{ 6192db3842SDevin Teske local arg="${1#-}" 6292db3842SDevin Teske [ "${arg:-x}" = "${arg%[!0-9]*}" ] 6392db3842SDevin Teske} 6492db3842SDevin Teske 650cb8bea7SDevin Teske# f_substr [-v $var_to_set] $string $start [$length] 66ab2043b8SDevin Teske# 670cb8bea7SDevin Teske# Similar to awk(1)'s substr(), return length substring of string that begins 680cb8bea7SDevin Teske# at start position counted from 1. 69ab2043b8SDevin Teske# 70ab2043b8SDevin Teskef_substr() 71ab2043b8SDevin Teske{ 720cb8bea7SDevin Teske local OPTIND=1 OPTARG __flag __var_to_set= 730cb8bea7SDevin Teske while getopts v: __flag; do 740cb8bea7SDevin Teske case "$__flag" in 750cb8bea7SDevin Teske v) __var_to_set="$OPTARG" ;; 760cb8bea7SDevin Teske esac 770cb8bea7SDevin Teske done 780cb8bea7SDevin Teske shift $(( $OPTIND - 1 )) 79ab2043b8SDevin Teske 800cb8bea7SDevin Teske local __tmp="$1" __start="${2:-1}" __size="$3" 810cb8bea7SDevin Teske local __tbuf __tbuf_len __trim __trimq 820f913ed5SDevin Teske 830cb8bea7SDevin Teske if [ ! "$__tmp" ]; then 840cb8bea7SDevin Teske [ "$__var_to_set" ] && setvar "$__var_to_set" "" 850f913ed5SDevin Teske return ${SUCCESS:-0} 860cb8bea7SDevin Teske fi 870cb8bea7SDevin Teske [ "$__start" -ge 1 ] 2> /dev/null || __start=1 880cb8bea7SDevin Teske if ! [ "${__size:-1}" -ge 1 ] 2> /dev/null; then 890cb8bea7SDevin Teske [ "$__var_to_set" ] && setvar "$__var_to_set" "" 900f913ed5SDevin Teske return ${FAILURE:-1} 910f913ed5SDevin Teske fi 920f913ed5SDevin Teske 930cb8bea7SDevin Teske __trim=$(( $__start - 1 )) 940cb8bea7SDevin Teske while [ $__trim -gt 0 ]; do 950cb8bea7SDevin Teske __tbuf="?" 960cb8bea7SDevin Teske __tbuf_len=1 970cb8bea7SDevin Teske while [ $__tbuf_len -lt $(( $__trim / $__tbuf_len )) ]; do 980cb8bea7SDevin Teske __tbuf="$__tbuf?" 990cb8bea7SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1000cb8bea7SDevin Teske done 1010cb8bea7SDevin Teske __trimq=$(( $__trim / $__tbuf_len )) 1020cb8bea7SDevin Teske __trim=$(( $__trim - $__tbuf_len * $__trimq )) 1030cb8bea7SDevin Teske while [ $__trimq -gt 0 ]; do 1040cb8bea7SDevin Teske __tmp="${__tmp#$__tbuf}" 1050cb8bea7SDevin Teske __trimq=$(( $__trimq - 1 )) 1060cb8bea7SDevin Teske done 1070cb8bea7SDevin Teske done 1080f913ed5SDevin Teske 1090cb8bea7SDevin Teske local __tmp_size=${#__tmp} 1100f913ed5SDevin Teske local __mask __mask_len 1110cb8bea7SDevin Teske __trim=$(( $__tmp_size - ${__size:-$__tmp_size} )) 1120f913ed5SDevin Teske while [ $__trim -gt 0 ]; do 1130f913ed5SDevin Teske __tbuf="?" 1140f913ed5SDevin Teske __tbuf_len=1 1150f913ed5SDevin Teske if [ $__trim -le $__size ]; then 1160f913ed5SDevin Teske while [ $__tbuf_len -lt $(( $__trim / $__tbuf_len )) ] 1170f913ed5SDevin Teske do 1180f913ed5SDevin Teske __tbuf="$__tbuf?" 1190f913ed5SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1200f913ed5SDevin Teske done 1210f913ed5SDevin Teske __trimq=$(( $__trim / $__tbuf_len )) 1220f913ed5SDevin Teske __trim=$(( $__trim - $__tbuf_len * $__trimq )) 1230f913ed5SDevin Teske while [ $__trimq -gt 0 ]; do 1240cb8bea7SDevin Teske __tmp="${__tmp%$__tbuf}" 1250f913ed5SDevin Teske __trimq=$(( $__trimq - 1 )) 1260f913ed5SDevin Teske done 1270f913ed5SDevin Teske else 1280cb8bea7SDevin Teske __mask="$__tmp" 1290f913ed5SDevin Teske while [ $__tbuf_len -lt $(( $__size / $__tbuf_len )) ] 1300f913ed5SDevin Teske do 1310f913ed5SDevin Teske __tbuf="$__tbuf?" 1320f913ed5SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1330f913ed5SDevin Teske done 1340f913ed5SDevin Teske __trimq=$(( $__size / $__tbuf_len )) 1350f913ed5SDevin Teske if [ $(( $__trimq * $__tbuf_len )) -ne $__size ]; then 1360f913ed5SDevin Teske __tbuf="$__tbuf?" 1370f913ed5SDevin Teske __tbuf_len=$(( $__tbuf_len + 1 )) 1380f913ed5SDevin Teske fi 1390f913ed5SDevin Teske __mask_len=$(( $__tmp_size - $__tbuf_len * $__trimq )) 1400f913ed5SDevin Teske __trim=$(( $__tmp_size - $__mask_len - $__size )) 1410f913ed5SDevin Teske while [ $__trimq -gt 0 ]; do 1420f913ed5SDevin Teske __mask="${__mask#$__tbuf}" 1430f913ed5SDevin Teske __trimq=$(( $__trimq - 1 )) 1440f913ed5SDevin Teske done 1450cb8bea7SDevin Teske __tmp="${__tmp%"$__mask"}" 1460f913ed5SDevin Teske fi 1470f913ed5SDevin Teske done 1480cb8bea7SDevin Teske 1490cb8bea7SDevin Teske setvar "$__var_to_set" "$__tmp" 1500cb8bea7SDevin Teske} 1510cb8bea7SDevin Teske 1520efb8b7aSDevin Teske# f_sprintf $var_to_set $format [$arguments ...] 1530efb8b7aSDevin Teske# 1540efb8b7aSDevin Teske# Similar to sprintf(3), write a string into $var_to_set using printf(1) syntax 1550efb8b7aSDevin Teske# (`$format [$arguments ...]'). 1560efb8b7aSDevin Teske# 1570efb8b7aSDevin Teskef_sprintf() 1580efb8b7aSDevin Teske{ 1590efb8b7aSDevin Teske local __var_to_set="$1" 1600efb8b7aSDevin Teske shift 1 # var_to_set 161fcb16c10SDevin Teske 162fcb16c10SDevin Teske case "$BASH_VERSION" in 163fcb16c10SDevin Teske 3.1*|4.*) 164fcb16c10SDevin Teske local __tmp 165fcb16c10SDevin Teske printf -v __tmp "$@" 166fcb16c10SDevin Teske eval "$__var_to_set"=\"\${__tmp%\$NL}\" 167fcb16c10SDevin Teske ;; 168fcb16c10SDevin Teske *) eval "$__var_to_set"=\$\( printf -- \"\$@\" \) 169fcb16c10SDevin Teske esac 1700efb8b7aSDevin Teske} 1710efb8b7aSDevin Teske 172e4f08d49SDevin Teske# f_vsprintf $var_to_set $format $format_args 173e4f08d49SDevin Teske# 174e4f08d49SDevin Teske# Similar to vsprintf(3), write a string into $var_to_set using printf(1) 175e4f08d49SDevin Teske# syntax (`$format $format_args'). 176e4f08d49SDevin Teske# 177e4f08d49SDevin Teskef_vsprintf() 178e4f08d49SDevin Teske{ 179e4f08d49SDevin Teske eval f_sprintf \"\$1\" \"\$2\" $3 180e4f08d49SDevin Teske} 181e4f08d49SDevin Teske 1823c8cd13bSDevin Teske# f_snprintf $var_to_set $size $format [$arguments ...] 1833c8cd13bSDevin Teske# 1843c8cd13bSDevin Teske# Similar to snprintf(3), write at most $size number of bytes into $var_to_set 1853c8cd13bSDevin Teske# using printf(1) syntax (`$format [$arguments ...]'). 1863c8cd13bSDevin Teske# 1873c8cd13bSDevin Teskef_snprintf() 1883c8cd13bSDevin Teske{ 1893c8cd13bSDevin Teske local __var_to_set="$1" __size="$2" 1903c8cd13bSDevin Teske shift 2 # var_to_set size 1913c8cd13bSDevin Teske 1923c8cd13bSDevin Teske local __f_snprintf_tmp 1933c8cd13bSDevin Teske f_sprintf __f_snprintf_tmp "$@" 1943c8cd13bSDevin Teske f_substr "$__var_to_set" "$__f_snprintf_tmp" 1 "$__size" 1953c8cd13bSDevin Teske} 1963c8cd13bSDevin Teske 197dd5cc066SDevin Teske# f_vsnprintf $var_to_set $size $format $format_args 198dd5cc066SDevin Teske# 199dd5cc066SDevin Teske# Similar to vsnprintf(3), write at most $size number of bytes into $var_to_set 200dd5cc066SDevin Teske# using printf(1) syntax (`$format $format_args'). The value of $var_to_set is 201dd5cc066SDevin Teske# NULL unless at-least one byte is stored from the output. 202dd5cc066SDevin Teske# 203dd5cc066SDevin Teske# Example 1: 204dd5cc066SDevin Teske# 205dd5cc066SDevin Teske# limit=7 format="%s" 206dd5cc066SDevin Teske# format_args="'abc 123'" # 3-spaces between abc and 123 207dd5cc066SDevin Teske# f_vsnprintf foo $limit "$format" "$format_args" # foo=[abc 1] 208dd5cc066SDevin Teske# 209dd5cc066SDevin Teske# Example 2: 210dd5cc066SDevin Teske# 211dd5cc066SDevin Teske# limit=12 format="%s %s" 21233291485SDevin Teske# format_args=" 'doghouse' 'fox' " 213dd5cc066SDevin Teske# # even more spaces added to illustrate escape-method 214dd5cc066SDevin Teske# f_vsnprintf foo $limit "$format" "$format_args" # foo=[doghouse fox] 215dd5cc066SDevin Teske# 216dd5cc066SDevin Teske# Example 3: 217dd5cc066SDevin Teske# 218dd5cc066SDevin Teske# limit=13 format="%s %s" 219dd5cc066SDevin Teske# f_shell_escape arg1 'aaa"aaa' # arg1=[aaa"aaa] (no change) 220dd5cc066SDevin Teske# f_shell_escape arg2 "aaa'aaa" # arg2=[aaa'\''aaa] (escaped s-quote) 221dd5cc066SDevin Teske# format_args="'$arg1' '$arg2'" # use single-quotes to surround args 222dd5cc066SDevin Teske# f_vsnprintf foo $limit "$format" "$format_args" # foo=[aaa"aaa aaa'a] 223dd5cc066SDevin Teske# 224dd5cc066SDevin Teske# In all of the above examples, the call to f_vsnprintf() does not change. Only 225dd5cc066SDevin Teske# the contents of $limit, $format, and $format_args changes in each example. 226dd5cc066SDevin Teske# 227dd5cc066SDevin Teskef_vsnprintf() 228dd5cc066SDevin Teske{ 229dd5cc066SDevin Teske eval f_snprintf \"\$1\" \"\$2\" \"\$3\" $4 230dd5cc066SDevin Teske} 231dd5cc066SDevin Teske 232d3a0f918SDevin Teske# f_replaceall $string $find $replace [$var_to_set] 233d3a0f918SDevin Teske# 234f82ca17bSDevin Teske# Replace all occurrences of $find in $string with $replace. If $var_to_set is 235d3a0f918SDevin Teske# either missing or NULL, the variable name is produced on standard out for 236d3a0f918SDevin Teske# capturing in a sub-shell (which is less recommended due to performance 237d3a0f918SDevin Teske# degradation). 238d3a0f918SDevin Teske# 23933db33a7SDevin Teske# To replace newlines or a sequence containing the newline character, use $NL 24033db33a7SDevin Teske# as `\n' is not supported. 24133db33a7SDevin Teske# 242d3a0f918SDevin Teskef_replaceall() 243d3a0f918SDevin Teske{ 244d3a0f918SDevin Teske local __left="" __right="$1" 245d3a0f918SDevin Teske local __find="$2" __replace="$3" __var_to_set="$4" 246d3a0f918SDevin Teske while :; do 247d3a0f918SDevin Teske case "$__right" in *$__find*) 248d3a0f918SDevin Teske __left="$__left${__right%%$__find*}$__replace" 249d3a0f918SDevin Teske __right="${__right#*$__find}" 250d3a0f918SDevin Teske continue 251d3a0f918SDevin Teske esac 252d3a0f918SDevin Teske break 253d3a0f918SDevin Teske done 254d3a0f918SDevin Teske __left="$__left${__right#*$__find}" 255d3a0f918SDevin Teske if [ "$__var_to_set" ]; then 256d3a0f918SDevin Teske setvar "$__var_to_set" "$__left" 257d3a0f918SDevin Teske else 258d3a0f918SDevin Teske echo "$__left" 259d3a0f918SDevin Teske fi 260d3a0f918SDevin Teske} 261d3a0f918SDevin Teske 262d3a0f918SDevin Teske# f_str2varname $string [$var_to_set] 263d3a0f918SDevin Teske# 264d3a0f918SDevin Teske# Convert a string into a suitable value to be used as a variable name 265d3a0f918SDevin Teske# by converting unsuitable characters into the underscrore [_]. If $var_to_set 266d3a0f918SDevin Teske# is either missing or NULL, the variable name is produced on standard out for 267d3a0f918SDevin Teske# capturing in a sub-shell (which is less recommended due to performance 268d3a0f918SDevin Teske# degradation). 269d3a0f918SDevin Teske# 270d3a0f918SDevin Teskef_str2varname() 271d3a0f918SDevin Teske{ 272d3a0f918SDevin Teske local __string="$1" __var_to_set="$2" 273d3a0f918SDevin Teske f_replaceall "$__string" "[!$VALID_VARNAME_CHARS]" "_" "$__var_to_set" 274d3a0f918SDevin Teske} 275d3a0f918SDevin Teske 276d3a0f918SDevin Teske# f_shell_escape $string [$var_to_set] 277d3a0f918SDevin Teske# 278d3a0f918SDevin Teske# Escape $string for shell eval statement(s) by replacing all single-quotes 279d3a0f918SDevin Teske# with a special sequence that creates a compound string when interpolated 280d3a0f918SDevin Teske# by eval with surrounding single-quotes. 281d3a0f918SDevin Teske# 282d3a0f918SDevin Teske# For example: 283d3a0f918SDevin Teske# 284d3a0f918SDevin Teske# foo="abc'123" 285d3a0f918SDevin Teske# f_shell_escape "$foo" bar # bar=[abc'\''123] 28610908a6fSDevin Teske# eval echo \'$bar\' # produces abc'123 287d3a0f918SDevin Teske# 288d3a0f918SDevin Teske# This is helpful when processing an argument list that has to retain its 289d3a0f918SDevin Teske# escaped structure for later evaluations. 290d3a0f918SDevin Teske# 291d3a0f918SDevin Teske# WARNING: Surrounding single-quotes are not added; this is the responsibility 292d3a0f918SDevin Teske# of the code passing the escaped values to eval (which also aids readability). 293d3a0f918SDevin Teske# 294d3a0f918SDevin Teskef_shell_escape() 295d3a0f918SDevin Teske{ 296d3a0f918SDevin Teske local __string="$1" __var_to_set="$2" 297d3a0f918SDevin Teske f_replaceall "$__string" "'" "'\\''" "$__var_to_set" 298d3a0f918SDevin Teske} 299d3a0f918SDevin Teske 300d3a0f918SDevin Teske# f_shell_unescape $string [$var_to_set] 301d3a0f918SDevin Teske# 302d3a0f918SDevin Teske# The antithesis of f_shell_escape(), this function takes an escaped $string 303d3a0f918SDevin Teske# and expands it. 304d3a0f918SDevin Teske# 305d3a0f918SDevin Teske# For example: 306d3a0f918SDevin Teske# 307d3a0f918SDevin Teske# foo="abc'123" 308d3a0f918SDevin Teske# f_shell_escape "$foo" bar # bar=[abc'\''123] 309d3a0f918SDevin Teske# f_shell_unescape "$bar" # produces abc'123 310d3a0f918SDevin Teske# 311d3a0f918SDevin Teskef_shell_unescape() 312d3a0f918SDevin Teske{ 313d3a0f918SDevin Teske local __string="$1" __var_to_set="$2" 314d3a0f918SDevin Teske f_replaceall "$__string" "'\\''" "'" "$__var_to_set" 315d3a0f918SDevin Teske} 316d3a0f918SDevin Teske 317a96ea66fSDevin Teske# f_expand_number $string [$var_to_set] 318a96ea66fSDevin Teske# 319a96ea66fSDevin Teske# Unformat $string into a number, optionally to be stored in $var_to_set. This 320a96ea66fSDevin Teske# function follows the SI power of two convention. 321a96ea66fSDevin Teske# 322a96ea66fSDevin Teske# The prefixes are: 323a96ea66fSDevin Teske# 324a96ea66fSDevin Teske# Prefix Description Multiplier 325a96ea66fSDevin Teske# k kilo 1024 326a96ea66fSDevin Teske# M mega 1048576 327a96ea66fSDevin Teske# G giga 1073741824 328a96ea66fSDevin Teske# T tera 1099511627776 329a96ea66fSDevin Teske# P peta 1125899906842624 330a96ea66fSDevin Teske# E exa 1152921504606846976 331a96ea66fSDevin Teske# 332a96ea66fSDevin Teske# NOTE: Prefixes are case-insensitive. 333a96ea66fSDevin Teske# 3349acbeddcSDevin Teske# Upon successful completion, success status is returned; otherwise the number 3359acbeddcSDevin Teske# -1 is produced ($var_to_set set to -1 or if $var_to_set is NULL or missing) 3369acbeddcSDevin Teske# on standard output. In the case of failure, the error status will be one of: 337a96ea66fSDevin Teske# 3389acbeddcSDevin Teske# Status Reason 3399acbeddcSDevin Teske# 1 Given $string contains no digits 3409acbeddcSDevin Teske# 2 An unrecognized prefix was given 3419acbeddcSDevin Teske# 3 Result too large to calculate 342a96ea66fSDevin Teske# 343a96ea66fSDevin Teskef_expand_number() 344a96ea66fSDevin Teske{ 345a96ea66fSDevin Teske local __string="$1" __var_to_set="$2" 34605a0a04aSDevin Teske local __cp __num __bshift __maxinput 347a96ea66fSDevin Teske 34805a0a04aSDevin Teske # Remove any leading non-digits 349ae978c36SDevin Teske __string="${__string#${__string%%[0-9]*}}" 35005a0a04aSDevin Teske 35105a0a04aSDevin Teske # Store the numbers (no trailing suffix) 35205a0a04aSDevin Teske __num="${__string%%[!0-9]*}" 353a96ea66fSDevin Teske 3549acbeddcSDevin Teske # Produce `-1' if string didn't contain any digits 35505a0a04aSDevin Teske if [ ! "$__num" ]; then 356a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 357a96ea66fSDevin Teske setvar "$__var_to_set" -1 358a96ea66fSDevin Teske else 359a96ea66fSDevin Teske echo -1 360a96ea66fSDevin Teske fi 3619acbeddcSDevin Teske return 1 # 1 = "Given $string contains no digits" 362a96ea66fSDevin Teske fi 363a96ea66fSDevin Teske 364a96ea66fSDevin Teske # Remove all the leading numbers from the string to get at the prefix 36505a0a04aSDevin Teske __string="${__string#"$__num"}" 366a96ea66fSDevin Teske 3679acbeddcSDevin Teske # 3689acbeddcSDevin Teske # Test for invalid prefix (and determine bitshift length) 3699acbeddcSDevin Teske # 370a96ea66fSDevin Teske case "$__string" in 3719acbeddcSDevin Teske ""|[[:space:]]*) # Shortcut 3729acbeddcSDevin Teske if [ "$__var_to_set" ]; then 37305a0a04aSDevin Teske setvar "$__var_to_set" $__num 3749acbeddcSDevin Teske else 37505a0a04aSDevin Teske echo $__num 3769acbeddcSDevin Teske fi 3779acbeddcSDevin Teske return $SUCCESS ;; 3789acbeddcSDevin Teske [Kk]*) __bshift=10 ;; 3799acbeddcSDevin Teske [Mm]*) __bshift=20 ;; 3809acbeddcSDevin Teske [Gg]*) __bshift=30 ;; 3819acbeddcSDevin Teske [Tt]*) __bshift=40 ;; 3829acbeddcSDevin Teske [Pp]*) __bshift=50 ;; 3839acbeddcSDevin Teske [Ee]*) __bshift=60 ;; 384a96ea66fSDevin Teske *) 385a96ea66fSDevin Teske # Unknown prefix 386a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 387a96ea66fSDevin Teske setvar "$__var_to_set" -1 388a96ea66fSDevin Teske else 389a96ea66fSDevin Teske echo -1 390a96ea66fSDevin Teske fi 3919acbeddcSDevin Teske return 2 # 2 = "An unrecognized prefix was given" 392a96ea66fSDevin Teske esac 393a96ea66fSDevin Teske 3949acbeddcSDevin Teske # Determine if the wheels fall off 3959acbeddcSDevin Teske __maxinput=$(( 0x7fffffffffffffff >> $__bshift )) 39605a0a04aSDevin Teske if [ $__num -gt $__maxinput ]; then 3979acbeddcSDevin Teske # Input (before expanding) would exceed 64-bit signed int 398a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 399a96ea66fSDevin Teske setvar "$__var_to_set" -1 400a96ea66fSDevin Teske else 401a96ea66fSDevin Teske echo -1 402a96ea66fSDevin Teske fi 4039acbeddcSDevin Teske return 3 # 3 = "Result too large to calculate" 404a96ea66fSDevin Teske fi 405a96ea66fSDevin Teske 4069acbeddcSDevin Teske # Shift the number out and produce it 40705a0a04aSDevin Teske __num=$(( $__num << $__bshift )) 408a96ea66fSDevin Teske if [ "$__var_to_set" ]; then 40905a0a04aSDevin Teske setvar "$__var_to_set" $__num 410a96ea66fSDevin Teske else 41105a0a04aSDevin Teske echo $__num 412a96ea66fSDevin Teske fi 413a96ea66fSDevin Teske} 414a96ea66fSDevin Teske 415*0f9fec9dSDevin Teske# f_longest_line_length 416*0f9fec9dSDevin Teske# 417*0f9fec9dSDevin Teske# Simple wrapper to an awk(1) script to print the length of the longest line of 418*0f9fec9dSDevin Teske# input (read from stdin). Supports the newline escape-sequence `\n' for 419*0f9fec9dSDevin Teske# splitting a single line into multiple lines. 420*0f9fec9dSDevin Teske# 421*0f9fec9dSDevin Teskef_longest_line_length_awk=' 422*0f9fec9dSDevin TeskeBEGIN { longest = 0 } 423*0f9fec9dSDevin Teske{ 424*0f9fec9dSDevin Teske if (split($0, lines, /\\n/) > 1) 425*0f9fec9dSDevin Teske { 426*0f9fec9dSDevin Teske for (n in lines) 427*0f9fec9dSDevin Teske { 428*0f9fec9dSDevin Teske len = length(lines[n]) 429*0f9fec9dSDevin Teske longest = ( len > longest ? len : longest ) 430*0f9fec9dSDevin Teske } 431*0f9fec9dSDevin Teske } 432*0f9fec9dSDevin Teske else 433*0f9fec9dSDevin Teske { 434*0f9fec9dSDevin Teske len = length($0) 435*0f9fec9dSDevin Teske longest = ( len > longest ? len : longest ) 436*0f9fec9dSDevin Teske } 437*0f9fec9dSDevin Teske} 438*0f9fec9dSDevin TeskeEND { print longest } 439*0f9fec9dSDevin Teske' 440*0f9fec9dSDevin Teskef_longest_line_length() 441*0f9fec9dSDevin Teske{ 442*0f9fec9dSDevin Teske awk "$f_longest_line_length_awk" 443*0f9fec9dSDevin Teske} 444*0f9fec9dSDevin Teske 445*0f9fec9dSDevin Teske# f_number_of_lines 446*0f9fec9dSDevin Teske# 447*0f9fec9dSDevin Teske# Simple wrapper to an awk(1) script to print the number of lines read from 448*0f9fec9dSDevin Teske# stdin. Supports newline escape-sequence `\n' for splitting a single line into 449*0f9fec9dSDevin Teske# multiple lines. 450*0f9fec9dSDevin Teske# 451*0f9fec9dSDevin Teskef_number_of_lines_awk=' 452*0f9fec9dSDevin TeskeBEGIN { num_lines = 0 } 453*0f9fec9dSDevin Teske{ 454*0f9fec9dSDevin Teske num_lines += split(" "$0, unused, /\\n/) 455*0f9fec9dSDevin Teske} 456*0f9fec9dSDevin TeskeEND { print num_lines } 457*0f9fec9dSDevin Teske' 458*0f9fec9dSDevin Teskef_number_of_lines() 459*0f9fec9dSDevin Teske{ 460*0f9fec9dSDevin Teske awk "$f_number_of_lines_awk" 461*0f9fec9dSDevin Teske} 462*0f9fec9dSDevin Teske 463*0f9fec9dSDevin Teske# f_uriencode [$text] 464*0f9fec9dSDevin Teske# 465*0f9fec9dSDevin Teske# Encode $text for the purpose of embedding safely into a URL. Non-alphanumeric 466*0f9fec9dSDevin Teske# characters are converted to `%XX' sequence where XX represents the hexa- 467*0f9fec9dSDevin Teske# decimal ordinal of the non-alphanumeric character. If $text is missing, data 468*0f9fec9dSDevin Teske# is instead read from standard input. 469*0f9fec9dSDevin Teske# 470*0f9fec9dSDevin Teskef_uriencode_awk=' 471*0f9fec9dSDevin TeskeBEGIN { 472*0f9fec9dSDevin Teske output = "" 473*0f9fec9dSDevin Teske for (n = 0; n < 256; n++) pack[sprintf("%c", n)] = sprintf("%%%02x", n) 474*0f9fec9dSDevin Teske} 475*0f9fec9dSDevin Teske{ 476*0f9fec9dSDevin Teske sline = "" 477*0f9fec9dSDevin Teske slen = length($0) 478*0f9fec9dSDevin Teske for (n = 1; n <= slen; n++) { 479*0f9fec9dSDevin Teske char = substr($0, n, 1) 480*0f9fec9dSDevin Teske if ( char !~ /^[[:alnum:]_]$/ ) char = pack[char] 481*0f9fec9dSDevin Teske sline = sline char 482*0f9fec9dSDevin Teske } 483*0f9fec9dSDevin Teske output = output ( output ? "%0a" : "" ) sline 484*0f9fec9dSDevin Teske} 485*0f9fec9dSDevin TeskeEND { print output } 486*0f9fec9dSDevin Teske' 487*0f9fec9dSDevin Teskef_uriencode() 488*0f9fec9dSDevin Teske{ 489*0f9fec9dSDevin Teske if [ $# -gt 0 ]; then 490*0f9fec9dSDevin Teske echo "$1" | awk "$f_uriencode_awk" 491*0f9fec9dSDevin Teske else 492*0f9fec9dSDevin Teske awk "$f_uriencode_awk" 493*0f9fec9dSDevin Teske fi 494*0f9fec9dSDevin Teske} 495*0f9fec9dSDevin Teske 496*0f9fec9dSDevin Teske# f_uridecode [$text] 497*0f9fec9dSDevin Teske# 498*0f9fec9dSDevin Teske# Decode $text from a URI. Encoded characters are converted from their `%XX' 499*0f9fec9dSDevin Teske# sequence into original unencoded ASCII sequences. If $text is missing, data 500*0f9fec9dSDevin Teske# is instead read from standard input. 501*0f9fec9dSDevin Teske# 502*0f9fec9dSDevin Teskef_uridecode_awk=' 503*0f9fec9dSDevin TeskeBEGIN { for (n = 0; n < 256; n++) chr[n] = sprintf("%c", n) } 504*0f9fec9dSDevin Teske{ 505*0f9fec9dSDevin Teske sline = "" 506*0f9fec9dSDevin Teske slen = length($0) 507*0f9fec9dSDevin Teske for (n = 1; n <= slen; n++) 508*0f9fec9dSDevin Teske { 509*0f9fec9dSDevin Teske seq = substr($0, n, 3) 510*0f9fec9dSDevin Teske if ( seq ~ /^%[[:xdigit:]][[:xdigit:]]$/ ) { 511*0f9fec9dSDevin Teske hex = substr(seq, 2, 2) 512*0f9fec9dSDevin Teske sline = sline chr[sprintf("%u", "0x"hex)] 513*0f9fec9dSDevin Teske n += 2 514*0f9fec9dSDevin Teske } else 515*0f9fec9dSDevin Teske sline = sline substr(seq, 1, 1) 516*0f9fec9dSDevin Teske } 517*0f9fec9dSDevin Teske print sline 518*0f9fec9dSDevin Teske} 519*0f9fec9dSDevin Teske' 520*0f9fec9dSDevin Teskef_uridecode() 521*0f9fec9dSDevin Teske{ 522*0f9fec9dSDevin Teske if [ $# -gt 0 ]; then 523*0f9fec9dSDevin Teske echo "$1" | awk "$f_uridecode_awk" 524*0f9fec9dSDevin Teske else 525*0f9fec9dSDevin Teske awk "$f_uridecode_awk" 526*0f9fec9dSDevin Teske fi 527*0f9fec9dSDevin Teske} 528*0f9fec9dSDevin Teske 529d3a0f918SDevin Teske############################################################ MAIN 530d3a0f918SDevin Teske 53156961fd7SDevin Teskef_dprintf "%s: Successfully loaded." strings.subr 53256961fd7SDevin Teske 533ab2043b8SDevin Teskefi # ! $_STRINGS_SUBR 534