1if [ ! "$_STRINGS_SUBR" ]; then _STRINGS_SUBR=1 2# 3# Copyright (c) 2006-2013 Devin Teske 4# All Rights Reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27# $FreeBSD$ 28# 29############################################################ GLOBALS 30 31# 32# Valid characters that can appear in an sh(1) variable name 33# 34# Please note that the character ranges A-Z and a-z should be avoided because 35# these can include accent characters (which are not valid in a variable name). 36# For example, A-Z matches any character that sorts after A but before Z, 37# including A and Z. Although ASCII order would make more sense, that is not 38# how it works. 39# 40VALID_VARNAME_CHARS="0-9ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_" 41 42############################################################ FUNCTIONS 43 44# f_substr "$string" $start [ $length ] 45# 46# Simple wrapper to awk(1)'s `substr' function. 47# 48f_substr() 49{ 50 local string="$1" start="${2:-0}" len="${3:-0}" 51 echo "$string" | awk "{ print substr(\$0, $start, $len) }" 52} 53 54# f_longest_line_length 55# 56# Simple wrapper to an awk(1) script to print the length of the longest line of 57# input (read from stdin). Supports the newline escape-sequence `\n' for 58# splitting a single line into multiple lines. 59# 60f_longest_line_length_awk=' 61BEGIN { longest = 0 } 62{ 63 if (split($0, lines, /\\n/) > 1) 64 { 65 for (n in lines) 66 { 67 len = length(lines[n]) 68 longest = ( len > longest ? len : longest ) 69 } 70 } 71 else 72 { 73 len = length($0) 74 longest = ( len > longest ? len : longest ) 75 } 76} 77END { print longest } 78' 79f_longest_line_length() 80{ 81 awk "$f_longest_line_length_awk" 82} 83 84# f_number_of_lines 85# 86# Simple wrapper to an awk(1) script to print the number of lines read from 87# stdin. Supports newline escape-sequence `\n' for splitting a single line into 88# multiple lines. 89# 90f_number_of_lines_awk=' 91BEGIN { num_lines = 0 } 92{ 93 num_lines += split(" "$0, unused, /\\n/) 94} 95END { print num_lines } 96' 97f_number_of_lines() 98{ 99 awk "$f_number_of_lines_awk" 100} 101 102# f_isinteger $arg 103# 104# Returns true if argument is a positive/negative whole integer. 105# 106f_isinteger() 107{ 108 local arg="$1" 109 110 # Prevent division-by-zero 111 [ "$arg" = "0" ] && return $SUCCESS 112 113 # Attempt to perform arithmetic divison (an operation which will exit 114 # with error unless arg is a valid positive/negative whole integer). 115 # 116 ( : $((0/$arg)) ) > /dev/null 2>&1 117} 118 119# f_uriencode [$text] 120# 121# Encode $text for the purpose of embedding safely into a URL. Non-alphanumeric 122# characters are converted to `%XX' sequence where XX represents the hexa- 123# decimal ordinal of the non-alphanumeric character. If $text is missing, data 124# is instead read from standard input. 125# 126f_uriencode_awk=' 127BEGIN { 128 output = "" 129 for (n = 0; n < 256; n++) pack[sprintf("%c", n)] = sprintf("%%%02x", n) 130} 131{ 132 sline = "" 133 slen = length($0) 134 for (n = 1; n <= slen; n++) { 135 char = substr($0, n, 1) 136 if ( char !~ /^[[:alnum:]_]$/ ) char = pack[char] 137 sline = sline char 138 } 139 output = output ( output ? "%0a" : "" ) sline 140} 141END { print output } 142' 143f_uriencode() 144{ 145 if [ $# -gt 0 ]; then 146 echo "$1" | awk "$f_uriencode_awk" 147 else 148 awk "$f_uriencode_awk" 149 fi 150} 151 152# f_uridecode [$text] 153# 154# Decode $text from a URI. Encoded characters are converted from their `%XX' 155# sequence into original unencoded ASCII sequences. If $text is missing, data 156# is instead read from standard input. 157# 158f_uridecode_awk=' 159BEGIN { for (n = 0; n < 256; n++) chr[n] = sprintf("%c", n) } 160{ 161 sline = "" 162 slen = length($0) 163 for (n = 1; n <= slen; n++) 164 { 165 seq = substr($0, n, 3) 166 if ( seq ~ /^%[[:xdigit:]][[:xdigit:]]$/ ) { 167 hex = substr(seq, 2, 2) 168 sline = sline chr[sprintf("%u", "0x"hex)] 169 n += 2 170 } else 171 sline = sline substr(seq, 1, 1) 172 } 173 print sline 174} 175' 176f_uridecode() 177{ 178 if [ $# -gt 0 ]; then 179 echo "$1" | awk "$f_uridecode_awk" 180 else 181 awk "$f_uridecode_awk" 182 fi 183} 184 185# f_replaceall $string $find $replace [$var_to_set] 186# 187# Replace all occurrences of $find in $sting with $replace. If $var_to_set is 188# either missing or NULL, the variable name is produced on standard out for 189# capturing in a sub-shell (which is less recommended due to performance 190# degradation). 191# 192f_replaceall() 193{ 194 local __left="" __right="$1" 195 local __find="$2" __replace="$3" __var_to_set="$4" 196 while :; do 197 case "$__right" in *$__find*) 198 __left="$__left${__right%%$__find*}$__replace" 199 __right="${__right#*$__find}" 200 continue 201 esac 202 break 203 done 204 __left="$__left${__right#*$__find}" 205 if [ "$__var_to_set" ]; then 206 setvar "$__var_to_set" "$__left" 207 else 208 echo "$__left" 209 fi 210} 211 212# f_str2varname $string [$var_to_set] 213# 214# Convert a string into a suitable value to be used as a variable name 215# by converting unsuitable characters into the underscrore [_]. If $var_to_set 216# is either missing or NULL, the variable name is produced on standard out for 217# capturing in a sub-shell (which is less recommended due to performance 218# degradation). 219# 220f_str2varname() 221{ 222 local __string="$1" __var_to_set="$2" 223 f_replaceall "$__string" "[!$VALID_VARNAME_CHARS]" "_" "$__var_to_set" 224} 225 226# f_shell_escape $string [$var_to_set] 227# 228# Escape $string for shell eval statement(s) by replacing all single-quotes 229# with a special sequence that creates a compound string when interpolated 230# by eval with surrounding single-quotes. 231# 232# For example: 233# 234# foo="abc'123" 235# f_shell_escape "$foo" bar # bar=[abc'\''123] 236# eval echo \'$foo\' # produces abc'123 237# 238# This is helpful when processing an argument list that has to retain its 239# escaped structure for later evaluations. 240# 241# WARNING: Surrounding single-quotes are not added; this is the responsibility 242# of the code passing the escaped values to eval (which also aids readability). 243# 244f_shell_escape() 245{ 246 local __string="$1" __var_to_set="$2" 247 f_replaceall "$__string" "'" "'\\''" "$__var_to_set" 248} 249 250# f_shell_unescape $string [$var_to_set] 251# 252# The antithesis of f_shell_escape(), this function takes an escaped $string 253# and expands it. 254# 255# For example: 256# 257# foo="abc'123" 258# f_shell_escape "$foo" bar # bar=[abc'\''123] 259# f_shell_unescape "$bar" # produces abc'123 260# 261f_shell_unescape() 262{ 263 local __string="$1" __var_to_set="$2" 264 f_replaceall "$__string" "'\\''" "'" "$__var_to_set" 265} 266 267############################################################ MAIN 268 269f_dprintf "%s: Successfully loaded." strings.subr 270 271fi # ! $_STRINGS_SUBR 272