Deleted Added
full compact
strings.subr (247280) strings.subr (249751)
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#
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: head/usr.sbin/bsdconfig/share/strings.subr 247280 2013-02-25 19:55:32Z dteske $
27# $FreeBSD: head/usr.sbin/bsdconfig/share/strings.subr 249751 2013-04-22 05:52:06Z dteske $
28#
29############################################################ GLOBALS
28
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
29# f_substr "$string" $start [ $length ]
30#
31# Simple wrapper to awk(1)'s `substr' function.
32#
33f_substr()
34{
35 local string="$1" start="${2:-0}" len="${3:-0}"
36 echo "$string" | awk "{ print substr(\$0, $start, $len) }"
37}
38
39# f_longest_line_length
40#
41# Simple wrapper to an awk(1) script to print the length of the longest line of
42# input (read from stdin). Supports the newline escape-sequence `\n' for
43# splitting a single line into multiple lines.
44#
45f_longest_line_length_awk='
46BEGIN { longest = 0 }
47{
48 if (split($0, lines, /\\n/) > 1)
49 {
50 for (n in lines)
51 {
52 len = length(lines[n])
53 longest = ( len > longest ? len : longest )
54 }
55 }
56 else
57 {
58 len = length($0)
59 longest = ( len > longest ? len : longest )
60 }
61}
62END { print longest }
63'
64f_longest_line_length()
65{
66 awk "$f_longest_line_length_awk"
67}
68
69# f_number_of_lines
70#
71# Simple wrapper to an awk(1) script to print the number of lines read from
72# stdin. Supports newline escape-sequence `\n' for splitting a single line into
73# multiple lines.
74#
75f_number_of_lines_awk='
76BEGIN { num_lines = 0 }
77{
78 num_lines += split(" "$0, unused, /\\n/)
79}
80END { print num_lines }
81'
82f_number_of_lines()
83{
84 awk "$f_number_of_lines_awk"
85}
86
87# f_isinteger $arg
88#
89# Returns true if argument is a positive/negative whole integer.
90#
91f_isinteger()
92{
93 local arg="$1"
94
95 # Prevent division-by-zero
96 [ "$arg" = "0" ] && return $SUCCESS
97
98 # Attempt to perform arithmetic divison (an operation which will exit
99 # with error unless arg is a valid positive/negative whole integer).
100 #
101 ( : $((0/$arg)) ) > /dev/null 2>&1
102}
103
104# f_uriencode [$text]
105#
106# Encode $text for the purpose of embedding safely into a URL. Non-alphanumeric
107# characters are converted to `%XX' sequence where XX represents the hexa-
108# decimal ordinal of the non-alphanumeric character. If $text is missing, data
109# is instead read from standard input.
110#
111f_uriencode_awk='
112BEGIN {
113 output = ""
114 for (n = 0; n < 256; n++) pack[sprintf("%c", n)] = sprintf("%%%02x", n)
115}
116{
117 sline = ""
118 slen = length($0)
119 for (n = 1; n <= slen; n++) {
120 char = substr($0, n, 1)
121 if ( char !~ /^[[:alnum:]_]$/ ) char = pack[char]
122 sline = sline char
123 }
124 output = output ( output ? "%0a" : "" ) sline
125}
126END { print output }
127'
128f_uriencode()
129{
130 if [ $# -gt 0 ]; then
131 echo "$1" | awk "$f_uriencode_awk"
132 else
133 awk "$f_uriencode_awk"
134 fi
135}
136
137# f_uridecode [$text]
138#
139# Decode $text from a URI. Encoded characters are converted from their `%XX'
140# sequence into original unencoded ASCII sequences. If $text is missing, data
141# is instead read from standard input.
142#
143f_uridecode_awk='
144BEGIN { for (n = 0; n < 256; n++) chr[n] = sprintf("%c", n) }
145{
146 sline = ""
147 slen = length($0)
148 for (n = 1; n <= slen; n++)
149 {
150 seq = substr($0, n, 3)
151 if ( seq ~ /^%[[:xdigit:]][[:xdigit:]]$/ ) {
152 hex = substr(seq, 2, 2)
153 sline = sline chr[sprintf("%u", "0x"hex)]
154 n += 2
155 } else
156 sline = sline substr(seq, 1, 1)
157 }
158 print sline
159}
160'
161f_uridecode()
162{
163 if [ $# -gt 0 ]; then
164 echo "$1" | awk "$f_uridecode_awk"
165 else
166 awk "$f_uridecode_awk"
167 fi
168}
169
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
170f_dprintf "%s: Successfully loaded." strings.subr
171
172fi # ! $_STRINGS_SUBR
269f_dprintf "%s: Successfully loaded." strings.subr
270
271fi # ! $_STRINGS_SUBR