1 |
On Sat, Jun 01, 2013 at 11:03:20PM -0400, Mike Frysinger wrote: |
2 |
> simple set of helpers to save/restore a variable in a limited section of code |
3 |
> |
4 |
> you can see an example of it in action at the end of the file where i need to |
5 |
> tweak epatch (and no, doing `LC_COLLATE=C set -- ....` does not work). |
6 |
> -mike |
7 |
> |
8 |
> --- eutils.eclass 22 May 2013 05:10:29 -0000 1.421 |
9 |
> +++ eutils.eclass 2 Jun 2013 03:00:46 -0000 |
10 |
> @@ -146,6 +146,77 @@ estack_pop() { |
11 |
> eval unset ${__estack_name}\[${__estack_i}\] |
12 |
> } |
13 |
Just in passing, one of the places you don't want nullglob messing things up. |
14 |
|
15 |
> +# @FUNCTION: evar_push |
16 |
> +# @USAGE: <variable to save> [more vars to save] |
17 |
> +# @DESCRIPTION: |
18 |
> +# This let's you temporarily modify a variable and then restore it (including |
19 |
> +# set vs unset semantics). Arrays are not supported at this time. |
20 |
> +# |
21 |
> +# For example: |
22 |
> +# @CODE |
23 |
> +# evar_push LC_ALL |
24 |
> +# export LC_ALL=C |
25 |
> +# ... do some stuff that needs LC_ALL=C set ... |
26 |
> +# evar_pop |
27 |
> +# |
28 |
> +# # You can also save/restore more than one var at a time |
29 |
> +# evar_push BUTTERFLY IN THE SKY |
30 |
> +# ... do stuff with the vars ... |
31 |
> +# evar_pop # This restores just one var, SKY |
32 |
> +# ... do more stuff ... |
33 |
> +# evar_pop 3 # This pops the remaining 3 vars |
34 |
> +# @CODE |
35 |
> +evar_push() { |
36 |
> + local var val |
37 |
> + for var ; do |
38 |
> + [[ ${!var+set} == "set" ]] \ |
39 |
> + && val=${!var} \ |
40 |
> + || val="${___ECLASS_ONCE_EUTILS}" |
41 |
> + estack_push evar "${var}" "${val}" |
42 |
> + done |
43 |
> +} |
44 |
> + |
45 |
> +# @FUNCTION: evar_push_set |
46 |
> +# @USAGE: <variable to save> [new value to store] |
47 |
> +# @DESCRIPTION: |
48 |
> +# This is a handy shortcut to save and temporarily set a variable. If a value |
49 |
> +# is not specified, the var will be unset. |
50 |
> +evar_push_set() { |
51 |
> + local var=$1 |
52 |
> + evar_push ${var} |
53 |
> + case $# in |
54 |
> + 1) unset ${var} ;; |
55 |
> + 2) eval ${var}=\$2 ;; |
56 |
|
57 |
I wish you wouldn't use eval for this. I know it's technically okay here, or would be |
58 |
if you verified the parameter, but bash has printf -v for this purpose: |
59 |
|
60 |
printf -v "$1" '%s' "$2" 2>/dev/null || die "unable to set: '$1' to: '$2'" |
61 |
|
62 |
Note you should verify the variable name, ime, irrespective of a die on the printf |
63 |
(or eval in sh.) It's much better feedback to the developer using the routine. |
64 |
Here's what we currently use in sh: |
65 |
# lib_key_ok "$input_name" |
66 |
# is the input name ok as a variable or key identifier |
67 |
lib_key_ok(){ |
68 |
case $1 in |
69 |
''|[![:alpha:]_]*|*[![:alnum:]_]*) return 1 |
70 |
;; *) return 0 |
71 |
esac |
72 |
} |
73 |
|
74 |
# lib_check_key foo bar.. |
75 |
# die if any param is not lib_key_ok |
76 |
lib_check_key() { |
77 |
local i |
78 |
for i; do |
79 |
lib_key_ok "$i" || die "bad key: '$i'" |
80 |
done |
81 |
} |
82 |
|
83 |
So I'd probably just use: lib_key_ok "$1" || die "$FUNCNAME: bad varname: '$1'" |
84 |
in this context, or amend the check_key function to use: |
85 |
.. || die "${FUNCNAME[1]}: bad key '$i'" |
86 |
- since you're working in bash by definition. |
87 |
|
88 |
printf -v also works with array members btw, if you do decide to extend in that |
89 |
direction: |
90 |
$ set -- 'foo[2]' 'array madness' |
91 |
$ printf -v "$1" %s "$2" |
92 |
$ echo "'${foo[2]}'" |
93 |
'array madness' |
94 |
|
95 |
And yeah, you can compose the variable name, eg: |
96 |
set -- foo 'array 1' 1 |
97 |
printf -v "$1${3:+[$3]}" %s "$2" |
98 |
echo "'${foo[1]}'" |
99 |
|
100 |
So long as the developer using the routines knows about quoting, that works fine. |
101 |
(If they don't, you have bigger problems.) |
102 |
|
103 |
> + *) die "${FUNCNAME}: incorrect # of args: $*" ;; |
104 |
> + esac |
105 |
> +} |
106 |
> + |
107 |
> +# @FUNCTION: evar_pop |
108 |
> +# @USAGE: [number of vars to restore] |
109 |
> +# @DESCRIPTION: |
110 |
> +# Restore the variables to the state saved with the corresponding |
111 |
> +# evar_push call. See that function for more details. |
112 |
> +evar_pop() { |
113 |
> + local cnt=$1 |
114 |
might as well use: cnt=${1:-bad} |
115 |
> + case $# in |
116 |
> + 0) cnt=1 ;; |
117 |
> + 1) |
118 |
and lose this line. |
119 |
> + : ${cnt:=bad} |
120 |
> + [[ -n ${cnt//[0-9]} ]] && die "${FUNCNAME}: first arg must be a number: $*" |
121 |
> + ;; |
122 |
Though a generic is_int function comes in much handier, ime. |
123 |
is_int() { |
124 |
[[ $1 && $1 != *[^0-9]* ]] |
125 |
} |
126 |
1) is_int "$1" || die .. |
127 |
cnt=$1 |
128 |
|
129 |
(I tend to guard against 0? as well, as octal inputs tend to mess things up later. I'm |
130 |
sure you can see the case for sh.) |
131 |
|
132 |
> + *) die "${FUNCNAME}: only accepts one arg: $*" ;; |
133 |
> + esac |
134 |
> + |
135 |
> + local var val |
136 |
> + while (( cnt-- )) ; do |
137 |
> + estack_pop evar val || die "${FUNCNAME}: unbalanced push" |
138 |
> + estack_pop evar var || die "${FUNCNAME}: unbalanced push" |
139 |
> + [[ ${val} == "${___ECLASS_ONCE_EUTILS}" ]] \ |
140 |
> + && unset ${var} \ |
141 |
> + || eval ${var}=\${val} |
142 |
|
143 |
again: printf -v "$var" %s "$val" |
144 |
Though I'd rather this were in an if, so you can test for error better: |
145 |
|
146 |
if [[ $val = "$___ECLASS_ONCE_EUTILS" ]]; then |
147 |
unset "$var" 2>/dev/null || die "unable to unset: '$var'" |
148 |
else printf -v "$var" %s "$val" 2>/dev/null \ |
149 |
|| die "unable to reset: '$var'" |
150 |
fi |
151 |
|
152 |
(Or you can use: fi 2>/dev/null || die "unable to pop: '$var'" |
153 |
if you prefer.) |
154 |
|
155 |
> + done |
156 |
> +} |
157 |
> + |
158 |
> # @FUNCTION: eshopts_push |
159 |
> # @USAGE: [options to `set` or `shopt`] |
160 |
> # @DESCRIPTION: |
161 |
> @@ -344,8 +415,11 @@ epatch() { |
162 |
> local EPATCH_SUFFIX=$1 |
163 |
> |
164 |
> elif [[ -d $1 ]] ; then |
165 |
> - # Some people like to make dirs of patches w/out suffixes (vim) |
166 |
> + # We have to force sorting to C so that the wildcard expansion is consistent #471666. |
167 |
> + evar_push_set LC_COLLATE C |
168 |
> + # Some people like to make dirs of patches w/out suffixes (vim). |
169 |
> set -- "$1"/*${EPATCH_SUFFIX:+."${EPATCH_SUFFIX}"} |
170 |
> + evar_pop |
171 |
|
172 |
Have to say I'd just do this in a function adding to a locally-scoped array, if it were me, |
173 |
eg local args; foo "$1" "$EPATCH_SUFFIX"; set -- "${args[@]}"; unset args |
174 |
foo() { |
175 |
local LC_COLLATE=C |
176 |
args=("$1"/*${2:+."$2"}) |
177 |
} |
178 |
though I'd prefer it if EPATCH_SUFFIX were allowed to be a list, personally. |
179 |
Something like this (untested) with foo "$1" $EPATCH_SUFFIX |
180 |
foo() { |
181 |
local LC_COLLATE=C |
182 |
set_nullglob |
183 |
case $# in |
184 |
0) fnusage |
185 |
;; 1) args=("$1"/*) |
186 |
;; 2) args=("$1"/*${2+".$2"}) |
187 |
;; *) local i n=0 d=$1 |
188 |
shift; args=() |
189 |
for i; do |
190 |
[[ $i ]] || { n=1; continue; } |
191 |
args+=("$d"/*."$i") |
192 |
done |
193 |
# if you want to allow for empty args from an ebuild to mean sth: |
194 |
((n && ! ${#args[*]})) && args=("$d"/*) |
195 |
esac |
196 |
reset_nullglob |
197 |
} |
198 |
(I'm not discounting dealing with the input variable to check for array etc, |
199 |
it's just not my concern here.) |
200 |
|
201 |
HTH, |
202 |
steveL. |
203 |
-- |
204 |
#friendly-coders -- We're friendly, but we're not /that/ friendly ;-) |