On Sun, May 19, 2024 at 02:23:23PM +0100, Harald van Dijk wrote:
>
> This interacts terribly with the not fully reliable but nevertheless fairly
> commonly used "local OPTIND". When the local OPTIND goes out of scope and
> the prior value of OPTIND is restored, the expectation is not that option
> processing restarts from the beginning.

Dash doesn't actually need "local OPTIND".  In fact, if you do
"local OPTIND" then dash will already be broken because even
if OPTIND is reset to the same value, the other internal state
optoff will end up being wrong.

However, it's not hard to make dash ignore "local OPTIND" and
make it work as if it wasn't there.

---8<---
Always reset OPTIND if it is modified by the user, regardless of
its value.

Do not call getoptsreset when returning from a function because
of "local OPTIND" as this simply trashes the caller's getopts
state.

Reported-by: наб <nabijaczlew...@nabijaczleweli.xyz>
Reported-by: Harald van Dijk <har...@gigawatt.nl>
Signed-off-by: Herbert Xu <herb...@gondor.apana.org.au>

diff --git a/src/options.c b/src/options.c
index 4d0a53a..c74e4fe 100644
--- a/src/options.c
+++ b/src/options.c
@@ -393,7 +393,7 @@ setcmd(int argc, char **argv)
 
 void getoptsreset(const char *value)
 {
-       shellparam.optind = number(value) ?: 1;
+       shellparam.optind = 1;
        shellparam.optoff = -1;
 }
 
diff --git a/src/var.c b/src/var.c
index df432b5..b06b36c 100644
--- a/src/var.c
+++ b/src/var.c
@@ -93,7 +93,7 @@ struct var varinit[] = {
        { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0 },
        { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0 },
        { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0 },
-       { 0,    VSTRFIXED|VTEXTFIXED,           defoptindvar,   getoptsreset },
+       { 0,    VSTRFIXED|VTEXTFIXED|VNOFUNC,   defoptindvar,   getoptsreset },
 #ifdef WITH_LINENO
        { 0,    VSTRFIXED|VTEXTFIXED,           linenovar,      0 },
 #endif
@@ -535,7 +535,7 @@ poplocalvars(void)
                                ckfree(vp->text);
                        vp->flags = lvp->flags;
                        vp->text = lvp->text;
-                       if (vp->func)
+                       if (vp->func && !(vp->flags & VNOFUNC))
                                (*vp->func)(varnull(vp->text));
                }
                ckfree(lvp);
-- 
Email: Herbert Xu <herb...@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

Reply via email to