Added helper function __expand_tilde_by_ref()
Expands only tilde (~), if first char, in variable. This function displays bash's capabilities of passing a variable by reference (variable indirection) which allows us to avoid using a subshell. As far as I can see it works surprisingly well? To run the automated test: ./runUnit __expand_tilde_by_ref.exp Also fixed some testsuite issues regarding list splitting.
This commit is contained in:
parent
048e27bf28
commit
eb860b7b9f
@ -557,6 +557,46 @@ _available_interfaces()
|
|||||||
COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Expand variable starting with tilde (~)
|
||||||
|
# Only the first portion of the variable from the tilde up to the first slash
|
||||||
|
# (~../) is expanded. The remainder of the variable, containing for example
|
||||||
|
# a dollar sign variable ($) or asterisk (*) is not expanded.
|
||||||
|
# Example usage:
|
||||||
|
#
|
||||||
|
# $ v="~"; __expand_tilde v; echo "$v"
|
||||||
|
#
|
||||||
|
# Example output:
|
||||||
|
#
|
||||||
|
# v output
|
||||||
|
# -------- ----------------
|
||||||
|
# ~ /home/user
|
||||||
|
# ~foo/bar /home/foo/bar
|
||||||
|
# ~foo/$HOME /home/foo/$HOME
|
||||||
|
# ~foo/a b /home/foo/a b
|
||||||
|
# ~foo/* /home/foo/*
|
||||||
|
#
|
||||||
|
# @param $1 Name of variable (not the value of the variable) to expand
|
||||||
|
__expand_tilde_by_ref() {
|
||||||
|
# Does $1 start with tilde (~)?
|
||||||
|
if [ "${!1:0:1}" = "~" ]; then
|
||||||
|
# Does $1 contain slash (/)?
|
||||||
|
if [ "${!1}" != "${!1//\/}" ]; then
|
||||||
|
# Yes, $1 contains slash;
|
||||||
|
# 1: Remove * including and after first slash (/), i.e. "~a/b"
|
||||||
|
# becomes "~a". Double quotes allow eval.
|
||||||
|
# 2: Remove * before the first slash (/), i.e. "~a/b"
|
||||||
|
# becomes "b". Single quotes prevent eval.
|
||||||
|
# +-----1----+ +---2----+
|
||||||
|
eval $1="${!1/%\/*}"/'${!1#*/}'
|
||||||
|
else
|
||||||
|
# No, $1 doesn't contain slash
|
||||||
|
eval $1="${!1}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
} # __expand_tilde_by_ref()
|
||||||
|
|
||||||
|
|
||||||
# This function expands tildes in pathnames
|
# This function expands tildes in pathnames
|
||||||
#
|
#
|
||||||
_expand()
|
_expand()
|
||||||
@ -1270,8 +1310,8 @@ _known_hosts_real()
|
|||||||
for i in "${tmpkh[@]}"; do
|
for i in "${tmpkh[@]}"; do
|
||||||
# Remove possible quotes
|
# Remove possible quotes
|
||||||
i=${i//\"}
|
i=${i//\"}
|
||||||
# Eval/expand `~' or `~user', only if first char is tilde (~)
|
# Eval/expand possible `~' or `~user'
|
||||||
[ "${i:0:1}" = "~" ] && i=$( eval echo "$i" )
|
__expand_tilde_by_ref i
|
||||||
[ -r "$i" ] && kh=( "${kh[@]}" "$i" )
|
[ -r "$i" ] && kh=( "${kh[@]}" "$i" )
|
||||||
done
|
done
|
||||||
IFS=$OIFS
|
IFS=$OIFS
|
||||||
|
@ -458,6 +458,16 @@ proc get_signals {} {
|
|||||||
}; # get_signals()
|
}; # get_signals()
|
||||||
|
|
||||||
|
|
||||||
|
# Sort list.
|
||||||
|
# `exec sort' is used instead of `lsort' to achieve exactly the
|
||||||
|
# same sort order as in bash.
|
||||||
|
# @param list $items
|
||||||
|
# @return list Sort list
|
||||||
|
proc bash_sort {items} {
|
||||||
|
return [split [exec sort << [join $items "\n"]] "\n"]
|
||||||
|
}; # bash_sort()
|
||||||
|
|
||||||
|
|
||||||
# Expect items.
|
# Expect items.
|
||||||
# Break items into chunks because `expect' seems to have a limited buffer size
|
# Break items into chunks because `expect' seems to have a limited buffer size
|
||||||
# @param list $items
|
# @param list $items
|
||||||
@ -466,8 +476,8 @@ proc get_signals {} {
|
|||||||
proc match_items {items test {size 20}} {
|
proc match_items {items test {size 20}} {
|
||||||
# NOTE: `exec sort' is used instead of `lsort' to achieve exactly the
|
# NOTE: `exec sort' is used instead of `lsort' to achieve exactly the
|
||||||
# same sort order as in bash -- FVu, Wed Nov 25 22:25:28 CET 2009
|
# same sort order as in bash -- FVu, Wed Nov 25 22:25:28 CET 2009
|
||||||
#set items [list [exec sort << [join $items "\n"]]]
|
set items [bash_sort $items]
|
||||||
set items [exec sort << [join $items "\n"]]
|
#set items [exec sort << [join $items "\n"]]
|
||||||
set result false
|
set result false
|
||||||
for {set i 0} {$i < [llength $items]} {set i [expr {$i + $size}]} {
|
for {set i 0} {$i < [llength $items]} {set i [expr {$i + $size}]} {
|
||||||
set expected ""
|
set expected ""
|
||||||
|
87
test/unit/__expand_tilde_by_ref.exp
Normal file
87
test/unit/__expand_tilde_by_ref.exp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# @param string $out Reference to variable to hold value of bash environment
|
||||||
|
# variable $HOME.
|
||||||
|
proc setup {home user} {
|
||||||
|
upvar $home _home
|
||||||
|
upvar $user _user
|
||||||
|
save_env
|
||||||
|
assert_bash_exec {echo "$HOME"} {} /@ _home
|
||||||
|
set _home [string trim $_home]
|
||||||
|
assert_bash_exec {echo "$USER"} {} /@ _user
|
||||||
|
set _user [string trim $_user]
|
||||||
|
}; # setup()
|
||||||
|
|
||||||
|
|
||||||
|
proc teardown {} {
|
||||||
|
assert_env_unmodified {
|
||||||
|
/var=/d
|
||||||
|
}
|
||||||
|
}; # teardown()
|
||||||
|
|
||||||
|
|
||||||
|
setup home user
|
||||||
|
|
||||||
|
|
||||||
|
set test "function should run without errors"
|
||||||
|
assert_bash_exec {__expand_tilde_by_ref > /dev/null} $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
set test "function should not pollute environment"
|
||||||
|
# NOTE: A possible environment pollution is detected by assert_env_modified() in teardown()
|
||||||
|
assert_bash_exec {foo() { local aa="~"; __expand_tilde_by_ref aa; }; foo; unset foo} $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
set test "~user should return /home/user"
|
||||||
|
set cmd [format {var="~%s"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user]
|
||||||
|
assert_bash_list "$home" $cmd $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
set test "~/foo should return /home/user/foo"
|
||||||
|
set cmd {var='~/foo'; __expand_tilde_by_ref var; printf "%s" "$var"}
|
||||||
|
assert_bash_list "$home/foo" $cmd $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
set test "~user/bar should return /home/user/bar"
|
||||||
|
set cmd [format {var="~%s/bar"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user]
|
||||||
|
assert_bash_list "$home/bar" $cmd $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
set test "~user/\$HOME should return /home/user/\$HOME"
|
||||||
|
set cmd [format {var="~%s/\$HOME"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user]
|
||||||
|
assert_bash_list "$home/\$HOME" $cmd $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
set test "'~user/a b' should return '/home/user/a b'"
|
||||||
|
set cmd [format {var="~%s/a b"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user]
|
||||||
|
assert_bash_list [list [format {%s/a b} $home]] $cmd $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
set test "~user/* should return /home/user/*"
|
||||||
|
set cmd [format {var="~%s/*"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user]
|
||||||
|
assert_bash_list "$home/\*" $cmd $test
|
||||||
|
|
||||||
|
|
||||||
|
sync_after_int
|
||||||
|
|
||||||
|
|
||||||
|
teardown
|
@ -57,7 +57,7 @@ sync_after_int
|
|||||||
|
|
||||||
set test {a b\ c| should return b\ c}; # | = cursor position
|
set test {a b\ c| should return b\ c}; # | = cursor position
|
||||||
set cmd {COMP_WORDS=(a 'b\ c'); COMP_CWORD=1; COMP_LINE='a b\ c'; COMP_POINT=6; _get_cword}
|
set cmd {COMP_WORDS=(a 'b\ c'); COMP_CWORD=1; COMP_LINE='a b\ c'; COMP_POINT=6; _get_cword}
|
||||||
assert_bash_list {{"b\\ c"}} $cmd $test
|
assert_bash_list {"b\\ c"} $cmd $test
|
||||||
|
|
||||||
|
|
||||||
sync_after_int
|
sync_after_int
|
||||||
@ -65,7 +65,7 @@ sync_after_int
|
|||||||
|
|
||||||
set test {a b\| c should return b\ }; # | = cursor position
|
set test {a b\| c should return b\ }; # | = cursor position
|
||||||
set cmd {COMP_WORDS=(a 'b\ c'); COMP_CWORD=1; COMP_LINE='a b\ c'; COMP_POINT=4; _get_cword}
|
set cmd {COMP_WORDS=(a 'b\ c'); COMP_CWORD=1; COMP_LINE='a b\ c'; COMP_POINT=4; _get_cword}
|
||||||
assert_bash_list {{"b\\"}} $cmd $test
|
assert_bash_list {"b\\"} $cmd $test
|
||||||
|
|
||||||
|
|
||||||
sync_after_int
|
sync_after_int
|
||||||
@ -73,7 +73,7 @@ sync_after_int
|
|||||||
|
|
||||||
set test {a "b\| should return "b\ }; # | = cursor position
|
set test {a "b\| should return "b\ }; # | = cursor position
|
||||||
set cmd {COMP_WORDS=(a '"b\'); COMP_CWORD=1; COMP_LINE='a "b\'; COMP_POINT=5; _get_cword}
|
set cmd {COMP_WORDS=(a '"b\'); COMP_CWORD=1; COMP_LINE='a "b\'; COMP_POINT=5; _get_cword}
|
||||||
assert_bash_list {{"\"b\\"}} $cmd $test
|
assert_bash_list {"\"b\\"} $cmd $test
|
||||||
|
|
||||||
|
|
||||||
sync_after_int
|
sync_after_int
|
||||||
|
@ -53,9 +53,9 @@ lappend hosts gee hus two
|
|||||||
set hosts_config $hosts
|
set hosts_config $hosts
|
||||||
# Hosts `doo' and `ike' are defined in `./fixtures/_known_hosts_/spaced known_hosts'
|
# Hosts `doo' and `ike' are defined in `./fixtures/_known_hosts_/spaced known_hosts'
|
||||||
lappend hosts doo ike
|
lappend hosts doo ike
|
||||||
set hosts [join [lsort -ascii $hosts ] "\\s+"]
|
set hosts [join [bash_sort $hosts ] "\\s+"]
|
||||||
set hosts_orig [join [lsort -ascii $hosts_orig ] "\\s+"]
|
set hosts_orig [join [bash_sort $hosts_orig ] "\\s+"]
|
||||||
set hosts_config [join [lsort -ascii $hosts_config] "\\s+"]
|
set hosts_config [join [bash_sort $hosts_config] "\\s+"]
|
||||||
# Call _known_hosts
|
# Call _known_hosts
|
||||||
set cmd {unset COMPREPLY; _known_hosts_real -aF 'fixtures/_known_hosts_real/spaced conf' ''; echo_array COMPREPLY}
|
set cmd {unset COMPREPLY; _known_hosts_real -aF 'fixtures/_known_hosts_real/spaced conf' ''; echo_array COMPREPLY}
|
||||||
send "$cmd\r"
|
send "$cmd\r"
|
||||||
@ -77,7 +77,7 @@ set hosts [get_hosts]
|
|||||||
# Host `two' is defined in ./fixtures/_known_hosts_real/known_hosts2
|
# Host `two' is defined in ./fixtures/_known_hosts_real/known_hosts2
|
||||||
# Host `three' is defined in ./fixtures/_known_hosts_real/known_hosts3
|
# Host `three' is defined in ./fixtures/_known_hosts_real/known_hosts3
|
||||||
lappend hosts two three
|
lappend hosts two three
|
||||||
set hosts [join [lsort -ascii $hosts] "\\s+"]
|
set hosts [join [bash_sort $hosts] "\\s+"]
|
||||||
# Setup environment
|
# Setup environment
|
||||||
set cmd {OLDHOME=$HOME; HOME=$TESTDIR}
|
set cmd {OLDHOME=$HOME; HOME=$TESTDIR}
|
||||||
send "$cmd\r"
|
send "$cmd\r"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user