new "@k" parameter transformation; minor completion fix for uncommon case

This commit is contained in:
Chet Ramey
2021-08-23 15:54:49 -04:00
parent 2adf06d9f8
commit ea32b611f7
19 changed files with 221 additions and 9 deletions
+29
View File
@@ -1746,4 +1746,33 @@ bashline.c
- orig_rl_completer_word_break_characters: now const char * like
rl_completer_word_break_characters
8/20
----
bashline.c
- bash_directory_completion_hook: if direxpand and dirspell are both
set while trying to complete an absolute pathname as a command, don't
take a spell-corrected directory name that is shorter than the
original hint. https://bugzilla.redhat.com/show_bug.cgi?id=1782809
builtins/common.[ch]
- sh_noassign: convenience function to print an error message when a
user attempts an assignment to a "noassign" variable. Not used yet
assoc.[ch]
- assoc_to_kvpair_list: new function, returns a WORD_LIST containing
key-value pairs as separate words
array.[ch]
- array_to_kvpair_list: new function, returns a WORD_LIST containing
index-value pairs as separate words
subst.c
- string_transform: handle '@k' transform like '@K'
- valid_parameter_transform: 'k' is a valid transform operator
- array_transform: handle '@k' transformation by calling one of
array_to_kvpair_list or assoc_to_kvpair_list and treating the
result as if expanding the array depending on whether the index is
`@' or `*' with the usual meanings
doc/{bash.1,bashref.texi}
- document new '@k' parameter transformation operator
+1
View File
@@ -949,6 +949,7 @@ tests/assoc10.sub f
tests/assoc11.sub f
tests/assoc12.sub f
tests/assoc13.sub f
tests/assoc14.sub f
tests/attr.tests f
tests/attr.right f
tests/attr1.sub f
+21
View File
@@ -793,6 +793,27 @@ ARRAY *a;
return (REVERSE_LIST(list, WORD_LIST *));
}
WORD_LIST *
array_to_kvpair_list(a)
ARRAY *a;
{
WORD_LIST *list;
ARRAY_ELEMENT *ae;
char *k, *v;
if (a == 0 || array_empty(a))
return((WORD_LIST *)NULL);
list = (WORD_LIST *)NULL;
for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
k = itos(element_index(ae));
v = element_value(ae);
list = make_word_list (make_bare_word(k), list);
list = make_word_list (make_bare_word(v), list);
free(k);
}
return (REVERSE_LIST(list, WORD_LIST *));
}
ARRAY *
array_assign_list (array, list)
ARRAY *array;
+1
View File
@@ -80,6 +80,7 @@ extern char *array_reference PARAMS((ARRAY *, arrayind_t));
extern WORD_LIST *array_to_word_list PARAMS((ARRAY *));
extern ARRAY *array_from_word_list PARAMS((WORD_LIST *));
extern WORD_LIST *array_keys_to_word_list PARAMS((ARRAY *));
extern WORD_LIST *array_to_kvpair_list PARAMS((ARRAY *));
extern ARRAY *array_assign_list PARAMS((ARRAY *, WORD_LIST *));
+25 -1
View File
@@ -7,7 +7,7 @@
* chet@ins.cwru.edu
*/
/* Copyright (C) 2008,2009,2011-2020 Free Software Foundation, Inc.
/* Copyright (C) 2008,2009,2011-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -544,6 +544,30 @@ assoc_keys_to_word_list (h)
return (assoc_to_word_list_internal (h, 1));
}
WORD_LIST *
assoc_to_kvpair_list (h)
HASH_TABLE *h;
{
WORD_LIST *list;
int i;
BUCKET_CONTENTS *tlist;
char *k, *v;
if (h == 0 || assoc_empty (h))
return((WORD_LIST *)NULL);
list = (WORD_LIST *)NULL;
for (i = 0; i < h->nbuckets; i++)
for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
{
k = (char *)tlist->key;
v = (char *)tlist->data;
list = make_word_list (make_bare_word (k), list);
list = make_word_list (make_bare_word (v), list);
}
return (REVERSE_LIST(list, WORD_LIST *));
}
char *
assoc_to_string (h, sep, quoted)
HASH_TABLE *h;
+1
View File
@@ -60,6 +60,7 @@ extern char *assoc_to_assign PARAMS((HASH_TABLE *, int));
extern WORD_LIST *assoc_to_word_list PARAMS((HASH_TABLE *));
extern WORD_LIST *assoc_keys_to_word_list PARAMS((HASH_TABLE *));
extern WORD_LIST *assoc_to_kvpair_list PARAMS((HASH_TABLE *));
extern char *assoc_to_string PARAMS((HASH_TABLE *, char *, int));
#endif /* _ASSOC_H_ */
+9
View File
@@ -3580,7 +3580,16 @@ bash_directory_completion_hook (dirname)
subsequent directory checks don't fail. */
if (temp2 == 0 && dircomplete_spelling && dircomplete_expand)
{
size_t l1, l2;
temp2 = dirspell (temp1);
l2 = STRLEN (temp2);
/* Don't take matches if they are shorter than the original path */
if (temp2 && l2 < strlen (temp1) && STREQN (temp1, temp2, l2))
{
free (temp2);
temp2 = 0;
}
if (temp2)
{
free (temp1);
+7
View File
@@ -266,6 +266,13 @@ sh_readonly (s)
builtin_error (_("%s: readonly variable"), s);
}
void
sh_noassign (s)
const char *s;
{
internal_error (_("%s: cannot assign"), s); /* XXX */
}
void
sh_erange (s, desc)
char *s, *desc;
+2 -1
View File
@@ -95,10 +95,11 @@ extern void sh_invalidoptname PARAMS((char *));
extern void sh_invalidid PARAMS((char *));
extern void sh_invalidnum PARAMS((char *));
extern void sh_invalidsig PARAMS((char *));
extern void sh_readonly PARAMS((const char *));
extern void sh_noassign PARAMS((const char *));
extern void sh_erange PARAMS((char *, char *));
extern void sh_badpid PARAMS((char *));
extern void sh_badjob PARAMS((char *));
extern void sh_readonly PARAMS((const char *));
extern void sh_nojobs PARAMS((char *));
extern void sh_restricted PARAMS((char *));
extern void sh_notbuiltin PARAMS((char *));
+6 -2
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
.\" Last Change: Tue Aug 10 11:06:20 EDT 2021
.\" Last Change: Mon Aug 23 10:08:28 EDT 2021
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2021 August 10" "GNU Bash 5.1"
.TH BASH 1 "2021 August 23" "GNU Bash 5.1"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -3461,6 +3461,10 @@ indexed and associative arrays as a sequence of quoted key-value pairs
.B a
The expansion is a string consisting of flag values representing
\fIparameter\fP's attributes.
.TP
.B k
Like the K transformation, but expands the keys and values of
indexed and associative arrays to separate words after word splitting.
.PD
.PP
If
+3
View File
@@ -2478,6 +2478,9 @@ indexed and associative arrays as a sequence of quoted key-value pairs
@item a
The expansion is a string consisting of flag values representing
@var{parameter}'s attributes.
@item k
Like the @samp{K} transformation, but expands the keys and values of
indexed and associative arrays to separate words after word splitting.
@end table
If @var{parameter} is @samp{@@} or @samp{*},
+2 -2
View File
@@ -2,10 +2,10 @@
Copyright (C) 1988-2021 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Tue Aug 10 11:06:03 EDT 2021
@set LASTCHANGE Mon Aug 23 10:07:59 EDT 2021
@set EDITION 5.1
@set VERSION 5.1
@set UPDATED 10 August 2021
@set UPDATED 23 August 2021
@set UPDATED-MONTH August 2021
+20 -1
View File
@@ -7915,6 +7915,7 @@ string_transform (xc, v, s)
ret = string_var_assignment (v, s);
break;
case 'K':
case 'k':
ret = sh_quote_reusable (s, 0);
break;
/* Transformations that modify the variable's value */
@@ -8008,7 +8009,7 @@ array_transform (xc, var, starsub, quoted)
{
ARRAY *a;
HASH_TABLE *h;
int itype;
int itype, qflags;
char *ret;
WORD_LIST *list;
SHELL_VAR *v;
@@ -8035,6 +8036,23 @@ array_transform (xc, var, starsub, quoted)
a = (v && array_p (v)) ? array_cell (v) : 0;
h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
/* XXX - for now */
if (xc == 'k')
{
if (v == 0)
return ((char *)NULL);
list = array_p (v) ? array_to_kvpair_list (a) : assoc_to_kvpair_list (h);
qflags = quoted;
/* If we are expanding in a context where word splitting will not be
performed, treat as quoted. This changes how $* will be expanded. */
if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
ret = string_list_pos_params (itype, list, qflags, 0);
dispose_words (list);
return ret;
}
list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
if (list == 0)
return ((char *)NULL);
@@ -8058,6 +8076,7 @@ valid_parameter_transform (xform)
case 'a': /* expand to a string with just attributes */
case 'A': /* expand as an assignment statement with attributes */
case 'K': /* expand assoc array to list of key/value pairs */
case 'k': /* XXX - for now */
case 'E': /* expand like $'...' */
case 'P': /* expand like prompt string */
case 'Q': /* quote reusably */
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+41
View File
@@ -288,3 +288,44 @@ declare -a ia
declare -A a=(["@"]="at2" )
declare -A a=(["@"]=" string" )
declare -A a=(["*"]="star2" ["@"]="at" )
declare -A assoc=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" )
argv[1] = <world>
argv[2] = <value with spaces>
argv[3] = <bar>
argv[4] = <1>
argv[1] = <hello>
argv[2] = <world>
argv[3] = <key with spaces>
argv[4] = <value with spaces>
argv[5] = <foo>
argv[6] = <bar>
argv[7] = <one>
argv[8] = <1>
argv[1] = <world value with spaces bar 1>
argv[1] = <hello world key with spaces value with spaces foo bar one 1>
argv[1] = <hello>
argv[2] = <world>
argv[3] = <key with spaces>
argv[4] = <value with spaces>
argv[5] = <one>
argv[6] = <1>
argv[7] = <foo>
argv[8] = <bar>
argv[1] = <'hello'>
argv[2] = <'world'>
argv[3] = <'key with spaces'>
argv[4] = <'value with spaces'>
argv[5] = <'one'>
argv[6] = <'1'>
argv[7] = <'foo'>
argv[8] = <'bar'>
argv[1] = <'hello'>
argv[2] = <'world'>
argv[3] = <'key with spaces'>
argv[4] = <'value with spaces'>
argv[5] = <'one'>
argv[6] = <'1'>
argv[7] = <'foo'>
argv[8] = <'bar'>
declare -A clone=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" )
declare -A posparams=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" )
+3
View File
@@ -250,3 +250,6 @@ ${THIS_SH} ./assoc12.sub
# assignment to @ and *
${THIS_SH} ./assoc13.sub
# tests of the @k transformation on associative arrays
${THIS_SH} ./assoc14.sub
+21
View File
@@ -0,0 +1,21 @@
declare -A assoc=(hello world "key with spaces" "value with spaces" one 1 foo bar)
declare -p assoc
recho "${assoc[@]}"
recho "${assoc[@]@k}"
recho "${assoc[*]}"
recho "${assoc[*]@k}"
set -- hello world "key with spaces" "value with spaces" one 1 foo bar
recho "${@}"
recho "${@@K}"
recho "${@@k}"
declare -A clone
eval clone=\( "${assoc[@]@K}" \)
declare -p clone
declare -A posparams
eval posparams=\( "${@@K}" \)
declare -p posparams
+10
View File
@@ -703,11 +703,21 @@ aaa bbb
a bbb
aaa bb
'string'
'string'
'value with spaces'
'value with spaces'
'a b' 'c d' 'e f'
'a b' 'c d' 'e f'
0 "zero" 1 "one" 2 "two" 3 "three"
0 "zero z" 1 "one o" 2 "two t" 3 "three t"
argv[1] = <0>
argv[2] = <zero z>
argv[3] = <1>
argv[4] = <one o>
argv[5] = <2>
argv[6] = <two t>
argv[7] = <3>
argv[8] = <three t>
declare -a foo=()
ai
declare -ai foo
+18 -1
View File
@@ -1,4 +1,18 @@
# test the other uses of the 'K' tranform operator
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# test the other uses of the 'K' tranform operator and its sibling 'k'
# the associative array tests are performed separately, since that was the
# original motivation for this feature
foo=string
@@ -7,7 +21,9 @@ bar='value with spaces'
set -- 'a b' 'c d' 'e f'
echo ${foo@K}
echo ${foo@k}
echo ${bar@K}
echo ${bar@k}
echo ${@@K}
echo "${@@K}"
@@ -17,3 +33,4 @@ echo ${foo[@]@K}
foo=( 'zero z' 'one o' 'two t' 'three t' )
echo ${foo[@]@K}
recho "${foo[@]@k}"