diff options
68 files changed, 1534 insertions, 539 deletions
@@ -1,5 +1,138 @@ +2026-05-03 dana <dana@dana.is> + + * unposted: Test/Y01completion.ztst: Y01: fix test broken by + _echo + + * unposted: Completion/Darwin/Command/_caffeinate, + Completion/Linux/Command/_mdadm, Completion/Unix/Command/_man: + add missing + to some short-option specs + + * unposted: Completion/Unix/Command/_echo: add _echo + +2026-05-03 Mikael Magnusson <mikachu@gmail.com> + + * unposted: Completion/Cygwin/Command/_cygcheck, + Completion/Linux/Command/_acpi, Completion/Unix/Command/_myrepos, + Completion/Unix/Command/_tex: remove the 'this' from 'show this + help and exit' in completers + +2026-05-02 dana <dana@dana.is> + + * 54437 (tweaked): Src/lex.c, Test/D04parameter.ztst: lex: fix + <-> in parameter flags + + * 54424: Doc/Zsh/params.yo, NEWS, Test/D04parameter.ztst: + ZSH_EXEPATH: improve documentation, add test + + * 54423 (tweaked): Completion/Zsh/Command/_compinit, + Completion/compinit, Doc/Zsh/compsys.yo: compinit: improve and + document -w + + * unposted: Test/Y05describe.ztst: add basic tests for _describe + + * unposted: Test/Z04zgetopt.ztst: zgetopt: make sure zsh/zutil + loads + +2026-05-02 Mikael Magnusson <mikachu@gmail.com> + + * unposted: Completion/Unix/Command/_mpc: fix typo for -h flag + +2026-04-30 Oliver Kiddle <opk@zsh.org> + + * Ryan Rotter: 54218: Completion/Unix/Command/_ip: add some + missing flags + + * Philippe Altherr: 54383: Src/Modules/watch.c, Src/module.c, + Test/V01zmodload.ztst: Fix WATCH/watch tying + + * Christopher Bock: github #168: Completion/Debian/Command/_apt: + add apt history commands + + * unposted: Completion/X/Command/_nedit: nedit-client is + also commonly used as as the name for nc + + * unposted: Completion/Unix/Command/_ghostscript, + Completion/Unix/Type/_pspdf: ghostscript completion does a + better job of handling gsnd + + * unposted: Completion/Unix/Command/_lua: complete also for + FreeBSD's flua + + * unposted: Test/Y04regexargs.ztst: minimal tests of + _regex_arguments + + * unposted: Completion/Unix/Command/_sudo: fix for approximate + completion/correction + + * 54404: Src/Zle/termquery.c, Test/X06termquery.ztst: skip + the RGB terminal query on older versions of the Apple terminal + which fail to consume the sequence + +2026-04-29 dana <dana@dana.is> + + * unposted: Completion/Linux/Command/_opkg: guard zparseopts + long-option specs + + * 54376: Doc/Zsh/mod_zutil.yo, NEWS, README, + Src/Modules/zutil.c, Test/V12zparseopts.ztst: zparseopts: use + standard option parsing + + * 54381: Doc/Zsh/mod_zutil.yo, README, Src/Modules/zutil.c, + Test/V12zparseopts.ztst: zparseopts -M: use last as-given + option name in arrays + + * 54395: Doc/Zsh/contrib.yo, Functions/Misc/zgetopt, NEWS, + Test/Z04zgetopt.ztst: contrib: add zgetopt (again) + + * unposted: Completion/Zsh/Command/_compinit: add _compinit + +2026-04-28 dana <dana@dana.is> + + * 54394: Completion/Unix/Command/_7zip: add _7zip + + * Matt Koscica: github #167: Completion/Unix/Command/_tmux: + include new options added between 3.4 and next-3.7 + +2026-04-28 Mikael Magnusson <mikachu@gmail.com> + + * Philippe Altherr: 54342: Src/params.c, Test/A06assign.ztst: + Fix handling of reversed slices of scalar values + + * 54402: Src/Modules/pcre.c: Fix crash in pcre_callout with + numerical callout 0 + + * 54403: Doc/Zsh/mod_pcre.yo: Add some more details on pcre + callouts + + * 54406: Doc/Zsh/arith.yo, Doc/Zsh/mod_pcre.yo: Fix my yodl code + and another instance in arith.yo + +2026-04-19 dana <dana@dana.is> + + * 54362: Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c, + Test/V12zparseopts.ztst: zparseopts: support empty optspec + + * 54361 (tweaked): Completion/Zsh/Command/_zparseopts, + Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c, + Test/V12zparseopts.ztst: zparseopts: print friendlier usage + errors, add -n option + +2026-04-14 Oliver Kiddle <opk@zsh.org> + + * 54181, 54331: Completion/Zsh/Command/_set, + Doc/Makefile.in, Doc/Zsh/builtins.yo, Doc/Zsh/compat.yo, + Doc/Zsh/grammar.yo, Doc/Zsh/invoke.yo, Doc/Zsh/manual.yo, + Doc/Zsh/options.yo, Doc/Zsh/restricted.yo, README, + Src/Modules/db_gdbm.c, Src/Modules/parameter.c, Src/builtin.c, + Src/exec.c, Src/init.c, Src/jobs.c, Src/options.c, Src/params.c, + Src/signals.c, Test/E01options.ztst, configure.ac: + remove support for restricted shell + 2026-04-13 dana <dana@dana.is> + * dana + Jun T: 54329 + 54339: Doc/Makefile.in, Doc/intro.ms: + replace pdfroff by `groff -Tpdf` + * 54318: Doc/Zsh/arith.yo, Doc/Zsh/mod_mathfunc.yo, Functions/Misc/zmathfuncdef, NEWS, Src/Modules/mathfunc.c, Test/V03mathfunc.ztst: mathfunc: add isnan() and isinf(). also diff --git a/Completion/Cygwin/Command/_cygcheck b/Completion/Cygwin/Command/_cygcheck index e0d7532e2..018c891a5 100644 --- a/Completion/Cygwin/Command/_cygcheck +++ b/Completion/Cygwin/Command/_cygcheck @@ -18,7 +18,7 @@ _arguments -C -s -S \ '(* -)'{-l,--list-package}'[list contents of the specified package (or all packages if none given)]:*:package:->package' \ '(* -)'{-p,--package-query}'[search for the specified regexp in the entire cygwin.com package repository (requires internet connectivity)]:regexp:' \ '(-V --version -k --keycheck -f --find-package -l --list-package -p --package-query -c --check-setup -d --dump-only -v --verbose)'{-v,--verbose}'[produce more verbose output]' \ - '(-V --version -k --keycheck -f --find-package -l --list-package -p --package-query -c --check-setup -d --dump-only -h --help)'{-h,--help}'[annotate output with explanatory comments when given with another command, otherwise print this help]' \ + '(-V --version -k --keycheck -f --find-package -l --list-package -p --package-query -c --check-setup -d --dump-only -h --help)'{-h,--help}'[annotate output with explanatory comments when given with another command, otherwise print generic help]' \ '(* -)'{-V,--version}'[print the version of cygcheck and exit]' \ '(-)*:program: _command_names -e' && return diff --git a/Completion/Darwin/Command/_caffeinate b/Completion/Darwin/Command/_caffeinate index 9e361a5bd..f7d67695b 100644 --- a/Completion/Darwin/Command/_caffeinate +++ b/Completion/Darwin/Command/_caffeinate @@ -6,7 +6,7 @@ _arguments -s -S : \ '-m[prevent disk idle sleep]' \ '-s[prevent system sleep (AC power only)]' \ '-u[declare that user is active]' \ - '(:)-t[specify assertion timeout value]:timeout (seconds)' \ - '(:)-w[wait for specified PID]: :_pids' \ + '(:)-t+[specify assertion timeout value]:timeout (seconds)' \ + '(:)-w+[wait for specified PID]: :_pids' \ '(-)1: : _command_names -e' \ '(-)*::command argument' diff --git a/Completion/Debian/Command/_apt b/Completion/Debian/Command/_apt index 19c2dfc8c..ac3095a4d 100644 --- a/Completion/Debian/Command/_apt +++ b/Completion/Debian/Command/_apt @@ -468,7 +468,9 @@ _apt-cmd () { /$'full-upgrade\0'/ \| \ /$'dist-upgrade\0'/ \| \ /$'edit-sources\0'/ /$'[^\0]#\0'/ ': ::_apt_sources' \# \| \ - /"[]"/ ':argument-1::compadd "$expl_action[@]" list search showsrc show depends rdepends policy update install reinstall download source build-dep remove upgrade full-upgrade dist-upgrade edit-sources autoclean changelog autopurge autoremove purge why why-not' + /$'history-list\0'/ \| \ + /$'(history-(info|redo|undo|rollback))\0'/ /$'[^\0]#\0'/ ': ::_apt_history_ids' \# \| \ + /"[]"/ ':argument-1::compadd "$expl_action[@]" list search showsrc show depends rdepends policy update install reinstall download source build-dep remove upgrade full-upgrade dist-upgrade edit-sources autoclean changelog autopurge autoremove purge why why-not history-list history-info history-redo history-undo history-rollback' _apt-cmd () { local expl_action expl_packages subcmd @@ -793,4 +795,10 @@ _apt_snapshot_dates() { _wanted list expl 'wayback date (yyyymmdd[ThhmmssZ])' compadd -- $dates } +_apt_history_ids() { + local -a expl historyids + historyids=( ${${${(f)"$(_call_program history-ids apt history-list)"}:#ID*}%% *} ) + _wanted history-ids expl 'history id' compadd -o numeric,reverse -a historyids +} + _apt "$@" diff --git a/Completion/Linux/Command/_acpi b/Completion/Linux/Command/_acpi index 850687506..5ebf1447c 100644 --- a/Completion/Linux/Command/_acpi +++ b/Completion/Linux/Command/_acpi @@ -14,5 +14,5 @@ _arguments -s \ '(-c --celsius -f --fahrenheit -k --kelvin)'{-f,--fahrenheit}'[use Fahrenheit as the temperature scale]' \ '(-c --celsius -f --fahrenheit -k --kelvin)'{-k,--kelvin}'[use Kelvin as the temperature scale]' \ '(-d --directory)'{-d,--directory}'[path to ACPI info (/proc/acpi)]:directory:_files -/' \ - '(-h --help)'{-h,--help}'[display this help and exit]' \ + '(-h --help)'{-h,--help}'[display help and exit]' \ '(-v --version)'{-v,--version}'[output version information and exit]' diff --git a/Completion/Linux/Command/_mdadm b/Completion/Linux/Command/_mdadm index 5b73ef4be..89c3ac036 100644 --- a/Completion/Linux/Command/_mdadm +++ b/Completion/Linux/Command/_mdadm @@ -71,14 +71,14 @@ _layouts () { if (( $+words[(r)-(A|-assemble)] )); then args=( '(--bitmap)'--bitmap='[bitmap file to use with the array]::bitmap file:_files' - '(--uuid -u)'{--uuid=,-u}'[UUID of array to assemble]:UUID' - '(--super-minor -m)'{--super-minor=,-m}'[minor number to look for in super-block]:minor number' - '(--name -N)'{--name=,-N}'[array name to look for in super-block]:array name' - '(--config -c)'{--config=,-c}'[config file]::config file:_files' + '(--uuid -u)'{--uuid=,-u+}'[UUID of array to assemble]:UUID' + '(--super-minor -m)'{--super-minor=,-m+}'[minor number to look for in super-block]:minor number' + '(--name -N)'{--name=,-N+}'[array name to look for in super-block]:array name' + '(--config -c)'{--config=,-c+}'[config file]::config file:_files' '(--scan -s)'{--scan,-s}'[scan config file for missing information]' '(--run -R)'{--run,-R}'[try to start the array even if not enough devices for a full array are present]' '(--force -f)'{--force,-f}'[assemble the array even if some superblocks appear out-of-date]' - '(--update -U)'{--update=,-U}'[update superblock]::update the superblock:(sparc2.2 summaries uuid resync byteorder super-minor)' + '(--update -U)'{--update=,-U+}'[update superblock]::update the superblock:(sparc2.2 summaries uuid resync byteorder super-minor)' ) fi diff --git a/Completion/Linux/Command/_opkg b/Completion/Linux/Command/_opkg index ddaefe1eb..f726a3e32 100644 --- a/Completion/Linux/Command/_opkg +++ b/Completion/Linux/Command/_opkg @@ -181,7 +181,7 @@ _opkg_dest_path() { _opkg_pkg_all() { local -a upd copts - zparseopts -a upd -D -E -update + zparseopts -a upd -D -E - -update copts=( "$@" ) { (( ! $#_opkg_cache_pkg_all )) || _cache_invalid opkg-pkg-all } && @@ -207,7 +207,7 @@ _opkg_pkg_all() { _opkg_pkg_inst() { local -a upd copts - zparseopts -a upd -D -E -update + zparseopts -a upd -D -E - -update copts=( "$@" ) { (( ! $#_opkg_cache_pkg_inst )) || _cache_invalid opkg-pkg-inst } && @@ -233,7 +233,7 @@ _opkg_pkg_inst() { _opkg_pkg_new() { local -a upd copts - zparseopts -a upd -D -E -update + zparseopts -a upd -D -E - -update copts=( "$@" ) { (( ! $#_opkg_cache_pkg_new )) || _cache_invalid opkg-pkg-new } && @@ -257,7 +257,7 @@ _opkg_pkg_new() { _opkg_pkg_upgr() { local -a upd copts - zparseopts -a upd -D -E -update + zparseopts -a upd -D -E - -update copts=( "$@" ) { (( ! $#_opkg_cache_pkg_upgr )) || _cache_invalid opkg-pkg-upgr } && diff --git a/Completion/Unix/Command/_7zip b/Completion/Unix/Command/_7zip new file mode 100644 index 000000000..6867d353c --- /dev/null +++ b/Completion/Unix/Command/_7zip @@ -0,0 +1,209 @@ +#compdef 7z 7za 7zr 7zz + +# this covers both the official 7-zip and the now deprecated p7zip (but not the +# p7zip command, which is a gzip-like wrapper) +# +# notes: +# - seemingly all 7zip commands, options, and option arguments are +# case-insensitive. we only partially support this +# - most options only work with certain commands. the html documentation lists +# which ones, but it was so consistently wrong or contradictory that i gave up +# on trying to separate them. do not blindly trust the documentation on this + +local ret=1 +local -a context line state state_descr args +local -A opt_args + +args=( + '*-ai-[specify archives to include]: :->file-refs' + "(2)-an[don't take archive name on command line (with -ai)]" + '-ao-[specify overwrite mode]:overwrite mode:(( + a\:"overwrite existing files without prompt" + s\:"skip extracting files that already exist" + t\:"auto-rename existing files" + u\:"auto-rename extracting files" + ))' + '*-ax-[specify archives to exclude]: :->file-refs' + '-bb-[specify output log level]::log level:(( + 0\:"disable log" + 1\:"show names of processed files" + 2\:"show names of additional files processed internally" + 3\:"show information about additional operations" + ))' + '-bd[disable progress indicator]' + '*-bs-[specify output stream]: :->output-streams' + '-bt[show execution time statistics]' + '*-i-[specify files to include]: :->file-refs' + '*-m-[specify compression method parameter]:method parameter' # @todo complete these + '-o-[specify output directory]:output directory:_files -/' + '-p-[specify password]:password' + "-r-[recurse into subdirectories (or specify)]::recursion method:(( + -\:\"don't recurse into subdirectories\" + 0\:'recurse into subdirectories only for wildcard names' + ))" + '-sa-[specify archive naming mode]:archive naming mode:(( + a\:"always add archive type extension" + e\:"use file name exactly as given" + s\:"add archive type extension only if file name has no extension" + ))' + '-scc-[specify charset for console input/output]: :->charsets-io' + '-scrc-[specify hash function]: :->hash-functions' + '-scs-[specify charset for list files]: :->charsets-listfile' + '-sdel[delete files after adding to archive]' + '-seml-[send archive by e-mail (specify behaviour)]::e-mail behaviour:(( + .\:"delete archive after attaching to e-mail" + ))' + '-sfx-[create SFX archive]:: :->sfx-modules' + '-si-[compress data from stdin (specify file name)]::file name in archive:_files' + '-slt[show technical information]' + '-snc[extract as alternate stream if : in file name]' + '-snh[store hard links as links (tar and WIM only)]' + '-sni[store NTFS security information (WIM only)]' + '-snl[store symbolic links as links (tar and WIM only)]' + "-sns-[store NTFS alternate streams (or specify) (WIM only)]::alternate-streams behaviour:(( + -\:\"don't store NTFS alternate streams\" + ))" + "-snt-[replace trailing dots and spaces in file names (or specify)]::trailing-character behaviour:(( + -\:\"don't replace trailing dots and spaces in file names\" + ))" + '-so[write data to stdout]' + '-spd[disable wildcard matching for file names]' + '-spe[eliminate duplication of root folder]' + '-spf-[use fully qualified (absolute) file paths (or specify)]::absolute-file-path behaviour::(( + 2\:"use full path without leading slash or drive letter" + ))' + '-ssc-[enable case-sensitive mode (or specify)]::case-sensitive mode:(( + -\:"disable case-sensitive mode" + ))' + '-sse[stop archive creation if unable to open input file]' + "-ssp[don't change access time of source files]" + '-ssw[compress files open for writing by other programs]' + '-stl[set archive time stamp from most recently modified file]' + '-stm-[specify CPU thread affinity mask]:affinity mask (hexadecimal)' + '-stx-[exclude specified archive type]: :->archive-types' + '-t-[specify archive type]: :->archive-types' + '-u-[specify update options]:update options' # @todo complete these + '-v-[create volume of specified size]: :_numbers -u bytes "volume size" b k m g' + '-w-[use temporary work directory (or specify)]::work directory:_files -/' + '*-x-[specify files to exclude]: :->file-refs' + '-y[assume yes to all queries]' + '1:command:(( + a\:"add files to archive" + b\:"benchmark" + d\:"delete files from archive" + e\:"extract files from archive (without full paths)" + h\:"calculate hash values for files" + i\:"show information about supported formats" + l\:"list contents of archive" + rn\:"rename files in archive" + t\:"test integrity of archive" + u\:"update files in archive" + x\:"extract files (with full paths)" + ))' + '(-an)2:archive file:_files' + '*: :_files' # @todo complete more specifically, handle list files +) + +_arguments -S : $args && ret=0 + +case $state in + archive-types) + local -a formats=( "${(@f)"$( _call_program 7z-info $words[1] i )"}" ) + formats=( "${(@)formats[(r)*Formats:*,-1]}" ) + formats=( ${formats[2,(r)]} ) + + # 'C' appears in fourth column if compression is supported + [[ ${(L)words[(rn:2:)^-*]} == (a|d|rn|u) ]] && + formats=( ${(M)formats:#???C*} ) + + # new (?) format + if [[ -n ${(M)formats:#*....*} ]]; then + formats=( ${formats/#?(#c28)/} ) + # old/p7zip format + else + formats=( ${formats/#?(#c17)/} ) + fi + formats=( ${formats%%[[:space:]]*} ) + + (( $#formats )) || formats=( 7z bzip2 gzip tar xz zip ) + formats=( ${formats//:/\\:} ) + + # @todo also complete the various -t* and -t# modes + _describe \ + -t formats \ + 'archive type' \ + formats \ + -M 'm:{a-z}={A-Z}' \ + && ret=0 + ;; + + charsets-io) + _describe \ + -t charsets \ + 'character set' \ + '( UTF-8 WIN DOS )' \ + -M 'm:{a-z}={A-Z}' \ + && ret=0 + ;; + + charsets-listfile) + _describe \ + -t charsets \ + 'character set (or Windows code-page number)' \ + '( UTF-8 UTF-16LE UTF-16BE WIN DOS )' \ + -M 'm:{a-z}={A-Z}' \ + && ret=0 + ;; + + file-refs) + # @todo complete this properly + if compset -P 1 '*[@!]'; then + _files && ret=0 + else + _describe -t file-refs 'file-ref type' '( + "@:list file" + "!:file name or wildcard" + )' && ret=0 + fi + ;; + + hash-functions) + local -a hashers=( "${(@f)"$( _call_program 7z-info $words[1] i )"}" ) + hashers=( "${(@)hashers[(r)*Hashers:*,-1]}" ) + hashers=( ${hashers[2,(r)]} ) + hashers=( ${hashers##*[[:space:]]} ) + (( $#hashers )) || hashers=( CRC32 CRC64 SHA1 SHA256 BLAKE2sp ) + hashers+=( \* ) + hashers=( ${hashers//:/\\:} ) + _describe -t hashers 'hash function' hashers -M 'm:{a-z}={A-Z}' && ret=0 + ;; + + output-streams) + if compset -P '?'; then + _describe -t stream-dests 'output stream destination' '( + 0:disabled + 1:stdout + 2:stderr + )' && ret=0 + else + _describe -t stream-types 'output stream type' '( + "e:error messages" + "o:standard output messages" + "p:progress information" + )' && ret=0 + fi + ;; + + sfx-modules) + # sfx modules should be in the same directory as the 7zip executable. on + # some systems they live in some lib directory so we look there too + local -aU sfxes=( + ${${(Q)words[1]}:c:h}/*.sfx(#q.N:t) + ${${(Q)words[1]}:c:P:h}/*.sfx(#q.N:t) + {,/opt,/usr}{,/local}/lib/7zip/*.sfx(#q.N:t) + ) + _describe -t sfx-modules 'SFX modules' sfxes && ret=0 + ;; +esac + +return ret diff --git a/Completion/Unix/Command/_echo b/Completion/Unix/Command/_echo new file mode 100644 index 000000000..e835847c2 --- /dev/null +++ b/Completion/Unix/Command/_echo @@ -0,0 +1,32 @@ +#compdef echo gecho + +local variant +local -a args + +_pick_variant -r variant -b zsh gnu='Free Soft' $OSTYPE --version + +args=( + # these are only interpreted as options when they're the only arg + + gnu-hv + '(-)--help[display help information]' + '(-)--version[display version information]' + + other + '(gnu-hv -E)-e[interpret escape sequences]' + "(gnu-hv -e)-E[don't interpret escape sequences]" + "(gnu-hv)-n[don't output trailing newline]" +) + +case $variant in + gnu) ;; # pass + zsh|openbsd*) + args=( ${args:#(|\(*\))--*} ) + ;; + darwin*|dragonfly*|netbsd*|freebsd*) + args=( ${args:#(|\(*\))(--|-[eE]\[)*} ) + ;; + *) + args=( ) + ;; +esac + +_arguments -s -A '' : $args '*:string:_default' diff --git a/Completion/Unix/Command/_ghostscript b/Completion/Unix/Command/_ghostscript index 2c6f40a35..021668c60 100644 --- a/Completion/Unix/Command/_ghostscript +++ b/Completion/Unix/Command/_ghostscript @@ -1,4 +1,4 @@ -#compdef gs ghostscript +#compdef gs ghostscript gsnd local -a specs names device diff --git a/Completion/Unix/Command/_ip b/Completion/Unix/Command/_ip index 9a7cbd821..0dde5e5f0 100644 --- a/Completion/Unix/Command/_ip +++ b/Completion/Unix/Command/_ip @@ -225,6 +225,7 @@ local -a addr_show_cmds # TODO: broadcast can take + or = _regex_words addr-show-commands "addr show commands" \ 'dev:specify device:$subcmd_dev' \ + 'up:limit display to running devices' \ 's*cope:specify scope for address:$subcmd_scope' \ 't*o:limit to given IP address/prefix:$subcmd_ipaddr' \ 'la*bel:list tags matching glob patter:$subcmd_string' \ @@ -553,6 +554,8 @@ _regex_words options "ip options" \ '-M:family MPLS' \ '-0:link protocol, no networking' \ '-o*neline:output one record per line' \ + '-j*son:output results in JSON' \ + '-p*retty:pretty print JSON' \ '-t*imestamp:display current time when using monitor option' \ '-ts*hort:display current time in shorter format when using monitor option' \ '-r*esolve:use system resolver for DNS names' diff --git a/Completion/Unix/Command/_lua b/Completion/Unix/Command/_lua index 3a1ef4fd7..0a4facbe3 100644 --- a/Completion/Unix/Command/_lua +++ b/Completion/Unix/Command/_lua @@ -1,4 +1,4 @@ -#compdef lua -P lua[0-9.-]## +#compdef lua flua -P lua[0-9.-]## # Complete lua library names. We go out of our way here to support sub-modules # (of the format foo.bar.baz), even though the way `lua -l` handles those isn't diff --git a/Completion/Unix/Command/_man b/Completion/Unix/Command/_man index 28bc12fe7..888d73895 100644 --- a/Completion/Unix/Command/_man +++ b/Completion/Unix/Command/_man @@ -76,7 +76,7 @@ _man() { [[ $variant == (freebsd)* ]] && args+=( '(: -)-h[display help information]' # @todo Could enumerate these - '-m[search manual of specified architecture]:architecture' + '-m+[search manual of specified architecture]:architecture' '-o[use non-localized man pages]' '(-a)-S+[specify manual sections to search]: :->sects' ) @@ -135,7 +135,7 @@ _man() { [[ $variant == openbsd* ]] && args+=( "(${(j< >)modes})-l+[format and display specified file]:*:::manual file:_files" # @todo Could enumerate these - '-S[search manual of specified architecture]:architecture' + '-S+[search manual of specified architecture]:architecture' ) [[ $variant == solaris* ]] && args+=( "(${(j< >)modes})-l[display file locations]" diff --git a/Completion/Unix/Command/_mpc b/Completion/Unix/Command/_mpc index e3383e56d..45b181f55 100644 --- a/Completion/Unix/Command/_mpc +++ b/Completion/Unix/Command/_mpc @@ -380,7 +380,7 @@ local mpccmd="$words[1]" _arguments -C \ '(-q --quiet --no-status -v --verbose)'{-v,--verbose}'[give verbose output]' \ '(-q --quiet --no-status -v --verbose)'{-q,--quiet,--no-status}'[prevent printing song status on completion]' \ - '(-h --host)'{-h,--host=}'[connect to specified host]:_hosts' \ + '(-h --host)'{-h,--host=}'[connect to specified host]: :_hosts' \ '(-p --port)'{-p,--port=}'[connect to server port]:port' \ '(-f --format)'{-f,--format=}'[specify the format of song display]:format string:->formats' \ '(-w --wait)'{-w,--wait}'[wait for operation to finish (e.g. database update)]' \ diff --git a/Completion/Unix/Command/_myrepos b/Completion/Unix/Command/_myrepos index d26c1245b..b667746e8 100644 --- a/Completion/Unix/Command/_myrepos +++ b/Completion/Unix/Command/_myrepos @@ -61,7 +61,7 @@ case $state in "offline:advise mr that it is in offline mode" "online:advise mr that it is in online mode" "remember:remember a command to be run later" - "help:display this help." + "help:display help." ) mr_alias=( diff --git a/Completion/Unix/Command/_sudo b/Completion/Unix/Command/_sudo index c334c6765..18da0f79e 100644 --- a/Completion/Unix/Command/_sudo +++ b/Completion/Unix/Command/_sudo @@ -85,7 +85,7 @@ if [[ $state = normal ]]; then 'options:option:(-s --shell -l --login)' \ 'parameters: :_parameters -g "*export*~*readonly*" -qS=' && ret=0 else - _normal + _normal && ret=0 fi fi diff --git a/Completion/Unix/Command/_tex b/Completion/Unix/Command/_tex index 1a70b5058..c5f0c370c 100644 --- a/Completion/Unix/Command/_tex +++ b/Completion/Unix/Command/_tex @@ -24,6 +24,6 @@ _arguments : \ '-src-specials=-[insert source specials in certain places of the DVI file]:WHERE:_values -s , WHERE cr display hbox math par parend vbox' \ '-translate-file=-[use the TCX file TCXNAME]:TCXNAME:' \ '-8bit[make all characters printable by default]' \ - '-help[display this help and exit]' \ + '-help[display help and exit]' \ '-version[output version information and exit]' \ '*:TeX or LaTeX file:_files -g "*.(tex|TEX|texinfo|texi|dtx)(-.)"' diff --git a/Completion/Unix/Command/_tmux b/Completion/Unix/Command/_tmux index b9c220f17..62b8cdf7c 100644 --- a/Completion/Unix/Command/_tmux +++ b/Completion/Unix/Command/_tmux @@ -1648,16 +1648,22 @@ function __tmux-session-options() { 'display-panes-active-colour:colour for active pane in display-panes' 'display-panes-time:time (in msecs) of display-panes output' 'display-time:time (in msecs) messages are displayed' + 'focus-follows-mouse:select panes when the mouse enters them' 'history-limit:number of copy-mode lines per window' + 'initial-repeat-time:initial repeat-key timeout' 'key-table:default key table' 'lock-after-time:lock sessions after N seconds' 'lock-command:command to run for locking a client' 'message-command-style:status line message command style' + 'message-format:prompt and message area format' 'message-line:status message and command prompt position' 'message-style:status line message style' 'mouse:enable mouse support' 'prefix:primary prefix key' 'prefix2:secondary prefix key' + 'prompt-command-cursor-style:cursor style in vi prompt command mode' + 'prompt-cursor-colour:prompt cursor colour' + 'prompt-cursor-style:prompt cursor style' 'renumber-windows:renumber windows if a window is closed' 'repeat-time:time for multiple commands without prefix-key presses' 'set-titles:try to set xterm window titles' @@ -1729,22 +1735,29 @@ function __tmux-server-options() { tmux_server_options=( 'backspace:set key sent by tmux for backspace' 'buffer-limit:number of buffers kept per session' + 'codepoint-widths:list of override widths for Unicode codepoints' 'command-alias:custom command aliases' 'copy-command:specify the default command when "copy-pipe" is called without arguments' + 'default-client-command:default tmux command with no subcommand' 'default-terminal:default terminal definition string' 'escape-time:set timeout to detect single escape characters (in msecs)' 'editor:specify the command used when tmux runs an editor' 'exit-unattached:make server exit if it has no attached clients' 'exit-empty:exit when there are no active sessions' 'extended-keys:control whether tmux will send extended keys through to the terminal' + 'extended-keys-format:extended-key output format' 'focus-events:request focus events from terminal' + 'get-clipboard:how tmux answers clipboard requests' 'history-file:tmux command history file name' + 'input-buffer-size:input bytes allowed before dropping' 'message-limit:set size of message log per client' + 'prefix-timeout:prefix-key timeout' 'prompt-history-limit:set the number of history items to save in the history file' 'set-clipboard:use esc sequences to set terminal clipboard' 'terminal-features:set terminal features not detected by terminfo' 'terminal-overrides:override terminal descriptions' 'user-keys:set list of user-defined key escape sequences' + 'variation-selector-always-wide:treat Unicode VS16 as always wide' ) _describe -t tmux-server-options 'tmux server option' tmux_server_options } @@ -1800,6 +1813,7 @@ function __tmux-window-options() { 'aggressive-resize:aggressively resize windows' 'allow-passthrough:allow programs in the pane to bypass tmux' 'allow-rename:allow programs to change window titles' + 'allow-set-title:allow apps to set pane titles' 'alternate-screen:allow alternate screen feature to be used' 'automatic-rename-format:format for automatic renames' 'automatic-rename:attempt to automatically rename windows' @@ -1808,6 +1822,9 @@ function __tmux-window-options() { 'copy-mode-current-match-style:set the style of the current search match in copy mode' 'copy-mode-mark-style:set the style of the line containing the mark in copy mode' 'copy-mode-match-style:set the style of search matches in copy mode' + 'copy-mode-position-format:format for the position indicator in copy mode' + 'copy-mode-position-style:style for position indicator in copy mode' + 'copy-mode-selection-style:style for selection in copy mode' 'cursor-colour:set the colour of the cursor' 'cursor-style:set the style of the cursor' 'fill-character:set the character used to fill unused window areas' @@ -1832,13 +1849,21 @@ function __tmux-window-options() { 'pane-border-status:turn border status off or set its position' 'pane-border-style:style of border pane' "pane-colours:an array used to configure tmux's colour palette" + 'pane-scrollbars:pane scrollbar visibility mode' + 'pane-scrollbars-position:side used for pane scrollbars' + 'pane-scrollbars-style:pane scrollbar style' + 'pane-status-current-style:current pane status-line style' + 'pane-status-style:pane status-line style' 'popup-border-lines:set the type of line used to draw popup borders' "popup-border-style:set the style for the popup's border" 'popup-style:set the popup style' "remain-on-exit:don't destroy windows after the program exits" "remain-on-exit-format:set the text shown at bottom of exited panes" 'scroll-on-clear:scroll previous contents into history before clear' + 'session-status-current-style:current session status-line style' + 'session-status-style:session status-line style' 'synchronize-panes:send input to all panes of a window' + 'tiled-layout-max-columns:column limit for the tiled layout' 'window-active-style:style of active window' 'window-size:indicate how to automatically size windows' 'window-status-activity-style:style of status bar activity tag' diff --git a/Completion/Unix/Type/_pspdf b/Completion/Unix/Type/_pspdf index 1df3f860c..3fcc2175f 100644 --- a/Completion/Unix/Type/_pspdf +++ b/Completion/Unix/Type/_pspdf @@ -1,4 +1,4 @@ -#compdef gsbj gsdj gsdj500 gslj gslp gsnd ps2ascii ghostview mgv pstoedit pstotgif +#compdef gsbj gsdj gsdj500 gslj gslp ps2ascii ghostview mgv pstoedit pstotgif local expl ext diff --git a/Completion/X/Command/_nedit b/Completion/X/Command/_nedit index 75ca1bad4..8bf7cac43 100644 --- a/Completion/X/Command/_nedit +++ b/Completion/X/Command/_nedit @@ -1,4 +1,4 @@ -#compdef nedit nedit-nc=nc ncl=nc +#compdef nedit nedit-nc=nc ncl=nc nedit-client=nc local state line expl nedit_common curcontext="$curcontext" ret=1 typeset -A opt_args diff --git a/Completion/Zsh/Command/_compinit b/Completion/Zsh/Command/_compinit new file mode 100644 index 000000000..eed4dacb8 --- /dev/null +++ b/Completion/Zsh/Command/_compinit @@ -0,0 +1,9 @@ +#compdef compinit + +_arguments : \ + '(-i -u)-C[bypass security and dump-file checks]' \ + '-d+[automatically create dump file / specify dump-file path]::dump file:_files' \ + "-D[don't automatically create dump file]" \ + '(-C -u)-i[ignore insecure files]' \ + "(-C -i)-u[don't check for insecure files]" \ + "-w[explain why dump file isn't loaded]" diff --git a/Completion/Zsh/Command/_set b/Completion/Zsh/Command/_set index 27c7f3c7d..720c667a9 100644 --- a/Completion/Zsh/Command/_set +++ b/Completion/Zsh/Command/_set @@ -21,5 +21,5 @@ noglob _arguments -s -S \ {-,+}d[no-globalrcs] {-,+}e[errexit] {-,+}f[no-rcs] {-,+}g[histignorespace] \ {-,+}h[histignoredups] {-,+}i[interactive] {-,+}k[interactivecomments] \ {-,+}l[login] {-,+}m[monitor] {-,+}n[no-exec] {-,+}p[privileged] \ - {-,+}r[restricted] {-,+}t[singlecommand] {-,+}u[no-unset] {-,+}v[verbose] \ + {-,+}t[singlecommand] {-,+}u[no-unset] {-,+}v[verbose] \ {-,+}w[chaselinks] {-,+}x[xtrace] {-,+}y[shwordsplit] diff --git a/Completion/Zsh/Command/_zparseopts b/Completion/Zsh/Command/_zparseopts index ae81937c1..cc5e28a9a 100644 --- a/Completion/Zsh/Command/_zparseopts +++ b/Completion/Zsh/Command/_zparseopts @@ -13,6 +13,7 @@ _arguments -A '-*' : \ '-G[enable GNU-style parsing]' \ '-K[preserve contents of arrays/associations when specs are not matched]' \ '-M[enable mapping among equivalent options with opt1=opt2 spec form]' \ + '-n+[specify program name for usage errors]:program name' \ '-v+[specify array from which to parse options]:array:_parameters -g "*array*"' \ '(-)-[end zparseopts options; specs follow]' \ '*: :->spec' \ diff --git a/Completion/compinit b/Completion/compinit index 60dbb599d..f1280fc60 100644 --- a/Completion/compinit +++ b/Completion/compinit @@ -461,6 +461,7 @@ if [[ -n "$_i_check" ]]; then if ! read -q \ "?zsh compinit: insecure $_i_q, run compaudit for list. Ignore insecure $_i_q and continue [y] or abort compinit [n]? "; then + print -u2 print -u2 "$0: initialization aborted" unfunction compinit compdef unset _comp_dumpfile _comp_secure compprefuncs comppostfuncs \ @@ -468,6 +469,7 @@ Ignore insecure $_i_q and continue [y] or abort compinit [n]? "; then return 1 fi + print -u2 fi fpath=(${fpath:|_i_wdirs}) (( $#_i_wfiles )) && _i_files=( "${(@)_i_files:#(${(j:|:)_i_wfiles%.zwc})}" ) @@ -484,6 +486,8 @@ autoload -RUz compdump compinstall _i_done='' +[[ _i_why -eq 1 ]] && print -ru2 "Using dump file: $_comp_dumpfile" + if [[ -f "$_comp_dumpfile" ]]; then if [[ -n "$_i_check" ]]; then IFS=$' \t' read -rA _i_line < "$_comp_dumpfile" @@ -493,7 +497,7 @@ if [[ -f "$_comp_dumpfile" ]]; then builtin . "$_comp_dumpfile" _i_done=yes elif [[ _i_why -eq 1 ]]; then - print -nu2 "Loading dump file skipped, regenerating" + print -nu2 "Loading dump file skipped" local pre=" because: " if [[ _i_autodump -ne 1 ]]; then print -nu2 $pre"-D flag given" @@ -513,8 +517,9 @@ if [[ -f "$_comp_dumpfile" ]]; then _i_done=yes fi elif [[ _i_why -eq 1 ]]; then - print -u2 "No existing compdump file found, regenerating" + print -u2 "No existing dump file found" fi + if [[ -z "$_i_done" ]]; then typeset -A _i_test @@ -547,6 +552,7 @@ if [[ -z "$_i_done" ]]; then # If autodumping was requested, do it now. if [[ $_i_autodump = 1 ]]; then + [[ _i_why -eq 1 ]] && print -u2 "Regenerating dump file" compdump fi fi diff --git a/Doc/Makefile.in b/Doc/Makefile.in index f68f40a9e..3b68ed61a 100644 --- a/Doc/Makefile.in +++ b/Doc/Makefile.in @@ -84,7 +84,7 @@ Zsh/filelist.yo Zsh/files.yo \ Zsh/func.yo Zsh/grammar.yo Zsh/manual.yo \ Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \ Zsh/modules.yo Zsh/modlist.yo Zsh/modmenu.yo Zsh/manmodmenu.yo $(MODDOCSRC) \ -Zsh/options.yo Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo Zsh/restricted.yo \ +Zsh/options.yo Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo \ Zsh/seealso.yo Zsh/tcpsys.yo Zsh/zftpsys.yo Zsh/zle.yo # ========== DEPENDENCIES FOR BUILDING ========== @@ -121,9 +121,9 @@ zsh.pdf zsh_a4.pdf zsh_us.pdf: $(sdir)/zsh.texi intro.pdf intro.a4.pdf intro.us.pdf: $(sdir)/intro.ms if test $@ = intro.us.pdf || \ { test $@ = intro.pdf && test "$(PAPERSIZE)" = us; }; then \ - pdfroff -mspdf --no-kill-null-pages -P-pletter --pdf-output=$@ $(sdir)/intro.ms; \ + groff -ms -Tpdf -P-pletter $(sdir)/intro.ms > $@; \ else \ - pdfroff -mspdf --no-kill-null-pages -P-pa4 --pdf-output=$@ $(sdir)/intro.ms; \ + groff -ms -Tpdf -P-pa4 $(sdir)/intro.ms > $@; \ fi intro.html: $(sdir)/intro.ms @@ -219,7 +219,7 @@ $(MAN): zmacros.yo zman.yo zsh.1 zshall.1: Zsh/intro.yo Zsh/metafaq.yo Zsh/invoke.yo Zsh/files.yo \ Zsh/filelist.yo Zsh/filelist.yo Zsh/seealso.yo \ - Zsh/compat.yo Zsh/restricted.yo + Zsh/compat.yo zshbuiltins.1: Zsh/builtins.yo diff --git a/Doc/Zsh/arith.yo b/Doc/Zsh/arith.yo index 17eb3cc36..4a0709b27 100644 --- a/Doc/Zsh/arith.yo +++ b/Doc/Zsh/arith.yo @@ -144,7 +144,7 @@ provided by the tt(zsh/mathfunc) module or compare it to the string tt(NaN): example(% zmodload zsh/mathfunc -% (( isnan(0.0 / 0) )) && print is nan +% LPAR()LPAR() isnan+LPAR()0.0 / 0+RPAR() RPAR()RPAR() && print is nan is nan % typeset -F f=nan && [[ $f == NaN ]] && print is nan is nan) diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index c322cee77..c63d66e0c 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -570,8 +570,7 @@ change. The var(flags) may be any of the invocation-time flags described in sectref(Invocation)(zsh), -except that `tt(-o EMACS)' and `tt(-o VI)' may not be used. Flags such -as `tt(+r)'/`tt(+o RESTRICTED)' may be prohibited in some circumstances. +except that `tt(-o EMACS)' and `tt(-o VI)' may not be used. If tt(-c) var(arg) appears in var(flags), var(arg) is evaluated while the requested emulation is temporarily in effect. In this case the emulation diff --git a/Doc/Zsh/compat.yo b/Doc/Zsh/compat.yo index 4d3567d45..df0ace63d 100644 --- a/Doc/Zsh/compat.yo +++ b/Doc/Zsh/compat.yo @@ -1,12 +1,11 @@ -texinode(Compatibility)(Restricted Shell)()(Invocation) +texinode(Compatibility)()()(Invocation) sect(Compatibility) cindex(compatibility) cindex(sh compatibility) cindex(ksh compatibility) Zsh tries to emulate bf(sh) or bf(ksh) when it is invoked as tt(sh) or tt(ksh) respectively; more precisely, it looks at the first -letter of the name by which it was invoked, excluding any initial `tt(r)' -(assumed to stand for `restricted'), and if that is `tt(b)', `tt(s)' or `tt(k)' it +letter of the name by which it was invoked, and if that is `tt(b)', `tt(s)' or `tt(k)' it will emulate bf(sh) or bf(ksh). Furthermore, if invoked as tt(su) (which happens on certain systems when the shell is executed by the tt(su) command), the shell will try to find an alternative name from the tt(SHELL) diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index fbfccf82e..83032b54f 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -167,7 +167,8 @@ change, it is easiest to delete the dump file by hand so that tt(compinit) will re-create it the next time it is run. The check performed to see if there are new functions can be omitted by giving the option tt(-C). In this case the dump file will only be created if -there isn't one already. +there isn't one already. Use option tt(-w) to explain why a dump file +isn't loaded and/or why it's regenerated. The dumping is actually done by another function, tt(compdump), but you will only need to run this yourself if you change the configuration diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 03572bf45..1e088907c 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -4651,6 +4651,79 @@ Same as tt(zmv -C) and tt(zmv -L), respectively. These functions do not appear in the zsh distribution, but can be created by linking tt(zmv) to the names tt(zcp) and tt(zln) in some directory in your tt(fpath). ) +findex(zgetopt) +item(tt(zgetopt) [ tt(-A) var(array) ] [ tt(-l) var(spec) ] [ tt(-n) var(name) ] [ tt(-o) var(spec) ] tt(--) [ var(arg) ... ])( +This is a wrapper around tt(zparseopts) (from tt(zsh/zutil)) which +provides an interface similar to the util-linux implementation of +tt(getopt+LPAR()1+RPAR()) (sometimes called `GNU tt(getopt)'). It +simplifies GNU-style argument parsing (including permutation) and +can make it easier to write functions and scripts with complex APIs, +particularly ones where the order of options is significant. + +The typical usage pattern is as follows: + +example(zgetopt -o abc: -l aaa,bbb,ccc: -- "$@" || return +while (( $# )); do + case $1 in + -a|--aaa+RPAR() ...; shift ;; # handle -a + -b|--bbb+RPAR() ...; shift ;; # handle -b + -c|--ccc+RPAR() ...; shift 2 ;; # handle -c and arg + --+RPAR() ...; shift; break ;; # end of options + esac +done +# handle operands) + +It can also be called as a stand-alone script from other shells +using the more traditional print-and-eval pattern: + +example(args=$( zgetopt -n myscript -o abc: -l aaa,bbb,ccc: -- "$@" ) || return +eval set -- "$args" +while [ $# -ne 0 ]; do ...; done) + +Options: + +startsitem() +sitem(tt(-A var(array)))(When called as a function, assign the parsed +arguments to the named array var(array). Defaults to tt(argv), which +overwrites the caller's positional parameters. Has no meaning when +called as a script, in which case the parsed and quoted arguments are +always printed to standard output. An empty string forces the +printing behaviour in either mode.) +sitem(tt(-l var(spec)))(Specify long options to recognise when +parsing. These should be given using just the option name (no +dashes), suffixed by `tt(:)' or `tt(::)' if it takes a mandatory or +optional argument respectively. Multiple options can be defined +either by separating them by commas or by supplying -l again. +Example: tt(-l foo,bar: -l baz)) +sitem(tt(-n var(name)))(Specify the name to use in the error message +if argument parsing fails. Defaults to the name of the nearest +calling function or the base name of tt($ZSH_ARGZERO). Note that +errors related to the usage of tt(zgetopt) itself are always reported +as coming from tt(zgetopt).) +sitem(tt(-o var(spec)))(Specify short options to recognise when +parsing. These should be given as a single string, in the same format +used by the tt(getopts) built-in or the tt(getopt+LPAR()3+RPAR()) +library function, again using `tt(:)' or `tt(::)' to indicate a +mandatory or optional argument. The spec may be prefixed with `tt(+)' +to indicate that option parsing should stop at the first non-option +argument (equivalent to setting the environment variable +tt(POSIXLY_CORRECT)). Example: tt(-o ab:cd::)) +endsitem() + +At least one of tt(-o) or tt(-l) must be given. The function's own +options should be followed by zero or more arguments to parse. It is +critical that these be separated explicitly by `tt(--)', as in the +above examples, to ensure that the function can accurately +distinguish the arguments it's meant to parse from its own. + +Refer to the manual for util-linux's tt(getopt+LPAR()1+RPAR()) for +more information about the way arguments are parsed and results are +returned. Note however that this function is not intended to be a +complete re-implementation. In particular: it omits all +portability/compatibility features, it doesn't support the +tt(--alternative) option, and it doesn't support abbreviating long +options. +) item(tt(zkbd))( See subref(Keyboard Definition)(above). ) diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo index e75e66a6c..8dbfd1164 100644 --- a/Doc/Zsh/grammar.yo +++ b/Doc/Zsh/grammar.yo @@ -531,7 +531,6 @@ itemiz(Execution of incorrectly positioned loop control structures (tt(continue), tt(break))) itemiz(Attempts to use regular expression with no regular expression module available) -itemiz(Disallowed operations when the tt(RESTRICTED) options is set) itemiz(Failure to create a pipe needed for a pipeline) itemiz(Failure to create a multio) itemiz(Failure to autoload a module needed for a declared shell feature) diff --git a/Doc/Zsh/invoke.yo b/Doc/Zsh/invoke.yo index 9c589b278..b6ed73fe5 100644 --- a/Doc/Zsh/invoke.yo +++ b/Doc/Zsh/invoke.yo @@ -105,8 +105,6 @@ can be stacked after the `tt(-b)' and will take effect as normal. startmenu() menu(Compatibility) -menu(Restricted Shell) endmenu() includefile(Zsh/compat.yo) -includefile(Zsh/restricted.yo) diff --git a/Doc/Zsh/manual.yo b/Doc/Zsh/manual.yo index 8cbe2cfd2..c7882cebd 100644 --- a/Doc/Zsh/manual.yo +++ b/Doc/Zsh/manual.yo @@ -64,7 +64,6 @@ menu(See Also) Invocation menu(Compatibility) -menu(Restricted Shell) Shell Grammar diff --git a/Doc/Zsh/mod_pcre.yo b/Doc/Zsh/mod_pcre.yo index 41fab4475..8458145dd 100644 --- a/Doc/Zsh/mod_pcre.yo +++ b/Doc/Zsh/mod_pcre.yo @@ -66,18 +66,26 @@ while [[ $? -eq 0 ]] do pcre_match -b -n $b[2] -- $string done print -l $accum) -) -enditem() - -If the regular expression contains callouts, these are executed as shell code. -During the execution of the callout, the string the regular expression is -matching against is available in the parameter tt(.pcre.subject). If there is a -non-zero return status from the shell code, the callout does not match. The option tt(-d) uses the alternative breadth-first DFA search algorithm of pcre. This sets tt(match), or the array given with tt(-a), to all the matches found from the same start point in the subject. +If the regular expression contains string callouts, these are executed as +shell code, while numerical callouts are ignored. During the execution of the +callout, the string the regular expression is matching against is available +in the parameter tt(.pcre.subject). The parameter tt(.pcre.pos) contains the +position in that string that is currently being matched against. If there is +a non-zero return status from the shell code, the callout does not match. Note +that callouts are not available in the below -pcre-match test condition. It is +also likely not a good idea to call any pcre related builtins from a callout. As +an example, the following will print out `tt(bar)': + +example(pcre_compile 'foo+LPAR()?C"echo ${.pcre.subject[${.pcre.pos},-1]}"+RPAR()' +pcre_match foobar) +) +enditem() + The tt(zsh/pcre) module makes available the following test condition: startitem() diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index 06b953f69..62f87fc28 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -230,7 +230,7 @@ item(tt(zregexparse))( This implements some internals of the tt(_regex_arguments) function. ) findex(zparseopts) -item(tt(zparseopts) [ tt(-D) tt(-E) tt(-F) tt(-G) tt(-K) tt(-M) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] [ tt(-v) var(argv) ] [ tt(-) ] var(spec) ...)( +item(tt(zparseopts) [ tt(-DEFGKM) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] [ tt(-n) var(name) ] [ tt(-v) var(argv) ] [ tt(-) ] var(spec) ...)( This builtin simplifies the parsing of options in positional parameters, i.e. the set of arguments given by tt($*). Each var(spec) describes one option and must be of the form `var(opt)[tt(=)var(array)]'. If an option @@ -239,7 +239,11 @@ into the var(array) specified with the tt(-a) option; if the optional `tt(=)var(array)' is given, it is instead copied into that array, which should be declared as a normal array and never as an associative array. -Note that it is an error to give any var(spec) without an +At least one var(spec) must be given. If a single spec is given which +is either an empty string or a single hyphen (as in +tt(zparseopts -DF '')), it signifies that no options are recognised. +(This is useful for future-proofing functions that might gain options +later.) Otherwise, it is an error to give any var(spec) without an `tt(=)var(array)' unless one of the tt(-a) or tt(-A) options is used. Unless the tt(-E) option is given, parsing stops at the first string @@ -298,10 +302,11 @@ ambiguities may arise when at least one overlapping var(spec) takes an argument, as in `tt(-foo: -foobar)'. In that case, the last matching var(spec) wins. (This is not an issue with GNU-style parsing.) -The options of tt(zparseopts) itself cannot be stacked because, for -example, the stack `tt(-DEK)' is indistinguishable from a var(spec) for -the GNU-style long option `tt(-)tt(-DEK)'. The options of tt(zparseopts) -itself are: +In order to distinguish GNU-style long option var(spec)s from +tt(zparseopts)'s own options, they em(must) be preceded by a `tt(-)', +`tt(--)', or short option tt(spec), as in tt(zparseopts -Ga opts - -foo). + +The options of tt(zparseopts) itself are: startitem() item(tt(-a) var(array))( @@ -386,11 +391,20 @@ item(tt(-M))( This changes the assignment rules to implement a map among equivalent option names. If any var(spec) uses the `tt(=)var(array)' form, the string var(array) is interpreted as the name of another var(spec), -which is used to choose where to store the values. If no other var(spec) +which is used to choose where to store the values. +Values stored in an associative array (tt(-A)) use the name of the +mapped-to option, whereas values stored in an array use the last +as-given option name. If no other var(spec) is found, the values are stored as usual. This changes only the way the values are stored, not the way tt($*) is parsed, so results may be unpredictable if the `var(name)tt(+)' specifier is used inconsistently. ) +item(tt(-n) var(name))( +If this option is given, var(name) is used when printing usage errors +intended for the end user. Otherwise, the name of the calling function +or script is used. Error messages arising from misusage of tt(zparseopts) +itself are not affected by this option. +) item(tt(-v) var(argv))( With this option, the elements of the named array var(argv) are used as the positional parameters to parse, rather than those given by tt($*). The @@ -433,4 +447,12 @@ to have the effect of example(foo=(-a) bar=(-a '' -b xyz)) ) + +The following is a useful general-purpose pattern: + +example(local -A opts +zparseopts -DFGA opts - x -long: || return +(( $+opts[-x] )) && ... # handle -x +(( $+opts[--long] )) && ... # handle --long, optarg in $opts[--long] +) enditem() diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index a7e862c70..77dfb3fdb 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -1837,8 +1837,8 @@ pindex(NOLOCALOPTIONS) item(tt(LOCAL_OPTIONS) <K>)( If this option is set at the point of return from a shell function, most options (including this one) which were in force upon entry to -the function are restored; options that are not restored are -tt(PRIVILEGED) and tt(RESTRICTED). Otherwise, only this option, +the function are restored; the tt(PRIVILEGED) option is not restored. +Otherwise, only this option, and the tt(LOCAL_LOOPS), tt(XTRACE) and tt(PRINT_EXIT_VALUE) options are restored. Hence if this is explicitly unset by a shell function the other options in force at the point of return will remain so. @@ -2466,16 +2466,6 @@ tt(-m) option of tt(setopt) and tt(unsetopt), and changing it inside a function always changes it globally regardless of the tt(LOCAL_OPTIONS) option. ) -pindex(RESTRICTED) -pindex(NO_RESTRICTED) -pindex(NORESTRICTED) -cindex(restricted shell) -item(tt(RESTRICTED) (tt(-r)))( -Enables restricted mode. This option cannot be changed using -tt(unsetopt), and setting it inside a function always changes it -globally regardless of the tt(LOCAL_OPTIONS) option. See -sectref(Restricted Shell)(zsh). -) pindex(SHIN_STDIN) pindex(NO_SHIN_STDIN) pindex(SHINSTDIN) diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index ecedc3862..8fdc7353f 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1175,6 +1175,9 @@ the argument passed to the option. Otherwise it is not set. vindex(ZSH_EXEPATH) item(tt(ZSH_EXEPATH))( Full pathname of the executable file of the current zsh process. +This value should be accurate on Linux, macOS, FreeBSD, DragonflyBSD, +NetBSD, Solaris, Cygwin, and their derivatives. On other systems, it is +determined from tt(argv[0]), which is not always accurate. ) vindex(ZSH_NAME) item(tt(ZSH_NAME))( diff --git a/Doc/Zsh/restricted.yo b/Doc/Zsh/restricted.yo deleted file mode 100644 index a84fd28ea..000000000 --- a/Doc/Zsh/restricted.yo +++ /dev/null @@ -1,84 +0,0 @@ -texinode(Restricted Shell)()(Compatibility)(Invocation) -sect(Restricted Shell) -cindex(restricted shell) -pindex(RESTRICTED) -When the basename of the command used to invoke zsh starts with the letter -`tt(r)' or the `tt(-r)' command line option is supplied at invocation, the -shell becomes restricted. Emulation mode is determined after stripping the -letter `tt(r)' from the invocation name. The following are disabled in -restricted mode: - -startitemize() -itemiz(changing directories with the tt(cd) builtin) -itemiz(changing or unsetting the tt(EGID), tt(EUID), tt(GID), -tt(HISTFILE), tt(HISTSIZE), tt(IFS), tt(LD_AOUT_LIBRARY_PATH), -tt(LD_AOUT_PRELOAD), tt(LD_LIBRARY_PATH), tt(LD_PRELOAD), -tt(MODULE_PATH), tt(module_path), tt(PATH), tt(path), tt(SHELL), -tt(UID) and tt(USERNAME) parameters) -itemiz(specifying command names containing tt(/)) -itemiz(specifying command pathnames using tt(hash)) -itemiz(redirecting output to files) -itemiz(using the tt(exec) builtin command to replace the shell with another -command) -itemiz(using tt(jobs -Z) to overwrite the shell process' argument and -environment space) -itemiz(using the tt(ARGV0) parameter to override tt(argv[0]) for external -commands) -itemiz(turning off restricted mode with tt(set +r) or tt(unsetopt -RESTRICTED)) -enditemize() - -These restrictions are enforced after processing the startup files. The -startup files should set up tt(PATH) to point to a directory of commands -which can be safely invoked in the restricted environment. They may also -add further restrictions by disabling selected builtins. - -Restricted mode can also be activated any time by setting the -tt(RESTRICTED) option. This immediately enables all the restrictions -described above even if the shell still has not processed all startup -files. - -A shell em(Restricted Mode) is an outdated way to restrict what users may -do: modern systems have better, safer and more reliable ways to -confine user actions, such as em(chroot jails), em(containers) and -em(zones). - -A restricted shell is very difficult to implement safely. The feature -may be removed in a future version of zsh. - -It is important to realise that the restrictions only apply to the shell, -not to the commands it runs (except for some shell builtins). While a -restricted shell can only run the restricted list of commands accessible -via the predefined `tt(PATH)' variable, it does not prevent those -commands from running any other command. - -As an example, if `tt(env)' is among the list of em(allowed) commands, -then it allows the user to run any command as `tt(env)' is not a shell -builtin command and can run arbitrary executables. - -So when implementing a restricted shell framework it is important to be -fully aware of what actions each of the em(allowed) commands or features -(which may be regarded as em(modules)) can perform. - -Many commands can have their behaviour affected by environment -variables. Except for the few listed above, zsh does not restrict -the setting of environment variables. - -If a `tt(perl)', `tt(python)', `tt(bash)', or other general purpose -interpreted script is treated as a restricted -command, the user can work around the restriction by -setting specially crafted `tt(PERL5LIB)', `tt(PYTHONPATH)', -`tt(BASH_ENV)' (etc.) environment variables. On GNU systems, any -command can be made to run arbitrary code when performing character set -conversion (including zsh itself) by setting a `tt(GCONV_PATH)' -environment variable. Those are only a few examples. - -Bear in mind that, contrary to some other shells, `tt(readonly)' is not a -security feature in zsh as it can be undone and so cannot be used to -mitigate the above. - -A restricted shell only works if the allowed commands are few -and carefully written so as not to grant more access to users than -intended. It is also important to restrict what zsh module the user may -load as some of them, such as `tt(zsh/system)', `tt(zsh/mapfile)' and -`tt(zsh/files)', allow bypassing most of the restrictions. diff --git a/Doc/intro.ms b/Doc/intro.ms index 49f6cc07f..cb1775490 100644 --- a/Doc/intro.ms +++ b/Doc/intro.ms @@ -47,6 +47,7 @@ .de Sh .NH .XN \\$1 +.pdfbookmark 1 \\*[SN-DOT] \\$1 .. .\} .\" diff --git a/Functions/Misc/zgetopt b/Functions/Misc/zgetopt new file mode 100755 index 000000000..718381cbd --- /dev/null +++ b/Functions/Misc/zgetopt @@ -0,0 +1,178 @@ +#!/bin/zsh -f + +# wrapper around zparseopts which gives it an interface similar to util-linux's +# getopt(1). see zshcontrib(1) for documentation + +emulate -L zsh -o extended_glob +zmodload -i zsh/zutil || return 3 + +local caller=${funcstack[2]:-${ZSH_ARGZERO:t}} +local errname=$caller:${0:t} +local optspec pat i posix=0 +local -a match mbegin mend optvv argvv +local -a array lopts sopts name +local -a specs no_arg_opts req_arg_opts opt_arg_opts tmp + +# same as leading + in short-opts spec +(( $+POSIXLY_CORRECT )) && posix=1 + +zparseopts -n $errname -D -F -G - \ + {A,-array}:-=array \ + {l,-longoptions,-long-options}+:-=lopts \ + {n,-name}:-=name \ + {o,-options}:-=sopts \ +|| { + print -ru2 "usage: ${0:t} [-A <array>] [-l <spec>] [-n <name>] [-o <spec>] -- <arg> ..." + return 2 +} + +name=( ${(@)name/#(-n|--name=)/} ) +[[ -n $name ]] || name=( $caller ) + +(( $#array )) && array=( "${(@)array/#(-A|--array=)/}" ) + +if [[ $zsh_eval_context[-1] == shfunc ]]; then + [[ $array == *[^A-Za-z0-9_.]* ]] && { + print -ru2 - "$errname: invalid array name: $array" + return 2 + } + (( $#array )) || array=( argv ) + +elif [[ -n $array ]]; then + print -ru2 - "$errname: -A option not meaningful unless called as function" + return 2 +fi + +# getopt requires a short option spec; we'll require either short or long +(( $#sopts || $#lopts )) || { + print -ru2 - "$errname: missing option spec" + return 2 +} + +optspec=${(@)sopts/#(-o|--options=)/} +sopts=( ) + +for (( i = 1; i <= $#optspec; i++ )); do + # leading '+': act POSIXLY_CORRECT + if [[ $i == 1 && $optspec[i] == + ]]; then + posix=1 + # leading '-': should leave operands interspersed with options, but this is + # not really possible with zparseopts + elif [[ $i == 1 && $optspec[i] == - ]]; then + print -ru2 - "$errname: optspec with leading - (disable operand collection) not supported" + return 2 + # special characters: [+=\\] because they're special to zparseopts, ':' + # because it's special to getopt, '-' because it's the parsing terminator + elif [[ $optspec[i] == [+:=\\-] ]]; then + print -ru2 - "$errname: invalid short-option name: $optspec[i]" + return 2 + # 'a' + elif [[ $optspec[i+1] != : ]]; then + sopts+=( $optspec[i] ) + # 'a:' + elif [[ $optspec[i+2] != : ]]; then + sopts+=( $optspec[i]: ) + (( i += 1 )) + # 'a::' + elif [[ $optspec[i+3] != : ]]; then + sopts+=( $optspec[i]:: ) + (( i += 2 )) + fi +done + +lopts=( ${(@)lopts/#(-l|--long(|-)options=)/} ) +lopts=( ${(@s<,>)lopts} ) + +# don't allow characters that are special to zparseopts in long-option specs. +# see above +pat='(*[+=\\]*|:*|*:::##|*:[^:]*)' +[[ -n ${(@M)lopts:#$~pat} ]] && { + print -ru2 - "$errname: invalid long-option spec: ${${(@M)lopts:#$~pat}[1]}" + return 2 +} + +lopts=( ${(@)lopts/#/-} ) +specs=( $sopts $lopts ) + +# used below to identify options with optional optargs +no_arg_opts=( ${(@)${(@M)specs:#*[^:]}/#/-} ) +req_arg_opts=( ${(@)${(@)${(@M)specs:#*[^:]:}/#/-}/%:#} ) +opt_arg_opts=( ${(@)${(@)${(@M)specs:#*::}/#/-}/%:#} ) + +# getopt returns all instances of each option given, so add + +specs=( ${(@)specs/%(#b)(:#)/+$match[1]} ) + +# if we've got nothing now, the user probably gave -o '' or sth. pass an +# explicit '' to zparseopts +(( $#specs )) || specs=( '' ) + +# POSIXLY_CORRECT: stop parsing options after first non-option argument +if (( posix )); then + argvv=( "$@" ) + zparseopts -n $name -a optvv -v argvv -D -F -G - "${(@)specs}" || return 1 + +# default: permute options following non-option arguments +else + zparseopts -n $name -a optvv -D -E -F -G - "${(@)specs}" || return 1 + # -D + -E leaves an explicit -- in argv where-ever it might appear + local seen + while (( $# )); do + [[ -z $seen && $1 == -- ]] && seen=1 && shift && continue + argvv+=( "$1" ) + shift + done +fi + +# getopt outputs all optargs as separate parameters, even missing optional ones, +# so we scan through and add/separate those if needed +(( $#opt_arg_opts )) && { + local cur next + local -a old_optvv=( "${(@)optvv}" ) + optvv=( ) + + for (( i = 1; i <= $#old_optvv; i++ )); do + cur=$old_optvv[i] + next=$old_optvv[i+1] + # option with no optarg + if [[ -n ${no_arg_opts[(r)$cur]} ]]; then + optvv+=( $cur ) + # option with required optarg -- will appear in next element + elif [[ -n ${req_arg_opts[(r)$cur]} ]]; then + optvv+=( $cur "$next" ) + (( i++ )) + # long option with optional optarg -- will appear in same element delimited + # by = (even if missing) + elif [[ $cur == *=* && -n ${opt_arg_opts[(r)${cur%%=*}]} ]]; then + optvv+=( ${cur%%=*} "${cur#*=}" ) + # short option with optional optarg -- will appear in same element with no + # delimiter (thus the option appears alone if the optarg is missing) + elif [[ -n ${opt_arg_opts[(r)${(M)cur#-?}]} ]]; then + optvv+=( ${(M)cur#-?} "${cur#-?}" ) + # ??? + else + print -ru2 - "$errname: parse error, please report!" + print -ru2 - "$errname: specs: ${(j< >)${(@q+)specs}}" + print -ru2 - "$errname: old_optvv: ${(j< >)${(@q+)old_optvv}}" + print -ru2 - "$errname: cur: $cur" + optvv+=( $cur ) # i guess? + fi + done +} + +# called as function, assign to array. use EXIT trap to assign in caller's +# context +if [[ -n $array ]]; then + trap "$array=( ${(j< >)${(@q+)optvv}} -- ${(j< >)${(@q+)argvv}} )" EXIT + +# called as function, print +elif [[ $zsh_eval_context[-1] == shfunc ]]; then + print -r - "${(@q+)optvv}" -- "${(@q+)argvv}" + +# called as a script, print. use unconditional single-quoting. this is ugly but +# it's the closest to what getopt does and it offers compatibility with legacy +# shells +else + print -r - "${(@qq)optvv}" -- "${(@qq)argvv}" +fi + +return 0 @@ -20,8 +20,8 @@ The parameter expansion flag ! was added for the referred-to name of a named reference. The parameter ZSH_EXEPATH expands to the full path of the current zsh -process, reliably on Linux, Mac, {Net,Free,Dragonfly}BSD and falls -back to argv[0] elsewhere. +process, reliably on Linux, Mac, {Net,Free,Dragonfly}BSD, Solaris, and +Cygwin, and falls back to argv[0] elsewhere. The default keymap is now emacs. Users of the vi keymaps please check README to see if you are affected. @@ -54,11 +54,23 @@ NTP, etc. For the most part this is transparent to users. However, as a side effect, some features like $SECONDS and the time keyword gained (nominal) nanosecond precision. -The zsh/zutil module's zparseopts builtin learnt a -v option which can -be used to specify the array of arguments to parse instead of $@. +The zsh/zutil module's zparseopts builtin learnt the following: -The zparseopts builtin also learnt a -G option which enables GNU-style -argument parsing ('--opt=arg', etc.). + - a new -G option enables GNU-style argument parsing + ('--opt=arg', etc.) + + - a new -n option sets the program name for usage errors + + - a new -v option specifies the array of arguments to parse instead + of $@ + + - a single empty option spec signifies that no options are recognised + +Also, zparseopts now uses standard argument parsing for its own options, +enabling support for option stacking (-DFG instead of -D -F -G). + +A new contrib function zgetopt was added. It wraps `zparseopts -G` to +provide an interface similar to util-linux's getopt(1). The module zsh/pcre has been updated to use the pcre2 library. @@ -52,6 +52,11 @@ or, if your $VISUAL and $EDITOR environment variables vary, to your .zshrc file. These snippets are compatible with previous versions of the shell. +Restricted mode has been removed. This was associated with the option +RESTRICTED (-r). This was an outdated way to restrict what users may do and +was very difficult to apply safely. Furthermore, modern systems have better, +safer and more reliable ways to confine user actions. + The ERR_EXIT and ERR_RETURN options were refined to be more self- consistent and better aligned with the POSIX-2017 specification of `set -e`: @@ -136,6 +141,14 @@ The typeset builtin now prints the floating-point values NaN, Inf, and -Inf using that capitalisation, which matches the capitalisation used by arithmetic expansion. (Previously they were printed in lowercase.) +The zsh/zutil module's zparseopts builtin now always uses the last +option name as given when storing it in an array. (Previously, options +mapped with -M would sometimes be stored using the first name given.) + +Also, as a consequence of the zparseopts builtin now using standard +argument parsing for its own options, long-option specs must be guarded +using -- or similar. + Incompatibilities between 5.8.1 and 5.9 --------------------------------------- diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c index 7d1720de5..34f577e30 100644 --- a/Src/Modules/db_gdbm.c +++ b/Src/Modules/db_gdbm.c @@ -150,7 +150,7 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) * We need to do this before attempting to open the DB * in case this variable is already tied to a DB. * - * This can fail if the variable is readonly or restricted. + * This can fail if the variable is readonly. * We could call unsetparam() and check errflag instead * of the return status. */ diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 779dcd024..66483ad24 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -150,17 +150,12 @@ scanpmparameters(UNUSED(HashTable ht), ScanFunc func, int flags) static void setpmcommand(Param pm, char *value) { - if (isset(RESTRICTED)) { - zwarn("restricted: %s", value); - zsfree(value); - } else { - Cmdnam cn = zshcalloc(sizeof(*cn)); + Cmdnam cn = zshcalloc(sizeof(*cn)); - cn->node.flags = HASHED; - cn->u.cmd = value; + cn->node.flags = HASHED; + cn->u.cmd = value; - cmdnamtab->addnode(cmdnamtab, ztrdup(pm->node.nam), &cn->node); - } + cmdnamtab->addnode(cmdnamtab, ztrdup(pm->node.nam), &cn->node); } /**/ diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c index 67157cc01..98b52f8de 100644 --- a/Src/Modules/pcre.c +++ b/Src/Modules/pcre.c @@ -134,7 +134,7 @@ pcre_callout(pcre2_callout_block_8 *block, UNUSED(void *callout_data)) Eprog prog; int ret=0; - if (!block->callout_number && + if (!block->callout_number && block->callout_string && ((prog = parse_string((char *) block->callout_string, 0)))) { int ef = errflag, lv = lastval; diff --git a/Src/Modules/watch.c b/Src/Modules/watch.c index bb27ab9db..f23819b25 100644 --- a/Src/Modules/watch.c +++ b/Src/Modules/watch.c @@ -695,8 +695,10 @@ static struct builtin bintab[] = { }; static struct paramdef partab[] = { - PARAMDEF("WATCH", PM_SCALAR|PM_SPECIAL, &watch, NULL), - PARAMDEF("watch", PM_ARRAY|PM_SPECIAL, &watch, NULL), + PARAMDEF("WATCH", PM_SCALAR|PM_SPECIAL|PM_TIED, &watch, + NULL /* &colonarr_gsu (see setup_()) */), + PARAMDEF("watch", PM_ARRAY|PM_SPECIAL|PM_TIED, &watch, + NULL /* &vararray_gsu (see setup_() */), }; static struct features module_features = { @@ -739,15 +741,6 @@ boot_(UNUSED(Module m)) { static char const * const default_watchfmt = DEFAULT_WATCHFMT; - Param pma = (Param) paramtab->getnode(paramtab, "watch"); - Param pms = (Param) paramtab->getnode(paramtab, "WATCH"); - if (pma && pms && pma->u.arr == watch && pms->u.arr == watch) { - /* only tie the two parameters if both were added */ - pma->ename = "WATCH"; - pms->ename = "watch"; - pma->node.flags |= PM_TIED; - pms->node.flags |= PM_TIED; - } watch = mkarray(NULL); /* These two parameters are only set to defaults if not set. diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 9e1eabcf1..7be25d306 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1654,9 +1654,9 @@ add_opt_val(Zoptdesc d, char *arg) if (!v) { v = (Zoptval) zhalloc(sizeof(*v)); v->next = v->onext = NULL; - v->name = n; new = 1; } + v->name = n; // insert the last given name into arrays v->arg = arg; if ((d->flags & ZOF_ARG) && !(d->flags & (ZOF_OPT | ZOF_SAME))) { v->str = NULL; @@ -1735,11 +1735,12 @@ zalloc_default_array(char ***aval, char *assoc, int keep, int num) } static int -bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) +bin_zparseopts(char *nam, char **args, Options ops, UNUSED(int func)) { char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np; char *paramsname = NULL, **params; - int del = 0, flags = 0, extract = 0, fail = 0, gnu = 0, keep = 0; + char *progname = scriptname ? scriptname : (argzero ? argzero : nam); + int flags = 0, del, extract, fail, gnu, keep; Zoptdesc sopts[256], d; Zoptarr a, defarr = NULL; Zoptval v; @@ -1748,133 +1749,61 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) opt_arrs = NULL; memset(sopts, 0, 256 * sizeof(Zoptdesc)); - while ((o = *args++)) { - if (*o == '-') { - switch (o[1]) { - case '\0': - o = NULL; - break; - case '-': - if (o[2]) - args--; - /* else unreachable, default parsing removes "--" */ - o = NULL; - break; - case 'D': - if (o[2]) { - args--; - o = NULL; - break; - } - del = 1; - break; - case 'E': - if (o[2]) { - args--; - o = NULL; - break; - } - extract = 1; - break; - case 'F': - if (o[2]) { - args--; - o = NULL; - break; - } - fail = 1; - break; - case 'G': - if (o[2]) { - args--; - o = NULL; - break; - } - gnu = 1; - break; - case 'K': - if (o[2]) { - args--; - o = NULL; - break; - } - keep = 1; - break; - case 'M': - if (o[2]) { - args--; - o = NULL; - break; - } - flags |= ZOF_MAP; - break; - case 'a': - if (defarr) { - zwarnnam(nam, "default array given more than once"); - return 1; - } - if (o[2]) - n = o + 2; - else if (*args) - n = *args++; - else { - zwarnnam(nam, "missing array name"); - return 1; - } - defarr = (Zoptarr) zhalloc(sizeof(*defarr)); - defarr->name = n; - defarr->num = 0; - defarr->vals = defarr->last = NULL; - defarr->next = NULL; - opt_arrs = defarr; - break; - case 'A': - if (assoc) { - zwarnnam(nam, "associative array given more than once"); - return 1; - } - if (o[2]) - assoc = o + 2; - else if (*args) - assoc = *args++; - else { - zwarnnam(nam, "missing array name"); - return 1; - } - break; - case 'v': - if (paramsname) { - zwarnnam(nam, "argv array given more than once"); - return 1; - } - if (o[2]) - paramsname = o + 2; - else if (*args) - paramsname = *args++; - else { - zwarnnam(nam, "missing array name"); - return 1; - } - break; - default: - /* Anything else is an option description */ - args--; - o = NULL; - break; - } - if (!o) { - o = ""; - break; - } - } else { - args--; - break; + del = OPT_ISSET(ops, 'D'); + extract = OPT_ISSET(ops, 'E'); + fail = OPT_ISSET(ops, 'F'); + gnu = OPT_ISSET(ops, 'G'); + keep = OPT_ISSET(ops, 'K'); + flags |= OPT_ISSET(ops, 'M') ? ZOF_MAP : 0; + + if (OPT_ISSET(ops, 'a')) { + if (!*OPT_ARG(ops, 'a')) { + zwarnnam(nam, "missing array name for -a"); + return 1; + } + defarr = (Zoptarr) zhalloc(sizeof(*defarr)); + defarr->name = OPT_ARG(ops, 'a'); + defarr->num = 0; + defarr->vals = defarr->last = NULL; + defarr->next = NULL; + opt_arrs = defarr; + } + if (OPT_ISSET(ops, 'A')) { + if (!*OPT_ARG(ops, 'A')) { + zwarnnam(nam, "missing array name for -A"); + return 1; + } + assoc = OPT_ARG(ops, 'A'); + } + if (OPT_ISSET(ops, 'n')) { + if (!*OPT_ARG(ops, 'n')) { + zwarnnam(nam, "missing program name for -n"); + return 1; + } + progname = OPT_ARG(ops, 'n'); + } + if (OPT_ISSET(ops, 'v')) { + if (!*OPT_ARG(ops, 'v')) { + zwarnnam(nam, "missing array name for -v"); + return 1; } + paramsname = OPT_ARG(ops, 'v'); } - if (!o) { + + params = getaparam((paramsname = paramsname ? paramsname : "argv")); + if (!params) { + zwarnnam(nam, "no such array: %s", paramsname); + return 1; + } + + /* allow a single '' or - spec to signify no options recognised */ + if (*args && !args[1] && (!**args || !strcmp(*args, "-"))) { + args++; + } else if (!*args) { zwarnnam(nam, "missing option descriptions"); return 1; } + while ((o = dupstring(*args++))) { int f = 0; if (!*o) { @@ -1952,11 +1881,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } } - params = getaparam((paramsname = paramsname ? paramsname : "argv")); - if (!params) { - zwarnnam(nam, "no such array: %s", paramsname); - return 1; - } + np = cp = pp = ((extract && del) ? arrdup(params) : params); for (; (o = *pp); pp++) { /* Not an option. With GNU style, this includes '-' */ @@ -1981,9 +1906,9 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) if (!(d = sopts[(unsigned char) *o])) { if (fail) { if (*o != '-' || o > *pp + 1) - zwarnnam(nam, "bad option: -%c", *o); + fprintf(stderr, "%s: bad option: -%c\n", progname, *o); else - zwarnnam(nam, "bad option: -%s", o); + fprintf(stderr, "%s: bad option: -%s\n", progname, o); return 1; } o = NULL; @@ -2002,8 +1927,8 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) (!(d->flags & (ZOF_GNUL | ZOF_GNUS)) && pp[1] && pp[1][0] != '-')) { if (!pp[1]) { - zwarnnam(nam, "missing argument for option: -%s", - d->name); + fprintf(stderr, "%s: missing argument for option: -%s\n", + progname, d->name); return 1; } add_opt_val(d, *++pp); @@ -2045,8 +1970,8 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) (!(d->flags & (ZOF_GNUL | ZOF_GNUS)) && pp[1] && pp[1][0] != '-')) { if (!pp[1]) { - zwarnnam(nam, "missing argument for option: -%s", - d->name); + fprintf(stderr, "%s: missing argument for option: -%s\n", + progname, d->name); return 1; } add_opt_val(d, *++pp); @@ -2134,7 +2059,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) static struct builtin bintab[] = { BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL), - BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL), + BUILTIN("zparseopts", 0, bin_zparseopts, 0, -1, 0, "a:A:DEFGKMn:v:", NULL), BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL), BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL), }; diff --git a/Src/Zle/termquery.c b/Src/Zle/termquery.c index d8be6e49a..bd601735f 100644 --- a/Src/Zle/termquery.c +++ b/Src/Zle/termquery.c @@ -507,8 +507,25 @@ query_terminal(void) { char *tqend = tquery; static seqstate_t states[] = QUERY_STATES; char **f, **flist = getaparam(EXTVAR); + char *envid = getsparam("TERM_PROGRAM"); + int badapple = 0; size_t i; + /* If TERM_PROGRAM is set in the environment, use that and + * skip the XTVERSION query */ + if (envid) { + char *envver; + handle_query(4, NULL, 0, envid, strlen(envid), NULL); + if ((envver = getsparam("TERM_PROGRAM_VERSION"))) { + handle_query(5, NULL, 0, envver, strlen(envver), NULL); + /* Older macOS terminal doesn't consume RGB queries, + * nor does it support truecolor. Given that it's widely + * used, we handle it explicitly. */ + badapple = !strcmp(envid, "Apple_Terminal") && + zstrtol(envver, NULL, 10) < 470; + } + } + for (f = flist; f && *f; f++) if (!strcmp(*f, "-query")) return; /* disable all queries */ @@ -536,7 +553,7 @@ query_terminal(void) { (!strcmp(cterm, "truecolor") || !strcmp(cterm, "24bit"))))) handle_query(3, NULL, 0, NULL, 0, NULL); - else + else if ((i != 4 || !badapple) && (i != 5 || !envid)) struncpy(&tqend, (char *) queries[i], /* collate escape sequences */ sizeof(tquery) - (tqend - tquery)); } diff --git a/Src/builtin.c b/Src/builtin.c index 26de1ab53..4b11aed60 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -841,10 +841,6 @@ bin_cd(char *nam, char **argv, Options ops, int func) { LinkNode dir; - if (isset(RESTRICTED)) { - zwarnnam(nam, "restricted"); - return 1; - } doprintdir = (doprintdir == -1); chasinglinks = OPT_ISSET(ops,'P') || @@ -2250,10 +2246,6 @@ typeset_single(char *cname, char *pname, Param pm, int func, paramtab->printnode(&pm->node, PRINT_INCLUDEVALUE|with_ns); return pm; } - if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerrnam(cname, "%s: restricted", pname); - return pm; - } if ((pm->node.flags & PM_READONLY) && !(off & PM_READONLY) && /* It seems as though these checks should not be specific to * PM_NAMEREF, but changing that changes historic behavior */ @@ -2388,10 +2380,6 @@ typeset_single(char *cname, char *pname, Param pm, int func, if (newspecial != NS_NONE) { Param tpm, pm2; - if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerrnam(cname, "%s: restricted", pname); - return pm; - } if (pm->node.flags & PM_SINGLE) { zerrnam(cname, "%s: can only have a single instance", pname); return pm; @@ -2633,12 +2621,7 @@ typeset_single(char *cname, char *pname, Param pm, int func, pm->gsu.s->setfn(pm, ztrdup("")); break; case PM_INTEGER: - /* - * Restricted integers are dangerous to initialize to 0, - * so don't do that. - */ - if (!(pm->old->node.flags & PM_RESTRICTED)) - pm->gsu.i->setfn(pm, 0); + pm->gsu.i->setfn(pm, 0); break; case PM_EFLOAT: case PM_FFLOAT: @@ -3098,8 +3081,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) for (i = 0; i < paramtab->hsize; i++) { for (pm = (Param) paramtab->nodes[i]; pm; pm = (Param) pm->node.next) { - if (((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) || - (pm->node.flags & PM_UNSET)) + if (pm->node.flags & PM_UNSET) continue; if (pattry(pprog, pm->node.nam)) addlinknode(pmlist, pm); @@ -3857,9 +3839,7 @@ bin_unset(char *name, char **argv, Options ops, int func) for (pm = (Param) paramtab->nodes[i]; pm; pm = next) { /* record pointer to next, since we may free this one */ next = (Param) pm->node.next; - if ((!(pm->node.flags & PM_RESTRICTED) || - unset(RESTRICTED)) && - pattry(pprog, pm->node.nam)) { + if (pattry(pprog, pm->node.nam)) { if (!OPT_ISSET(ops,'n') && (pm->node.flags & PM_NAMEREF) && pm->u.str) unsetparam(pm->u.str); @@ -3912,10 +3892,7 @@ bin_unset(char *name, char **argv, Options ops, int func) */ if (!pm) continue; - else if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerrnam(name, "%s: restricted", pm->node.nam); - returnval = 1; - } else if (ss) { + else if (ss) { if ((pm->node.flags & PM_NAMEREF) && (!(pm = resolve_nameref(pm)) || pm->width)) { /* warning? */ @@ -4317,34 +4294,28 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func)) returnval = 1; break; } else if (ASG_VALUEP(asg)) { - if(isset(RESTRICTED)) { - zwarnnam(name, "restricted: %s", asg->value.scalar); - returnval = 1; - } else { - /* The argument is of the form foo=bar, * - * so define an entry for the table. */ - if(OPT_ISSET(ops,'d')) { - /* shouldn't return NULL if asg->name is not NULL */ - if (*itype_end(asg->name, IUSER, 0)) { - zwarnnam(name, - "invalid character in directory name: %s", - asg->name); - returnval = 1; - continue; - } else { - Nameddir nd = hn = zshcalloc(sizeof *nd); - nd->node.flags = 0; - nd->dir = ztrdup(asg->value.scalar); - } + /* The argument is of the form foo=bar, * + * so define an entry for the table. */ + if (OPT_ISSET(ops, 'd')) { + /* shouldn't return NULL if asg->name is not NULL */ + if (*itype_end(asg->name, IUSER, 0)) { + zwarnnam(name, "invalid character in directory name: %s", + asg->name); + returnval = 1; + continue; } else { - Cmdnam cn = hn = zshcalloc(sizeof *cn); - cn->node.flags = HASHED; - cn->u.cmd = ztrdup(asg->value.scalar); + Nameddir nd = hn = zshcalloc(sizeof *nd); + nd->node.flags = 0; + nd->dir = ztrdup(asg->value.scalar); } - ht->addnode(ht, ztrdup(asg->name), hn); - if(OPT_ISSET(ops,'v')) - ht->printnode(hn, 0); + } else { + Cmdnam cn = hn = zshcalloc(sizeof *cn); + cn->node.flags = HASHED; + cn->u.cmd = ztrdup(asg->value.scalar); } + ht->addnode(ht, ztrdup(asg->name), hn); + if (OPT_ISSET(ops, 'v')) + ht->printnode(hn, 0); } else if (!(hn = ht->getnode2(ht, asg->name))) { /* With no `=value' part to the argument, * * work out what it ought to be. */ diff --git a/Src/exec.c b/Src/exec.c index 7a928a316..47d70b5a9 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -35,8 +35,6 @@ enum { /* Export the variable for "VAR=val cmd ..." */ ADDVAR_EXPORT = 1 << 0, - /* Apply restrictions for variable */ - ADDVAR_RESTRICT = 1 << 1, /* Variable list is being restored later */ ADDVAR_RESTORE = 1 << 2 }; @@ -731,10 +729,6 @@ execute(LinkList args, int flags, int defpath) int eno = 0, ee; arg0 = (char *) peekfirst(args); - if (isset(RESTRICTED) && (strchr(arg0, '/') || defpath)) { - zerr("%s: restricted", arg0); - _exit(1); - } /* If the parameter STTY is set in the command's environment, * * we first run the stty command with the value of this * @@ -755,7 +749,7 @@ execute(LinkList args, int flags, int defpath) /* If ARGV0 is in the commands environment, we use * * that as argv[0] for this external command */ - if (unset(RESTRICTED) && (z = zgetenv("ARGV0"))) { + if ((z = zgetenv("ARGV0"))) { setdata(firstnode(args), (void *) ztrdup(z)); /* * Note we don't do anything with the parameter structure @@ -2588,14 +2582,6 @@ addvars(Estate state, Wordcode pc, int addflags) fputc(' ', xtrerr); } if ((addflags & ADDVAR_EXPORT) && !strchr(name, '[')) { - if ((addflags & ADDVAR_RESTRICT) && isset(RESTRICTED) && - (pm = (Param) paramtab->removenode(paramtab, name)) && - (pm->node.flags & PM_RESTRICTED)) { - zerr("%s: restricted", pm->node.nam); - zsfree(val); - state->pc = opc; - return; - } if (strcmp(name, "STTY") == 0) { zsfree(STTYval); STTYval = ztrdup(val); @@ -2604,7 +2590,7 @@ addvars(Estate state, Wordcode pc, int addflags) opts[ALLEXPORT] = 1; if (isset(KSHARRAYS)) unsetparam(name); - pm = assignsparam(name, val, myflags); + pm = assignsparam(name, val, myflags); opts[ALLEXPORT] = allexp; } else pm = assignsparam(name, val, myflags); @@ -3418,15 +3404,6 @@ execcmd_exec(Estate state, Execcmd_params eparams, shelltime(&shti, &chti, &then, 1); return; } - } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) { - zerrnam("exec", "%s: restricted", - (char *) getdata(firstnode(args))); - lastval = 1; - if (forked) - _realexit(); - if (how & Z_TIMED) - shelltime(&shti, &chti, &then, 1); - return; } /* @@ -3783,10 +3760,6 @@ execcmd_exec(Estate state, Execcmd_params eparams, fixfds(save); execerr(); } - if (isset(RESTRICTED) && IS_WRITE_FILE(fn->type)) { - zwarn("writing redirection not allowed in restricted mode"); - execerr(); - } if (unset(EXECOPT)) continue; switch(fn->type) { @@ -4314,7 +4287,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, } if (type == WC_SIMPLE || type == WC_TYPESET) { if (varspc) { - int addflags = ADDVAR_EXPORT|ADDVAR_RESTRICT; + int addflags = ADDVAR_EXPORT; if (forked) addflags |= ADDVAR_RESTORE; addvars(state, varspc, addflags); @@ -4463,8 +4436,7 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p) tpm = (Param) zshcalloc(sizeof *tpm); tpm->node.nam = ztrdup(pm->node.nam); copyparam(tpm, pm, 0); - } else if (!(pm->node.flags & PM_READONLY) && - (unset(RESTRICTED) || !(pm->node.flags & PM_RESTRICTED))) { + } else if (!(pm->node.flags & PM_READONLY)) { /* * In this case we're just saving parts of * the parameter in a temporary, so use heap allocation @@ -6114,9 +6086,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) /* take care of SUNKEYBOARDHACK but not of EMACS/VI */ if (funcsave->opts[SUNKEYBOARDHACK] != opts[SUNKEYBOARDHACK]) keyboardhackchar = funcsave->opts[SUNKEYBOARDHACK] ? '`' : '\0'; - /* restore all shell options except PRIVILEGED and RESTRICTED */ + /* restore all shell options except PRIVILEGED */ funcsave->opts[PRIVILEGED] = opts[PRIVILEGED]; - funcsave->opts[RESTRICTED] = opts[RESTRICTED]; memcpy(opts, funcsave->opts, sizeof(opts)); emulation = funcsave->emulation; if (init_typtab) diff --git a/Src/init.c b/Src/init.c index 20b8cc7fd..7c3b82461 100644 --- a/Src/init.c +++ b/Src/init.c @@ -255,8 +255,6 @@ loop(int toplevel, int justonce) return LOOP_OK; } -static int restricted; - /* original argv[0]. This is already metafied */ static char *argv0; @@ -494,8 +492,6 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, if (!(optno = optlookup(*argv))) { WARN_OPTION("no such option: %s", *argv); return 1; - } else if (optno == RESTRICTED && toplevel) { - restricted = action; } else if ((optno == EMACSMODE || optno == VIMODE) && !toplevel) { WARN_OPTION("can't change option: %s", *argv); } else { @@ -524,8 +520,6 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, if (!(optno = optlookupc(**argv))) { WARN_OPTION("bad option: -%c", **argv); return 1; - } else if (optno == RESTRICTED && toplevel) { - restricted = action; } else if ((optno == EMACSMODE || optno == VIMODE) && !toplevel) { WARN_OPTION("can't change option: %s", *argv); @@ -1529,12 +1523,10 @@ run_init_scripts(void) void init_misc(char *cmd, char *zsh_name) { -#ifndef RESTRICTED_R - if ( restricted ) -#else - if (*zsh_name == 'r' || restricted) -#endif - dosetopt(RESTRICTED, 1, 0, opts); + if (*zsh_name == 'r') { + zerrnam(zsh_name, "no support for restricted mode"); + exit(1); + } if (cmd) { if (SHIN >= 10) close(SHIN); diff --git a/Src/jobs.c b/Src/jobs.c index 4905ae925..94c0679b1 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -2425,10 +2425,6 @@ bin_fg(char *name, char **argv, Options ops, int func) if (OPT_ISSET(ops,'Z')) { int len; - if(isset(RESTRICTED)) { - zwarnnam(name, "-Z is restricted"); - return 1; - } if(!argv[0] || argv[1]) { zwarnnam(name, "-Z requires one argument"); return 1; @@ -1198,7 +1198,7 @@ gettokstr(int c, int sub) break; } hungetc(e); - if(isnumglob()) { + if (!in_brace_param && isnumglob()) { add(Inang); while ((c = hgetc()) != '>') add(c); diff --git a/Src/module.c b/Src/module.c index 659bc3544..0b5cd5649 100644 --- a/Src/module.c +++ b/Src/module.c @@ -1085,6 +1085,9 @@ addparamdef(Paramdef d) */ switch (PM_TYPE(pm->node.flags)) { case PM_SCALAR: + if (pm->node.flags & PM_TIED) + pm->ename = ztrdup(casemodify(pm->node.nam, CASMOD_LOWER)); + /* fall-through */ case PM_NAMEREF: pm->gsu.s = d->gsu ? (GsuScalar)d->gsu : &varscalar_gsu; break; @@ -1099,6 +1102,8 @@ addparamdef(Paramdef d) break; case PM_ARRAY: + if (pm->node.flags & PM_TIED) + pm->ename = ztrdup(casemodify(pm->node.nam, CASMOD_UPPER)); pm->gsu.a = d->gsu ? (GsuArray)d->gsu : &vararray_gsu; break; diff --git a/Src/options.c b/Src/options.c index 8b13f0c5d..8127ccdca 100644 --- a/Src/options.c +++ b/Src/options.c @@ -240,7 +240,6 @@ static struct optname optns[] = { {{NULL, "rcs", OPT_ALL}, RCS}, {{NULL, "recexact", 0}, RECEXACT}, {{NULL, "rematchpcre", 0}, REMATCHPCRE}, -{{NULL, "restricted", OPT_SPECIAL}, RESTRICTED}, {{NULL, "rmstarsilent", OPT_BOURNE}, RMSTARSILENT}, {{NULL, "rmstarwait", 0}, RMSTARWAIT}, {{NULL, "sharehistory", OPT_KSH}, SHAREHISTORY}, @@ -357,7 +356,7 @@ static short zshletters[LAST_OPT - FIRST_OPT + 1] = { /* o */ 0, /* long option name follows */ /* p */ PRIVILEGED, /* q */ 0, - /* r */ RESTRICTED, + /* r */ 0, /* formerly RESTRICTED */ /* s */ SHINSTDIN, /* t */ SINGLECOMMAND, /* u */ -UNSET, @@ -434,7 +433,7 @@ static short kshletters[LAST_OPT - FIRST_OPT + 1] = { /* o */ 0, /* p */ PRIVILEGED, /* q */ 0, - /* r */ RESTRICTED, + /* r */ 0, /* s */ SHINSTDIN, /* t */ SINGLECOMMAND, /* u */ -UNSET, @@ -727,25 +726,6 @@ optlookupc(char c) return optletters[c - FIRST_OPT]; } -/**/ -static void -restrictparam(char *nam) -{ - Param pm = (Param) paramtab->getnode(paramtab, nam); - - if (pm) { - pm->node.flags |= PM_SPECIAL | PM_RESTRICTED; - return; - } - createparam(nam, PM_SCALAR | PM_UNSET | PM_SPECIAL | PM_RESTRICTED); -} - -/* list of restricted parameters which are not otherwise special */ -static char *rparams[] = { - "SHELL", "HISTFILE", "LD_LIBRARY_PATH", "LD_AOUT_LIBRARY_PATH", - "LD_PRELOAD", "LD_AOUT_PRELOAD", NULL -}; - /* Set or unset an option, as a result of user request. The option * * number may be negative, indicating that the sense is reversed * * from the usual meaning of the option. */ @@ -760,16 +740,7 @@ dosetopt(int optno, int value, int force, char *new_opts) optno = -optno; value = !value; } - if (optno == RESTRICTED) { - if (isset(RESTRICTED)) - return value ? 0 : -1; - if (value) { - char **s; - - for (s = rparams; *s; s++) - restrictparam(*s); - } - } else if(!force && optno == EXECOPT && !value && interact) { + if (!force && optno == EXECOPT && !value && interact) { /* cannot set noexec when interactive */ return -1; } else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN || diff --git a/Src/params.c b/Src/params.c index 001d89788..5fe7107af 100644 --- a/Src/params.c +++ b/Src/params.c @@ -296,18 +296,18 @@ static initparam special_params[] ={ #define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0} IPDEF1("#", pound_gsu, PM_READONLY_SPECIAL), IPDEF1("ERRNO", errno_gsu, PM_UNSET), -IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("HISTSIZE", histsize_gsu, PM_RESTRICTED), +IPDEF1("GID", gid_gsu, PM_DONTIMPORT), +IPDEF1("EGID", egid_gsu, PM_DONTIMPORT), +IPDEF1("HISTSIZE", histsize_gsu, 0), IPDEF1("RANDOM", random_gsu, 0), -IPDEF1("SAVEHIST", savehist_gsu, PM_RESTRICTED), +IPDEF1("SAVEHIST", savehist_gsu, 0), IPDEF1("SECONDS", intseconds_gsu, 0), -IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED), +IPDEF1("UID", uid_gsu, PM_DONTIMPORT), +IPDEF1("EUID", euid_gsu, PM_DONTIMPORT), IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY_SPECIAL), #define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0} -IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED), +IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT), IPDEF2("-", dash_gsu, PM_READONLY_SPECIAL), IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT), IPDEF2("HOME", home_gsu, PM_UNSET), @@ -315,7 +315,7 @@ IPDEF2("TERM", term_gsu, PM_UNSET), IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET), IPDEF2("TERMINFO_DIRS", terminfodirs_gsu, PM_UNSET), IPDEF2("WORDCHARS", wordchars_gsu, 0), -IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT | PM_RESTRICTED), +IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT), IPDEF2("_", underscore_gsu, PM_DONTIMPORT), IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT), IPDEF2("0", argzero_gsu, 0), @@ -396,12 +396,12 @@ IPDEF8("CDPATH", &cdpath, "cdpath", PM_TIED), IPDEF8("FIGNORE", &fignore, "fignore", PM_TIED), IPDEF8("FPATH", &fpath, "fpath", PM_TIED), IPDEF8("MAILPATH", &mailpath, "mailpath", PM_TIED), -IPDEF8("PATH", &path, "path", PM_RESTRICTED|PM_TIED), +IPDEF8("PATH", &path, "path", PM_TIED), IPDEF8("PSVAR", &psvar, "psvar", PM_TIED), IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY_SPECIAL|PM_TIED), /* MODULE_PATH is not imported for security reasons */ -IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED|PM_TIED), +IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_TIED), #define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0} @@ -430,8 +430,8 @@ IPDEF9("psvar", &psvar, "PSVAR", PM_TIED), IPDEF9("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_TIED|PM_READONLY_SPECIAL), -IPDEF9("module_path", &module_path, "MODULE_PATH", PM_TIED|PM_RESTRICTED), -IPDEF9("path", &path, "PATH", PM_TIED|PM_RESTRICTED), +IPDEF9("module_path", &module_path, "MODULE_PATH", PM_TIED), +IPDEF9("path", &path, "PATH", PM_TIED), /* These are known to zsh alone. */ @@ -449,12 +449,12 @@ IPDEF8("CDPATH", &cdpath, NULL, 0), IPDEF8("FIGNORE", &fignore, NULL, 0), IPDEF8("FPATH", &fpath, NULL, 0), IPDEF8("MAILPATH", &mailpath, NULL, 0), -IPDEF8("PATH", &path, NULL, PM_RESTRICTED), +IPDEF8("PATH", &path, NULL, 0), IPDEF8("PSVAR", &psvar, NULL, 0), IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY_SPECIAL), /* MODULE_PATH is not imported for security reasons */ -IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED), +IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT), {{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0}, }; @@ -1110,10 +1110,6 @@ createparam(char *name, int flags) zerr("read-only variable: %s", name); return NULL; } - if ((oldpm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerr("%s: restricted", name); - return NULL; - } if (!(oldpm->node.flags & PM_UNSET) || (oldpm->node.flags & PM_SPECIAL) || /* POSIXBUILTINS horror: we need to retain 'export' flags */ @@ -2702,11 +2698,6 @@ assignstrvalue(Value v, char *val, int flags) zsfree(val); return; } - if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerr("%s: restricted", v->pm->node.nam); - zsfree(val); - return; - } if ((v->pm->node.flags & PM_HASHED) && (v->scanflags & (SCANPM_MATCHMANY|SCANPM_ARRONLY))) { zerr("%s: attempt to set slice of associative array", v->pm->node.nam); @@ -2761,6 +2752,8 @@ assignstrvalue(Value v, char *val, int flags) #endif } } + if (v->end < v->start) + v->end = v->start; else if (v->end > zlen) v->end = zlen; @@ -2872,10 +2865,6 @@ setnumvalue(Value v, mnumber val) zerr("read-only variable: %s", v->pm->node.nam); return; } - if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerr("%s: restricted", v->pm->node.nam); - return; - } switch (PM_TYPE(v->pm->node.flags)) { case PM_SCALAR: case PM_NAMEREF: @@ -2914,11 +2903,6 @@ setarrvalue(Value v, char **val) freearray(val); return; } - if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerr("%s: restricted", v->pm->node.nam); - freearray(val); - return; - } if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED))) { freearray(val); zerr("%s: attempt to assign array value to non-array", @@ -3867,10 +3851,6 @@ unsetparam_pm(Param pm, int altflag, int exp) pm->node.nam); return 1; } - if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) { - zerr("%s: restricted", pm->node.nam); - return 1; - } if (pm->ename && !altflag) altremove = ztrdup(pm->ename); diff --git a/Src/signals.c b/Src/signals.c index 2257f862f..ff9797f35 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -451,7 +451,7 @@ zhandler(int sig) case SIGINT: if (!handletrap(SIGINT)) { - if ((isset(PRIVILEGED) || isset(RESTRICTED)) && + if (isset(PRIVILEGED) && isset(INTERACTIVE) && (noerrexit & NOERREXIT_SIGNAL)) zexit(SIGINT, ZEXIT_SIGNAL); errflag |= ERRFLAG_INT; diff --git a/Test/A06assign.ztst b/Test/A06assign.ztst index 9f779b9a8..af6f889cb 100644 --- a/Test/A06assign.ztst +++ b/Test/A06assign.ztst @@ -133,6 +133,12 @@ >1 2 42 43 44 5 >1 2 42 100 99 5 + array=(1 2 3 4 5) + array[4,2]=(42 43 44) + print $array +0:Replacement of slice with end index preceding start index +>1 2 3 42 43 44 4 5 + # (subsection: append to array) array=( ) @@ -708,6 +714,12 @@ 0:overwrite [-2,-1] characters in short string >ax + a="abcdefgh" + a[6,3]="xyz" + print $a +0:overwrite [6,3] characters in short string +>abcdexyzfgh + a="a" a[-1]="xx" print $a diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index ed25fd7a9..e192d480d 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -788,6 +788,23 @@ 0:${(r...)...} >why?! in?!! goodn name? am?!! I?!!! doing this? + print -r - ${(l<3><->):-} + print -r - ${(l<3><1->):-} + # these cases weren't affected by the fix for this, but just in case + str=abc123xyz + print -r - ${str//<->/.} + print -r - ${str//<1->/.} + arr=( abc 123 xyz ) + print -r - ${arr[(r)<->]} + print -r - ${arr[(r)<1->]} +0:regression test for <-> in flags +>--- +>-1- +>abc.xyz +>abc.xyz +>123 +>123 + array=(I\'m simply putting a brave face on) print ${(j:--:)array} 0:${(j)...} @@ -2864,3 +2881,24 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888 0:regression for workers/53179 unicode ZDOTDIR F:output ignorable as long as not an error *>* + + argv0=/not/a/real/path + exepath=$( + ARGV0=$argv0 $ZTST_testdir/../Src/zsh -fc 'print -r - $ZSH_EXEPATH' + ) + if + [[ $OSTYPE == (darwin|dragonfly|freebsd|netbsd)* ]] || # via library call + [[ $OSTYPE == (cygwin|linux|solaris)* && -e /proc/self ]] # via procfs + then + [[ $exepath == (/*)#/Src/zsh ]] && print -rn 'match: ' + print -r - $exepath + # on any other system without procfs, we should have argv[0] verbatim since + # it's already absolute + elif [[ ! -e /proc/$$ ]]; then + [[ $exepath == $argv0 ]] && print -rn 'match: ' + print -r - $exepath + else + ZTST_skip='ZSH_EXEPATH not reliable' + fi +-:ZSH_EXEPATH +*>match: /* diff --git a/Test/E01options.ztst b/Test/E01options.ztst index 969bd42d5..dcb14e013 100644 --- a/Test/E01options.ztst +++ b/Test/E01options.ztst @@ -1013,24 +1013,6 @@ >one'quoted'expression >anotherquotedexpression -# too lazy to test jobs -Z and ARGV0. - (setopt restricted; cd /) - (setopt restricted; PATH=/bin:/usr/bin) - (setopt restricted; /bin/ls) - (setopt restricted; hash ls=/bin/ls) - (setopt restricted; print ha >outputfile) - (setopt restricted; exec ls) - (setopt restricted; unsetopt restricted) - : -0:RESTRICTED option -?(eval):cd:1: restricted -?(eval):2: PATH: restricted -?(eval):3: /bin/ls: restricted -?(eval):hash:4: restricted: /bin/ls -?(eval):5: writing redirection not allowed in restricted mode -?(eval):exec:6: ls: restricted -?(eval):unsetopt:7: can't change option: restricted - # ' emacs deconfusion fn() { diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst index daf49cd72..ec55e0f95 100644 --- a/Test/V01zmodload.ztst +++ b/Test/V01zmodload.ztst @@ -236,6 +236,17 @@ fi 0d:Autoload a module via a math function + if [[ $mods[(r)zsh/watch] == zsh/watch ]]; then + zmodload -u zsh/watch + WATCH=foo:bar + typeset -p WATCH watch + else + ZTST_skip="zsh/watch module not available" + fi +0:Autoload tied parameters +>typeset -g -T WATCH watch=( foo bar ) +>typeset -g -aT WATCH watch=( foo bar ) + # Test module aliases zmodload -A example=zsh/example diff --git a/Test/V12zparseopts.ztst b/Test/V12zparseopts.ztst index 5736dd3a1..ede45eb7e 100644 --- a/Test/V12zparseopts.ztst +++ b/Test/V12zparseopts.ztst @@ -17,6 +17,35 @@ %test + () { zparseopts -D -F ''; print -r - ${(q+)@} } - foo + () { zparseopts -D -F ''; print -r - ${(q+)@} } -x + () { zparseopts -D -F - ''; print -r - ${(q+)@} } - foo + () { zparseopts -D -F - ''; print -r - ${(q+)@} } -x + () { zparseopts -D -F - -; print -r - ${(q+)@} } - foo + () { zparseopts -D -F - -; print -r - ${(q+)@} } -x +0:zparseopts with empty option spec (no options recognised) +>foo +?(anon): bad option: -x +>-x +>foo +?(anon): bad option: -x +>-x +>foo +?(anon): bad option: -x +>-x + + () { zparseopts -F -- } -x + () { zparseopts -F - } -x + () { zparseopts -F - a } -x + () { zparseopts -F - a } -x + () { zparseopts -F a } -x +1:zparseopts without option specs, without array +?(anon):zparseopts: missing option descriptions +?(anon):zparseopts: missing option descriptions +?(anon):zparseopts: no default array defined: a +?(anon):zparseopts: no default array defined: a +?(anon):zparseopts: no default array defined: a + () { local -a optv zparseopts -a optv - a b: c:- z @@ -65,15 +94,15 @@ } $=1 done 0:zparseopts -F -?(anon):zparseopts:2: bad option: -x +?(anon): bad option: -x >ret: 1, optv: , argv: -a -x -z -?(anon):zparseopts:2: bad option: -x +?(anon): bad option: -x >ret: 1, optv: , argv: -ax -z -?(anon):zparseopts:2: bad option: --x +?(anon): bad option: --x >ret: 1, optv: , argv: -a --x -z -?(anon):zparseopts:2: bad option: -x +?(anon): bad option: -x >ret: 1, optv: , argv: -axy -?(anon):zparseopts:2: bad option: -- +?(anon): bad option: -- >ret: 1, optv: , argv: -a-xy for 1 in '-a 1 2 3' '1 2 3'; do @@ -98,13 +127,20 @@ >ret: 0, opts: -a '' -b 1 -z '', argv: 1 2 3 >ret: 0, opts: -b 1 -z '', argv: 1 2 3 - () { + fn() { local -a optv local -A opts zparseopts -D -M -a optv -A opts - a:=-aaa -aaa: print -r - ret: $?, optv: $optv, opts: "$( order_assoc opts )", argv: $argv - } --aaa foo -a bar 1 2 3 + } + fn -a foo 1 2 3 + fn --aaa foo 1 2 3 + fn --aaa foo -a bar 1 2 3 + fn -a foo --aaa bar 1 2 3 0:zparseopts -M +>ret: 0, optv: -a foo, opts: --aaa foo, argv: 1 2 3 +>ret: 0, optv: --aaa foo, opts: --aaa foo, argv: 1 2 3 +>ret: 0, optv: -a bar, opts: --aaa bar, argv: 1 2 3 >ret: 0, optv: --aaa bar, opts: --aaa bar, argv: 1 2 3 () { @@ -218,7 +254,7 @@ print -r - ret: $?, optv: $optv, argv: $argv } -ab1 -c 0:missing optarg -?(anon):zparseopts:2: missing argument for option: -c +?(anon): missing argument for option: -c >ret: 1, optv: , argv: -ab1 -c for spec in -foo: -foo:- -foo::; do @@ -253,11 +289,11 @@ } --foobar 1 2 3 done 0:zparseopts -G, single parameter, without = -?(anon):zparseopts:2: bad option: --foobar +?(anon): bad option: --foobar >ret: 1, optv: , argv: --foobar 1 2 3 -?(anon):zparseopts:2: bad option: --foobar +?(anon): bad option: --foobar >ret: 1, optv: , argv: --foobar 1 2 3 -?(anon):zparseopts:2: bad option: --foobar +?(anon): bad option: --foobar >ret: 1, optv: , argv: --foobar 1 2 3 for spec in -foo: -foo:- -foo::; do @@ -352,15 +388,15 @@ >ret: 0, gopt: , optv: -foobar, argv: 1 2 3 >ret: 0, gopt: , optv: -foo=bar, argv: 1 2 3 >ret: 0, gopt: , optv: -foobar, argv: 1 2 3 -?(anon):zparseopts:2: bad option: -f +?(anon): bad option: -f >ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 >ret: 0, gopt: -G, optv: -foo bar, argv: 1 2 3 >ret: 0, gopt: -G, optv: -foo bar, argv: 1 2 3 -?(anon):zparseopts:2: bad option: -f +?(anon): bad option: -f >ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 >ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 >ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 -?(anon):zparseopts:2: bad option: -f +?(anon): bad option: -f >ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 >ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 >ret: 0, gopt: -G, optv: -foo=, argv: bar 1 2 3 @@ -382,10 +418,78 @@ done done 0:only -- acts as explicit parsing terminator with -G -?(anon):zparseopts:2: bad option: --baz +?(anon): bad option: --baz >ret: 1, term: -, optv: , argv: --foo x --bar - --baz >ret: 0, term: -, gopt: , optv: --foo, argv: --bar >ret: 0, term: -, gopt: -G, optv: --foo, argv: - --bar >ret: 0, term: --, optv: --foo --bar, argv: x -- --baz >ret: 0, term: --, gopt: , optv: --foo, argv: --bar >ret: 0, term: --, gopt: -G, optv: --foo, argv: --bar + + fn1() { + zparseopts -F - a + } + fn2() { + local -a optv + zparseopts -a optv -F - a + } + fn3() { + local -a optv + zparseopts -a optv -nprog -F - a + zparseopts -a optv -n prog -F - a + } + fn1 -x + fn2 -x + fn3 -x +1:zparseopts -n, internal vs external usage errors +?fn1:zparseopts:1: no default array defined: a +?fn2: bad option: -x +?prog: bad option: -x +?prog: bad option: -x + + () { zparseopts -DF - '' } -x + () { + local -a optv + zparseopts -DFa optv - a + typeset -p optv + } -a +0:zparseopts option stacking +?(anon): bad option: -x +>typeset -a optv=( -a ) + + () { + local -a optv + zparseopts -DFa optv -x + } + () { + local -a optv + zparseopts -DFa optv - -D + typeset -p optv + } --D + () { + local -a optv + zparseopts -DFa optv - -DFa + typeset -p optv + } --DFa +0:zparseopts long-option spec guarding +?(anon):zparseopts:2: bad option: -x +>typeset -a optv=( --D ) +>typeset -a optv=( --DFa ) + + () { zparseopts -a } + () { zparseopts -A } + () { zparseopts -n } + () { zparseopts -v } + () { zparseopts -a '' } + () { zparseopts -A '' } + () { zparseopts -n '' } + () { zparseopts -v '' } +1:zparseopts missing/empty optargs +?(anon):zparseopts: argument expected: -a +?(anon):zparseopts: argument expected: -A +?(anon):zparseopts: argument expected: -n +?(anon):zparseopts: argument expected: -v +?(anon):zparseopts: missing array name for -a +?(anon):zparseopts: missing array name for -A +?(anon):zparseopts: missing program name for -n +?(anon):zparseopts: missing array name for -v diff --git a/Test/X06termquery.ztst b/Test/X06termquery.ztst index 5f3a81aae..701cd625b 100644 --- a/Test/X06termquery.ztst +++ b/Test/X06termquery.ztst @@ -5,6 +5,7 @@ termresp() { setopt localoptions extendedglob export PS1= PS2= COLORTERM= TERM= + typeset +x TERM_PROGRAM typeset +x -m .term.\* zpty -d zpty zsh "${(q)ZTST_testdir}/../Src/zsh -fiV +Z" diff --git a/Test/Y01completion.ztst b/Test/Y01completion.ztst index d7215f381..53d49df37 100644 --- a/Test/Y01completion.ztst +++ b/Test/Y01completion.ztst @@ -144,9 +144,9 @@ F:regression test workers/51641 >line: {: ~[name/1}{]} >line: {: ~[name2}{]} - comptest $'echo ;:\C-b\C-b\t' + comptest $'ls ;:\C-b\C-b\t' 0:directories and files before separator ->line: {echo }{;:} +>line: {ls }{;:} >DESCRIPTION:{file} >DI:{dir1} >DI:{dir2} diff --git a/Test/Y04regexargs.ztst b/Test/Y04regexargs.ztst new file mode 100644 index 000000000..d204fd312 --- /dev/null +++ b/Test/Y04regexargs.ztst @@ -0,0 +1,111 @@ +# Tests for _regex_arguments. + +%prep + if [[ $OSTYPE = cygwin ]]; then + ZTST_unimplemented="the zsh/zpty module does not work on Cygwin" + elif ( zmodload zsh/zpty 2>/dev/null ); then + . $ZTST_srcdir/comptest + mkdir comp.tmp + cd comp.tmp + comptestinit -z $ZTST_testdir/../Src/zsh && + { + word=$'[^\0]#\0' + comptesteval \ + 'compdef _tst tst' \ + 'setopt extended_glob' # running _regex_arguments outside of completion below + tst_regex() { comptesteval "_regex_arguments _tst /$'[^\0]#\0'/ ${${(@q)*}}" } + } + else + ZTST_unimplemented="the zsh/zpty module is not available" + fi + +%test + tst_regex /one/ ':first:first:(one)' + comptesteval "functions _tst >/tmp/hello" + comptest $'tst \t' +0:standalone spec +>line: {tst one }{} + + tst_regex \( /'one '/ ':fixed:fixed:(one)' \| /'two '/ ':second:second:compadd two' \| /'[0-9]## '/ ': _message -e numbers number' \| /'0x[0-9a-f]## '/ ':hex:hex:' \) + comptest $'tst \t' +0:simple alternation, use of _message for description with no matches +>line: {tst }{} +>DESCRIPTION:{fixed} +>NO:{one} +>DESCRIPTION:{second} +>NO:{two} +>DESCRIPTION:{number} + + tst_regex /$'rpc\0'/ \ + \(\ + /"$word"/ ':programs:program:compadd -qS, mountd nisd' \ + \|\ + /$'[^,\0]##,[^,\0]##,'/ /$'[^,\0]##\0'/ ':procedures:procedure:' \ + \|\ + /$'[^,\0]##,'/ /$'[^,\0]##\0'/ ':versions:version:' \ + \) + comptest $'tst rpc m\t\t1,\t' +0:optional fields after a suffix +>line: {tst rpc mountd,}{} +>line: {tst rpc mountd,}{} +>DESCRIPTION:{version} +>line: {tst rpc mountd,1,}{} +>DESCRIPTION:{procedure} + + tst_regex \( /$'[0-9]##,'/ ':numbers:number:compadd -qS, 1 2' \) \# /$'end\0'/ ':end:end:(end)' /next/ ':next:next:(next)' + comptest $'tst \t1\t2,e\t\t' +0:simple repetition, note zero repititions allowed +>line: {tst }{} +>DESCRIPTION:{number} +>NO:{1} +>NO:{2} +>DESCRIPTION:{end} +>NO:{end} +>line: {tst 1,}{} +>line: {tst 1,2,end }{} +>line: {tst 1,2,end next }{} + + tst_regex \( /--/+ /$'(on|fix)='/ $'/[^\0]##\0/' ':names:boolean value:(false true)' \|\ + /"[]"/ ':options:option:compadd -qS= - --on --fix' \) \# /next/ ':next:next:(next)' + comptest $'tst --\ton=t\t\t' +0:non-matching pattern to separate matches from consuming patterns +>line: {tst --}{} +>DESCRIPTION:{option} +>NO:{--fix} +>NO:{--on} +>line: {tst --on=true }{} +>line: {tst --on=true --}{} + + tst_regex \ + \(\ + /$'(true|false)\0'/ -'last=bool' ':names:boolean:(false true)' \ + \|\ + /$'(val|opt)\0'/ -'last=${match[1]%?}' ':opts:option:(val opt)' \ + \) \# \ + /$'[^\0]##\0'/ ':last:last:compadd - $last' + comptest $'tst true \tv\t \tfalse f\t' +0:use guard and $match to reference prior argument +>line: {tst true }{} +>DESCRIPTION:{boolean} +>NO:{false} +>NO:{true} +>DESCRIPTION:{option} +>NO:{opt} +>NO:{val} +>DESCRIPTION:{last} +>NO:{bool} +>line: {tst true val }{} +>line: {tst true val }{} +>DESCRIPTION:{boolean} +>NO:{false} +>NO:{true} +>DESCRIPTION:{option} +>NO:{opt} +>NO:{val} +>DESCRIPTION:{last} +>NO:{val} +>line: {tst true val false false }{} + +%clean + + zmodload -ui zsh/zpty diff --git a/Test/Y05describe.ztst b/Test/Y05describe.ztst new file mode 100644 index 000000000..ee8717a24 --- /dev/null +++ b/Test/Y05describe.ztst @@ -0,0 +1,97 @@ +# tests for _describe + +%prep + + if ( zmodload -s zsh/zpty ); then + source $ZTST_srcdir/comptest + mkdir comp.tmp + cd comp.tmp + comptestinit -z $ZTST_testdir/../Src/zsh && { + comptesteval 'compdef _tst tst' + tst_describe() { comptesteval "_tst() { _describe ${${(@q+)@}} }" } + } + else + ZTST_unimplemented='the zsh/zpty module is not available' + fi + +%test + + tst_describe desc '(a b:descb "c\:c:descc")' + comptest $'tst \t' +0:name1 as (...), description, escaped colon in name +>line: {tst }{} +>DESCRIPTION:{desc} +>NO:{b -- descb} +>NO:{c:c -- descc} +>NO:{a} + + tst_describe desc '(( a b:descb "c\:c:descc" ))' + comptest $'tst \t' +0:name1 as ((...)) not supported +>line: {tst }{} + + tst_describe desc '(a b:descb "c\:c:descc")' '(ax bx:descbx "cx\:cx:desccx")' + comptest $'tst \t\t' +0:name2 as (...) +>line: {tst }{} +>DESCRIPTION:{desc} +>NO:{b -- descb} +>NO:{c:c -- descc} +>NO:{a} +>line: {tst bx}{} + + tst_describe desc '(a b c)' -- '(x y z)' + comptest $'tst \t' +0:multiple groups +>line: {tst }{} +>DESCRIPTION:{desc} +>NO:{a} +>NO:{b} +>NO:{c} +>NO:{x} +>NO:{y} +>NO:{z} + + comptesteval '_tst() { + local -a name1=( a b:descb "c\:c:descc" ) + local -a name2=( ax bx:descbx "cx\:cx:desccx" ) + _describe desc name1 name2 + }' + comptest $'tst \t\t' +0:arrays by name +>line: {tst }{} +>DESCRIPTION:{desc} +>NO:{b -- descb} +>NO:{c:c -- descc} +>NO:{a} +>line: {tst bx}{} + + tst_describe desc '(b c a)' -oreverse + comptest $'tst \t' +0:compadd options, basic +>line: {tst }{} +>DESCRIPTION:{desc} +>NO:{c} +>NO:{b} +>NO:{a} + + tst_describe desc \ + '(b c a)' '(bx cx ax)' -oreverse \ + -- \ + '(y z x)' '(yx zx xx)' -onosort + comptest $'tst \t\t' +0:compadd options, complex +>line: {tst }{} +>DESCRIPTION:{desc} +>NO:{c} +>NO:{b} +>NO:{a} +>DESCRIPTION:{desc} +>NO:{y} +>NO:{z} +>NO:{x} +>line: {tst cx}{} + +%clean + + zmodload -ui zsh/zpty diff --git a/Test/Z04zgetopt.ztst b/Test/Z04zgetopt.ztst new file mode 100644 index 000000000..4de79b417 --- /dev/null +++ b/Test/Z04zgetopt.ztst @@ -0,0 +1,200 @@ +%prep + + if ! zmodload -s zsh/zutil; then + ZTST_unimplemented='the zsh/zutil module is not available' + else + autoload -Uz zgetopt + fi + +%test + + zgetopt -A '' -- a b c + zgetopt -A '' -o '' -- a b c + zgetopt -A '' -l '' -- a b c +0:-o or -l required +?(eval):zgetopt: missing option spec +>-- a b c +>-- a b c + + zgetopt -A '' -o - -- a b c + zgetopt -A '' -o -a -- a b c + zgetopt -A '' -o a- -- a b c + zgetopt -A '' -o a+ -- a b c + zgetopt -A '' -o a= -- a b c + zgetopt -A '' -o a\\ -- a b c + zgetopt -A '' -o :a -- a b c + zgetopt -A '' -o a::: -- a b c + zgetopt -A '' -o '' -- a b c + zgetopt -A '' -o + -- a b c +0:weird short-option specs +?(eval):zgetopt: optspec with leading - (disable operand collection) not supported +?(eval):zgetopt: optspec with leading - (disable operand collection) not supported +?(eval):zgetopt: invalid short-option name: - +?(eval):zgetopt: invalid short-option name: + +?(eval):zgetopt: invalid short-option name: = +?(eval):zgetopt: invalid short-option name: \ +?(eval):zgetopt: invalid short-option name: : +?(eval):zgetopt: invalid short-option name: : +>-- a b c +>-- a b c + + zgetopt -A '' -l a,+ -- a b c + zgetopt -A '' -l a,= -- a b c + zgetopt -A '' -l a,\\ -- a b c + zgetopt -A '' -l a,: -- a b c + zgetopt -A '' -l a,:b -- a b c + zgetopt -A '' -l a,b:b -- a b c + zgetopt -A '' -l a,b::: -- a b c + zgetopt -A '' -l '' -- a b c + zgetopt -A '' -l , -- a b c + zgetopt -A '' -l a,,,,,b -- a b c + zgetopt -A '' -l - -- a b c --- +0:weird long-option specs +?(eval):zgetopt: invalid long-option spec: + +?(eval):zgetopt: invalid long-option spec: = +?(eval):zgetopt: invalid long-option spec: \ +?(eval):zgetopt: invalid long-option spec: : +?(eval):zgetopt: invalid long-option spec: :b +?(eval):zgetopt: invalid long-option spec: b:b +?(eval):zgetopt: invalid long-option spec: b::: +>-- a b c +>-- a b c +>-- a b c +>--- -- a b c + + zgetopt -A '' -o ab:c:: -- a b c + zgetopt -A '' -o ab:c:: -- -a + zgetopt -A '' -o ab:c:: -- -a a b c + zgetopt -A '' -o ab:c:: -- -a a -b c + zgetopt -A '' -o ab:c:: -- -a a -b -c + zgetopt -A '' -o ab:c:: -- -a a -b -c d + zgetopt -A '' -o ab:c:: -- -a a -b -c -c + zgetopt -A '' -o ab:c:: -- -a a -b -c -c d + zgetopt -A '' -o ab:c:: -- -a a -b -c -cd +0:short options +>-- a b c +>-a -- +>-a -- a b c +>-a -b c -- a +>-a -b -c -- a +>-a -b -c -- a d +>-a -b -c -c '' -- a +>-a -b -c -c '' -- a d +>-a -b -c -c d -- a + + zgetopt -A '' -l aaa,bbb:,ccc:: -- a b c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a b c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb=c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc d + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc d + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc= d + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc=d +0:long options +>-- a b c +>--aaa -- +>--aaa -- a b c +>--aaa --bbb c -- a +>--aaa --bbb c -- a +>--aaa --bbb --ccc -- a +>--aaa --bbb --ccc -- a d +>--aaa --bbb --ccc --ccc '' -- a +>--aaa --bbb --ccc --ccc '' -- a d +>--aaa --bbb --ccc --ccc '' -- a d +>--aaa --bbb --ccc --ccc d -- a + + zgetopt -A '' -o '' +0:zero args to parse +>-- + + zgetopt -A '' -o '' -- -- a b c + zgetopt -A '' -o '' -- a b -- c + zgetopt -A '' -o '' -- a b c -- + zgetopt -A '' -o c -- a b -- -c + zgetopt -A '' -o c -- a b - -c +0:parsing terminator +>-- a b c +>-- a b c +>-- a b c +>-- a b -c +>-c -- a b - + + zgetopt -A '' -o a -- a -a b + zgetopt -A '' -o +a -- a -a b + POSIXLY_CORRECT=1 zgetopt -A '' -o a -- a -a b +0:POSIXLY_CORRECT +>-a -- a b +>-- a -a b +>-- a -a b + + zgetopt -A '' -o '' -- 'foo bar' $'bar\tbaz' $'\a\'\a' +0:function-mode quoting style +>-- 'foo bar' $'bar\tbaz' $'\C-G\'\C-G' + + zgetopt -A '' -o '' -- a -a b + zgetopt -A '' -o '' -- a --a b +1:bad options +?(eval): bad option: -a +?(eval): bad option: --a + + zgetopt -A '' -o a: -- a -a + zgetopt -A '' -l a: -- a --a +1:missing optargs +?(eval): missing argument for option: -a +?(eval): missing argument for option: --a + + zgetopt -A '' ; echo $? # missing spec + zgetopt -A '' -o '' -x ; echo $? # bad option to zgetopt + zgetopt -A '' -o '' -- -y; echo $? # bad option to parse +-:return status +*?\(eval\):zgetopt: missing option spec +*>2 +*?\(eval\):zgetopt: bad option: -x +*?usage:* +*>2 +*?\(eval\): bad option: -y +*>1 + + () { zgetopt -o a -- "$@"; typeset -p argv } -a b c + () { local -a v; zgetopt -A v -o a -- "$@"; typeset -p argv v } -a b c +0:array output +>typeset -g -a argv=( -a -- b c ) +>typeset -g -a argv=( -a b c ) +>typeset -a v=( -a -- b c ) + + zgetopt -A '' -o a: -- -x + zgetopt -A '' -o a: -- -a + () { zgetopt -A '' -o a: -- "$@"; : } -x + func() { zgetopt -A '' -o a: -- "$@"; : }; func -x + f1() { zgetopt -A '' -o a: -- "$@"; : }; f2() { f1 "$@" }; f2 -x +0:automatic name +?(eval): bad option: -x +?(eval): missing argument for option: -a +?(anon): bad option: -x +?func: bad option: -x +?f1: bad option: -x + + zgetopt -n aaa -A '' -o a: -- -x + zgetopt -n aaa -A '' -o a: -- -a + () { zgetopt -n bbb -A '' -o a: -- "$@"; : } -x + func() { zgetopt -n ccc -A '' -o a: -- "$@"; : }; func -x + f1() { zgetopt -n ddd -A '' -o a: -- "$@"; : }; f2() { f1 "$@" }; f2 -x +0:manual name with -n +?aaa: bad option: -x +?aaa: missing argument for option: -a +?bbb: bad option: -x +?ccc: bad option: -x +?ddd: bad option: -x + + () { + zgetopt -A '' -n example.bash -o ab:c:: -l a-long,b-long:,c-long:: -- "$@" + } \ + -a --a-long \ + -barg_bs1 -b arg_bs2 --b-long=arg_bl1 --b-long arg_bl2 \ + -carg_cs1 -c not_arg_cs1 --c-long=arg_cl1 --c-long not_arg_cl2 \ + arg_p "string with quotes and space: '' \"\" " +0:example from util-linux's getopt-example.bash +>-a --a-long -b arg_bs1 -b arg_bs2 --b-long arg_bl1 --b-long arg_bl2 -c arg_cs1 -c '' --c-long arg_cl1 --c-long '' -- not_arg_cs1 not_arg_cl2 arg_p 'string with quotes and space: '\'\'' "" ' diff --git a/configure.ac b/configure.ac index dee62dd5e..5002cca8b 100644 --- a/configure.ac +++ b/configure.ac @@ -248,20 +248,6 @@ AC_ARG_ENABLE(dynamic, AS_HELP_STRING([--disable-dynamic],[turn off dynamically loaded binary modules]), [dynamic="$enableval"], [dynamic=yes]) -dnl Do you want to disable restricted on r* commands -ifdef([restricted-r],[undefine([restricted-r])])dnl -AH_TEMPLATE([RESTRICTED_R], -[Undefine this if you don't want to get a restricted shell - when zsh is exec'd with basename that starts with r. - By default this is defined.]) -AC_ARG_ENABLE(restricted-r, -AS_HELP_STRING([--disable-restricted-r],[turn off r* invocation for restricted shell]), -[if test x$enableval = xyes; then - AC_DEFINE(RESTRICTED_R) -fi], -AC_DEFINE(RESTRICTED_R) -) - dnl Do you want to disable use of locale functions AH_TEMPLATE([CONFIG_LOCALE], [Undefine if you don't want local features. By default this is defined.]) |
