Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH] Fix math evaluation error in zargs when using --max-args=X syntax



Hello Zsh Workers,

I have identified a math evaluation bug in the autoloaded `zargs` contribution function when parsing long options with an embedded equals sign delimiter (e.g., `--max-args=200`), along with a proposed code-level patch.

Steps to reproduce:
$ zsh -f
$ autoload -U zargs
$ zargs --max-args=200 -- some_command ...

Actual behavior:
zargs:230: bad math _expression_: operand expected at `=200'
zargs:236: bad math _expression_: operand expected at `=200'
zargs: argument list too long

Analysis:
The function uses `zparseopts` to populate the `n`, `s`, `l`, and `P` arrays:
zparseopts -a opts -D -- ... -max-args:=n n:=n ...

When passing `--max-args=200`, `zparseopts` populates the `n` array with two distinct elements:
n[1] -> "--max-args"
n[2] -> "=200"

The current variable assignment mechanism on line 230 reads:
n=${${n##-(n|-max-args(=|))}:-$[ARGC+c]}

Because `n` is an array, Zsh applies the prefix truncation `##` to each element individually. Element 1 matches and is stripped. Element 2 (`=200`) fails the prefix match (as it does not start with `-n` or `-max-args`) and remains untouched. 

When the array is implicitly joined back into a scalar string, it results in the literal string `" =200"`. This raw equals sign is preserved downstream, causing the arithmetic evaluation block `(( end > n && ( end = n ) ))` to crash.

Proposed Patch:
Target the last array slice element explicitly and strip any potential leading equals operator (`[-1]#=`). This bypasses the need for a complex prefix match over the entire array, handles spaces or equals signs gracefully, and safely preserves the original fallback defaults.

--- functions/zargs.orig
+++ functions/zargs
@@ -226,7 +226,7 @@
     fi
 fi

-n=${${n##-(n|-max-args(=|))}:-$[ARGC+c]}
+n=${${n[-1]#=}:-$[ARGC+c]}
 if (( n <= 0 ))
 then
     print -u2 'zargs: value for max-args must be >= 1'
@@ -240,21 +240,21 @@
     return 1
 fi

-s=${${s##-(s|-max-chars(=|))}:-20480}
+s=${${s[-1]#=}:-20480}
 if (( s <= 0 ))
 then
     print -u2 'zargs: value for max-chars must be >= 1'
     return 1
 fi

-l=${${${l##*-(l|L|-max-lines(=|))}[-1]}:-${${l[1]:+1}:-$ARGC}}
+l=${${l[-1]#=}:-${${l[1]:+1}:-$ARGC}}
 if (( l <= 0 ))
 then
     print -u2 'zargs: value for max-lines must be >= 1'
     return 1
 fi

-P=${${P##-(P|-max-procs(=|))}:-1}
+P=${${P[-1]#=}:-1}
 if (( P < 0 ))
 then
     print -u2 'zargs: value for max-procs must be >= 0'


Environment Details:
- Zsh Version: zsh 5.9 (x86_64-apple-darwin23.6.0 via Homebrew Cellar)
- Operating System: macOS 15.7.5 (Build 24G624)
- Kernel Version: Darwin 24.6.0 (RELEASE_X86_64)

Thank you,
Bostjan H



Messages sorted by: Reverse Date, Date, Thread, Author