bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Passing variables by reference conflicts with local


From: Dennis Williamson
Subject: Re: Passing variables by reference conflicts with local
Date: Sun, 2 May 2010 08:11:03 -0500

I would discourage the use of "l" (ell) as a variable name for readability.

I like the fact that _blackbox_called_by uses a parameter rather than
parsing the caller's name. This allows you to permit multiple callers
to a common private function, if needed. However, I'm assuming that
you will name that function and _blackbox_safe_vars more generically
since I'm also assuming that there will be many public/private
function pairs that will be able to make use of them.

On Sun, May 2, 2010 at 6:35 AM, Freddy Vulto <fvulto@gmail.com> wrote:
> Here's another revised version.
>
> I figured I could use bash internal `printf -v' just before the `eval'
> to check if the variable name is a valid identifier.  This should be an
> exceptional case, so I don't mind doing this at the end of the function
> - checking just before the eval.  Now it's also easy to see the eval is
> safe (provided you don't make typos on the right hand side, see
> http://mywiki.wooledge.org/BashFAQ/006, thanks).
>
> I moved conflict checking to a central reusable function
> "_blackbox_safe_vars()" because one needs to do this for *every* library
> function which is returning variables by reference, in my opinion, unless
> you're willing to obfuscate all your local variables and still wait for a
> conflict to happen?
>
> The code below works around the following bash caveats?:
> - local variables conflict with variables to be returned by reference
> - `local' only lists variables having a value
> - `printf -v' can't be used to assign to an array
>
> Here's the code:
>
>    # Check whether variable name(s) conflicts with local(s)
>    # Params: $1  Local var names (output of 'local')
>    #         $*  Variables to check
>    # Return: False (1) if error
>    _blackbox_safe_vars() {
>        local IFS=$'\n' l v
>        for l in $1; do
>            for v in "${@:2}"; do
>                [[ ${l%=*} == $v ]] && echo "ERROR: ${FUNCNAME[1]}:"\
>                    "\`$v': conflicts with local" 1>&2 && return 1
>            done
>        done
>        return 0
>    }
>
>    # Check whether private function is being called by public interface
>    # Params: $1  Public function
>    # Return: False (1) if error
>    _blackbox_called_by() {
>        [[ ${FUNCNAME[2]} != $1 ]] && { echo "ERROR: ${FUNCNAME[1]}:"\
>            "MUST be called by $1()" 1>&2; return 1; } || return 0
>    }
>
>    # Private library function. Do not call directly. See blackbox()
>    _blackbox() {
>        _blackbox_called_by blackbox || return 1
>        local a b c d e f g h i j k=( foo "bar cee" )
>        # ...
>        # Lots of library code here, not more than one screen though ;-)
>        # ...
>        printf -v"$2" %s b                          # Return value
>        printf -v"$3" x && eval $3=\(\"\${k[@]}\"\) # Return array
>        return 0                                    # Return status
>    }
>
>    # Param: $1  input argument
>    # Param: $2  variable name to return value to
>    # Param: $3  variable name to return array value to
>    # Public library function
>    blackbox() {
>        # NOTE: Give all locals a value so they're listed with 'local'
>        local __2= __3= __x=
>        _blackbox_safe_vars "$(local)" "$2" "$3" || return 1
>        _blackbox "$1" __2 __3                        # Call private
>        __x=$?                                        # Catch status
>        printf -v"$2" %s "$__2"                       # Return value
>        printf -v"$3" x && eval $3=\(\"\${__3[@]}\"\) # Return array
>        return $__x                                   # Return status
>    }
>
>    blackbox i a b; printf $'%s\n' $a "${b[@]}"  # Outputs vars ok
>    blackbox i __2 __3                           # Outputs error
>    d='ls /;true'; blackbox i "$d" "$d"          # No oops
>    _blackbox a                                  # Force public access
>
>
> Freddy Vulto
> http://fvue.nl/wiki/Bash:_passing_variables_by_reference
>
>
>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]