From 940f264ee6b75e013658d4ba7f6a6dd77ae014d3 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Fri, 19 Sep 2014 17:31:34 -0700 Subject: [PATCH] Decrement SHLVL when running `exec` `exec` removes fish from the shell "stack", so SHLVL needs to be decremented to match. This means `exec fish` will result in the same SHLVL in the new fish instance. Also tweak the SHLVL logic to interpret an environment SHLVL of "3foo" as garbage instead of as the value "3". Fixes #1693. --- env.cpp | 6 ++++-- exec.cpp | 15 +++++++++++++++ tests/test3.in | 7 +++++++ tests/test3.out | 5 +++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/env.cpp b/env.cpp index 353085b8b..c9f986b10 100644 --- a/env.cpp +++ b/env.cpp @@ -542,8 +542,10 @@ void env_init(const struct config_paths_t *paths /* or NULL */) wcstring nshlvl_str = L"1"; if (! shlvl_str.missing()) { - long shlvl_i = wcstol(shlvl_str.c_str(), NULL, 10); - if (shlvl_i >= 0) + wchar_t *end; + long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10); + while (iswspace(*end)) ++end; /* skip trailing whitespace */ + if (shlvl_i >= 0 && *end == '\0') { nshlvl_str = to_string(shlvl_i + 1); } diff --git a/exec.cpp b/exec.cpp index 3b5506da6..7706dcc50 100644 --- a/exec.cpp +++ b/exec.cpp @@ -651,6 +651,21 @@ void exec_job(parser_t &parser, job_t *j) /* PCA This is for handling exec. Passing all_ios here matches what fish 2.0.0 and 1.x did. It's known to be wrong - for example, it means that redirections bound for subsequent commands in the pipeline will apply to exec. However, using exec in a pipeline doesn't really make sense, so I'm not trying to fix it here. */ if (!setup_child_process(j, 0, all_ios)) { + /* decrement SHLVL as we're removing ourselves from the shell "stack" */ + const env_var_t shlvl_str = env_get_string(L"SHLVL", ENV_GLOBAL | ENV_EXPORT); + wcstring nshlvl_str = L"0"; + if (!shlvl_str.missing()) + { + wchar_t *end; + long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10); + while (iswspace(*end)) ++end; /* skip trailing whitespace */ + if (shlvl_i > 0 && *end == '\0') + { + nshlvl_str = to_string(shlvl_i - 1); + } + } + env_set(L"SHLVL", nshlvl_str.c_str(), ENV_GLOBAL | ENV_EXPORT); + /* launch_process _never_ returns */ diff --git a/tests/test3.in b/tests/test3.in index 56cceeb57..b83b69c04 100644 --- a/tests/test3.in +++ b/tests/test3.in @@ -236,5 +236,12 @@ echo Missing: $testu # test SHLVL # use a subshell to ensure a clean slate env SHLVL= ../fish -c 'echo SHLVL: $SHLVL; ../fish -c \'echo SHLVL: $SHLVL\'' +# exec should decrement SHLVL +env SHLVL= ../fish -c 'echo SHLVL: $SHLVL; exec ../fish -c \'echo SHLVL: $SHLVL\'' +# garbage SHLVLs should be treated as garbage +env SHLVL=3foo ../fish -c 'echo SHLVL: $SHLVL' +# whitespace is allowed though (for bash compatibility) +env SHLVL="3 " ../fish -c 'echo SHLVL: $SHLVL' +env SHLVL=" 3" ../fish -c 'echo SHLVL: $SHLVL' true diff --git a/tests/test3.out b/tests/test3.out index 50563c05b..c6a21905a 100644 --- a/tests/test3.out +++ b/tests/test3.out @@ -23,3 +23,8 @@ Missing: Missing: SHLVL: 1 SHLVL: 2 +SHLVL: 1 +SHLVL: 1 +SHLVL: 1 +SHLVL: 4 +SHLVL: 4