A while loop now evaluates to the last executed command in the body, or
zero if the loop body is empty. This matches POSIX semantics.
Add a bunch of tricky tests.
See #4982
For some reason, we have two places where a variable can be read-only:
- By key in env.cpp:is_read_only(), which is checked via set*
- By flag on the actual env_var_t, which is checked e.g. in
parse_execution
The latter didn't happen for non-electric variables like hostname,
because they used the default constructor, because they were
constructed via operator[] (or some such C++-iness).
This caused for-loops to crash on an assert if they used a
non-electric read-only var like $hostname or $SHLVL.
Instead, we explicitly set the flag.
We might want to remove one of the two read-only checks, or something?
Fixes#5548.
There's just waaayy too many things that could go wrong with it, so it
annoys more than it helps, especially since we don't get any
indication what failed.
E.g. on FreeBSD, the test failed without a usable message just because
`tput` couldn't find an attribute (so colors were unset).
The one thing I was missing:
`echo -n` isn't POSIX. In practice, it appears the only shell to encounter this
is macOS' crusty old bash in sh-mode. Just replace it with `touch`.
This reverts commit fc5e8f9fec.
This makes the script worse, but it's good enough.
The required changes are:
- `shopt -s nullglob`, which we simply don't use (we have one glob, but that's
guaranteed to match because we ship the files)
- One array, which we replace with a direct use of the glob (plus it
used `echo` again?)
- The `function` word, which I'm still annoyed is even a thing!
- Variable indirection (`color=${!color_var}` - instead we pass the
value directly - which makes the script uglier!)
- One array, which we replace with a function
- A use of `type -t`, replaced with `command -v`
- A use of `${var:begin:end}` substring expansion, replaced with trickery.
- `set -o pipefail` is replaced with a function
Note that checkbashisms still complains about `command -v`, because
we're not using it with "-p". But we _want_ to check the current
$PATH, and `command -v` is POSIX.
This still uses `local`, which technically isn't in POSIX.
The tests now appear to pass in:
- bash
- dash
- zsh
- mksh
- busybox
Rather than killing the process with close, read EOF after sending the
"exit" command and wait for OS cleanup (per the expect examples).
Not cleaning up with wait caused expect to crash on all 32-bit platforms
including i586 and armv7l with "alloc: invalid block: 0xbf993ccb: 3d 3b".
64-bit platforms were not affected, for reasons that are not clear.
Turns out busybox diff (used on alpine) defaults to unified output,
which we can't use because that prints filenames, and those are
tempfiles made by psub.
Instead, we use builtins to print the first line and compare the others.
This isn't all that important, and it breaks on musl just because the message is different.
Just skip it for now, until we figure out how to better test this.
This `set TERM`. Which, if $TERM is inherited, is already exported,
but not if it isn't.
This is the case on sr.ht's arch images, so we failed without a TERM variable.
Return STATUS_INVALID_ARGS when failing due to evaluation errors,
so we can tell the difference between an error and falseness.
Add a test for the ERANGE error
This previously used /dev/tty to make sure we have `source` connected
to a terminal. Only as it turns out, FreeBSD doesn't have that (https://builds.sr.ht/~faho/job/15308).
So instead, let's just use the expect tests since stdin there is by
definition a terminal.
This broke fishtape, which did
somestuff | fish -c "source"
Because `source` didn't have a redirection, it refused to read from
stdin.
So, to keep the common issue of `source (command that does not print)`
from seeminly stopping fish, we instead actually check if stdin is a terminal.
The colors happening for the interactive tests didn't match the
expected output. For `history search` commands we test, have them
pipe through `cat` so the fishscript does not use a pager or try
to colorize.
realpath() will return NULL and sets errno if it fails.
We asserted that realpath(".") does not fail. We also didn't really
check that it was successful. Made sure we'll get a perror telling
us about what went wrong if something like this happens again.
Updated tests and added test case
Fixes#5351
Prior to this fix, cding into a symlink and then completing .. would complete
from the physical directory instead of the logical directory, which could not
actually be cd'd to. Teach cd completiond to use the logical directory.
For things like
source $undefined
or
source (nooutput)
it was quite annoying that it read from tty.
Instead we now require a "-" as the filename to read from the tty.
This does not apply to reading from stdin if it's redirected, so
something | source
still works.
Fixes#2633.
This adds flags --path and --unpath to builtin set, analogous to
--export and --unexport. These flags change whether a variable is
marked as a path variable.
Universal variables cannot yet be path variables.
This switches quoted expansion like "$foo" to use foo's delimiter instead of
space. The delimiter is space for normal variables and colonf or path variables.
Expansions like "$PATH" will now expand using ':'.