Re: nameref and referenced variable scope, setting other attributes (was "local -g" declaration references local var in enclosing scope)

2024-03-19 Thread Mike Jonkmans
On Mon, Mar 18, 2024 at 04:19:55PM -0400, Chet Ramey wrote:
> On 3/14/24 8:57 PM, Zachary Santer wrote:
> > On Thu, Mar 14, 2024 at 3:43 PM Chet Ramey  wrote:
> > > 
> > > In fact, before 2020, local -p with no name arguments behaved the same as
> > > local without arguments, which just printed all the local variable names 
> > > at
> > > the current scope in the form of assignment statements. That was certainly
> > > not usable to reproduce the current state.
> > 
> > While we're kind of on the subject, I find it really odd that the
> > ${var@A} parameter expansion will expand to either an assignment
> > statement or a 'declare' command, depending on whether or not the
> > variable has an attribute set.
> 
> Yes. There is one thing missing: the transformation should expand to a
> `declare' command when applied to a local variable at the current scope,
> even if there are no attributes to be displayed. Agreed?
> 
> I am less convinced about outputting a `-g' for a global variable when
> called from a function scope, but I could be persuaded.

This would be logical.
Forgot the use case, but it was about a year ago that I needed this.

-- 
Regards, Mike Jonkmans



Re: nameref and referenced variable scope, setting other attributes (was "local -g" declaration references local var in enclosing scope)

2024-03-19 Thread Chet Ramey

On 3/19/24 11:50 AM, Mike Jonkmans wrote:


Yes. There is one thing missing: the transformation should expand to a
`declare' command when applied to a local variable at the current scope,
even if there are no attributes to be displayed. Agreed?

I am less convinced about outputting a `-g' for a global variable when
called from a function scope, but I could be persuaded.


This would be logical.
Forgot the use case, but it was about a year ago that I needed this.


The former, the latter, or both?

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Re: nameref and referenced variable scope, setting other attributes (was "local -g" declaration references local var in enclosing scope)

2024-03-19 Thread Mike Jonkmans
On Tue, Mar 19, 2024 at 02:24:34PM -0400, Chet Ramey wrote:
> On 3/19/24 11:50 AM, Mike Jonkmans wrote:
> 
> > > Yes. There is one thing missing: the transformation should expand to a
> > > `declare' command when applied to a local variable at the current scope,
> > > even if there are no attributes to be displayed. Agreed?
> > > 
> > > I am less convinced about outputting a `-g' for a global variable when
> > > called from a function scope, but I could be persuaded.
> > 
> > This would be logical.
> > Forgot the use case, but it was about a year ago that I needed this.
> 
> The former, the latter, or both?

I can also agree to the former.

My use case was with needing the '-g'.

-- 
Regards, Mike Jonkmans



Re: ${var@A}; hypothetical, related parameter transformations

2024-03-19 Thread Zachary Santer
On Mon, Mar 18, 2024 at 6:26 PM Zachary Santer  wrote:
>
> I guess, in bash 5.1+, it could pass
> "${assoc[*]@K}"
> and then the receiving end could
> eval "assoc=( ${assoc_message} )"
> if I wanted to avoid declaring the associative array anew.

If I wanted to duplicate an indexed array, however, whether in sending it
to another process or not, I would need to be able to expand only the right
hand side of the compound assignment statement, i.e. ( [5]="Hello"
[12]="world!" )

> For my
> use case, if, for whatever reason, bash decided to send associative
> arrays as compound assignment statements without being in the context
> of a declare command, the receiving end would have to have already
> declared the associative array variable before eval'ing what it
> received. Given that the documentation doesn't specify when bash would
> choose to generate an assignment statement vice a declare command,
> maybe that would be the safe way to go.

Just changed what happens on the receiving end to:
eval "${assoc_message#declare * }"
to ensure the associative arrays only get declared where I want them to be.

I could have done
eval "assoc=${assoc_message#*=}"
expanding to only the right hand side of the compound assignment statement.
This seemed redundant in my case, because the associative arrays are named
the same thing in both sending and receiving processes.

So I can get a couple of the things I want by manipulating what I get out
of ${var@A} with fairly straightforward parameter expansions. If I needed a
declare command and wasn't sure if I would get one, I haven't found a way
to expand that to something that is guaranteed to be a declare command
maintaining attribute settings. I think you're stuck using an if block at
that point.


"${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax

2024-03-19 Thread Zachary Santer
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: msys
Compiler: gcc
Compilation CFLAGS: -march=nocona -msahf -mtune=generic -O2 -pipe
-D_STATIC_BUILD
uname output: MINGW64_NT-10.0-19045 Zack2021HPPavilion 3.4.10.x86_64
2024-02-10 08:39 UTC x86_64 Msys
Machine Type: x86_64-pc-msys

Bash Version: 5.2
Patch Level: 26
Release Status: release

Description:

The man page's descriptions of ${var@K} and ${var@k}:
K Produces a possibly-quoted version of the value of parameter, except
that it prints the values of indexed and associative arrays as a
sequence of quoted key-value pairs (see Arrays above).
k Like the K transformation, but expands the keys and values of
indexed and associative arrays to separate words after word splitting.

In the section on Arrays, we see:
When assigning to an associative array, the words in a compound
assignment may be either assignment statements, for which the
subscript is required, or a list of words that is interpreted as a
sequence of alternating keys and values: name=( key1 value1 key2
value2 ...). These are treated identically to name=( [key1]=value1
[key2]=value2 ...). The first word in the list determines how the
remaining words are interpreted; all assignments in a list must be of
the same type. When using key/value pairs, the keys may not be missing
or empty; a final missing value is treated like the empty string.

The "${assoc[@]@k}" transformation doesn't leave the separate
key/value words quoted. I'm not sure if the phrasing of the
documentation implies that it would or not.

As such, I would expect that
$ declare -A assoc_2=( "${assoc_1[@]@k}" )
would create assoc_2 as a duplicate of assoc_1. However, we see that
the entire expansion becomes the key for a single array element, with
its value being the empty string.

Repeat-By:

$ declare -A assoc_1=( [key 0]='value 0' [key 1]='value 1' [key
2]='value 2' [key 3]='value 3' )
$ unset assoc_2
$ declare -A assoc_2
$ printf '|%s|\n' "${assoc_1[*]@k}"
|key 2 value 2 key 3 value 3 key 0 value 0 key 1 value 1|
# All one word. Makes sense.
$ assoc_2=( "${assoc_1[*]@k}" )
$ declare -p assoc_2
declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1
value 1"]="" )
# Still makes sense.
$ printf '|%s|\n' "${assoc_1[@]@k}"
|key 2|
|value 2|
|key 3|
|value 3|
|key 0|
|value 0|
|key 1|
|value 1|
# Got expanded to separate words, like it's supposed to.
$ assoc_2=( "${assoc_1[@]@k}" )
$ declare -p assoc_2
declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1
value 1"]="" )
# Here, it did not.

If it were up to me, "${scalar@k}" wouldn't do anything different than
"${scalar}" and "${assoc[@]@K}" would expand to separate, quoted
words.

$ scalar='some words'
$ printf '|%s|\n' "${scalar@K}"
|'some words'|
$ printf '|%s|\n' "${scalar@k}"
|'some words'|
# This is inconsistent with what the @k parameter transformation does
with an array.
$ printf '|%s|\n' "${assoc_1[*]@K}"
|"key 2" "value 2" "key 3" "value 3" "key 0" "value 0" "key 1" "value 1" |
$ printf '|%s|\n' "${assoc_1[@]@K}"
|"key 2" "value 2" "key 3" "value 3" "key 0" "value 0" "key 1" "value 1" |
# Quoted [*] and [@] array expansions do things differently everywhere
else I can think of.



Re: Bash printf should diagnose integer overflow

2024-03-19 Thread Paul Eggert

On 3/18/24 12:41, Chet Ramey wrote:

I'm not sure what you're using, but that was not my experience on
macOS.


I am using Fedora 39 (the current version) on x86-64. That could explain 
our differing experiences.


I see several diagnostics (mostly diff output) with "make check" on 
Fedora 39. The diagnostics can vary from run to run, i.e., they aren't 
necessarily reproducible. I assumed these were OK because I got 'em 
before any patches. From my point of view the diff output was sort of 
random, so I eyeballed it and guessed which outputs mattered and which 
didn't. Apparently I guessed incorrectly with fw.


At some point I suppose it'd be nice if 'make check' succeeded (exit 
status 0) or failed (nonzero exit status) so that it is easy for 
non-experts to tell which diagnostics matter; that's what many other 
packages do. For now I'd rather focus on the integer overflow issues in 
Bash, while they're fresh in my mind.




First, the patched version doesn't build on macOS because your patches
don't include . Once you get past that, printf goes into an
infinite loop on

printf -v s "%b" ""

in printstr because `fw' is used unititialized (and randomly set to some
ridiculously large value). That and the old test's incorrect expectation
that a field width of 9223372036854775825 would always overflow to -1 (a
left-adjusted field width of 1) instead of being flagged as overflow are
the UB I was talking about.


Yes, I see now. I didn't get that behavior on Fedora, perhaps because 
the junk in fw was benign there.


Perhaps at some point we could enable more of GCC's static checking to 
catch silly mistakes like that. Again, a task for another time.




It should be mostly there in the changes I pushed today, once I made it
through the above.


Thanks, I checked the devel branch against what I submitted, found a few 
errors, and while reviewing all this found and fixed a few other 
integer-overflow issues in Bash. Proposed patches attached, in "git 
format-patch" format so you can use "git am" on them. If there's some 
reason a patch shouldn't be applied please let me know so that I can 
stop worrying about that subissue.From ccf906084c3aaf7cd75f0ee1e035986af7d58a82 Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Mon, 18 Mar 2024 13:44:27 -0700
Subject: [PATCH 01/10] Improve use of HAVE_C_BOOL
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* bashansi.h: If HAVE_C_BOOL, bool works as per C23, so
we needn’t include  or define any workarounds.
In pre-C99 compilers arrange for ‘false’ and ‘true’ as well;
although Bash doesn't use either symbol it's safer to
be compatible in case some system .h file unwisely uses it.
---
 bashansi.h | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/bashansi.h b/bashansi.h
index 4feaadfb..0bac61b4 100644
--- a/bashansi.h
+++ b/bashansi.h
@@ -35,13 +35,15 @@
 #  include "ansi_stdlib.h"
 #endif /* !HAVE_STDLIB_H */
 
-/* Prefer stdbool.h if we have it, maybe have to rethink this later */
-#if defined (HAVE_STDBOOL_H)
-#  include 
-#else
-#  ifndef HAVE_C_BOOL
+/* If bool is not builtin, prefer stdbool.h if we have it. */
+#ifndef HAVE_C_BOOL
+#  ifdef HAVE_STDBOOL_H
+#include 
+#  else
 #undef bool
 typedef unsigned char bool;
+#define false 0
+#define true 1
 #  endif
 #endif
 
-- 
2.44.0

From aeb21592ed88cac5072bcd41b2c478766d6e1dee Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Mon, 18 Mar 2024 13:54:29 -0700
Subject: [PATCH 02/10] Minor mkseq clarification/tuning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* braces.c (mkseq): All branches of an if end in ‘result[i++] =
t;’, so hoist that out of the ‘if’.
---
 braces.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/braces.c b/braces.c
index 444807a7..194000c2 100644
--- a/braces.c
+++ b/braces.c
@@ -399,7 +399,7 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width)
   QUIT;
 #endif
   if (type == ST_INT)
-	result[i++] = t = itos (n);
+	t = itos (n);
   else if (type == ST_ZINT)
 	{
 	  size_t tlen;
@@ -419,7 +419,6 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width)
 		  memset (t + (n < 0), '0', width - tlen);
 		}
 	}
-	  result[i++] = t;
 	}
   else
 	{
@@ -428,9 +427,10 @@ mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width)
 	  t[0] = n;
 	  t[1] = '\0';
 	}
-	  result[i++] = t;
 	}
 
+  result[i++] = t;
+
   /* We failed to allocate memory for this number, so we bail. */
   if (t == 0)
 	{
-- 
2.44.0

From 3c124056fbd07b31b259ec0fd87781d9a3ed4eed Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Mon, 18 Mar 2024 13:57:36 -0700
Subject: [PATCH 03/10] Simplify mkseq control
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* braces.c (mkseq): Replace ‘if (!TEST) break; } while (1);’
with ‘} while (TES

Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax

2024-03-19 Thread Zachary Santer
On Tue, Mar 19, 2024 at 11:18 PM Zachary Santer  wrote:
>
> Repeat-By:
>
> $ declare -A assoc_1=( [key 0]='value 0' [key 1]='value 1' [key
> 2]='value 2' [key 3]='value 3' )
> $ unset assoc_2
> $ declare -A assoc_2
> $ printf '|%s|\n' "${assoc_1[*]@k}"
> |key 2 value 2 key 3 value 3 key 0 value 0 key 1 value 1|
> # All one word. Makes sense.
> $ assoc_2=( "${assoc_1[*]@k}" )
> $ declare -p assoc_2
> declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1
> value 1"]="" )
> # Still makes sense.
> $ printf '|%s|\n' "${assoc_1[@]@k}"
> |key 2|
> |value 2|
> |key 3|
> |value 3|
> |key 0|
> |value 0|
> |key 1|
> |value 1|
> # Got expanded to separate words, like it's supposed to.
> $ assoc_2=( "${assoc_1[@]@k}" )
> $ declare -p assoc_2
> declare -A assoc_2=(["key 2 value 2 key 3 value 3 key 0 value 0 key 1
> value 1"]="" )
> # Here, it did not.

This is specific to the compound assignment syntax for an associative
array, even.

$ unset array_1
$ declare -a array_1
$ array_1=( "${assoc_1[*]@k}" )
$ declare -p array_1
declare -a array_1=([0]="key 2 value 2 key 3 value 3 key 0 value 0 key
1 value 1")
$ array_1=( "${assoc_1[@]@k}" )
$ declare -p array_1
declare -a array_1=([0]="key 2" [1]="value 2" [2]="key 3" [3]="value
3" [4]="key 0" [5]="value 0" [6]="key 1" [7]="value 1")



Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax

2024-03-19 Thread Lawrence Velázquez
On Tue, Mar 19, 2024, at 11:18 PM, Zachary Santer wrote:
> As such, I would expect that
> $ declare -A assoc_2=( "${assoc_1[@]@k}" )
> would create assoc_2 as a duplicate of assoc_1. However, we see that
> the entire expansion becomes the key for a single array element, with
> its value being the empty string.

This isn't specific to ${var[@]@k}.

$ kv1='a 1 b 2 c 3'
$ kv2=(a 1 b 2 c 3)
$ declare -A aa1=($kv1) aa2=(${kv2[@]}) aa3=("${kv2[@]}")
$ declare -p aa1 aa2 aa3
declare -A aa1=(["a 1 b 2 c 3"]="" )
declare -A aa2=(["a 1 b 2 c 3"]="" )
declare -A aa3=(["a 1 b 2 c 3"]="" )

A couple of previous discussions:
  - https://lists.gnu.org/archive/html/bug-bash/2020-12/msg00066.html
  - https://lists.gnu.org/archive/html/bug-bash/2023-06/msg00128.html

-- 
vq