diff options
228 files changed, 8184 insertions, 2489 deletions
@@ -1,3 +1,1268 @@ +2017-08-08 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Config/verson.mk, README, Etc/FAQ.yo: update to version + 5.4.1. + + * unposted: back off 41499 as it has side effects which, while + perfectly logical, are not what POSIX expects. + +2017-08-08 Peter Stephenson <p.stephenson@samsung.com> + + * 41510: Doc/Zsh/params.yo: update doc for $ZSH_PATCHLEVEL. + +2017-08-08 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 41481: Completion/Unix/Command/_df, + Completion/Unix/Command/_mount, Completion/Unix/Type/_umountable: + _df: Complete mounted device and mount points. + + * 41486: Completion/Unix/Command/_tmux: Correct completions of + new-window, split-window, respawn-window, respawn-pane. + + * unposted: Config/version.mk: Post-release version number bump + to 5.4-dev-0. + +2017-08-07 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: version 5.4. + + * 41499 (with one further tweak): Src/utils.c, + Doc/Zsh/options.yo, Test/E01options.ztst: With POSIX_STRINGS + ignore terminating separator when splitting. + +2017-08-07 Peter Stephenson <p.stephenson@samsung.com> + + * Anthony: 41500: Doc/Zsh/mod_zutil.yo: document '-' to end + zparseopts options. + +2017-08-05 Oliver Kiddle <opk@zsh.org> + + * 41493: Completion/Unix/Command/_git: fix to not print hash + into terminal and update options for git 2.14 + + * 41492: Completion/BSD/Command/_gstat, + Completion/Unix/Command/_flex, Completion/Unix/Command/_sqlite, + Completion/Unix/Command/_sudo: update options in completions + +2017-08-03 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 41485: Test/A03quoting.ztst: test for previous fix. + + * Martijn: 41484: Src/utils.c: ${(q+)...} didn't properly + quote backslashes. + +2017-08-02 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 41479: Completion/Unix/Command/_xz: Complete compressed, + rather than uncompressed, files after -d. + + * 41475: Completion/Unix/Command/_git: Complete files after + 'reset' when there are no commits, when the 'verbose' style + is set. + +2017-08-01 Peter Stephenson <p.stephenson@samsung.com> + + * 41470: Doc/Zsh/builtins.yo: note that 41464 stops exec finding + other precommand modifiers with POSIX_BUILTINS (for now, at + least). + +2017-08-01 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 41474: Completion/Debian/Command/_pbuilder, + Completion/Debian/Type/_deb_codenames: Fix pbuilder's + --distribution,--architecture completion. + +2017-07-31 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Config/version.mk: test release 5.3.1-test-2. + +2017-07-31 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Completion/Unix/Command/_git: Fix style lookup for + 'max-verbose'. + +2017-07-29 Barton E. Schaefer <schaefer@zsh.org> + + * 41472: Doc/Zsh/contrib.yo, Functions/Prompts/prompt_bart_setup, + Functions/Prompts/prompt_default_setup, + Functions/Prompts/prompt_off_setup, + Functions/Prompts/prompt_restore_setup, + Functions/Prompts/promptinit: introduce cleanup hooks default and + restore special themes, and update documentation + +2017-07-29 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Etc/FAQ.yo, NEWS, README: update in preparation for + 5.4 release. + +2017-07-28 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 41467: Completion/Unix/Command/_tmux, + Completion/Unix/Type/_cmdambivalent, Doc/Zsh/compsys.yo: + Correct completion of 'tmux new <TAB>'. + + * 41471 (tweaked): Completion/Unix/Command/_subversion: _svn: + Complete propvals in 'propset'. + + * 41458: Completion/Unix/Command/_subversion: Don't cache an + empty commands list when svn is not available at the first + invocation of _svn. + +2017-07-26 Peter Stephenson <p.stephenson@samsung.com> + + * 41464, 41466 (modified): Doc/Zsh/builtins.yo, + Doc/Zsh/options.yo, Src/exec.c, Test/E01options.ztst: + POSIX_BUILTINS stops "exec" finding builtins or shell + functions. Document existing behaviour. + + * Jim: 41461: Doc/Zsh/seealso.yo: complete list of zsh manual + pages in introduction. + +2017-07-20 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 41433: Doc/Zsh/expn.yo: Further clarification about expansion + processing. + +2017-07-17 Peter Stephenson <p.stephenson@samsung.com> + + * 41429: Doc/Zsh/expn.yo: Better documentation of how stages of + expansion fit together. + +2017-07-15 Oliver Kiddle <opk@zsh.org> + + * 41432: Completion/Unix/Command/_xz: use option grouping + + * 41431: Completion/Linux/Command/_lsblk, + Completion/Linux/Command/_ss, Completion/Linux/Command/_strace, + Completion/Unix/Command/_diffstat, Completion/Unix/Command/_dig, + Completion/Unix/Command/_dmidecode, Completion/Unix/Command/_irssi, + Completion/Unix/Command/_gsettings, Completion/Unix/Command/_ssh, + Completion/X/Command/_xclip: update options in assorted completions + +2017-07-14 Oliver Kiddle <opk@zsh.org> + + * Fabian Klötzl: 41414: Completion/Linux/Command/_iptables, + Completion/Unix/Command/_gcc, Completion/Unix/Command/_git, + Etc/completion-style-guide: fix for commas used in exclusion + lists, missing escape for _gcc and --no-index option for git diff + + * 41419: Completion/Unix/Command/_git: update for git 2.13.2 + +2017-07-13 Peter Stephenson <p.stephenson@samsung.com> + + * 41420: Src/glob.c, Test/D09brace.ztst: "{.." wasn't checked + properly. + +2017-07-11 Peter Stephenson <p.stephenson@samsung.com> + + * Marcin Mielniczuk: 41409: Completion/Unix/Command/_django: + complete "django startproject". + +2017-07-09 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Config/version.mk: update dev version due to + wordcode changes. + + * Sebastian: 41402: Src/parse.c: Delay checking tokens in + ecstrcode() as may not be needed. + + * Sebastian: 41402: Src/parse.c, Src/zsh.h: Add hasher to + ecstrcode() to reduce string comparisons. + +2017-07-04 Peter Stephenson <p.stephenson@samsung.com> + + * 41391: Doc/Zsh/jobs.yo, Src/jobs.c, Src/zsh.h: delay disown + for superjob. + + * Maxime de Roucy: 41385: Src/Zle/complist.c: Avoid invalid + access with isearch in completion list. + +2017-07-03 Peter Stephenson <p.stephenson@samsung.com> + + * Sebastian: 41375: Src/Modules/db_gdbm.c: GDBM interface bug fixes. + +2017-07-02 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 41386: Src/jobs.c: when backgrounding a STAT_CURSH job, remove + the flag, preventing it getting foreground signals. + + * 22760: Src/utils.c, Test/D04parameter.ztst: NO_MULTIBYTE + partial string lengths were reported as full string lengths. + +2017-06-27 Peter Stephenson <p.stephenson@samsung.com> + + * 41368: Src/Zle/compctl.c: missing unqueue_signals(). + +2017-06-26 Peter Stephenson <p.stephenson@samsung.com> + + * 41345: Functions/Prompts/prompt_walters_setup: use consistent + versions of the prompt variables in prompt themes. + +2017-06-22 Peter Stephenson <p.stephenson@samsung.com> + + * Axel: 41342: conigure.ac: check for yodl version 4. + + * 41339: Completion/Unix/Command/_git: unquote treeish argument + for git checkout completion. + + * Phil: 41308, tweaked: Src/Modules/pcre.c, Test/V07pcre.ztst: + Behaviour of PCRE with NULL bytes. + +2017-06-19 Barton E. Schaefer <schaefer@zsh.org> + + * Mikael Magnusson: 41319: Src/cond.c: dupstring a possibly + readonly string before modifying + + * 41322 + comment: Src/input.c: reduce number of changes in signal + queuing/blocking state during shingetline() to improve read speed + + * 41317: Src/exec.c: use heap allocation in getoutputfile() to + plug memory leak (cf. Sebastian: 41316) + +2017-06-17 Barton E. Schaefer <schaefer@zsh.org> + + * 41242: Src/Zle/compcore.c, Src/Zle/zle_tricky.c: zstrbcmp(...) + removed in favor of zstrcmp(..., SORTIT_IGNORING_BACKSLASHES) + +2017-06-16 Barton E. Schaefer <schaefer@zsh.org> + + * Wieland Hoffmann: 41265: Functions/Zle/insert-files: quote + the inserted file names as necessary + +2017-06-13 Eric Cook <llua@gmx.com> + + * unposted: Functions/Zle/url-quote-magic: fix typo + in the examples + + * Stephane: 41275: Src/Zle/zle_main.c: Leave stdin open + when executing widgets. + +2017-06-13 Peter Stephenson <p.stephenson@samsung.com> + + * 41284: Src/builtin.c, Test/B01cd.ztst: fix null dereference on + cd with no argument if HOME is not set. + +2017-06-12 Peter Stephenson <p.stephenson@samsung.com> + + * 41244: Doc/Zsh/builtins.yo, Src/Modules/zftp.c, + Src/Zle/zle_thingy.c, Src/builtin.c, Src/module.c: Add zmodload + -s (silent) option by exposing low-level argument to builtin. + +2017-06-09 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Etc/BUGS: Add to Etc/BUGS 41184,41203,41254 about + STTY and about modules. + +2017-06-07 Peter Stephenson <p.stephenson@samsung.com> + + * 41239: Src/hist.c, Src/zsh.h: Save and restore default history + event on context stack. This prevents expansions in ZLE from + propagating to the command line expansion. + + * Sebastian: 41232: Functions/Misc/zed: use terminfo to find + page up/down keys where available. + +2017-06-05 Barton E. Schaefer <schaefer@zsh.org> + + * 41225: Src/params.c: sethparam() should not attempt to change + special parameters into hashes + +2017-06-01 Peter Stephenson <p.stephenson@samsung.com> + + * 41191: Src/Zle/textobjects.c, Src/Zle/zle.h, + Src/Zle/zle_keymap.c: Check for .thingy when we check for a + particular thingy. + +2017-05-30 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 41177: Completion/Unix/Command/_nm: add support for macOS + and OpenBSD + +2017-05-26 Peter Stephenson <p.stephenson@samsung.com> + + * 41164: Src/hashtable.c, Src/hist.c, Src/zsh.h: Don't free a + history entry if it's the current line. This replaces 41113. + +2017-05-28 Barton E. Schaefer <schaefer@zsh.org> + + * Sebastian: 41153: Src/Modules/db_gdbm.c: finish module setup + only after all error conditions have been checked + + * Sebastian: 41151: Src/Modules/db_gdbm.c: propagate flags when + creating new parameter + + * unposted: Doc/Zsh/mod_complist.yo: clarify ZLS_COLORS pattern + matching contexts + + * 41159 (tweaked): Completion/Unix/Command/_ssh: handle "Include" + and "HostName" lines in ~/.ssh/config + +2017-05-24 Peter Stephenson <p.stephenson@samsung.com> + + * Sebastian: 41146: Src/Modules/db_gdbm.c: be more careful about + freeing strings with embedded nulls. + + * Sebastian: 40898: Src/Modules/db_gdbm.c: fix GDBM error handling. + +2017-05-23 Peter Stephenson <p.stephenson@samsung.com> + + * Stephane: 41142: Src/Modules/system.c: ensure close-on-exec is + applied to moved file descriptor. + +2017-05-22 Peter Stephenson <p.stephenson@samsung.com> + + * Marko Myllenen: 41087: Completion/Unix/Command/_kvno: Update + completion to MIT krb 1.14. + + * Marko Myllenen: 41086: Completion/Unix/Command/_libvirt: + update completion. + + * Marko Myllenen: 41085: Completion/Unix/Command/_openstack: + update completion. + + * Jörg Sommer: 41128: Doc/Zsh/compsys.yo: typo. + +2017-05-19 Peter Stephenson <p.stephenson@samsung.com> + + * users/22707: Doc/Zsh/compsys.yo: Document use of + accept-exact-dirs for allowing completion after "magic" + directories. + +2017-05-18 Peter Stephenson <p.stephenson@samsung.com> + + * 41113 (tweaked): Src/hashtable,c, Src/hist.c, Src/zsh.h: Save + and restore state of linking of current history line into history + ring, to avoid an attempt to free the current history line. + +2017-05-12 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 41090: Src/Zle/zle_refresh.c, Src/compat.c, Src/pattern.c, + Src/utils.c, Src/wcwidth9.h, Src/zsh.h, Src/ztype.h, + configure.ac: Replace iswprint() if unicode9 support is enabled. + Enable unicode9 if wcwidth() and/or iswprint() is broken. + +2017-05-11 Peter Stephenson <p.stephenson@samsung.com> + + * 41096: Src/string.c: Fix dupstring_wlen() for unmetafied + string. It's not safe to assume null termination. + +2017-05-09 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Test/D02glob.ztst: Adding comment to test changed + line number in output. + +2017-05-09 Peter Stephenson <p.stephenson@samsung.com> + + * 41081: Src/utils.c, Test/D02glob.ztst: Symlink expansion + didn't test all buffer length calculations. + + * 41078: Src/prompt.c, Test/D01prompt.ztst: Empty psvar could + cause bad reference in prompt expansion. + +2017-05-08 Peter Stephenson <p.stephenson@samsung.com> + + * 41059: Completion/compinit: use 2>&- to avoid error in + restricted shell. + + * 41073: Src/parse.c, Test/A04redirect.ztst: off-by-one error + checking for {varid} syntax. + + * users/22688: Src/parse.c, Test/A04redirect.ztst: Allow mixing + of redirections and arguments after anonymous functions. + + * 41060: Src/parse.c, Test/A04redirect.ztst: combination + of HERE document and |& was broken by miscounting wordcode owing + to missing flag. + +2017-05-04 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 41038: NEWS: Document recent, backwards-compatible precommand + modifiers changes. + +2017-05-03 Peter Stephenson <p.stephenson@samsung.com> + + * 41043: Src/exec.c: Close pipes in shell if disowning + backgrounded job with &!. + +2017-05-02 Peter Stephenson <p.stephenson@samsung.com> + + * unposted: Functions/Zle/insert-unicode-char: use typeset -g to + avoid warnnestedvar warning. + +2017-04-28 Peter Stephenson <p.stephenson@samsung.com> + + * 41020: Src/exec.c, Test/A01grammar.ztst: "command -p" was + broken by 41008, also add more tests for precommand modifiers. + +2017-04-27 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 41012: Src/builtin.c, Src/exec.c, Src/signals.c, + Test/C03traps.ztst: Fix early exit from nested functions in EXIT + trap. Drive-by fix of testing for need to exit if exiting when + already in EXIT trap for main shell --- we should just leave + immediately. + +2017-04-27 Peter Stephenson <p.stephenson@samsung.com> + + * 41016: Test/A01grammar.ztst: test that quoted precommand + modifiers now work. + +2017-04-26 Oliver Kiddle <opk@zsh.org> + + * unposted: Completion/Unix/Command/_dbus: fix syntax on line end + + * 40965 (tweaked c.f. 40968): Completion/BSD/Command/_portmaster, + Completion/Debian/Command/_a2utils, Completion/Debian/Command/_apt, + Completion/Debian/Command/_lighttpd, + Completion/Debian/Command/_lintian, + Completion/Debian/Command/_wajig, + Completion/Debian/Type/_deb_architectures, + Completion/Debian/Type/_debbugs_bugnumber, + Completion/Linux/Command/_ethtool, + Completion/Solaris/Command/_svcadm, + Completion/Solaris/Command/_svccfg, + Completion/Solaris/Type/_svcs_fmri, + Completion/Unix/Command/_cdrdao, Completion/Unix/Command/_darcs, + Completion/Unix/Command/_iftop, Completion/Unix/Command/_lha, + Completion/Unix/Command/_lsof, Completion/Unix/Command/_pkg-config, + Completion/Unix/Command/_rrdtool, Completion/Unix/Command/_stgit, + Completion/Unix/Command/_tcpdump, Completion/Unix/Command/_texinfo, + Completion/Unix/Command/_units, Completion/Unix/Command/_yafc, + Completion/Unix/Type/_absolute_command_paths, + Completion/X/Command/_setxkbmap, Completion/X/Type/_xft_fonts, + Completion/Zsh/Command/_fc, Completion/Zsh/Context/_value, + Completion/Zsh/Function/_add-zle-hook-widget, + Completion/Zsh/Function/_add-zsh-hook: + fix for missing local declarations of expl + +2017-04-26 Peter Stephenson <p.stephenson@samsung.com> + + * 41008: Src/exec.c, Src/linklist.c, Test/A01grammar.ztst, + Test/E01options.ztst: Handle expansions when analysing + precommand modifiers. + +2017-04-26 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 41006: Completion/Unix/Command/_ls: add new options for BSDs, + fix a few problems on Linux, etc. + +2017-04-23 Daniel Hahler <zsh@thequod.de> + + * 40943: Completion/Unix/Command/_git: __git_recent_commits: prefer + recent commit objects. + +2017-04-23 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40995: Src/lex.c, Test/D08cmdsubst.ztst: we need to expand + aliases when identifiying the end of a command substitution as + sometimes we can hit a parse error before. + +2017-04-23 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 40994: Src/utils.c: unmeta_one() need not count Meta + +2017-04-21 Peter Stephenson <p.stephenson@samsung.com> + + * 40990: Src/params.c: When starting in sh emulation, don't + link PATH-style parameters to array equivalents. Don't + check linkage when exporting colon-separated parameter. + +2017-04-18 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40973: Completion/Unix/Type/_remote_files: Fix completion of + remote files that start with a hyphen/minus. + +2017-04-15 Barton E. Schaefer <schaefer@zsh.org> + + * 40977: Src/init.c: "emulate" disallows "--help" and "--version" + +2017-04-10 Peter Stephenson <p.stephenson@samsung.com> + + * Orlov Sergey: 40935: Src/utils.c: User names need metafying as + they can contain multibyte characters on some systems. + +2017-04-07 Bart Schaefer <schaefer@zsh.org> + + * 40940: Src/cond.c: untokenize names of condition features + before attempting to look up the definition from a module. + Necessary because of 40760 (tokenization of '-' as Dash). + +2017-04-05 Daniel Shahaf <d.s@daniel.shahaf.name> + + * users/22653: Doc/Zsh/options.yo: Clarify REMATCH_PCRE + semantics. + +2017-04-04 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40933: Src/exec.c: we need job text in sourced files in case + of suspending. + +2017-04-03 Peter Stephenson <p.stephenson@samsung.com> + + * 40932: Src/params.c, Test/D06subscript.ztst: parameter + subscripts need to count parentheses to avoid terminating early. + +2017-04-02 Barton E. Schaefer <schaefer@zsh.org> + + * 40929 (replaces 40598): Src/subst.c: paramsubst() should always + return scalar when PREFORK_SINGLE was passed in from prefork() + +2017-04-01 Barton E. Schaefer <schaefer@zsh.org> + + * Sebastian: 40782: Completion/Unix/Type/_hosts: avoid dependency + on zsh/regex module + +2017-03-30 Peter Stephenson <p.stephenson@samsung.com> + + * Dag-Erling Smørgrav: 40915: Completion/BSD/Command/_kld: fix + breakage. + + * Sebastian: 40909: Test/D04parameter.ztst: stress test for + parameter substitution. + +2017-03-27 Peter Stephenson <p.stephenson@samsung.com> + + * 40906: Doc/Zsh/expn.yo: array subst needs [*] or [@] with + KSH_ARRAYS. Note this for (k) flag. + +2017-03-24 Peter Stephenson <p.stephenson@samsung.com> + + * Alexandre Rames: 40878: Completion/Unix/Command/_stgit: + additional squash command completion. + + * Aaron Schrab: 40892: Functions/Misc/run-help-ip: subcommand + matching for ip help. + +2017-03-23 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40891: Src/glob.c, Test/D04parameter.ztst: another similar fix + for zero-length matches at the end of a string. + +2017-03-23 Peter Stephenson <p.stephenson@samsung.com> + + * users/22601: Src/glob.c, Test/D04parameter.ztst: problem matching + pattern against zero-length string in parameter substitutions. + +2017-03-21 Peter Stephenson <p.stephenson@samsung.com> + + * 40875 (Martin Krafft): change description of REC_EXACT option. + + * 40821: Test/V11db_gdbm.ztst: Note this contains UTF-8 + characters and fix name. + +2017-03-20 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted (after 40859): Doc/Zsh/contrib.yo: Fix yodl warning. + +2017-03-19 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40859: Doc/Zsh/contrib.yo: vcs_info docs: Use proper internal + links through texinfo nodes. + +2017-03-18 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Doc/Zsh/contrib.yo: vcs_info quilt: Fix documentation + markup typo. + +2017-03-16 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40855: Completion/Unix/Command/_dmidecode: Fix _arguments + syntax error. + +2017-03-14 Oliver Kiddle <opk@zsh.org> + + * 40843: Completion/Unix/Command/_ruby: update options for + ruby 2.4.0p0 + + * 40842: Completion/Unix/Command/_basename, + Completion/Unix/Command/_cat, Completion/Unix/Command/_date, + Completion/Unix/Command/_df, Completion/Unix/Command/_fmt, + Completion/Unix/Command/_locate, Completion/Unix/Command/_ls, + Completion/Unix/Command/_nm, Completion/Unix/Command/_paste, + Completion/Unix/Command/_readelf, Completion/Unix/Command/_sed, + Completion/Unix/Command/_strip: update completions for coreutils + and similar utilities, also improving BSD and Solaris support + +2017-03-14 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40818: Completion/Unix/Command/_git: _git-checkout: When + completing local heads, prefer recently-checked-out ones. (after + 38592) + + * 40817: Completion/Unix/Command/_git: __git_recent_branches: + Retrieve less data, but faster. + + * 40822: Doc/Zsh/contrib.yo: vcs_info quilt: Document the + '.quilt-foo' zstyle context element. (Compare users/20807.) + +2017-03-12 Oliver Kiddle <opk@zsh.org> + + * Wieland Hoffmann: 40837: Completion/Unix/Command/_pgrep: + add -w on Linux + +2017-03-12 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40816: Doc/Zsh/builtins.yo, Test/D01prompt.ztst: Document + interaction of 'print -P' and 'print -f'. + +2017-03-12 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 40820: Test/V09datetime.ztst: add a few tests of strftime, + related to 40681 + +2017-03-11 Barton E. Schaefer <schaefer@zsh.org> + + * 40832: Src/subst.c: fix $x:P when PWD=/ + +2017-03-11 John Leuenhagen <john@zlima12.com> + + * unposted (github pull request #15): + Completion/Unix/Command/_ip: fix a small typo in `ip` + corrections file + +2017-03-10 Oliver Kiddle <opk@zsh.org> + + * 40824: Completion/Unix/Command/_grep: completion handling + of option deviations between different systems + + * 40823: Completion/Linux/Command/_sshfs: update for sshfs 2.8 + +2017-03-10 Peter Stephenson <p.stephenson@samsung.com> + + * 40819: Src/glob.c: Fix IS_DASH() test in BRACE_CCL handling. + +2017-03-10 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * unposted: Src/Modules/tcp.c: silence compiler warnings on Cygwin + + * unposted: Src/hashtable.c: declare file local variables as static + +2017-03-09 Barton E. Schaefer <schaefer@zsh.org> + + * Fabian Klotzl: 40808: Completion/Linux/Command/_mdadm, + Completion/Unix/Command/_git, Completion/Unix/Command/_grep, + Completion/Unix/Command/_hg, Completion/Unix/Command/_java, + Completion/Unix/Command/_ls, Completion/Unix/Command/_mysql_utils, + Completion/Unix/Command/_rake, Completion/Unix/Command/_user_admin, + Completion/Unix/Command/_wget, Completion/Unix/Command/_zpool: + fix typos where (x,y) should have been (x y) in _arguments syntax + + * 40801: Completion/Unix/Command/_mount: turns out that work of + art removed by 33963 was necessary after all: re-fix completion + of mount points with spaces in the name + +2017-03-09 Peter Stephenson <p.stephenson@samsung.com> + + * 40805: (combined with the previous change): + Test/D04parameter.ztst: Check that $- and ${-} produce a + plausible result. + + * Sebastian: 40803 as modified in 40804 and 40806: + Test/D04parameter.ztst: check for the (z) split flag on some + partly binary data that might be problematic. + + * 40796: Src/exec.c: We don't want magic '=' expansion if we are + already parsing a separate variable name and value. + +2017-03-08 Barton E. Schaefer <schaefer@zsh.org> + + * 40799: Src/params.c: fix $- expansion partly broken by 40760 + + * 40763: Src/Zle/compmatch.c, Src/Zle/computil.c, Src/utils.c: + count wide characters and Cmatcher pointers more sanely in + cfp_matcher_pats(), and count characters in pattern_match() + the same way to stay in sync; might not fix wide-char matching + in completion matcher-lists but should avoid wild pointer crash + +2017-03-08 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40745 + 40753: Src/init.c, Src/params.c: Fix 'unset + ZLE_RPROMPT_INDENT' not restoring the default behaviour. + + * 40744: Doc/Zsh/grammar.yo: Document the SHORT_LOOPS 'function' + syntax. + +2017-03-07 Peter Stephenson <p.stephenson@samsung.com> + + * Sebastian: 40706: Test/V11db_gdbm.ztst: Fix ordering + dependence in gdbm test. + + * 40760: Src/cond.c, Src/exec.c, Src/glob.c, Src/lex.c, + Src/math.c, Src/parse.c, Src/pattern.c, Src/subst.c, + Src/utils.c, Src/zsh.h, Test/D02glob.ztst: Always tokenise '-' + to Dash to eliminate niggles with range matches in complicated + contexts. Match both - or Dash in contexts that don't care. + +2017-03-07 Mikael Magnusson <mikachu@gmail.com> + + * 40780: Completion/Unix/Command/_mount: Don't use =~ for simple + prefix match + +2017-03-05 Barton E. Schaefer <schaefer@zsh.org> + + * Sebastian: 40726: Doc/Zsh/mod_curses.yo, Src/Modules/curses.c, + configure.ac: add "zcurses resize" for sane terminal size change + +2017-03-04 Barton E. Schaefer <schaefer@zsh.org> + + * Sebastian: 40781: Src/params.c, Test/A06assign.ztst: optimize + array assignment, similar to 39995 for string assignment + + * 40654: Src/exec.c: exit cleanly from special POSIXBUILTINS in + subshells + +2017-03-04 Oliver Kiddle <opk@zsh.org> + + * unposted (github): Christoffer Aasted: + Completion/Unix/Command/_ant: allow -Dproperty=/path_complete + + * unposted (from Ferenc- via github): Completion/Unix/Command/_gcc: + Add newer C++ standard options to gcc completion + + * unposted: Completion/Unix/Command/_tmux: complete 'tiled' layout + + * unposted: Completion/Unix/Command/_xz: fix argument to --format + + * 40715: Completion/Unix/Command/_git: update for git 2.12.0 + + * 40597: Completion/BSD/Command/_sysrc, + Completion/Base/Utility/_values: be flexible about order of + options to _values + +2017-03-03 Peter Stephenson <p.stephenson@samsung.com> + + * Sebastian: 40170: Src/Modules/curses.c: Fix up error number + resetting in curses module. This appears to resolve an issue + mentioned in comments but attributed elsewhere, so remove + confusion here. + + * 40173: Test/V11db_gdbm.ztst: don't report an error if gdbm + module doesn't load as this simply causes the test to be skipped. + + * 40702: Doc/Zsh/zle.yo, Src/Zle/zle_params.c: add + KEYS_QUEUED_COUNT variable to ZLE parameters. + +2017-03-02 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 40681: Src/Modules/datetime.c: strftime builtin should + return 1 if zstrftime() returns -1. + +2017-03-01 Peter Stephenson <p.stephenson@samsung.com> + + * 40622 (typos fixed): Doc/Zsh/builtins.yo, Src/builtin.c, + Src/math.c, Test/C04funcdef.ztst: add functions -Ms for + mathematical functions with string arguments. + + * Sebastian: 40562: Test/V11db_gdbm.ztst: this was missed out of + the previous commit. + +2017-02-28 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40641: Doc/Zsh/expn.yo, Doc/Zsh/roadmap.yo: docs: patterns: + Add '|' to the overview. Clarify that it short-circuits. + +2017-02-26 Barton E. Schaefer <schaefer@zsh.org> + + * 40650: Src/Modules/parameter.c: redo 40508 and 40626 with + comments explaining what is actually going on + +2017-02-25 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40644: Src/Modules/parameter.c, Test/V06parameter.ztst: + Revert 40626 which broke tests. + +2017-02-25 Barton E. Schaefer <schaefer@zsh.org> + + * 40640 (plus doc typo fixed): Doc/Zsh/expn.yo, Src/subst.c: the + (A) parameter flag forces array result even if assignment syntax + is not used + +2017-02-25 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Completion/Zsh/Context/_brace_parameter: Port 40617 + to the completion. + + * 40626: Src/Modules/parameter.c, Test/V06parameter.ztst: + Make $options re-settable. [reverted in 40644] + +2017-02-23 Barton E. Schaefer <schaefer@zsh.org> + + * unposted (cf. 40617): Doc/Zsh/expn.yo: clarify description of + the ${(A)name=value} and ${(AA)name=value} parameter flag uses. + + * 40624 (cf. Danek Duvall, 40563): Src/signals.c: conditionally + handle WIFCONTINUED to properly set SP_RUNNING process status + +2017-02-23 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 40604: configure.ac, Src/watch.c: revert to the old method if + getutent() is not available + +2017-02-21 Barton E. Schaefer <schaefer@zsh.org> + + * Julien Nicoulaud: 40586: + Functions/VCS_Info/Backends/VCS_INFO_get_data_git: discard stderr + +2017-02-20 Barton E. Schaefer <schaefer@zsh.org> + + * unposted: Test/ztst.zsh: use "diff -a" in case special characters + were written to the test output + + * 40598: Src/subst.c: paramsubst() should always return scalar + when PREFORK_SINGLE was passed in from prefork() + + * Martijn Dekker: 40565 (tweaked): test cases for assigning array + to scalar with various combinations of SHWORDSPLIT and IFS + +2017-02-19 Barton E. Schaefer <schaefer@zsh.org> + + * 40593: Src/subst.c: SHWORDSPLIT + unset IFS should cause default + splitting of $@ and other array references with (@) or [@] + + * 40576 (tweaked): Src/exec.c: entersubsh(): small improvement to + loop that resets trap handlers; unblock any signals that were + blocked for trap handling + +2017-02-19 Oliver Kiddle <opk@zsh.org> + + * 40569: Completion/Unix/Command/_gphoto2: update to gphoto2 2.5.11 + +2017-02-17 Peter Stephenson <p.stephenson@samsung.com> + + * Øystein Walle: 40568: REMATCH_PCRE option is not enabled by + default. + + * Sebastian: 40558, 40562: Doc/Zsh/mod_db_gdbm.yo, + Src/Modules/db_gdbm.c, Src/Modules/db_gdbm.mdd: General + improvements to zsh/db/gdbm module. + +2017-02-13 Barton E. Schaefer <schaefer@zsh.org> + + * 40539: Fabian Klotzl: Completion/Unix/Command/_gcc: typo in MIPS + branch of argument selection + + * 40524: Src/Modules/example.c: do not free a null array + +2017-02-13 Peter Stephenson <p.stephenson@samsung.com> + + * 40537: Doc/Zsh/builtins.yo: document the foregoing. + + * Sebastian: 40536: Src/builtin.c, Src/zsh.h: prepend directory + of function autoload with absolute path to fpath if loading a + function by relative path. + +2017-02-10 Oliver Kiddle <opk@zsh.org> + + * 40512: Completion/Unix/Command/_entr: new entr completion + + * unposted: Completion/Linux/Command/_lsusb: using a colon in + the tag name was not such a good idea + +2017-02-09 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40510: Misc/vcs_info-examples, README: vcs_info: Update the + $psvar episode with '%'-unescaping. (Follow-up to 40492.) + + * 40492: Doc/Zsh/contrib.yo, Etc/BUGS, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg, + Functions/VCS_Info/VCS_INFO_set-patch-format, README: vcs_info: + Escape '%' signs in payloads. + +2017-02-08 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Completion/Unix/Command/_subversion: _svn: Fix + '--show-revs' completion. + + * 40508: Src/Modules/parameter.c, Test/V06parameter.ztst: + Make $functions re-settable. + +2017-02-07 Peter Stephenson <p.stephenson@samsung.com> + + * Sebastian: 40507: Src/Modules/db_gdbm.c: remove extraneous + null byte creating records. + +2017-02-07 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40494: Completion/Unix/Command/_git: Use slashes matchspec + for references (as already used for branch names). + +2017-02-07 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40493/0002: Completion/Unix/Command/_git: _git-checkout: + Reorder default completions. + +2017-02-07 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40493/0001: Completion/Unix/Command/_git: _git-checkout: + No functional change. + +2017-02-06 Peter Stephenson <p.stephenson@samsung.com> + + * Jan Matejek: 40434: Completion/Unix/Command/_patchutils: + update. + +2017-02-04 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Doc/Zsh/contrib.yo, + Functions/VCS_Info/Backends/VCS_INFO_get_data_git: vcs_info git: + Fix typo in manual. + +2017-02-03 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40480: Functions/VCS_Info/Backends/VCS_INFO_get_data_git, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg, + Functions/VCS_Info/VCS_INFO_quilt, + Functions/VCS_Info/VCS_INFO_set-patch-format: vcs_info + set-patch-format: Eliminate the remaining code duplication. + + * 40479: Functions/VCS_Info/Backends/VCS_INFO_get_data_git, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg, + Functions/VCS_Info/VCS_INFO_quilt, + Functions/VCS_Info/VCS_INFO_set-patch-format: vcs_info + set-patch-format: Prepare for more code sharing between the + callers. + + * 40481: Functions/VCS_Info/Backends/VCS_INFO_get_data_hg: + vcs_info hg: Pass arguments to the set-patch-format hook. + + * 40478: Functions/VCS_Info/VCS_INFO_set-patch-format: vcs_info + set-patch-format: Guard against empty variable elision. + + * 40476: Doc/Zsh/contrib.yo, Functions/VCS_Info/VCS_INFO_quilt: + vcs_info $backend_misc: Document at the right point, provide + in quilt 'standalone' mode. + +2017-02-02 Peter Stephenson <p.stephenson@samsung.com> + + * 40486: Src/Modules/regex.c, Src/params.c: don't warn on + creation of MATCH etc. from regex test as this is implicit. + +2017-02-01 Barton E. Schaefer <schaefer@zsh.org> + + * 40483 (cf. Eric Freese: 40482): Src/Modules/zpty.c: Remove zpty + exit hook from forked processes + +2017-02-01 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40460: Src/params.c, Test/E01options.ztst: WARN_NESTED_VAR: + Don't warn when assigning to a slice of an existing array + +2017-02-01 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp> + + * 40470: Test/D07multibyte.ztst: make the test work also on + OSs which always use ASCII collation (e.g. macOS). + +2017-01-31 Peter Stephenson <p.stephenson@samsung.com> + + * 40466: Makefile.in: update depencencies so autoheader is run + after autoconf when configuration input files change. + +2017-01-30 Barton E. Schaefer <schaefer@zsh.org> + + * 40469: Src/Zle/complete.c: change strategy from 40453 to use + patcompile(PAT_HEAPDUP) instead of signal queueing. + +2017-01-30 Peter Stephenson <p.stephenson@samsung.com> + + * 40465: Test/C04funcdef.ztst, Test/V06parameter.ztst: use + method from cd tests to output current directory. + +2017-01-29 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Zhiming Wang: 40450, 40451: Completion/Unix/Command/_swift, + Completion/Unix/Command/_openstack: Add new swift language + completion and attempt to resolve against openstack swift command. + +2017-01-28 Barton E. Schaefer <schaefer@zsh.org> + + * 40453: Src/Modules/zpty.c, Src/Modules/zutil.c, + Src/Zle/compctl.c, Src/Zle/complete.c, Src/Zle/computil.c, + Src/Zle/zle_hist.c, Src/builtin.c, Src/cond.c, Src/glob.c, + Src/loop.c, Src/options.c, Src/parse.c: signal handler safety + for callers of patcompile(PAT_STATIC), which is not re-entrant. + + * 40439: Src/zsh.h: PAT_HEAPDUP definition just for clarity + +2017-01-28 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40440: ../Doc/Zsh/mod_parameter.yo, Modules/parameter.c, + hashtable.c, ../Test/C04funcdef.ztst, ../Test/V06parameter.ztst: + Add $functions_source to zsh/parameter to help find where + functions where loaded from. + +2017-01-27 Peter Stephenson <p.stephenson@samsung.com> + + * Zach Whaley: 40200: Completion/Unix/Command/_perforce: update + for latest Perforce versions. + + * 40425: configure.ac, Src/watch.c: HAVE_* tests for getutxent + etc. + +2017-01-26 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40423: Src/params.c, Test/E01options.ztst: similar for type + conversion the other way. + + * 40422: Src/params.c, Test/E01options.ztst: more + WARN_NESTED_VAR cases that were broken in the original patch. + +2017-01-25 Peter Stephenson <p.stephenson@samsung.com> + + * 40413: Src/params.c, Test/E01options.ztst: no WARN_NESTED_VAR + warning on bogus parameter created for subscripted assignment. + +2017-01-25 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40403/0004: Functions/VCS_Info/Backends/VCS_INFO_get_data_git, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg, + Functions/VCS_Info/VCS_INFO_quilt, + Functions/VCS_Info/VCS_INFO_set-patch-format: vcs_info + set-patch-format helper: Part #4. + + * 40403/0003: Functions/VCS_Info/Backends/VCS_INFO_get_data_git, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg, + Functions/VCS_Info/VCS_INFO_quilt, + Functions/VCS_Info/VCS_INFO_set-patch-format: vcs_info + set-patch-format helper: Part #3. + + * 40403/0002: Functions/VCS_Info/Backends/VCS_INFO_get_data_git, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg, + Functions/VCS_Info/VCS_INFO_quilt, + Functions/VCS_Info/VCS_INFO_set-patch-format: vcs_info + set-patch-format helper: Part #2. + + * 40403/0001: Functions/VCS_Info/Backends/VCS_INFO_get_data_git, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg, + Functions/VCS_Info/VCS_INFO_quilt, + Functions/VCS_Info/VCS_INFO_set-patch-format, + Functions/VCS_Info/vcs_info: vcs_info set-patch-format helper: + Part #1. + + * 40401: Functions/VCS_Info/Backends/VCS_INFO_get_data_git: + vcs_info git: Fix the %c patch-format expando. + + * 40396: Doc/Zsh/contrib.yo: vcs_info quilt: More documentation + of '%Q' and 'use-quilt'. + + * 40392: Functions/VCS_Info/VCS_INFO_patch2subject: vcs_info + patch2subject: Support `git show` output. + +2017-01-24 Mikael Magnusson <mikachu@gmail.com> + + * posted: Test/D07multibyte.ztst: Make D07 recognize more + spellings of pl_PL.UTF-8 + +2017-01-24 Peter Stephenson <p.stephenson@samsung.com> + + * 40404: Src/builtin.c: quoting of commands in whence should + only apply to whence -v. + +2017-01-23 Peter Stephenson <p.stephenson@samsung.com> + + * 40391: Completion/compinit, Doc/Zsh/builtins.yo, + Doc/Zsh/options.yo, Src/builtin.c, Src/exec.c, Src/options.c, + Src/params.c, Src/zsh.h, Test/E01options.ztst: Add + WARN_NESTED_VAR option and functions -W to turn it on similarly + to functions -T. + +2017-01-23 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Etc/BUGS: Record users/20807 vcs_info quilt issue. + +2017-01-18 Peter Stephenson <p.stephenson@samsung.com> + + * 43080: Test/C04funcdef.ztst: a few more tests for autoload + with absolute path. + + * 40375: Src/builtin.c, Src/subst.c: autoload with explicit path + mustn't trash already loaded function. Also drive-by removal of + duplicated duplication in =cmd expansion. + +2017-01-17 Peter Stephenson <p.stephenson@samsung.com> + + * unposted: Completion/Zsh/Command/_typeset: autoload ~... also + completes file. + +2017-01-16 Peter Stephenson <p.stephenson@samsung.com> + + * 40372: Completion/compinit: turn off POSIX_IDENTIFIERS option + for completion. + + * 40369: Src/builtin.c: whence -v should probably quote commands + since it quotes functions. + + * 40353 (plus improvement to whence -v): Src/exec.c, + Src/hashtable.c, Src/signals.c: use directory cache where + possible for all functions loaded from directory including + fpath. + +2017-01-15 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40362: Src/Zle/computil.c: need duplicated values for setting + parameter in compvalues. Was causing obscure but surprisingly + rare crashes in value completion. + +2017-01-13 Eric Cook <llua@gmx.com> + + * earnestly: 40355: Completion/Unix/Command/_mpc: improve + playlist completion + +2017-01-13 Oliver Kiddle <opk@zsh.org> + + * 40345: Completion/Linux/Command/_lsusb: update lsusb completion + + * 40344: Completion/Linux/Command/_lsblk: new lsblk completion + +2017-01-12 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Src/hashtable.c: one missing *name = NULL. + + * 40342: Src/builtin.c, Src/exec.c, Src/hashtable.c, + Src/signals.c, Test/C04funcdef.ztst: add directory name cache + for directories recorded for autoload files. + +2017-01-12 Peter Stephenson <p.stephenson@samsung.com> + + * 40335: Src/builtin.c, Src/exec.c, Src/zsh.h, + Test/C04funcdef.ztst: be more careful autoload filename is + directory, not source location. + + * Jens Elkner: 40333: Src/watch.c: Fix the utmpx interface for + watch as otherwise it failed on some OSes. + +2017-01-11 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40332: Completion/Zsh/Command/_typeset: completion for new + autoload features. + +2017-01-11 Oliver Kiddle <opk@zsh.org> + + * 40321: Doc/Zsh/compsys.yo, Src/Zle/computil.c, + Test/Y03arguments.ztst: _arguments option groups + +2017-01-11 Peter Stephenson <p.stephenson@samsung.com> + + * unposted: Src/builtin.c, Src/exec.c: be more careful to free + memory when updating filename in struct shfunc. + + * 40327 (with minor fixes): Doc/Zsh/builtins.yo, + README,Src/builtin.c, Src/exec.c, Src/hashtable.c, Src/parse.c, + Src/zsh.h, Test/C04funcdef.ztst: add ability to autoload + function from file using full path, with additional related + autoload options -r, -R, -d and extension to -X. + +2017-01-10 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 40305: Src/Zle/complist.c, Src/Zle/zle_main.c, + Src/Zle/zle_refresh.c, Src/Zle/zle_thingy.c: fix some problems + redisplaying command line after interrupts. + + * 40306 with documentation additions: Doc/Zsh/options.yo, + README, Src/input.c, Src/options.c, Src/parse.c, Src/zsh.h, + Test/A02alias.ztst: Add ALIAS_FUNC_DEF option and make + the default behaviour to disallow functions where the + name is expanded as an alias (unless part of a complete + function definition within the alias). + +2017-01-10 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40303: Completion/Debian/Command/_bts: Add more subcommands. + +2017-01-10 Phil Pennock <zsh-workers+phil.pennock@spodhuis.org> + + * 40318 (in part): Doc/Zsh/builtins.yo: Document echo \c + behaviour. + +2017-01-10 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40302: Completion/Unix/Command/_swaks: New _swaks completion + (common options only). + +2017-01-08 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: LICENCE: Update year to $now (2017). + +2017-01-06 Peter Stephenson <p.stephenson@samsung.com> + + * m0viefreak: 40285: Src/Zle/zle_hist.c: more care needed + managing patterns in history isearch if there are hooks + around. + +2017-01-05 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40270 (after 39995): Src/params.c: Add cross-reference for + robustness. + + * 40264: Completion/Unix/Command/_man: Complete all sections + after '-a'. + + * users/22320: Etc/BUGS: Add 40240, label 40106. + +2017-01-05 Oliver Kiddle <opk@zsh.org> + + * 40269: Src/Zle/computil.c, Test/Y03arguments.ztst: + handle option exclusion within current word for clumped options + +2017-01-04 Oliver Kiddle <opk@zsh.org> + + * 40227: Src/Zle/computil.c, Test/Y03arguments.ztst: new approach + to 39611 (_arguments sets and rest arguments starting with a dash) + + * 40226: Src/Zle/computil.c, Test/Y03arguments.ztst: + tidy up some of the _arguments set code + +2017-01-03 Peter Stephenson <p.stephenson@samsung.com> + + * 40265: Src/pattern.c: fix continuing problems with Meta characters + in pattern that resolves to a string by copying source string. + Triggered by string that (correctly) turned Dash into '-'. + + * Paulo Andrade: 40260: Src/prompt.c: Set newly allocated + space in prompt buffer to zero as it may be tested. + +2017-01-01 Barton E. Schaefer <schaefer@zsh.org> + + * users/22319: Src/subst.c: ${ary1:^ary2} should not change + the isarr state of the expansion of ary1 unless ary1 is made + from a scalar, lest semantics of (@) in double quotes be lost. + +2016-12-30 Barton E. Schaefer <schaefer@zsh.org> + + * 40248: Src/hist.c: suppress errors from zshaddhistoryhook, + and do not call it if no history entry will be written + +2016-12-28 Sebastian Gniazdowski <psprint@fastmail.com> + + * 40231: Src/params.c: Optimise setarrvalue(). + +2016-12-28 Daniel Shahaf <d.s@daniel.shahaf.name> + + * 40232: configure.ac: Remove SH_USE_BSD_ECHO autoconf test. + +2016-12-27 Barton E. Schaefer <schaefer@zsh.org> + + * unposted (see users/22287): Completion/compinit: _comp_options + needs to disable ERR_RETURN along with ERR_EXIT + +2016-12-24 Barton E. Schaefer <schaefer@zsh.org> + + * Oliver: 40118: Functions/Zle/bracketed-paste-magic: relocate + BUFFER/CURSOR reset to work around "fc -p" issue (alternate fix + replacing 40115). + + * unposted: Functions/Zle/bracketed-paste-magic: revert 40115, + thus restoring 38579. + +2016-12-22 Oliver Kiddle <opk@zsh.org> + + * 40162: Src/Zle/computil.c, Test/Y03arguments.ztst: _arguments + support for a match spec in combination with sets + +2016-12-22 Daniel Shahaf <d.s@daniel.shahaf.name> + + * unposted: Config/version.mk: Post-release version bump to + 5.3.1-dev-0. + 2016-12-21 Peter Stephenson <p.w.stephenson@ntlworld.com> * unposted: Config/version.mk, Etc/FAQ.yo, NEWS, README: diff --git a/Completion/BSD/Command/_gstat b/Completion/BSD/Command/_gstat index 7baaf0d62..c60e54422 100644 --- a/Completion/BSD/Command/_gstat +++ b/Completion/BSD/Command/_gstat @@ -2,10 +2,12 @@ _arguments -s : \ '-a[only display providers that are at least 0.1% busy]' \ - '-b[batch mode]' \ + '(-B)-b[batch mode]' \ + '(-b)-B[endless batch mode]' \ '-c[enable the display geom(4) consumers]' \ '-d[enable the display delete operations]' \ '-f+[filter by regex]:regex' \ '-o[enable the display for other operations]' \ + "-s[enable blocks' size statistics]" \ '-I+[display refresh rate]:interval (ms)' \ '-p[only display physical providers]' diff --git a/Completion/BSD/Command/_kld b/Completion/BSD/Command/_kld index 94528955c..42fdc2bd0 100644 --- a/Completion/BSD/Command/_kld +++ b/Completion/BSD/Command/_kld @@ -26,7 +26,7 @@ _kld() { case "$service" in kldload) _arguments -s -S -A "-*" \ - "-n[don't try to load module if already loaded]" + "-n[don't try to load module if already loaded]" \ '-v[be verbose]' \ '-q[silence any extraneous warnings]' \ '*:module to load:_kld_module' diff --git a/Completion/BSD/Command/_portmaster b/Completion/BSD/Command/_portmaster index 4c16e2d1b..48390c9ad 100644 --- a/Completion/BSD/Command/_portmaster +++ b/Completion/BSD/Command/_portmaster @@ -5,7 +5,7 @@ _portmaster_pkgs() { } _portmaster_ports() { - local ret=1 _fbsd_ports _fbsd_cat + local expl ret=1 _fbsd_ports _fbsd_cat _fbsd_cat=(${PORTSDIR:-/usr/ports}/[a-z]*(/:t)) if [[ $PREFIX != */* ]] ; then _wanted cat_packages expl 'category/ports' compadd -S '/' $_fbsd_cat diff --git a/Completion/BSD/Command/_sysrc b/Completion/BSD/Command/_sysrc index 651c18b89..246d73bd3 100644 --- a/Completion/BSD/Command/_sysrc +++ b/Completion/BSD/Command/_sysrc @@ -76,9 +76,9 @@ _sysrc() { if (( $#rc_conf_vars )); then if [[ $opt == N ]]; then - _values -w -C variable ${^rc_conf_vars%%\[*}'::value' && ret=0 + _values -w variable ${^rc_conf_vars%%\[*}'::value' && ret=0 else - _values -w -C variable ${^rc_conf_vars}'::value' && ret=0 + _values -w variable ${^rc_conf_vars}'::value' && ret=0 fi fi fi diff --git a/Completion/Base/Utility/_values b/Completion/Base/Utility/_values index c510b4cc0..6e38e00f4 100644 --- a/Completion/Base/Utility/_values +++ b/Completion/Base/Utility/_values @@ -1,13 +1,14 @@ #autoload -local subopts opt usecc garbage +local subopts opt usecc garbage keep subopts=() -zparseopts -D -a garbage C=usecc O:=subopts M: J: V: 1 2 n F: X: +zparseopts -D -a garbage s+:=keep S+:=keep w+=keep C=usecc O:=subopts \ + M: J: V: 1 2 n F: X: (( $#subopts )) && subopts=( "${(@P)subopts[2]}" ) -if compvalues -i "$@"; then +if compvalues -i "$keep[@]" "$@"; then local noargs args opts descr action expl sep argsep subc test='*' local oldcontext="$curcontext" diff --git a/Completion/Debian/Command/_a2utils b/Completion/Debian/Command/_a2utils index 46126282f..8ee30ecf1 100644 --- a/Completion/Debian/Command/_a2utils +++ b/Completion/Debian/Command/_a2utils @@ -1,6 +1,6 @@ #compdef a2ensite a2dissite a2enmod a2dismod -local -a mods +local -a expl mods case "$service" in a2ensite) @@ -21,4 +21,4 @@ case "$service" in ;; esac -return 0 +return diff --git a/Completion/Debian/Command/_apt b/Completion/Debian/Command/_apt index cd0783b4f..074fb0164 100644 --- a/Completion/Debian/Command/_apt +++ b/Completion/Debian/Command/_apt @@ -525,7 +525,7 @@ _apt-cache () { --installed:bool \ -- \ /$'help\0'/ \| \ - /$'add\0'/ /$'[^\0]#\0'/ ':files:index files:_files "$expl[@]"' \# \| \ + /$'add\0'/ /$'[^\0]#\0'/ ':files:index files:_files' \# \| \ /$'gencaches\0'/ \| \ /$'showpkg\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" avail' \# \| \ /$'showsrc\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" avail' \# \| \ @@ -595,10 +595,10 @@ _apt-config () { /$'shell\0'/ \ \( \ /$'[^\0]#\0'/ ':parameters:shell variable to assign:_parameters' \ - /$'[^\0]#\0'/ ':values:configuration key:compadd "$expl[@]" - ${${(f)"$(apt-config dump 2>&1)"}% *}' \ + /$'[^\0]#\0'/ ':values:configuration key:compadd - ${${(f)"$(apt-config dump 2>&1)"}% *}' \ \) \# \| \ /$'dump\0'/ \| \ - /"[]"/ ':argument-1:action:compadd "$expl[@]" shell dump' + /"[]"/ ':argument-1:action:compadd shell dump' _apt-config "$@" } diff --git a/Completion/Debian/Command/_bts b/Completion/Debian/Command/_bts index f415989b9..70b95ef96 100644 --- a/Completion/Debian/Command/_bts +++ b/Completion/Debian/Command/_bts @@ -22,16 +22,18 @@ compset -N '[,.]' && first=0 [[ $first -eq 0 ]] || compset -n 2 if [[ CURRENT -eq 1 ]]; then - _wanted cmd expl 'bts command' compadd show bugs close reopen retitle \ + _wanted cmd expl 'bts command' compadd show bugs reopen retitle \ reassign merge unmerge tag tags severity forwarded notforwarded help \ clone submitter found notfound block unblock user usertag usertags \ package owner noowner reportspam cache cleancache claim unclaim \ - subscribe unsubscribe fixed notfixed affects + subscribe unsubscribe fixed notfixed affects spamreport status \ + select done archive unarchive summary forcemerge limit listcachedbugs \ + version return fi case "$words[1]" in - (close|unmerge|notforwarded|noowner|reportspam) + (unmerge|notforwarded|noowner|reportspam|spamreport|archive|unarchive) if [[ CURRENT -eq 2 ]]; then _debbugs_bugnumber else @@ -75,7 +77,10 @@ case "$words[1]" in _wanted sep expl 'separator' compadd -S ' ' , . fi ;; - merge) + (status) + # TODO: some additional syntaxes aren't being completed. + ;& + (merge|forcemerge) _debbugs_bugnumber if [[ CURRENT -gt 2 ]]; then _wanted sep expl 'separator' compadd -S ' ' , . @@ -208,8 +213,10 @@ case "$words[1]" in ;; (cleancache) _alternative \ - 'package:package:_deb_packages avail' \ - 'email:email address:_email_addresses -c' \ + 'source-packages:source package:_deb_packages -P "src:" source' \ + 'package:binary package:_deb_packages avail' \ + 'email:email address:_email_addresses -c -P "from:"' \ + 'bugnum:bug number:_debbugs_bugnumber' \ 'all:all:compadd ALL' ;; (claim|unclaim) @@ -232,6 +239,51 @@ case "$words[1]" in _wanted package expl 'package' _deb_packages avail fi ;; + (summary) + case $CURRENT in + (2) _debbugs_bugnumber;; + (3) _message -e message-number 'message number';& + (4) _wanted sep expl 'separator' compadd -S ' ' , .;; + esac + ;; + (close|done) + case $CURRENT in + (2) _debbugs_bugnumber;; + (3) _message -e version 'version';& + (4) _wanted sep expl 'separator' compadd -S ' ' , .;; + esac + ;; + (select) + _values -S : -w "select field" \ + '*package[binary package]: :_deb_packages avail' \ + '*source[source package]: :_deb_packages source' \ + '*maintainer:email address of the maintainer:_email_addresses -c' \ + '*submitter:email address of the submitter:_email_addresses -c' \ + '*severity:severity:(wishlist minor normal important serious grave critical)' \ + '*tag[tags applied to the bug]:tags:' \ + '*owner:owner:_email_addresses -c' \ + '*correspondent:email address of a correspondent:_email_addresses -c' \ + '*affects:affected package:_deb_packages avail' \ + '*users:namespaces of usertags:_email_addresses -c' \ + '*archive:whether to search archived bugs:((0:no 1:yes both:both))' + # undocumented: bugs + _wanted sep expl 'separator' compadd -S ' ' , . + ;; + (limit) + _values -S : -w "limit field" \ + '*submitter[email address of the submitter]:submitter:_email_addresses -c' \ + '*date[bug submission timestamp]:unix timestamp' \ + '*subject[subject of the bug]:bug subject:' \ + '*msgid[message-id of the initial bug report]:message-id:' \ + '*package[binary package]: :_deb_packages avail' \ + '*source[source package]: :_deb_packages source' \ + '*tag[tags applied to the bug]:tags:' \ + '*severity:severity:(wishlist minor normal important serious grave critical)' \ + '*owner:owner:_email_addresses -c' \ + '*affects:affected package:_deb_packages avail' \ + '*archive:whether to search archived bugs:((0:no 1:yes both:both))' + _wanted sep expl 'separator' compadd -S ' ' , . + ;; help) ;& *) _wanted sep expl 'separator' compadd -S ' ' , . diff --git a/Completion/Debian/Command/_lighttpd b/Completion/Debian/Command/_lighttpd index 7f4385b90..c24b42d13 100644 --- a/Completion/Debian/Command/_lighttpd +++ b/Completion/Debian/Command/_lighttpd @@ -1,16 +1,16 @@ #compdef lighty-enable-mod lighty-disable-mod -local -a mods +local -a mods expl case "$service" in lighty-enable-mod) mods=( `echo /etc/lighttpd/conf-available/*.conf(N:r:t) | sed -e 's/\b[0-9][0-9]-//g'` ) - _wanted mods expl mods compadd -a mods + _wanted mods expl mod compadd -a mods ;; lighty-disable-mod) mods=( `echo /etc/lighttpd/conf-enabled/*.conf(N:r:t) | sed -e 's/\b[0-9][0-9]-//g'` ) - _wanted mods expl mods compadd -a mods + _wanted mods expl mod compadd -a mods ;; esac -return 0 +return diff --git a/Completion/Debian/Command/_lintian b/Completion/Debian/Command/_lintian index 16af5085b..d60acc9ed 100644 --- a/Completion/Debian/Command/_lintian +++ b/Completion/Debian/Command/_lintian @@ -1,6 +1,6 @@ #compdef lintian lintian-info -local line cmds ret=1 +local curcontext="$curcontext" state line expl cmds ret=1 case "$service" in (lintian) @@ -55,7 +55,7 @@ case "$service" in (args) case $line[1] in -t|--tags) - _wanted tag expl 'tag' compadd $(command awk '/^Tag:/ { print $2 }' /usr/share/lintian/checks/*.desc) && ret=0 + _wanted tags expl 'tag' compadd $(command awk '/^Tag:/ { print $2 }' /usr/share/lintian/checks/*.desc) && ret=0 ;; esac ;; diff --git a/Completion/Debian/Command/_pbuilder b/Completion/Debian/Command/_pbuilder index 9322d036a..6377538b2 100644 --- a/Completion/Debian/Command/_pbuilder +++ b/Completion/Debian/Command/_pbuilder @@ -14,8 +14,8 @@ else '--buildresult:location:_files -/' \ '--mirror:URL:_urls' \ '--othermirror:URL:_urls' \ - '--distribution:suite:(breezy dapper edgy etch feisty gutsy hardy hoary intrepid jaunty jessie karmic lenny lucid potato sarge sid squeeze warty woody' \ - '--architecture:architecture:i_deb_architectures' \ + '--distribution:codename:_deb_codenames' \ + '--architecture:architecture:_deb_architectures' \ '--components:component:(main contrib non-free)' \ '--override-config' \ '--hookdir:location:_files -/' \ diff --git a/Completion/Debian/Command/_wajig b/Completion/Debian/Command/_wajig index 350eee658..26d08cfd7 100644 --- a/Completion/Debian/Command/_wajig +++ b/Completion/Debian/Command/_wajig @@ -1,6 +1,6 @@ #compdef wajig -local curcontext="$curcontext" state line cmds argno ret=1 +local curcontext="$curcontext" state line expl cmds argno ret=1 _arguments -C -s \ '(- 1 *)'{-h,--help}'[print usage message]' \ diff --git a/Completion/Debian/Type/_deb_architectures b/Completion/Debian/Type/_deb_architectures index 22c43dd3e..1429112a8 100644 --- a/Completion/Debian/Type/_deb_architectures +++ b/Completion/Debian/Type/_deb_architectures @@ -1,6 +1,6 @@ #autoload -local extra +local extra expl zparseopts -E -D -a extra a: _description architectures expl 'architecture' diff --git a/Completion/Debian/Type/_deb_codenames b/Completion/Debian/Type/_deb_codenames new file mode 100644 index 000000000..feea8b49a --- /dev/null +++ b/Completion/Debian/Type/_deb_codenames @@ -0,0 +1,12 @@ +#autoload + +local distro codenames ret=1 + +for distro in /usr/share/distro-info/*.csv(N); do + # TODO: magic number "6" + codenames=( ${(f)"$(<$distro tail -n6 | cut -d, -f3,1)"} ) + codenames=( ${codenames/(#b)(*),(*)/${match[2]}:${match[1]}} ) + _describe -V -t codename-${distro:t:r} "${distro:t:r} codenames" codenames && ret=0 +done + +return ret diff --git a/Completion/Debian/Type/_debbugs_bugnumber b/Completion/Debian/Type/_debbugs_bugnumber index f7b09054d..85e0c60d6 100644 --- a/Completion/Debian/Type/_debbugs_bugnumber +++ b/Completion/Debian/Type/_debbugs_bugnumber @@ -1,6 +1,8 @@ #autoload # TODO: use _describe with some basic metadata (e.g., bug title/package/version) +local expl + [[ $PREFIX$SUFFIX == [0-9]# ]] || return 1 # The cache directory moved; try both locations. diff --git a/Completion/Linux/Command/_ethtool b/Completion/Linux/Command/_ethtool index 5d607741f..71f5ed3bf 100644 --- a/Completion/Linux/Command/_ethtool +++ b/Completion/Linux/Command/_ethtool @@ -1,6 +1,6 @@ #compdef ethtool -local -a cmds +local -a expl cmds if [[ $CURRENT -ge 4 ]]; then case $words[CURRENT-1] in diff --git a/Completion/Linux/Command/_iptables b/Completion/Linux/Command/_iptables index 8f990030c..4178a1a2e 100644 --- a/Completion/Linux/Command/_iptables +++ b/Completion/Linux/Command/_iptables @@ -47,7 +47,7 @@ case ${prev[${prev[(I)-p|--protocol]}+1]}; in esac case ${prev[${prev[(I)-j|--jump]}+1]}; in - DNAT) args+=( '(--to,--to-destination)'{--to,--to-destination}':address:_users-ports' ) ;; + DNAT) args+=( '(--to --to-destination)'{--to,--to-destination}':address:_users-ports' ) ;; DSCP) args+=( '--set-dscp[set the DSCP field]:value' @@ -67,7 +67,7 @@ case ${prev[${prev[(I)-j|--jump]}+1]}; in MARK) args+=( '--set-mark[set fwmark in packet]:number' ) ;; REDIRECT|MASQUERADE) args+=( '--to-ports[port (range) to map to]:port range:_ports' ) ;; REJECT) args+=( '--reject-with[drop packet and send reply]:reject type:->reject-types' ) ;; - SNAT) args+=( '(--to,--to-source)*'{--to,--to-source}'[specify address to map source to]:address:_users-ports' ) ;; + SNAT) args+=( '(--to --to-source)*'{--to,--to-source}'[specify address to map source to]:address:_users-ports' ) ;; TCPMSS) args+=( '--set-mss[explicitly set MSS option]:value' diff --git a/Completion/Linux/Command/_lsblk b/Completion/Linux/Command/_lsblk new file mode 100644 index 000000000..c8fbb27c7 --- /dev/null +++ b/Completion/Linux/Command/_lsblk @@ -0,0 +1,58 @@ +#compdef lsblk + +local sep ret=1 +local -a values dedup suf=( -qS , ) +local curcontext="$curcontext" state line expl +typeset -A opt_args + +_arguments -C -s -S \ + '(H -a --all)'{-a,--all}'[print all devices]' \ + '(H -b --bytes)'{-b,--bytes}'[print size in bytes rather than in human readable format]' \ + '(H -d --nodeps)'{-d,--nodeps}"[don't print slaves or holders]" \ + '(H -I --include)*'{-e,--exclude}'[exclude devices by major number]:major device number:->majorlist' \ + '(H -e --exclude)*'{-I+,--include=}'[show only devices with specified major numbers]:major device number:->majorlist' \ + '(H -n --noheadings)'{-n,--noheadings}"[don't print headings]" \ + '(H -p --paths)'{-p,--paths}'[print complete device path]' \ + '(H -s --inverse)'{-s,--inverse}'[reverse dependency order]' \ + '(H -x --sort)'{-x+,--sort=}'[sort output by specified column]:column:->columns' \ + '*:device:_files -g "*(-%b)" -P / -W /' \ + + fields \ + '(H -D --discard -o --output -O --output-all)'{-D,--discard}'[output discard capabilities]' \ + '(H -z --zoned -o --output -O --output-all)'{-z,--zoned}'[output zone model]' \ + '(H -f --fs -o --output -O --output-all)'{-f,--fs}'[output info about filesystems]' \ + '(H -m --perms -o --output -O --output-all)'{-m,--perms}'[output info about permissions]' \ + '(H -S --scsi -o --output -O --output-all)'{-S,--scsi}'[output info about SCSI devices]' \ + '(H -t --topology -o --output -O --output-all)'{-t,--topology}'[output info about topology]' \ + '(H fields)'{-o+,--output=}'[specify output columns]:output column:->columnlist' \ + '(H fields)'{-O,--output-all}'[output all columns]' \ + + '(format)' \ + '(H)'{-i,--ascii}'[output ascii characters only]' \ + '(H)'{-J,--json}'[use JSON output format]' \ + '(H)'{-l,--list}'[use list format output]' \ + '(H)'{-P,--pairs}'[use key="value" output format]' \ + '(H)'{-r,--raw}'[use raw output format]' \ + + 'H' \ + '(* -)'{-h,--help}'[display help information]' \ + '(* -)'{-V,--version}'[display version information]' && ret=0 + +case $state in + *list) + dedup=( ${(Ms.,.)PREFIX##*,} ${(Ms.,.)SUFFIX%%,*} ) + compset -S ',*' && suf=() + compset -P '*,' + ;| + column*) + values=( + ${${${${(f)"$(_call_program columns lsblk -h)"}[(r)Available*,-3]## #}[2,-1]//:/\\:}/ /:} + ) + _describe -t fields column values -M 'm:{a-z}={A-Z}' $suf -F dedup && ret=0 + ;; + major*) + zstyle -s ":completion:${curcontext}:" list-separator sep || sep=-- + values=( ${${${(f)"$(</proc/devices)"}[(r)Block*,-1]## #}[2,-1]/ /:} ) + zformat -a values " $sep " $values + _wanted -V devices expl 'major device number' compadd $suf -d values -F dedup ${values%% *} && ret=0 + ;; +esac + +return ret diff --git a/Completion/Linux/Command/_lsusb b/Completion/Linux/Command/_lsusb index 17240e03d..129309b8b 100644 --- a/Completion/Linux/Command/_lsusb +++ b/Completion/Linux/Command/_lsusb @@ -1,19 +1,21 @@ #compdef lsusb -local context state line usbidsline vendorid pair +local usbidsline vendorid pair ret=1 +local curcontext="$curcontext" state line expl typeset -A opt_args -_arguments \ - '(-v --verbose)'{-v,--verbose}'[be verbose]' \ - '-s:bus and/or devnum to show:' \ - '-d:vendor and product to show:->vendorproduct' \ - '-D:device to show:_files' \ - '-t[dump the physical USB device hierarchy as a tree]' \ - '(-V --version)'{-V,--version}'[print version info and exit]' && return 0 +_arguments -C \ + '(-v --verbose -t --tree)'{-v,--verbose}'[be verbose]' \ + '-s+[filter devices by bus and/or device number]:bus and/or devnum to show' \ + '-d+[filter devices by vendor/product ID]:vendor and product to show:->vendorproduct' \ + '-D+[display only specified device]:device:_files -g "*(-%)" -P / -W /' \ + '(-t --tree -v --verbose)'{-t,--tree}'[dump the physical USB device hierarchy as a tree]' \ + '(-)'{-V,--version}'[print version information]' \ + '(-)'{-h,--help}'[print help information]' && ret=0 - if [[ ${+_lsusb_vendors} -eq 0 ]]; then - typeset -A _lsusb_vendors _lsusb_devices - while IFS="" read usbidsline +if [[ -n $state && ${+_lsusb_vendors} -eq 0 ]]; then + typeset -A _lsusb_vendors _lsusb_devices + cat /usr/share/(misc|hwdata)/usb.ids | while IFS="" read usbidsline do case "$usbidsline" in ((#b)([0-9a-f]##) ##(*)) @@ -25,7 +27,9 @@ _arguments \ _lsusb_devices[${pair}]="$match[2]" ;; esac - done < /usr/share/misc/usb.ids + done fi -compadd -k _lsusb_devices +_wanted products expl 'vendor ID:product ID' compadd -k _lsusb_devices && ret=0 + +return ret diff --git a/Completion/Linux/Command/_mdadm b/Completion/Linux/Command/_mdadm index b2af3269d..b6dce7ccb 100644 --- a/Completion/Linux/Command/_mdadm +++ b/Completion/Linux/Command/_mdadm @@ -78,7 +78,7 @@ if (( $+words[(r)-(A|-assemble)] )); then '(--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/_ss b/Completion/Linux/Command/_ss index 90d83a4c4..e5289b0a7 100644 --- a/Completion/Linux/Command/_ss +++ b/Completion/Linux/Command/_ss @@ -28,6 +28,7 @@ _arguments -C -s \ "($info -4 --ipv4 -6 --ipv6)"{-6,--ipv6}'[display only IP version 6 sockets]' \ "($info -0 --packet)"{-0,--packet}'[display PACKET sockets]' \ "($info -t --tcp)"{-t,--tcp}'[display TCP sockets]' \ + "($info -S --sctp)"{-S,--sctp}'[display SCTP sockets]' \ "($info -u --udp)"{-u,--udp}'[display UDP sockets]' \ "($info -d --dccp)"{-d,--dccp}'[display DCCP sockets]' \ "($info -w --raw)"{-w,--raw}'[display RAW sockets]' \ diff --git a/Completion/Linux/Command/_sshfs b/Completion/Linux/Command/_sshfs index 534e806e3..fe976288d 100644 --- a/Completion/Linux/Command/_sshfs +++ b/Completion/Linux/Command/_sshfs @@ -1,39 +1,65 @@ #compdef sshfs -local context state state_descr line +local curcontext="$curcontext" state state_descr line typeset -A opt_args -local curcontext="$curcontext" integer ret=1 _arguments -C \ - '-V[version]' \ - '-p:tcp port:' \ - '-C[compression]' \ - '-o:options:->options' \ - '-d[debug]' \ + '(-)'{-h,--help}'[display help information]' \ + '(-)'{-V,--version}'[display version information]' \ + '-p[specify TCP port]:tcp port:_ports' \ + '-C[enable compression]' \ + '-F[specify ssh config file]:file:_files' \ + '-o[specify mount options]:options:->options' \ + '(-f)-d[enable debug output]' \ '-f[foreground]' \ '-s[disable multithreaded operation]' \ - '-r[mount read-only]' \ - '-h[help]' \ ':remote directory:_user_at_host -S:' \ ':mountpoint:_files -/' && ret=0 if [[ $state == options ]]; then _values -s , "sshfs or fuse or mount options" \ - reconnect sshfs_sync no_readahead sshfs_debug \ + debug reconnect delay_connect sshfs_sync no_readahead sync_readdir sshfs_debug \ 'cache:cache setting:(yes no)' \ - cache_timeout:seconds: \ - cache_stat_timeout:seconds: \ - cache_dir_timeout:seconds: \ - cache_link_timeout:seconds: \ + 'cache_max_size:size [10000]' \ + 'cache_timeout:timeout (seconds) [20]' \ + cache_{stat,dir,link}_timeout:'timeout (seconds)' \ + 'cache_clean_interval:interval [60]' \ + 'cache_min_clean_interval:interval [5]' \ + 'workaround:workaround:(none all rename delaysrv truncate nobuflimit)' \ + 'idmap:user/group mapping:(none user file)' \ + uidfile:file:_files \ + gidfile:file:_files \ + 'nomap:type:(ignore error)' \ 'ssh_command:ssh command:_command_names' \ - directport:port: \ - 'SSHOPT:ssh option:' \ - default_permissions allow_other allow_root kernel_cache large_read direct_io \ - max_read:size: \ - hard_remove debug \ - fs_name:name: \ - use_ino readdir_ino && ret=0 + 'ssh_protocol:version:(1 2)' \ + sftp_server:path:_files \ + directport:port:_ports \ + slave disable_hardlink transform_symlinks follow_symlinks no_check_root password_stdin \ + allow_other allow_root auto_unmount nonempty default_permissions \ + fsname:filesystem\ name \ + subtype:filesystem\ type \ + large_read \ + max_read:max\ size \ + hard_remove use_ino readdir_ino direct_io kernel_cache auto_cache \ + 'umask:permissions' \ + 'uid:owner' 'gid:group' \ + 'entry_timeout:timeout (seconds) [1]' \ + 'negative_timeout:timeout (seconds) [0]' \ + 'attr_timeout:timeout (seconds) [1]' \ + 'ac_attr_timeout:timeout (seconds) [= attr_timeout]' \ + noforget \ + 'remember:time (seconds)' \ + nopath intr \ + 'intr_signal:signal [10]' \ + modules:module \ + max_write:size \ + max_readahead:readahead \ + max_background:number \ + congestion_threshold:threshold \ + async_read sync_read atomic_o_trunc big_writes no_remote_lock no_remote_flock \ + no_remote_posix_lock splice_write splice_move splice_read \ + from_code:charset to_code:charset subdir:_directories rellinks && ret=0 fi return ret diff --git a/Completion/Linux/Command/_strace b/Completion/Linux/Command/_strace index cbf95d6c4..cff9a49c6 100644 --- a/Completion/Linux/Command/_strace +++ b/Completion/Linux/Command/_strace @@ -53,7 +53,8 @@ case $state in 'raw[print raw, undecoded arguments for the specified set of system calls]:system call:_sequence _sys_calls -a -n' \ 'signal[trace only the specified subset of signals]:signal:_sequence _signals -s -M "B\:!="' \ 'read[perform a full hex and ASCII dump of all the data read from listed file descriptors]:file descriptor:_sequence _file_descriptors' \ - 'write[perform a full hex and ASCII dump of all the data written to listed file descriptors]:file descriptor:_sequence _file_descriptors' && ret=0 + 'write[perform a full hex and ASCII dump of all the data written to listed file descriptors]:file descriptor:_sequence _file_descriptors' \ + 'fault[perform syscall fault injection]:system call:_sys_calls -a -n' && ret=0 if [[ $words[CURRENT] != *=* || $state = syscalls ]]; then local dedup sets suf="-qS," compset -P '!' diff --git a/Completion/Solaris/Command/_svcadm b/Completion/Solaris/Command/_svcadm index 347e25e2a..c9826f2eb 100644 --- a/Completion/Solaris/Command/_svcadm +++ b/Completion/Solaris/Command/_svcadm @@ -1,7 +1,7 @@ #compdef svcadm _svcadm() { - local context state line subcmds + local curcontext="$curcontext" state line expl subcmds typeset -A opt_args subcmds=( enable disable restart refresh mark delegate clear milestone ) diff --git a/Completion/Solaris/Command/_svccfg b/Completion/Solaris/Command/_svccfg index 08c5e4bcd..d31682e77 100644 --- a/Completion/Solaris/Command/_svccfg +++ b/Completion/Solaris/Command/_svccfg @@ -14,7 +14,7 @@ _svccfg_properties() { # Get all the property names for the FMRI props=( ${${${(f)"$(svccfg -s $fmri describe)"}:# *}%% *} ) - _multi_parts "$expl[@]" - / props + _multi_parts "$@" - / props } _svccfg() { diff --git a/Completion/Solaris/Type/_svcs_fmri b/Completion/Solaris/Type/_svcs_fmri index 80d3516c0..ffade6985 100644 --- a/Completion/Solaris/Type/_svcs_fmri +++ b/Completion/Solaris/Type/_svcs_fmri @@ -2,7 +2,7 @@ _svcs_fmri() { local type="$argv[$#]" - local fmri_abbrevs m i + local fmri_abbrevs m i expl typeset -a -g _smf_fmris local update_policy diff --git a/Completion/Unix/Command/_ant b/Completion/Unix/Command/_ant index 19c252a4e..080ce6857 100644 --- a/Completion/Unix/Command/_ant +++ b/Completion/Unix/Command/_ant @@ -51,7 +51,7 @@ _arguments -C \ '*-listener[add an instance of specified class as a project listener]:class:->class' \ '-noinput[do not allow interactive input]' \ '(-f -file -buildfile -s -find)'{-f,-file,-buildfile}'[use specified build file]:build file:_files -g "*.xml(-.)"' \ - '*-D[specify property with value to use]:property:->property' \ + '*-D+[specify property with value to use]:property:->property' \ '(-k -keep-going)'{-keep-going,-k}'[execute all targets that do not depend on failed target(s)]' \ '-propertyfile[load all properties from specified file with -D properties taking precedence]:property file:_files -g "*.properties(-.)"' \ '-inputhandler[specify class which will handle input requests]:class:->class' \ diff --git a/Completion/Unix/Command/_basename b/Completion/Unix/Command/_basename new file mode 100644 index 000000000..a826b56b0 --- /dev/null +++ b/Completion/Unix/Command/_basename @@ -0,0 +1,27 @@ +#compdef basename gbasename + +local args variant +_pick_variant -r variant gnu=GNU $OSTYPE --version + +case $variant in + gnu) + args=( -s -S -A "-*" + '(2 -a --multiple)'{-a,--multiple}'[support multiple arguments, handling each]' + '(2 -a --multiple -s --suffix)'{-s+,--suffix=}'[remove a trailing suffix]:suffix' + '(-z --zero)'{-z,--zero}'[separate output with NUL rather than newline]' + '(- *)--version[display version information]' + '(- *)--help[display help information]' + ) + ;; + darwin*|dragonfly*|freebsd*) + args=( -s -S -A "-*" + '(2)-a[support multiple arguments, handling each]' + '(-a 2)-s+[remove a trailing suffix]:suffix' + ) + ;; +esac + +_arguments $args \ + '1:file:_files' \ + '(*)2:suffix' \ + '*:file:_files' diff --git a/Completion/Unix/Command/_cat b/Completion/Unix/Command/_cat index 57b197038..46180f2c8 100644 --- a/Completion/Unix/Command/_cat +++ b/Completion/Unix/Command/_cat @@ -19,8 +19,9 @@ if _pick_variant gnu=GNU unix --version; then '*:files:_files' ) -elif [[ "$OSTYPE" == (freebsd|dragonfly|darwin)* ]]; then +elif [[ "$OSTYPE" == (*bsd|dragonfly|darwin)* ]]; then args=( + -A "-*" '(-n)-b[number non-blank output lines]' '(-v)-e[display $ at the end of each line (implies -v)]' '-n[number all output lines]' @@ -28,12 +29,27 @@ elif [[ "$OSTYPE" == (freebsd|dragonfly|darwin)* ]]; then '(-v)-t[display tab as ^I (implies -v)]' '-u[do not buffer output]' '-v[display non-printing chars as ^X or M-a]' - '(-)*:files:_files' + '*:files:_files' ) - [[ $OSTYPE = freebsd* ]] && args+=( + [[ $OSTYPE = (free|net)bsd* ]] && args+=( '-l[set a lock on the stdout file descriptor]' ) - + [[ $OSTYPE = netbsd* ]] && args+=( + '-B+[read with buffer of specified size]:size (bytes)' + '-f[only attempt to display regular files]' + ) +elif [[ $OSTYPE = solaris* ]]; then + args=( + -A "-*" + '(-b)-n[number all output lines]' + '(-n)-b[number non-blank output lines]' + "-u[don't buffer output]" + '-s[be silent about non-existent files]' + '-v[display non-printing chars as ^X or M-a]' + '-e[display $ at the end of each line (requires -v)]' + '-t[display tab as ^I and formfeeds and ^L (requires -v)]' + '*:files:_files' + ) else # POSIX reqires '-u', and most OSes may support '-n' args=( @@ -43,4 +59,4 @@ else ) fi -_arguments -s -S : $args +_arguments -s -S $args diff --git a/Completion/Unix/Command/_cdrdao b/Completion/Unix/Command/_cdrdao index 0c3cfb82e..ceb86267c 100644 --- a/Completion/Unix/Command/_cdrdao +++ b/Completion/Unix/Command/_cdrdao @@ -262,14 +262,14 @@ _cdrdao-copy () { __cdrdao-device () { # Use cdrdao scanbus and also check what OS we're running under and provide # additional stuff, like devices (/dev/sg0) - local -a devices + local -a expl devices devices=(${${(f)"$(_call_program devices cdrdao scanbus -v 0 2>&1)"}%% :*}) _wanted devices expl 'device' compadd -a devices } __cdrdao-drivers () { - local suf + local expl suf local -Ua drivers drivers=(${(f)"$(_call_program drivers cut -d'\|' -f4 /usr/share/cdrdao/drivers -s)"}) if compset -P \*:; then diff --git a/Completion/Unix/Command/_darcs b/Completion/Unix/Command/_darcs index d40ecda28..74734711d 100644 --- a/Completion/Unix/Command/_darcs +++ b/Completion/Unix/Command/_darcs @@ -13,6 +13,8 @@ ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. +local expl + if (($CURRENT == 2)); then # We're completing the first word after "darcs" -- the command. _wanted command expl 'darcs command' \ diff --git a/Completion/Unix/Command/_date b/Completion/Unix/Command/_date index 731f6963b..a3e933710 100644 --- a/Completion/Unix/Command/_date +++ b/Completion/Unix/Command/_date @@ -8,14 +8,15 @@ opts=( -s -w -C ) if _pick_variant gnu="Free Software Foundation" unix --version; then local d='(-d --date -f --file -r --reference -s --set)' - local f='(-I --iso-8601 -R --rfc-2822 --rfc-3339)' + local f='(-I --iso-8601 -R --rfc-email --rfc-3339)' args=( $d{-d+,--date=}'[output date specified by string]:time string' + '--debug[annotate parsed date and warn about questionable usage]' $d{-f+,--file=}'[output dates specified in file]:file:_files' $d{-r+,--reference=}'[output last modification time of specified file]:file:_files' $d{-s+,--set=}'[set time]:time string' $f{-I-,--iso-8601=-}'[display in ISO 8601 format]::precision:(date hours minutes seconds ns)' - $f{-R,--rfc-2822}'[display in RFC2822 format]' + $f{-R,--rfc-email}'[display in RFC5322 format]' $f'--rfc-3339=-[display in RFC 3339 format]:precision:(date seconds ns)' '(-u --utc --universal)'{-u,--utc,--universal}'[display or set time in UTC]' '(- :)--help[output help and exit]' diff --git a/Completion/Unix/Command/_dbus b/Completion/Unix/Command/_dbus index fd035743f..3f106cb5c 100644 --- a/Completion/Unix/Command/_dbus +++ b/Completion/Unix/Command/_dbus @@ -22,7 +22,7 @@ case $service in _arguments -A "--*" -C \ '*:watch expression:->expressions' \ - '(bus)' \ - --system --session + --system --session \ '--address=-:bus address:->addresses' \ - '(format)' \ --monitor --profile --pcap --binary && ret=0 diff --git a/Completion/Unix/Command/_df b/Completion/Unix/Command/_df index a98180a2c..d20ddea7e 100644 --- a/Completion/Unix/Command/_df +++ b/Completion/Unix/Command/_df @@ -5,12 +5,6 @@ local -A opt_args if _pick_variant gnu=GNU unix --version; then args=( - '(-B --block-size -k)'{-B+,--block-size=}'[specify block size]:size (bytes)' - '(-B --block-size -k)-k[like --block-size=1K]' - '(-P --portability)'{-P,--portability}'[use the POSIX output format]' - '(-h --human-readable -H --si)'{-h,--human-readable}'[print sizes in human readable format]' - '(-h --human-readable -H --si)'{-H,--si}'[human readable fomat, but use powers of 1000 not 1024]' - '(-i --inodes)'{-i,--inodes}'[list inode information instead of block usage]' '--total[produce a grand total]' '(-T --print-type)'{-T,--print-type}'[print file system type]' '(-a --all)'{-a,--all}'[include dummy file systems]' @@ -22,7 +16,14 @@ if _pick_variant gnu=GNU unix --version; then '-v[(ignored)]' '(- : *)--help[display help and exit]' '(- : *)--version[output version information and exit]' - '*:files:_files' + '*:files:_umountable' + - '(format)' + {-B+,--block-size=}'[specify block size]:size (bytes)' + '-k[like --block-size=1K]' + {-P,--portability}'[use the POSIX output format]' + {-h,--human-readable}'[print sizes in human readable format]' + {-H,--si}'[human readable format, but use powers of 1000 not 1024]' + {-i,--inodes}'[list inode information instead of block usage]' ) elif [[ "$OSTYPE" == (darwin|freebsd|dragonfly)* ]]; then args=( @@ -38,7 +39,7 @@ elif [[ "$OSTYPE" == (darwin|freebsd|dragonfly)* ]]; then '-i[include inode usage statistics (default)]' '-l[only display locally-mounted file systems]' '-n[use previously obtained statistics]' - '*:files:_files' + '*:files:_umountable' ) spec='[only display file systems of specified types]:file system type:->fslist' case "$OSTYPE" in @@ -58,7 +59,7 @@ else '-k[use 1024-byte blocks]' '-P[POSIX compliant output]' '-t[include total allocated-space figures in the output]' - '*:files:_files' + '*:files:_umountable' ) fi diff --git a/Completion/Unix/Command/_diffstat b/Completion/Unix/Command/_diffstat index 9b4b2da6e..c9f8e3049 100644 --- a/Completion/Unix/Command/_diffstat +++ b/Completion/Unix/Command/_diffstat @@ -1,19 +1,32 @@ #compdef diffstat -_arguments \ +_arguments -s -S \ + '-b[ignore lines indicating binary file differences]' \ '-c[prefix each line with hash mark]' \ - '-e:error file:_files' \ - '-f:histogram format:((0\:concise 1\:normal 2\:dots 3\:dots+normal 4\:value 5\:value+normal 6\:value+dots 7\:value+dots+normal))' \ - '-h[help]' \ + '-C[use color highlighting of histogram]' \ + '-d[print debug information]' \ + '-D[specify location of patched files for unchanged count]:location:_directories' \ + '-e[redirect standard error to specified file]:error file:_files' \ + '-E[trim escape sequences, e.g. from colordiff]' \ + '-f[specify histogram format]:format:((0\:concise 1\:normal 2\:dots 3\:dots+normal 4\:value 5\:value+normal 6\:value+dots 7\:value+dots+normal))' \ + '(- *)-h[display help information]' \ '-k[suppress merging of filenames in report]' \ + '-K[resolve ambiguity of "only" filenames]' \ '-l[list only the filenames]' \ - '-n:minimum width for filenames:' \ - '-o:output file:_files' \ - '-p:number of path components:' \ - '-f:rounding code:((0\:none 1\:round 2\:round+adjustment))' \ - '-t[overrides histogram, generates csv output]' \ + '-m[merge insert/delete data in chunks as modified-lines]' \ + '-n[specify minimum width for filenames]:width [auto]' \ + '-N[specify maximum width for filenames]:width [auto]' \ + '-o[redirect standard output to specified file]:output file:_files' \ + '-p[specify number of path separators to strip]:path components [common]' \ + '-q[suppress "0 files changed" message for empty diffs]' \ + '-r[specify rounding for histogram]:rounding:((0\:none 1\:simple 2\:simple+adjustment))' \ + '(-t)-s[show only the summary line]' \ + '-S[specify location of original files for unchanged count]:location:_directories' \ + '-R[assume patch was created with old and new files swapped]' \ + '(-T -s)-t[overrides histogram, generates csv output]' \ + '(-t)-T[print amounts (like -t) in addition to histogram]' \ '-u[suppress sorting of filenames in report]' \ '-v[show progress]' \ - '-V[print version number]' \ - '-w:maximum width of histogram:' \ - '*:file specifications:_files' + '(- *)-V[print version number]' \ + '-w[specify maximumn width of output]:maximum width [80]' \ + '*:patch file:_files' diff --git a/Completion/Unix/Command/_dig b/Completion/Unix/Command/_dig index 2b851c91f..a4e175808 100644 --- a/Completion/Unix/Command/_dig +++ b/Completion/Unix/Command/_dig @@ -15,15 +15,33 @@ local -a alts args '*+'{no,}'tcp[use TCP instead of UDP for queries]' '*+'{no,}'ignore[ignore truncation in UDP responses]' '*+domain=[set search list to single domain]:domain:_hosts' + '*+dscp=[set DSCP code point for query]:code point (0..63)' '*+'{no,}'search[use search list defined in resolv.conf]' '*+'{no,}'showsearch[show intermediate results in domain search]' + '*+split[split hex/base64 fields into chunks]:width (characters) [56]' '*+'{no,}'aaonly[set aa flag in the query]' + '*+'{no,}'additional[print additional section of a reply]' '*+'{no,}'adflag[set the AD (authentic data) bit in the query]' + '*+'{no,}'badcookie[retry BADCOOKIE responses]' '*+'{no,}'cdflag[set the CD (checking disabled) bit in the query]' - '*+'{no,}'cl[display the CLASS whening printing the record]' - '*+'{no,}'ttlid[display the TTL whening printing the record]' + '*+'{no,}'class[display the CLASS whening printing the record]' + '*+'{no,}'cookie[add a COOKIE option to the request]' + '*+'{no,}'crypto[display cryptographic fields in DNSSEC records]' + '*+edns=[specify EDNS version for query]:version (0-255)' + '*+noedns[clear EDNS version to be sent]' + '*+ednsflags=[set EDNS flags bits]:flags' + '*+'{no,}'ednsnegotiation[set EDNS version negotiation]' + '*+ednsopt=[specify EDNS option]:code point' + '*+noedns[clear EDNS options to be sent]' + '*+'{no,}'expire[send an EDNS Expire option]' + '*+'{no,}'header-only[send query without a question section]' + '*+'{no,}'idnout[set conversion of IDN puny code on output]' + '*+'{no,}'keepopen[keep TCP socket open between queries]' + '*+'{no,}'mapped[allow mapped IPv4 over IPv6 to be used]' '*+'{no,}'recurse[set the RD (recursion desired) bit in the query]' '*+'{no,}'nssearch[search all authoritative nameservers]' + '*+opcode[set DNS message opcode of the request]:opcode [QUERY]:(QUERY IQUERY STATUS NOTIFY UPDATE)' + '*+noopcode[clear DNS message opcode]' '*+'{no,}'trace[trace delegation down from root]' '*+'{no,}'cmd[print initial comment in output]' '*+'{no,}'short[print terse output]' @@ -34,15 +52,14 @@ local -a alts args '*+'{no,}'question[print question section of a query]' '*+'{no,}'answer[print answer section of a reply]' '*+'{no,}'authority[print authority section of a reply]' - '*+'{no,}'additional[print additional section of a reply]' '*+'{no,}'all[set all print/display flags]' - '*+time=[set query timeout]:timeout (seconds)' + '*+'{no,}'subnet[send EDNS client subnet option]:addr/prefix-length' + '*+timeout=[set query timeout]:timeout (seconds) [5]' '*+tries=[specify number of UDP query attempts]:tries' '*+retry=[specify number of UDP query retries]:retries' + '*+'{no,}'rrcomments[set display of per-record comments]' '*+ndots=[specify number of dots to be considered absolute]:dots' '*+bufsize=[specify UDP buffer size]:size (bytes)' - '*+edns=[specify EDNS version for query]:version (0-255)' - '*+noedns[clean EDNS version]' '*+'{no,}'multiline[verbose multi-line output]' '*+'{no,}'onesoa[AXFR prints only one soa record]' '*+'{no,}"fail[don't try next server on SERVFAIL]" @@ -52,6 +69,10 @@ local -a alts args '*+trusted-key=[specify file conrtaing trusted kets]:file:_files' '*+'{no,}'topdown[do DNSSEC validation in top down mode]' '*+'{no,}'nsid[include EDNS name server ID request in query]' + '*+'{no,}'ttlid[display the TTL whening printing the record]' + '*+'{no,}'ttlunits[display the TTL in human-readable units]' + '*+'{no,}'unknownformat[print RDATA in RFC 3597 "unknown" format]' + '*+'{no,}'zflag[set Z flag in query]' ) _arguments -s -C $args \ '(- *)-h[display help information]' \ diff --git a/Completion/Unix/Command/_django b/Completion/Unix/Command/_django index 029687696..9eaa2284a 100644 --- a/Completion/Unix/Command/_django +++ b/Completion/Unix/Command/_django @@ -49,6 +49,7 @@ case $state in "sqlreset:print the DROP TABLE and CREATE TABLE statements for the given app(s)" "sqlsequencereset:print the SQL statements for resetting sequences for the given app(s)" "startapp:create Django app directory in this project's directory" + "startproject:create a Django project directory structure for a given project name" "syncdb:create database tables for apps in INSTALLED_APPS where required" "test:run the test suite for the specified app, or the entire site" "testserver:run a development server with data from the given fixture(s)" diff --git a/Completion/Unix/Command/_dmidecode b/Completion/Unix/Command/_dmidecode index 5701a9403..eb273586f 100644 --- a/Completion/Unix/Command/_dmidecode +++ b/Completion/Unix/Command/_dmidecode @@ -5,9 +5,10 @@ _arguments -s \ '(-)'{-h,--help}'[display usage information]' \ '(-q --quiet -u --dump)'{-q,--quiet}'[be less verbose]' \ '(--type -u --dump --dump-bin -s --string)'{-s+,--string=}':DMI string:(bios-vendor bios-version bios-release-date system-manufacturer system-product-name system-version system-serial-number system-uuid baseboard-manufacturer baseboard-product-name baseboard-version baseboard-serial-number baseboard-asset-tag chassis-manufacturer chassis-type chassis-version chassis-serial-number chassis-asset-tag processor-family processor-manufacturer processor-version processor-frequency)' \ - '*(-s --string --dump-bin)'{-t+,--type=}'[only display entries of specified type]:entry type:(bios system baseboard chassis processor memory cache connector slot)' \ + '(-s --string --dump-bin)*'{-t+,--type=}'[only display entries of specified type]:entry type:(bios system baseboard chassis processor memory cache connector slot)' \ '(-q --quiet -u --dump -s --string)'{-u,--dump}"[don't decode entries]" \ '--dump-bin=[dump DMI data to a binary file]:file:_files' \ '(-d --dev-mem)--from-dump=[read DMI data from a binary file]:file:_files' \ "--no-sysfs[don't attempt to read DMI data from sysfs files]" \ + '--oem-string=[only display the value of the specified OEM string]:OEM string number' \ '(-)'{-V,--version}'[display version information]' diff --git a/Completion/Unix/Command/_entr b/Completion/Unix/Command/_entr new file mode 100644 index 000000000..8a830ae71 --- /dev/null +++ b/Completion/Unix/Command/_entr @@ -0,0 +1,9 @@ +#compdef entr + +_arguments -s -S \ + '-c[execute clear before invoking utility]' \ + '-d[track directories and exit if a new file is added]' \ + '-p[postpone first execution of the utility]' \ + '-r[reload a persistent child process]' \ + '(-):command name:_command_names -e' \ + '*::arguments:_normal' diff --git a/Completion/Unix/Command/_flex b/Completion/Unix/Command/_flex index 7ca5b0f83..80b0cd7fc 100644 --- a/Completion/Unix/Command/_flex +++ b/Completion/Unix/Command/_flex @@ -1,35 +1,52 @@ -#compdef flex +#compdef flex flex++ local curcontext="$curcontext" state line ret=1 typeset -A opt_args -_arguments -C -s \ - --help --version \ - '-b[generate backing-up information]' \ - '-d[make scanner running in debug mode]' \ - '-f[generate fast scanner (full table)]' \ - '-h[show help]' \ - '-i[generate case-insensitive scanner]' \ - '-l[maximum compatibility with lex]' \ - '-p[generate performance report]' \ - '-s[suppress default rule]' \ - '-t[write scanner to stdout]' \ - '-v[show summary of statistics about scanner]' \ - '-w[suppress warnings]' \ - '-B[generate batch scanner]' \ - '-F[use fast scanner table representation]' \ - '-I[generate interactive scanner]' \ - '-L[don'"'"'t generate #line directives]' \ - '-T[trace mode]' \ - '-V[show version]' \ - '-7[generate 7-bit scanner]' \ - '-8[generate 8-bit scanner]' \ - '-\+[generate C++ scanner class]' \ +_arguments -C -s -S \ '-C-[specify degree of table compression]:table compression:->tabcomp' \ - '-o-[specify output file]:output file:_files' \ - '-P-[change yy prefix]:prefix string:' \ - '-S-[override skeleton file]:skeleton file:_files' \ - '*:input files:_files -g "*.(#i)(f|)lex(-.)"' && ret=0 + '--align[trade off larger tables for better memory alignment]' \ + '--ecs[construct equivalence classes]' \ + '--meta-ecs[construct meta-equivalence classes]' \ + '--read[use read() instead of stdio for scanner input]' \ + '(-f --full)'{-f,--full}'[generate fast scanner (full table)]' \ + '(-F --fast)'{-F,--fast}'[use fast scanner table representation]' \ + '(-d --debug)'{-d,--debug}'[enable debug mode in scanner]' \ + '(-b --backup)'{-b,--backup}'[write backup information to lex.backup]' \ + '(-p --perf-report)'{-p,--perf-report}'[generate performance report]' \ + '(-s --nodefault)'{-s,--nodefault}'[suppress default rule to ECHO unmatched text]' \ + '(-T --trace)'{-T,--trace}'[trace mode]' \ + '(-w --nowarn)'{-w,--nowarn}'[suppress warnings]' \ + '(-v --verbose)'{-v,--verbose}'[show summary of statistics about scanner]' \ + '--hex[use hexadecimal numbers instead of octal in debug outputs]' \ + '(-o --outfile)'{-o+,--outfile=}'[specify output file]:output file:_files' \ + '(-S --skel)'{-S+,--skel=}'-[override skeleton file]:skeleton file:_files' \ + '(-t --stdout)'{-t,--stdout}'[write scanner to stdout]' \ + '--yyclass=[specify name of C++ class]:class name' \ + '--header-file=-[create a C header file in addition to the scanner]:file:_files' \ + '--tables-file=-[write tables to file]::tables file:_files' \ + '(-7 -8 --7bit --8bit)'{-7,--7bit}'[generate 7-bit scanner]' \ + '(-7 -8 --7bit --8bit)'{-8,--8bit}'[generate 8-bit scanner]' \ + '(-B --batch -I --interactive)'{-B,--batch}'[generate batch scanner]' \ + '(-i --case-insensitive)'{-i,--case-insensitive}'[generate case-insensitive scanner]' \ + '(-l --lex-compat)'{-l,--lex-compat}'[maximum compatibility with original lex]' \ + '(-X --posix-compat)'{-l,--posix-compat}'[maximum compatibility with POSIX lex]' \ + '(-B --batch -I --interactive)'{-I,--interactive}'[generate interactive scanner]' \ + '--yylineno[track line count in yylineno]' \ + '-\+[generate C++ scanner class]' \ + '-D-[define macro]:macro' \ + '(-L --noline)'{-L,--noline}"[don't generate #line directives]" \ + '(-P --prefix)'{-P+,--prefix=}'[change yy prefix]:prefix string' \ + '(-R --reentrant)'{-R,--reentrant}'[generate a reentrant C scanner]' \ + '--bison-bridge[scanner for bison pure parser]' \ + '--bison-locations[include yylloc support]' \ + '--stdinit[initialize yyin/yyout to stdin/stdout]' \ + "--nounistd[don't include <unistd.h>]" \ + "--no-[don't generate a particular function]:function" \ + '(-c -n)'{-c,-n}'[do nothing]' \ + '(- *)'{-h,--help}'[display help information]' \ + '( *)'{-V,--version}'[display version information]' \ + '*:input file:_files -g "*.(#i)(f|)lex(-.)"' && ret=0 if [[ -n "$state" ]]; then _values -s '' 'table compression' \ @@ -38,7 +55,7 @@ if [[ -n "$state" ]]; then '(m)f[generate full tables]' \ '(m)F[generate fast tables]' \ '(f F)m[construct meta-equivalence classes]' \ - 'r[don'"'"'t use stdio library]' && ret=0 + "r[don't use stdio library]" && ret=0 fi return ret diff --git a/Completion/Unix/Command/_fmt b/Completion/Unix/Command/_fmt new file mode 100644 index 000000000..759396637 --- /dev/null +++ b/Completion/Unix/Command/_fmt @@ -0,0 +1,60 @@ +#compdef fmt + +local variant +local -a args +local copt="[preserve indentation of first two lines]" +local wopt="[specify maximum line width]:width [75]" +local sopt="[don't join short lines\: split only]" + +args=( -A "-*" "(1 2)-w+$wopt" '*:file:_files' ) +_pick_variant -r variant gnu=GNU unix --version +case $variant in + gnu) + args=( + '(-c --crown-margin)'{-c,--crown-margin}$copt + '(-w --width)'{-w+,--width=}$wopt + '(-p --prefix)'{-p+,--prefix=}'[only reformat lines with specified prefix]:prefix' + '(-s --split-only)'{-s,--split-only}$sopt + '(-t --tagged-paragraph)'{-t,--tagged-paragraph}'[indentation of first line different from second]' + '(-u --uniform-spacing)'{-u,--uniform-spacing}'[use one space between words, two after sentences]' + '(-g --goal)'{-g,--goal=}'[specify goal width]:goal width [93% of width]' + '(- *)--help[display help information]' + '(- *)--version[display version information]' + '*:file:_files' + ) + ;; + solaris*) + args=( + "-c$copt" + "-s$sopt" + ) + ;; + netbsd*) + args+=( + '-C[center the text]' + '(1 2)-g+[specify goal width]:goal width' + '(1 2)-m+[specify maximum width]:maximum width' + '-r[format all lines]' + ) + ;| + darwin*|dragonfly*|freebsd*|openbsd*) + args+=( + '-c[center the text line by line]' + '-m[sensible formatting of mail header lines]' + '-n[format lines beginning with a . (dot) character]' + "-p[change in indentation doesn't start new paragraph]" + '-s[collapse whitespace inside lines]' + '-d+[specify sentence-ending characters]:sentence ends [.?!]' + '-l+[replace initial spaces with tabs]:tab width [8]' + '-t+[specify tab width of input files]:tab width [8]' + ) + ;& # fall-through + netbsd*) + args+=( ':: :_guard "[0-9]#" goal width' ) + (( ${(M)#words[1,CURRENT-1]:#[0-9]##} )) && args+=( + ':: :_guard "[0-9]#" maximum width' + ) + ;; +esac + +_arguments -s -S $args diff --git a/Completion/Unix/Command/_gcc b/Completion/Unix/Command/_gcc index 1276054db..28a2ccbda 100644 --- a/Completion/Unix/Command/_gcc +++ b/Completion/Unix/Command/_gcc @@ -94,7 +94,7 @@ romp) ;; mips*) args=( - '-mcpu=:CPU type:(r2000 r3000 r4000 r4400 r4600 r6000_' + '-mcpu=:CPU type:(r2000 r3000 r4000 r4400 r4600 r6000)' -mabicalls -membedded-data -membedded-pic -mfp32 -mfp64 -mgas -mgp32 -mgp64 -mgpopt -mhalf-pic -mhard-float -mint64 -mips1 @@ -353,7 +353,7 @@ args+=( '-print-file-name=-[Display the full path to library <library>]:library:->library' '-print-prog-name=-[Display the full path to compiler component <program>]:program:' '*-specs=-[Override built-in specs with the contents of <file>]:file:_files' - '-std=-[Assume that the input sources are for <standard>]:standard:(c90 c89 c99 c11 gnu90 gnu89 gnu99 gnu11 c++98 c++03 gnu++98 gnu++03 c++11 gnu++11 c++1y gnu++1y)' + '-std=-[assume that the input sources are for specified standard]:standard:(c90 c89 c99 c11 gnu90 gnu89 gnu99 gnu11 c++98 c++03 gnu++98 gnu++03 c++11 gnu++11 c++1y gnu++1y c++14 gnu++14 c++1z gnu++1z)' '*-include:include file:_files -g \*.h\(-.\)' '*-imacros:macro input file:_files -g \*.h\(-.\)' '*-idirafter:second include path directory:_files -/' @@ -428,7 +428,7 @@ args+=( '-Wdisabled-optimization[Warn when an optimization pass is disabled]' '-Wdiv-by-zero[Warn about compile-time integer division by zero]' '-Wdouble-promotion[Warn about implicit conversions from "float" to "double"]' - '-Weffc++[Warn about violations of Effective C++ style rules]' + '-Weffc\+\+[Warn about violations of Effective C++ style rules]' '-Wempty-body[Warn about an empty body in an if or else statement]' '-Wendif-labels[Warn about stray tokens after #elif and #endif]' '-Wenum-compare[Warn about comparison of different enum types]' diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git index b5b3e79eb..518e6d198 100644 --- a/Completion/Unix/Command/_git +++ b/Completion/Unix/Command/_git @@ -292,7 +292,7 @@ _git-branch () { declare l c m d e l='--color --no-color -r --remotes -a -v --verbose --abbrev --no-abbrev --list --points-at --sort' - c='-l --create-reflog -f --force -t --track --no-track -u --set-upstream --set-upstream-to --unset-upstream --contains --merged --no-merged' + c='-l --create-reflog -f --force -t --track --no-track -u --set-upstream --set-upstream-to --unset-upstream --contains --no-contains --merged --no-merged' m='-m --move -M' d='-d --delete -D' e='--edit-description' @@ -341,9 +341,10 @@ _git-branch () { "($l $m $d $e)--no-track[override the branch.autosetupmerge configuration variable]" \ "($l $m $d $e -u --set-upstream --set-upstream-to --unset-upstream)"{-u+,--set-upstream-to=}"[set up configuration so that pull merges]:remote-branches:__git_remote_branch_names" \ "($l $m $d $e -u --set-upstream --set-upstream-to --unset-upstream)--unset-upstream[remove upstream configuration]" \ - "($l $m $d $e)--contains=[only list branches which contain the specified commit]: :__git_committishs" \ - "($l $m $d $e)--merged=[only list branches which are fully contained by HEAD]: :__git_committishs" \ - "($l $m $d $e)--no-merged=[don't list branches which are fully contained by HEAD]: :__git_committishs" \ + "($l $m $d $e)*--contains=[only list branches that contain the specified commit]: :__git_committishs" \ + "($l $m $d $e)*--no-contains=[only list branches that don't contain the specified commit]: :__git_committishs" \ + "($l $m $d $e)--merged=[only list branches that are fully contained by HEAD]: :__git_committishs" \ + "($l $m $d $e)--no-merged=[don't list branches that are fully contained by HEAD]: :__git_committishs" \ "($c $l $m $d)--edit-description[edit branch description]" \ $dependent_creation_args \ "($l $c $d $m $e)"{-m,--move}"[rename a branch and the corresponding reflog]" \ @@ -354,6 +355,7 @@ _git-branch () { {-q,--quiet}"[be more quiet]" \ '*--sort=[specify field to sort on]: :__git_ref_sort_keys' \ '--points-at=[only list tags of the given object]: :__git_commits' \ + "($c $m $d $e -i --ignore-case)"{-i,--ignore-case}'[sorting and filtering are case-insensitive]' \ $dependent_deletion_args } @@ -460,6 +462,7 @@ _git-checkout () { '(-)'{-p,--patch}'[interactively select hunks in diff between given tree-ish and working tree]' \ "--ignore-skip-worktree-bits[don't limit pathspecs to sparse entries only]" \ "--ignore-other-worktrees[don't check if another worktree is holding the given ref]" \ + '--recurse-submodules=-[control recursive updating of submodules]::checkout:__git_commits' \ '(-q --quiet)--progress[force progress reporting]' \ '(-)--[start file arguments]' \ '*:: :->branch-or-tree-ish-or-file' && ret=0 @@ -473,32 +476,29 @@ _git-checkout () { [[ $line[CURRENT] = -* ]] && return if (( CURRENT == 1 )) && [[ -z $opt_args[(I)--] ]]; then # TODO: Allow A...B - local branch_arg='' \ + local \ remote_branch_noprefix_arg='remote-branch-names-noprefix::__git_remote_branch_names_noprefix' \ - tree_ish_arg='tree-ishs::__git_tree_ishs' \ + tree_ish_arg='tree-ishs::__git_commits_prefer_recent' \ file_arg='modified-files::__git_modified_files' if [[ -n ${opt_args[(I)-b|-B|--orphan|--detach]} ]]; then - remote_branch_noprefix_arg= - file_arg= + _alternative $tree_ish_arg && ret=0 elif [[ -n $opt_args[(I)--track] ]]; then - branch_arg='remote-branches::__git_remote_branch_names' - remote_branch_noprefix_arg= - tree_ish_arg= - file_arg= + _alternative remote-branches::__git_remote_branch_names && ret=0 elif [[ -n ${opt_args[(I)--ours|--theirs|-m|--conflict|--patch]} ]]; then - remote_branch_noprefix_arg= + _alternative $tree_ish_arg $file_arg && ret=0 + else + _alternative \ + $file_arg \ + $tree_ish_arg \ + $remote_branch_noprefix_arg \ + && ret=0 fi - _alternative \ - $branch_arg \ - $remote_branch_noprefix_arg \ - $tree_ish_arg \ - $file_arg && ret=0 elif [[ -n ${opt_args[(I)-b|-B|-t|--track|--orphan|--detach]} ]]; then _nothing - elif [[ -n $line[1] ]] && __git_is_treeish $line[1]; then - __git_ignore_line __git_tree_files ${PREFIX:-.} $line[1] && ret=0 + elif [[ -n $line[1] ]] && __git_is_treeish ${(Q)line[1]}; then + __git_ignore_line __git_tree_files ${PREFIX:-.} ${(Q)line[1]} && ret=0 else __git_ignore_line __git_modified_files && ret=0 fi @@ -628,9 +628,10 @@ _git-clone () { '*--shallow-exclude=[shallow clone excluding commits reachable from specified remote revision]:revision' \ '(--no-single-branch)--single-branch[clone only history leading up to the main branch or the one specified by -b]' \ '(--single-branch)--no-single-branch[clone history leading up to each branch]' \ + "--no-tags[don't clone any tags and make later fetches not follow them]" \ '--shallow-submodules[any cloned submodules will be shallow]' \ '--recursive[initialize all contained submodules]' \ - '--recurse-submodules[initialize submodules in the clone]' \ + '--recurse-submodules=-[initialize submodules in the clone]::file:__git_files' \ '--separate-git-dir[place .git dir outside worktree]:path to .git dir:_path_files -/' \ '(-4 --ipv4 -6 --ipv6)'{-4,--ipv4}'[use IPv4 addresses only]' \ '(-4 --ipv4 -6 --ipv6)'{-6,--ipv6}'[use IPv6 addresses only]' \ @@ -688,7 +689,7 @@ _git-commit () { '(--reset-author)--author[override the author name used in the commit]:author name' \ '--date=[override the author date used in the commit]:date' \ '(-s --signoff)'{-s,--signoff}'[add Signed-off-by line at the end of the commit message]' \ - '(-n --no-verify)'{-n,--no-verify}'[do not look for suspicious lines the commit introduces]' \ + '(-n --no-verify)'{-n,--no-verify}'[bypass pre-commit and commit-msg hooks]' \ '--allow-empty[allow recording an empty commit]' \ '--allow-empty-message[allow recording a commit with an empty message]' \ '--cleanup=[specify how the commit message should be cleaned up]:mode:((verbatim\:"do not change the commit message at all" @@ -726,6 +727,7 @@ _git-commit () { _git-describe () { _arguments -S -s \ '(*)--dirty=-[describe HEAD, adding mark if dirty]::mark' \ + '(*)--broken=-[describe HEAD, adding mark if broken]::mark' \ '--all[use any ref found in "$GIT_DIR/refs/"]' \ '--tags[use any ref found in "$GIT_DIR/refs/tags"]' \ '(--tags)--contains[find the tag after the commit instead of before]' \ @@ -734,7 +736,8 @@ _git-describe () { '(--candidates )--exact-match[only output exact matches, same as --candidates=0]' \ '--debug[display information about the searching strategy]' \ '(--abbrev)--long[always show full format, even for exact matches]' \ - '--match=[only consider tags matching glob pattern]:pattern' \ + '*--match=[only consider tags matching glob pattern]:pattern' \ + "*--exclude=[don't consider tags matching glob pattern]:pattern" \ '--always[show uniquely abbreviated commit object as fallback]' \ '--first-parent[follow only the first parent of merge commits]' \ '*: :__git_committishs' @@ -754,7 +757,8 @@ _git-diff () { $diff_options \ '(--exit-code)--quiet[disable all output]' \ $diff_stage_options \ - '(--cached --staged)'{--cached,--staged}'[show diff between index and named commit]' \ + '(--cached --staged)--no-index[show diff between two paths on the filesystem]' \ + '(--cached --staged --no-index)'{--cached,--staged}'[show diff between index and named commit]' \ '(-)--[start file arguments]' \ '*:: :->from-to-file' && ret=0 @@ -772,6 +776,12 @@ _git-diff () { return ret fi + # If "--no-index" was given, only file paths need to be completed. + if [[ -n ${opt_args[(I)--no-index]} ]]; then + _alternative 'files::_files' && ret=0 + return ret + fi + # Otherwise, more complex conditions need to be checked. case $CURRENT in (1) @@ -965,6 +975,8 @@ _git-grep () { '(--cached)--no-index[search files in current directory, not just tracked files]' \ '(--exclude-standard)--no-exclude-standard[search also in ignored files]' \ '(--no-exclude-standard)--exclude-standard[exclude files standard ignore mechanisms]' \ + '--recurse-submodules[recursively search in each submodule]' \ + "--parent-basename=[prepend parent project's basename to output]:basename" \ '--untracked[search also in untracked files]' \ '(-a --text)'{-a,--text}'[process binary files as if they were text]' \ '(--textconv --no-textconv)--textconv[honor textconv filter settings]' \ @@ -1001,7 +1013,7 @@ _git-grep () { '(1)*-e+[use the given pattern for matching]:pattern' \ $pattern_operators \ '--all-match[all patterns must match]' \ - ':pattern' \ + ': :_guard "^-*" pattern' \ '*:: :->tree-or-file' && ret=0 # TODO: If --cached, --no-index, -O, or --open-files-in-pager was given, @@ -1175,6 +1187,7 @@ _git-merge () { '( --no-rerere-autoupdate)--rerere-autoupdate[allow the rerere mechanism to update the index]' \ '(--rerere-autoupdate )--no-rerere-autoupdate[do not allow the rerere mechanism to update the index]' \ '--abort[restore the original branch and abort the merge operation]' \ + '--continue[continue the current in-progress merge]' \ '--progress[force progress reporting]' \ '*: : __git_commits -O expl:git_commit_opts' } @@ -1355,6 +1368,7 @@ _git-push () { '--recurse-submodules=[submodule handling]:submodule handling:(( check\:"refuse to push if submodule commit not to be found on remote" on-demand\:"push all changed submodules" + only\:"submodules will be recursively pushed while the superproject is left unpushed" no\:"no submodule handling"))' \ "(--no-signed --signed)--sign=-[GPG sign the push]::signing enabled:(($^^sign))" \ '(--no-signed --sign)--signed[GPG sign the push]' \ @@ -1396,6 +1410,7 @@ _git-rebase () { '(-)--abort[abort current rebase]' \ '(-)--edit-todo[edit interactive instruction sheet in an editor]' \ '(-)--skip[skip the current patch]' \ + '(-)--quit[abort but keep HEAD where it is]' \ - options \ '(-m --merge)'{-m,--merge}'[use merging strategies to rebase]' \ '(-S --gpg-sign --no-gpg-sign)'{-S-,--gpg-sign=-}'[GPG-sign the commit]::key id' \ @@ -1421,6 +1436,7 @@ _git-rebase () { '(--autostash --no-autostash)--no-autostash[do not stash uncommitted changes before rebasing and apply them afterwards]' \ '--fork-point[use merge-base --fork-point to refine upstream]' \ '--ignore-date[use current timestamp for author date]' \ + '--signoff[add Signed-off-by: line to the commit message]' \ '--no-ff[cherry-pick all rebased commits with --interactive, otherwise synonymous to --force-rebase]' \ '--onto=[start new branch with HEAD equal to given revision]:newbase:__git_revisions' \ ':upstream branch:__git_revisions' \ @@ -1439,6 +1455,7 @@ _git-reset () { '(--soft --mixed --merge --keep -p --patch -- *)--hard[match the working tree and index to the given tree]' \ '(--soft --mixed --hard --keep -p --patch -- *)--merge[reset out of a conflicted merge]' \ '(--soft --mixed --hard --merge -p --patch -- *)--keep[like --hard, but keep local working tree changes]' \ + '--recurse-submodules=-[control recursive updating of submodules]::reset:__git_commits' \ '(-p --patch)'{-p,--patch}'[select diff hunks to remove from the index]' \ '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ '(--soft --mixed --hard --merge --keep):: :__git_commits' \ @@ -1447,6 +1464,12 @@ _git-reset () { case $state in (file) local tree=HEAD + if zstyle -t :completion:${curcontext}: verbose; then + if ! tree=$(_call_program headed git rev-parse --verify HEAD); then + # well-known sha1 of the empty tree + tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + fi + fi if [[ -n $line[1] ]] && __git_is_treeish $line[1]; then tree=$line[1] fi @@ -1606,6 +1629,7 @@ _git-stash () { _arguments -C \ '*::: :->args' \ + '(-m --message)'{-m,--message}'[specify stash description]' \ ${save_arguments//#\(/(* } && ret=0 if [[ -n $state ]]; then @@ -1613,7 +1637,7 @@ _git-stash () { local -a commands commands=( - save:'save your local modifications to a new stash' + {push,save}:'save your local modifications to a new stash' list:'list the stashes that you currently have' show:'show the changes recorded in the stash as a diff' pop:'remove and apply a single stashed state from the stash list' @@ -1635,6 +1659,12 @@ _git-stash () { $save_arguments \ ':: :_guard "([^-]?#|)" message' && ret=0 ;; + (push) + _arguments -S \ + $save_arguments \ + '(-m --message)'{-m,--message}'[specify stash description]' \ + ':: :__git_modified_files' && ret=0 + ;; (list) local -a log_options revision_options __git_setup_log_options @@ -1693,9 +1723,10 @@ _git-status () { fi _arguments -S -s \ - '(-s --short --column --no-column)'{-s,--short}'[output in short format]' \ + '(-s --short --column --no-column --show-stash)'{-s,--short}'[output in short format]' \ $branch_opts \ '(-s --short)--porcelain=-[produce machine-readable output]:version:(v1)' \ + '(-s --short)--show-stash[show stash information]' \ '(-u --untracked-files)'{-u-,--untracked-files=-}'[show untracked files]::mode:((no\:"show no untracked files" \ normal\:"show untracked files and directories" \ all\:"also show untracked files in untracked directories (default)"))' \ @@ -1729,6 +1760,7 @@ _git-submodule () { update:'update a submodule' summary:'show commit summary between given commit and working tree/index' foreach:'evaluate shell command in each checked-out submodule' + absorbgitdirs:'move the git directory of a submodule into its superprojects' sync:'synchronize submodule settings') _describe -t commands command commands && ret=0 @@ -1817,8 +1849,13 @@ _git-submodule () { '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ '*: :__git_ignore_line_inside_arguments __git_submodules' && ret=0 ;; + (absorbgitdirs) + _arguments -S \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '*:path:_directories' + ;; (*) - _nothing + _default ;; esac ;; @@ -1947,14 +1984,16 @@ _git-tag () { '(-l --list)'{-l,--list}'[list tags matching pattern]' \ '(--no-column)--column=-[display tag listing in columns]::column.tag option:((always\:"always show in columns" never\:"never show in columns" auto\:"show in columns if the output is to the terminal" column\:"fill columns before rows (default)" row\:"fill rows before columns" plain\:"show in one column" dense\:"make unequal size columns to utilize more space" nodense\:"make equal size columns"))' \ '(--column)--no-column[do not display in columns]' \ - '--contains=[only list tags which contain the specified commit]: :__git_commits' \ + '*--contains=[only list tags that contain the specified commit]: :__git_commits' \ + "*--no-contains=[only list tags that don't contain the specified commit]: :__git_commits" \ '--merged=-[print only tags that are merged]:: :__git_commits' \ '--no-merged=-[print only tags that are not merged]:: :__git_commits' \ '--sort=[specify how the tags should be sorted]:mode:((refname\:"lexicographic order" version\\\:refname\:"tag names are treated as version numbers"))' \ '--points-at=[only list tags of the given object]: :__git_commits' \ - '--format=[specify format to use for the output]' \ - '::pattern' \ + '--format=[specify format to use for the output]:format' \ + '(-i --ignore-case)'{-i,--ignore-case}'[sorting and filtering are case-insensitive]' \ + ':: :_guard "^-*" pattern' \ - verification \ '(-v --verify)'{-v,--verify}'[verify gpg signutare of tags]' \ '*:: :__git_ignore_line_inside_arguments __git_tags' @@ -3336,6 +3375,7 @@ _git-filter-branch () { # such. # TODO: * should be git-rev-arg and git-rev-list arguments. _arguments -S -A '-*' \ + '--setup[specify one time setup command]: :_cmdstring' \ '--env-filter[filter for modifying environment in which commit will be performed]: :_cmdstring' \ '--tree-filter[filter for rewriting tree and its contents]: :_cmdstring' \ '--index-filter[filter for rewriting index]: :_cmdstring' \ @@ -3607,6 +3647,7 @@ _git-repack () { '--window=[number of objects to consider when doing delta compression]:number of objects' \ '--window-memory=[scale window size dynamically to not use more than specified amount of memory]: : __git_guard_bytes' \ '--depth=[maximum delta depth]:maximum delta depth' \ + '--threads=[limit maximum number of threads]:threads' \ '--max-pack-size=-[maximum size of each output packfile]: : __git_guard_bytes "maximum pack size"' \ '--pack-kept-objects[repack objects in packs marked with .keep]' } @@ -3661,7 +3702,6 @@ _git-blame () { '-s[suppress author name and timestamp]' \ '-w[ignore whitespace when finding lines]' \ '--indent-heuristic[use indent-based heuristic to improve diffs]' \ - '--compaction-heuristic[use blank-line-based heuristic to improve diffs]' \ $revision_options \ ':: :__git_revisions' \ ': :__git_cached_files' && ret=0 @@ -3714,7 +3754,8 @@ _git-difftool () { '--tool-help[print a list of diff tools that may be used with --tool]' \ '(--symlinks)--no-symlinks[make copies of instead of symlinks to the working tree]' \ '(---no-symlinks)--symlinks[make symlinks to instead of copies of the working tree]' \ - '(-g --gui)'{-g,--gui}'[use diff.guitool instead of diff.tool]' + '(-g --gui)'{-g,--gui}'[use diff.guitool instead of diff.tool]' \ + '--trust-exit-code[make git-difftool exit when diff tool returns a non-zero exit code]' } (( $+functions[_git-fsck] )) || @@ -3949,6 +3990,7 @@ _git-verify-tag () { _arguments -S -s \ '(-v --verbose)'{-v,--verbose}'[print contents of the tag object before validating it]' \ '--raw[print raw gpg status output]' \ + '--format=[specify format to use for the output]:format' \ '*: :__git_tags' } @@ -4661,6 +4703,8 @@ _git-read-tree () { $exclude_per_directory_opt \ '--index-output=[write index in the named file instead of $GIT_INDEX_FILE]: :_files' \ '--no-sparse-checkout[display sparse checkout support]' \ + '--debug-unpack[debug unpack-trees]' \ + '--recurse-submodules=-[control recursive updating of submodules]::checkout:__git_commits' \ '--empty[instead of reading tree object(s) into the index, just empty it]' \ '1:first tree-ish to be read/merged:__git_tree_ishs' \ '2::second tree-ish to be read/merged:__git_tree_ishs' \ @@ -4875,7 +4919,9 @@ _git-for-each-ref () { '*--points-at=[print only refs which point at the given object]:object:__git_commits' \ '*--merged=[print only refs that are merged]:object:__git_commits' \ '*--no-merged=[print only refs that are not merged]:object:__git_commits' \ - '*--contains=[print only refs which contain the commit]:object:__git_commits' \ + '*--contains=[print only refs that contain specified commit]:object:__git_commits' \ + "*--no-contains=[print only refs that don't contain specified commit]:object:__git_commits" \ + '--ignore-case[sorting and filtering are case-insensitive]' \ '(-s --shell -p --perl --python --tcl)'{-s,--shell}'[use string literals suitable for sh]' \ '(-s --shell -p --perl --python --tcl)'{-p,--perl}'[use string literals suitable for Perl]' \ '(-s --shell -p --perl --tcl)'--python'[use string literals suitable for Python]' \ @@ -4980,7 +5026,9 @@ _git-merge-base () { _git-name-rev () { _arguments -S \ '--tags[only use tags to name commits]' \ - '--refs=[only use refs matching given pattern]: :_guard "?#" "shell pattern"' \ + '*--refs=[only use refs matching given pattern]: :_guard "?#" "shell pattern"' \ + '--no-refs[clear any previous ref patterns given]' \ + '*--exclude=[ignore refs matching specified pattern]:pattern' \ '(--stdin :)--all[list all commits reachable from all refs]' \ '(--all :)--stdin[read from stdin and append revision-name]' \ '--name-only[display only name of commits]' \ @@ -5159,6 +5207,7 @@ _git-send-pack () { "(--no-signed --signed)--sign=-[GPG sign the push]::signing enabled:(($^^sign))" \ '(--no-signed --sign)--signed[GPG sign the push]' \ "(--sign --signed)--no-signed[don't GPG sign the push]" \ + '--push-option=[specify option to transmit]:option' \ '--progress[force progress reporting]' \ '--thin[send a thin pack]' \ '--atomic[request atomic transaction on remote side]' \ @@ -5294,7 +5343,7 @@ _git-check-attr () { {-a,--all}'[list all attributes that are associated with the specified paths]' \ '--stdin[read file names from stdin instead of from command line]' \ '--cached[consider .gitattributes in the index only, ignoring the working tree.]' \ - '-z[make output format machine-parseable and treat input-paths as NUL-separated with --stdin]' \ + '-z[terminate input and output records by a NUL character]' \ $z_opt \ '(-)--[interpret preceding arguments as attributes and following arguments as path names]' \ '*:: :->attribute-or-file' && ret=0 @@ -5477,7 +5526,7 @@ __git_describe_branch () { shift 3 integer maxverbose - if zstyle -s :completion:$curcontext max-verbose maxverbose && + if zstyle -s :completion:$curcontext: max-verbose maxverbose && (( ${compstate[nmatches]} <= maxverbose )); then local __c local -a __commits @@ -6114,12 +6163,13 @@ __git_recent_branches__names() # 2. Extracts the move-source from each # 3. Eliminates duplicates # 4. Eliminates commit hashes (leaving only ref names) + # [This step is done again by the caller.] # # See workers/38592 for an equivalent long-hand implementation, and the rest # of that thread for why this implementation was chosen instead. # # Note: since we obtain the "from" part of the reflog, we only obtain heads, not tags. - reply=(${${(u)${${(0)"$(_call_program reflog git reflog -1000 -z --grep-reflog='\^checkout:\ moving\ from\ ' --pretty='%gs')"}#checkout: moving from }%% *}:#[[:xdigit:]](#c40)}) + reply=(${${(u)${${(M)${(0)"$(_call_program reflog git reflog -1000 -z --pretty='%gs')"}:#(#s)checkout: moving from *}#checkout: moving from }%% *}:#[0-9a-f](#c40)}) } (( $+functions[__git_recent_branches] )) || @@ -6156,6 +6206,10 @@ __git_recent_branches() { _describe -V -t recent-branches "recent branches" branches_colon_descriptions } +(( $+functions[__git_commits_prefer_recent] )) || +__git_commits_prefer_recent () { + _alternative 'recent-branches::__git_recent_branches' 'commits::__git_commits' +} (( $+functions[__git_commits] )) || __git_commits () { @@ -6309,11 +6363,11 @@ __git_recent_commits () { ret=1 # Resetting expl to avoid it 'leaking' from one line to the next. expl=() + _describe -V -t commits 'recent commit object name' descr && ret=0 + expl=() _wanted commit-tags expl 'commit tag' compadd "$@" -a - tags && ret=0 expl=() _wanted heads expl 'head' compadd "$@" -a - heads && ret=0 - expl=() - _describe -V -t commits 'recent commit object name' descr && ret=0 return $ret } @@ -6484,9 +6538,10 @@ __git_references () { _git_refs_cache_pwd=$PWD fi - _wanted references expl 'reference' compadd -a - _git_refs_cache + _wanted references expl 'reference' compadd -M 'r:|/=**' -a - _git_refs_cache } +# ### currently unused; are some callers of __git_references supposed to call this function? (( $+functions[__git_local_references] )) || __git_local_references () { local expl @@ -6497,7 +6552,7 @@ __git_local_references () { _git_local_refs_cache_pwd=$PWD fi - _wanted references expl 'reference' compadd -a - _git_local_refs_cache + _wanted references expl 'reference' compadd -M 'r:|/=**' -a - _git_local_refs_cache } (( $+functions[__git_remote_references] )) || @@ -6864,7 +6919,8 @@ __git_setup_diff_options () { $diff_types'--name-only[show only names of changed files]' $diff_types'--name-status[show only names and status of changed files]' '--submodule=-[select output format for submodule differences]::format:((short\:"show pairs of commit names" - log\:"list commits like git submodule does"))' + log\:"list commits like git submodule does" + diff\:"show differences"))' '( --no-color --color-words)--color=-[show colored diff]:: :__git_color_whens' '(--color --color-words)--no-color[turn off colored diff]' '--word-diff=-[show word diff]::mode:((color\:"highlight changed words using color" @@ -6908,7 +6964,7 @@ __git_setup_diff_options () { '(--no-prefix)--dst-prefix=[use given prefix for destination]:prefix' '(--src-prefix --dst-prefix)--no-prefix[do not show any source or destination prefix]' - '(-c,--cc)'{-c,--cc}'[combined diff format for merge commits]' + '(-c --cc)'{-c,--cc}'[combined diff format for merge commits]' # TODO: --output is undocumented. '--output[undocumented]:undocumented') diff --git a/Completion/Unix/Command/_gphoto2 b/Completion/Unix/Command/_gphoto2 index 314d83e3a..788c9702f 100644 --- a/Completion/Unix/Command/_gphoto2 +++ b/Completion/Unix/Command/_gphoto2 @@ -1,47 +1,96 @@ #compdef gphoto2 -_arguments -s \ +local curcontext="$curcontext" ret=1 +local -a state line values expl +typeset -A opt_args + +_arguments -s -C \ + '(-)'{-\?,--help}'[display help information]' \ + '(-)'{-h,--usage}'[display a short usage message]' \ '--debug[turn on debugging]' \ + '--debug-loglevel=[set debug level]:debug level:(error debug data all)' \ + '--debug-logfile=[name of file to write debug info to]:file:_files' \ '(-q --quiet)'{-q,--quiet}'[quiet output]' \ - '(-v --version)'{-v,--version}'[display version and exit]' \ - '(-h --help)'{-h,--help}'[display a short usage message]' \ - '--list-cameras[list supported camera models]' \ - '--list-ports[list supported port devices]' \ + '--hook-script=[hook script to call after downloads, captures, etc.]:file:_files' \ '--stdout[send file to stdout]' \ '--stdout-size[print filesize before data]' \ '--auto-detect[list auto-detected cameras]' \ - '--port[specify port device]:port' \ - '--speed[specify serial transfer speed]:speed' \ - '--camera[specify camera model]:camera model' \ - '--filename[specify pattern to save file as]:pattern' \ - '--usbid[override USB IDs (expert only)]:usbid' \ + '--show-exif=[show EXIF information of JPEG images]:range' \ + '--show-info=[show image information, like width, height, and capture time]:range' \ + '--summary[summary of camera status]' \ + '--manual[camera driver manual]' \ + '--about[show information about the camera driver]' \ + '--storage-info[show storage information]' \ + '--shell[start the gphoto2 shell]' \ + '(-)'{-v,--version}'[display version and exit]' \ + '--list-cameras[list supported camera models]' \ + '--list-ports[list supported port devices]' \ '(-a --abilities)'{-a,--abilities}'[display camera abilities]' \ - '(-f --folder)'{-f,--folder}'[specify camera folder]:folder' \ - '(-R --recurse --no-recurse)'{-R,--recurse}'[recursion (default for download)]' \ - '(-R --recurse)--no-recurse[no recursion (default for deletion)]' \ + '--port=[specify port device]:port:->ports' \ + '--speed=[specify serial transfer speed]:speed' \ + '--camera=[specify camera model]:camera model:->models' \ + '--usbid=[override USB IDs (expert only)]:usbid' \ + '--list-config[list configuration tree]' \ + '--list-all-config[dump full configuration tree]' \ + '--get-config=[get configuration value]:string' \ + '--set-config=[set configuration value or index in choices]:string' \ + '--set-config-index=[set configuration value index in choices]:string' \ + '--set-config-value=[set configuration value]:string' \ + '--config[start curses configuration menu]' \ + '--reset[reset device port]' \ + '--keep[keep images on camera after capturing]' \ + '--keep-raw[keep the RAW images on the camera with --capture-image-and-download]' \ + '--no-keep[remove images from camera after capturing]' \ + '--wait-event=-[wait for event from camera]::count' \ + '--wait-event-and-download=-[wait for event from camera and download new images]::count' \ + '--capture-preview[capture a quick preview]' \ + '--show-preview[capture a quick preview and display using ASCII art]' \ + '(-B --bulb)'{-B,--bulb=}'[set bulb exposure time]:exposure time (seconds)' \ + '(-F --frames)'{-F,--frames=}'[set number of frames to capture]:frames [unlimited]' \ + '(-I --interval)'{-I,--interval=}'[set capture interval in seconds]:interval (seconds)' \ + '--reset-interval[reset capture interval on signal]' \ + '--capture-image[capture an image]' \ + '--trigger-capture[trigger capture of an image]' \ + '--capture-image-and-download[capture an image and download it]' \ + '--capture-movie=-[capture a movie]:count or seconds' \ + '--capture-sound[capture an audio clip]' \ + '--capture-tethered=-[wait for shutter release on the camera and download]::count' \ '(-l --list-folders)'{-l,--list-folders}'[list folders in folder]' \ '(-L --list-files)'{-L,--list-files}'[list files in folder]' \ - '(-m --mkdir)'{-m,--mkdir}'[create a directory]:directory' \ - '(-r --rmdir)'{-r,--rmdir}'[remove a directory]:directory' \ - '(-n --num-files)'{-n,--num-files}'[sisplay number of files]' \ - '(-p --get-file)'{-p,--get-file}'[get files given in range]:range' \ + '(-m --mkdir)'{-m,--mkdir=}'[create a directory]:directory' \ + '(-r --rmdir)'{-r,--rmdir=}'[remove a directory]:directory' \ + '(-n --num-files)'{-n,--num-files}'[display number of files]' \ + '(-p --get-file)'{-p,--get-file=}'[get files given in range]:range' \ '(-P --get-all-files)'{-P,--get-all-files}'[get all files from folder]' \ - '(-t --get-thumbnail)'{-t,--get-thumbnail}'[get thumbnails given in range]:range' \ + '(-t --get-thumbnail)'{-t,--get-thumbnail=}'[get thumbnails given in range]:range' \ '(-T --get-all-thumbnails)'{-T,--get-all-thumbnails}'[get all thumbnails from folder]' \ - '(-r --get-raw-data)'{-r,--get-raw-data}'[get raw data given in range]:range' \ + '--get-metadata=[get metadata given in range]:range' \ + '--get-all-metadata[get all metadata from folder]' \ + '--upload-metadata=[upload metadata for file]:string' \ + '--get-raw-data=[get raw data given in range]:range' \ '--get-all-raw-data[get all raw data from folder]' \ - '--get-audio-data[get audio data given in range]:range' \ + '--get-audio-data=[get audio data given in range]:range' \ '--get-all-audio-data[get all audio data from folder]' \ - '--delete-file[delete files given in range]:range' \ - '--delete-all-files[delete all files in folder]' \ - '(-u --upload-file)'{-u,--upload-file}'[upload a file to camera]:file:_files' \ - '--capture-preview[capture a quick preview]' \ - '--capture-image[capture an image]' \ - '--capture-movie[capture a movie]' \ - '--capture-sound[capture an audio clip]' \ - '--show-info[show info about given range]:range' \ - '--summary[summary of camera status]' \ - '--manual[camera driver manual]' \ - '--about[show information about the camera driver]' \ - '--shell[start the gphoto2 shell]' + '(-d --delete-file)'{-d,--delete-file=}'[delete files in given range]:range' \ + '(-D --delete-all-files)'{-D,--delete-all-files}'[delete all files in folder]' \ + '(-u --upload-file)'{-u,--upload-file=}'[upload a file to camera]:file:_files' \ + '--filename=[specify pattern to save file as]:pattern:_date_formats' \ + '(-f --folder)'{-f,--folder=}'[specify camera folder]:folder [/]' \ + '(-R --recurse --no-recurse)'{-R,--recurse}'[recursion (default for download)]' \ + '(-R --recurse)--no-recurse[no recursion (default for deletion)]' \ + '--new[process new files only]' \ + '--force-overwrite[overwrite files without asking]' \ + '--skip-existing[skip files that already exist on local filesystem]' && ret=0 + +case $state in + models) + _wanted models expl 'camera model' compadd \ + ${${${(f)"$(_call_program models $words[1] --list-cameras)"}[3,-1]#*\"}%%\"*} && ret=0 + ;; + ports) + values=( ${${${(f)"$(gphoto2 --list-ports)"}[4,-1]/:/\\:}/ ##/:} ) + _describe -t ports 'port' values + ;; +esac +return ret diff --git a/Completion/Unix/Command/_grep b/Completion/Unix/Command/_grep index 5d548b567..5f45ce9a8 100644 --- a/Completion/Unix/Command/_grep +++ b/Completion/Unix/Command/_grep @@ -1,7 +1,6 @@ -#compdef grep egrep fgrep bsdgrep zgrep zegrep zfgrep -value-,GREP_OPTIONS,-default- -# Ulrik Haugen 2001 +#compdef grep egrep fgrep bsdgrep zgrep zegrep zfgrep ggrep gegrep gfgrep gzgrep gzegrep gzfgrep -value-,GREP_OPTIONS,-default- -local arguments matchers command +local arguments matchers command variant if [[ $service = *GREP_OPT* ]]; then compset -q @@ -9,7 +8,7 @@ if [[ $service = *GREP_OPT* ]]; then (( CURRENT++ )) command=grep else - arguments=( '(-e --regexp -f --file)1: :_guard "^--*" pattern' ) + arguments=( '(-e --regexp -f --file)1: :_guard "^-*" pattern' ) if [[ $service = z* ]]; then arguments+=( '*:files:_files -g "*.gz(-.)"' ) else @@ -18,13 +17,12 @@ else command="$words[1]" fi -if [[ $service != (|z)[ef]grep ]]; then +if [[ $service != (|g)(|z)[ef]grep ]]; then matchers='(--extended-regexp --fixed-strings --basic-regexp --perl-regexp -E -F -G -P)' arguments+=( $matchers{--extended-regexp,-E}'[use extended regular expression]' $matchers{--fixed-strings,-F}'[use literal strings]' $matchers{--basic-regexp,-G}'[use basic regular expression]' - $matchers{--perl-regexp,-P}'[use perl regular expression]' ) fi @@ -32,14 +30,11 @@ arguments+=( '(--after-context -A)'{--after-context=,-A+}'[specify lines of trailing context]:lines' '(--text -a --binary-files -I)'{--text,-a}'[process binary file as if it were text]' '(--before-context -B)'{--before-context=,-B+}'[specify lines of leading context]:lines' - '(--context,-C)'{--context=,-C-}'[specify lines of context]:lines' + '(--context -C)'{--context=,-C-}'[specify lines of context]:lines' '(--color --colour)--'{color,colour}'=-[distinguish matching string]::when:(always never auto)' - '(--no-group-separator)--group-separator=[specify separator between blocks of context]:separator [--]' - "(--group-separator)--no-group-separator[don't separate context blocks]" '(--byte-offset -b -c)'{--byte-offset,-b}'[print the byte offset with output lines]' '(--text -a -I)--binary-files=[specify type to assume for binary files]:file type:(binary without-match text)' '(--count -c --byte-offset -b --line-number -n)'{--count,-c}'[only print a count of matching lines]' - '(-T --initial-tab)'{-T,--initial-tab}'[make tabs line up (if needed)]' '(--directories -d -r --recursive)'{--directories=,-d+}'[specify handling of directories]:action on directory:(read skip recurse)' '(--devices -D)'{--devices=,-D+}'[specify handling of devices, FIFOs and sockets]:action on device:(read skip)' '(1)*'{--regexp=,-e+}'[specify pattern]:pattern' @@ -50,30 +45,75 @@ arguments+=( '--line-buffered[flush output on every line]' '(--text -a --binary-files)-I[process binary files as if non-matching]' '(--ignore-case -i -y)'{--ignore-case,-i,-y}'[case-insensitive]' - '(--files-without-match -L --file-with-matches -l --no-filename -h)'{--files-without-match,-L}"[output non-matching files' names only]" - '(--files-with-matches -l --files-without-match -L --no-filename -h)'{--files-with-matches,-l}"[output matching files' names only]" - '(--max-count -m)'{--max-count=,-m+}'[stop after specified no of matches]:max number of matches' + '(--files-without-match -L --file-with-matches -l --no-filename -h -o --only-matching)'{--files-without-match,-L}"[output non-matching files' names only]" + '(--files-with-matches -l --files-without-match -L --no-filename -h -o --only-matching)'{--files-with-matches,-l}"[output matching files' names only]" + '(--max-count -m)'{--max-count=,-m+}'[stop after specified no of matches in each file]:max number of matches' '(--line-number -n -c)'{--line-number,-n}'[prefix output with line numbers]' - '(--only-matching -o)'{--only-matching,-o}'[show only matching part of line]' + '(--only-matching -o --files-with-matches -l --files-without-match -L)'{--only-matching,-o}'[show only matching part of line]' '(--quiet --silent -q)'{--quiet,--silent,-q}'[suppress normal output]' '(--recursive -r --dereference-recursive -R -d --directories)'{--recursive,-r}'[recurse subdirectories]' - '(--recursive -r --dereference-recursive -R -d --directories)'{--dereference-recursive,-R}'[recurse subdirectories, following symlinks]' '*--include=[examine files matching specified pattern]:file pattern' '*--exclude=[skip files matching specified pattern]:file pattern' - '*--exclude-from=[skip files matching pattern in specified file]:file:_files' '*--exclude-dir=[skip directories matching specified pattern]:directory pattern' '(--no-messages -s)'{--no-messages,-s}'[suppress messages about unreadable]' '(--version -V)'{--version,-V}'[display version info]' '(--invert-match -v)'{--invert-match,-v}'[select non-matching lines]' '(--word-regexp -w --line-regexp -x)'{--word-regexp,-w}'[force pattern to match only whole words]' '(--line-regexp -x --word-regexp -w)'{--line-regexp,-x}'[force pattern to match only whole lines]' - '(--null -Z --no-filename -h)'{--null,-Z}'[print 0 byte after FILE name]' - '--help[display help]' + '(-)--help[display help information]' ) -# remove long options? -_pick_variant -c "$command" gnu=gnu unix --help || - arguments=( ${arguments:#(|*\)(\*|))--*} ) +_pick_variant -r variant -c "$command" gnu=gnu gpl2=2.5.1 unix --version +case $variant:$OSTYPE in + (gnu:*|gpl2:freebsd*)) + [[ $service != (|g)(|z)[ef]grep ]] && arguments+=( + $matchers{--perl-regexp,-P}'[use perl regular expression]' + ) + ;| + (gnu:*|gpl2:(free|net)bsd*)) + arguments+=( + '*--exclude-from=[skip files matching pattern in specified file]:file:_files' + '(-z --null-data)'{-z,--null-data}'[input data separated by 0 byte, not newline]' + ) + ;| + gpl2:freebsd*) + arguments+=( + '(--null --no-filename -h)--null[print 0 byte after each filename]' + ) + ;| + gpl2:(freebsd|darwin)*) + arguments+=( + '(-Z --decompress -J --bz2decompress)'{-J,--bz2decompress}"[decompress bzip2'ed input before searching]" + '(-Z --decompress -J --bz2decompress)'{-Z,--decompress}"[decompress gzip'ed input before searching]" + ) + ;| + (gnu:*|gpl2:netbsd*)) + arguments+=( + '(--null -Z --no-filename -h)'{--null,-Z}'[print 0 byte after each filename]' + ) + ;| + gnu:*) + arguments+=( + '(--no-group-separator)--group-separator=[specify separator between blocks of context]:separator [--]' + "(--group-separator)--no-group-separator[don't separate context blocks]" + '(-T --initial-tab)'{-T,--initial-tab}'[make tabs line up (if needed)]' + '(--recursive -r --dereference-recursive -R -d --directories)'{--dereference-recursive,-R}'[recurse subdirectories, following symlinks]' + ) + ;; + gpl2:*) arguments=( ${${arguments:#*\)-r}/\)-r/\)-R} ) ;; + *:openbsd*) + arguments=( + ${(M)arguments:#((#s)|*\))--(context|binary-files|line-buffered)*} + ${${arguments:#((#s)|*\))(\*|)-[d-]*}/\)-r/\)-R} + "-U[search binary files but don't print them]" + '-Z[behave as zgrep]' + ) + ;; + *) + # remove long options and GNU specific short opts, this is right for solaris + arguments=( ${arguments:#((#s)|*\))(\*|)-[aABCdDfGHILmorVy-]*} ) + ;; +esac _arguments -S -s $arguments[@] diff --git a/Completion/Unix/Command/_gsettings b/Completion/Unix/Command/_gsettings index 72f015729..890b56403 100644 --- a/Completion/Unix/Command/_gsettings +++ b/Completion/Unix/Command/_gsettings @@ -13,7 +13,7 @@ if [[ $state = subargs ]]; then curcontext="${curcontext%:*}-$words[1]:" case $words[1] in help) state=subcmds;; - get|range|reset|writable|monitor) + describe|get|range|reset|writable|monitor) _arguments ':schema:->schemata' ':key:->keys' ;; set) diff --git a/Completion/Unix/Command/_hg b/Completion/Unix/Command/_hg index 8d31cd377..8eaa457c8 100644 --- a/Completion/Unix/Command/_hg +++ b/Completion/Unix/Command/_hg @@ -876,7 +876,7 @@ _hg_cmd_qdiff() { _hg_cmd_qfold() { _arguments -s : $_hg_global_opts $_h_commit_opts \ - '(--keep,-k)'{-k,--keep}'[keep folded patch files]' \ + '(--keep -k)'{-k,--keep}'[keep folded patch files]' \ '*:unapplied patch:_hg_qunapplied' } diff --git a/Completion/Unix/Command/_iftop b/Completion/Unix/Command/_iftop index 41ffb4ea1..05db3fa03 100644 --- a/Completion/Unix/Command/_iftop +++ b/Completion/Unix/Command/_iftop @@ -1,9 +1,16 @@ #compdef iftop _interfaces () { - _wanted interfaces expl 'network interface' \ - _net_interfaces - _values "Pseudo-device that captures on all interfaces" "any" + local disp expl sep + _description interfaces expl 'network interface' + _net_interfaces "$expl[@]" + if zstyle -t ":completion:${curcontext}:interfaces" verbose; then + zstyle -s ":completion:${curcontext}:interfaces" list-separator sep || sep=-- + disp=( "any $sep capture on all interfaces" ) + compadd "$expl[@]" -ld disp any + else + compadd "$expl[@]" any + fi } _arguments \ @@ -14,7 +21,7 @@ _arguments \ -P'[turn on port display]' \ -b"[don't display bar graphs of traffic]" \ -B'[display bandwidth rates in bytes/sec rather than bits/sec]' \ - -i'[interface]:network interface:_interfaces' \ - -f'[filter]:BPF filter' \ - -F'[net/mask]:network/mask' \ - -c'[config file]:config file:_files' + '-i+[interface]:network interface:_interfaces' \ + '-f+[filter]:BPF filter' \ + '-F+[net/mask]:network/mask' \ + '-c+[config file]:config file:_files' diff --git a/Completion/Unix/Command/_ip b/Completion/Unix/Command/_ip index 1ca3f1ade..6e1cc3b78 100644 --- a/Completion/Unix/Command/_ip +++ b/Completion/Unix/Command/_ip @@ -172,7 +172,7 @@ _regex_words \ link-set-commands 'link set commands' \ 'dev:specify device:$subcmd_dev' \ 'u*p:change state to up' \ - 'do*wn:change state do down' \ + 'do*wn:change state to down' \ 'ar*p:change ARP flag on device:$subcmd_onoff' \ 'mu*lticast:change MULTICAST flag on device:$subcmd_onoff' \ 'pr*omisc:set promiscuous mode:$subcmd_onoff' \ diff --git a/Completion/Unix/Command/_irssi b/Completion/Unix/Command/_irssi index fd64b5efc..ee1e1ef43 100644 --- a/Completion/Unix/Command/_irssi +++ b/Completion/Unix/Command/_irssi @@ -30,7 +30,6 @@ _arguments -s \ '--noconnect[disable autoconnect]' \ '(-n --nick)'{-n,--nick=}'[set nick name]:nick:_irssi_nick' \ '(-h --hostname)'{-h,--hostname=}'[specify hostname]:hostname:_hosts' \ - '(-d --dummy)'{-d,--dummy}'[use the dummy terminal mode]' \ '(-)'{-v,--version}'[display version information]' \ '(-)'{-\?,--help}'[display help information]' \ '(-)--usage[display usage]' diff --git a/Completion/Unix/Command/_java b/Completion/Unix/Command/_java index 7a1224677..30231c5ee 100644 --- a/Completion/Unix/Command/_java +++ b/Completion/Unix/Command/_java @@ -65,7 +65,7 @@ java) '-D-[specify a property]:property:->property' \ \*{-enableassertions,-ea}-::class \ \*{-disableassertions,-da}-::class \ - '(-enablesystemassertions,-esa,-disablesystemassertions,-dsa)'{-enablesystemassertions,-esa,-disablesystemassertions,-dsa} \ + '(-enablesystemassertions -esa -disablesystemassertions -dsa)'{-enablesystemassertions,-esa,-disablesystemassertions,-dsa} \ '(-verbose:class)-verbose[print class information]' \ '(-verbose)-verbose\:class[print class information]' \ '-verbose\:gc[print gc information]' \ diff --git a/Completion/Unix/Command/_kvno b/Completion/Unix/Command/_kvno index 782d9e6fc..9664e187b 100644 --- a/Completion/Unix/Command/_kvno +++ b/Completion/Unix/Command/_kvno @@ -3,15 +3,17 @@ local curcontext="$curcontext" state line ret=1 _arguments -C \ - '(-4)-c[specify credentials cache to use]:cache:_files' \ - '(-4)-e[specify encryption type]:encryption type' \ + '-c[specify credentials cache to use]:cache:_files' \ + '-e[specify encryption type]:encryption type' \ '-q[suppress printing]' \ '(- :)-h[display help information]' \ - '(-c -e)-4[kerberos 4 tickets]' \ + '-P[acquire credentials for the principal during S4U2Self]' \ + '-S[specify the service name of the principal]:service' \ + '-U[specify user for S4U2Self]:user:_users' \ ':principal:->principal' && ret=0 if [[ $state = principal ]]; then - if compset -P host/; then + if compset -P '*/'; then _hosts && ret=0 else _alternative \ diff --git a/Completion/Unix/Command/_lha b/Completion/Unix/Command/_lha index c2d5e7d8d..e8d47fcdb 100644 --- a/Completion/Unix/Command/_lha +++ b/Completion/Unix/Command/_lha @@ -1,5 +1,7 @@ #compdef lha +local expl + if (( CURRENT == 2 )); then compset -P - diff --git a/Completion/Unix/Command/_libvirt b/Completion/Unix/Command/_libvirt index 1aa8ed817..a3ab5a68a 100644 --- a/Completion/Unix/Command/_libvirt +++ b/Completion/Unix/Command/_libvirt @@ -20,6 +20,7 @@ typeset -A dom_opts dom_opts=( console " " destroy " " + edit " " managedsave " " reboot " " reset " " @@ -95,7 +96,7 @@ case $service in '(- *)'{-h,--help}'[print help information and exit]' \ '(- *)'{-v,--version}'[print version information and exit]' \ '(- *)'{-q,--quiet}'[quiet mode]' \ - '1:hv-type:(qemu lxc)' && return + '1:hv-type:(qemu lxc bhyve)' && return ;; virt-pki-validate) _arguments -A "-*" -S \ @@ -197,7 +198,7 @@ case $state in return 1 fi # Allow passing domain without --domain with few of the most used commands - if [[ $cmd == (destroy|reboot|reset|start|shutdown) ]]; then + if [[ $cmd == (destroy|edit|reboot|reset|start|shutdown) ]]; then if [[ $words[CURRENT-1] == $cmd ]]; then values=( $(_call_program domains "noglob virsh $conn_opt list ${dom_opts[$cmd]:-"--all"} --name") ) [[ -n $values ]] && _wanted domains expl domain compadd ${=values} && return 0 diff --git a/Completion/Unix/Command/_locate b/Completion/Unix/Command/_locate index 694f506c3..23305f798 100644 --- a/Completion/Unix/Command/_locate +++ b/Completion/Unix/Command/_locate @@ -1,132 +1,96 @@ -#compdef locate mlocate slocate +#compdef locate mlocate slocate glocate -# Decide if we are using mlocate or slocate. -local ltype basename=${words[1]:t} input -# If we can't, use this guess. -local best_guess=mlocate +local variant=$service +local -a args +[[ $service = locate ]] && + _pick_variant -r variant glocate=findutils mlocate=mlocate slocate=secure $OSTYPE -V +args=( '(-)'{-V,--version}'[display version information]' ) -case $basename in - ([ms]locate) - ltype=$basename - ;; - - (locate) - input="$(_call_program locate $words[1] -V 2>&1)" - case $input in - (*mlocate*) - ltype=mlocate - ;; - - (*(#i)secure locate*) - ltype=slocate - ;; - - (*(#i)gnu locate*|*findutils*gnu*) - ltype=gnu - ;; - - (*"illegal option"*) - if [[ $OSTYPE == (freebsd|openbsd|dragonfly|darwin)* ]]; then - ltype=bsd - else - ltype=$best_guess - fi - ;; - - # guess - (*) - ltype=$best_guess - ;; - esac - ;; - - (*) - # too dangerous to run: guess - ltype=$best_guess -esac +case $variant in + [mg]locate) + args+=( + '(-A --all)'{-A,--all}'[only print entries that match all patterns]' + '(-E --non-existing -e --existing)'{-e,--existing}'[restrict display to existing files]' + '(-c --count)'{-c,--count}'[output the number of matching entries]' + '(-i --ignore-case)'{-i,--ignore-case}'[ignore case distinctions in patterns]' + '(-w --wholename -b --basename)'{-w,--wholename}'[match entire file path (default)]' + '(-w --wholename -b --basename)'{-b,--basename}'[match only the basename of files in the database]' + '(-P -H --no-follow -L --follow)'{-P,-H,--nofollow}"[don't follow symbolic links]" + '(-P -H --no-follow -L --follow)'{-L,--follow}'[follow symbolic links to find existing files (default)]' + '(-0 --null)'{-0,--null}'[output separated by NUL characters]' + '(-S --statistics)'{-S,--statistics}'[show database statistics]' + ) + ;| -case $ltype in (mlocate) - # actually, -d can take a colon-separate list # -r/--regexp mean no normal arguments, so shouldn't complete # -m and --mmap are ignored, so don't bother # -s and --stdio likewise - _arguments -s -S : \ - {-b,--basename}'[match only the basename of files in the database]' \ - {-c,--count}'[output the number of matching entries]' \ - {-d,--database=}'[use alternative database]:database:_files' \ - {-e,--existing}'[restrict display to existing files]' \ - {-L,--follow}'[follow symbolic links to find existing files (default)]' \ - {-h,--help}'[show help]' \ - {-i,--ignore-case}'[ignore case distinctions in patterns]' \ - {-l,-n,--limit=}'[limit search results]:file limit: ' \ - {-P,-H,--nofollow}'[don'\''t follow symbolic links]' \ - {-0,--null}'[output separated by NUL characters]' \ - {-S,--statistics}'[show database statistics]' \ - {-q,--quiet}'[don'\''t report errors]' \ - {-r,--regexp=}'[search for given basic regexp]:basic regexp: ' \ - --regex'[patterns are extended regexps]' \ - {-V,--version}'[show version]' \ - {-w,--wholename}'[match entire file path (default)]' \ - '*:pattern: ' + args=( -s -S : $args + \*{-d,--database=}'[use alternative database]:database:_sequence -s \: _files' + '(-)'{-h,--help}'[display help information]' + '(-l -n --limit)'{-l,-n,--limit=}'[limit search results]:file limit' + '(-q --quiet)'{-q,--quiet}"[don't report errors]" + '(:)*'{-r,--regexp=}'[search for given basic regexp]:basic regexp' + '--regex[patterns are extended regexps]' + ) ;; (slocate) # -d can take path # -e can take a comma-separated list of directories. # -f should complete list of file system types like mount - _arguments -s -S : \ - -u'[create slocate database starting at path /]' \ - -U'[create slocate database starting at given path]:directory:_files -/' \ - -c'[parse GNU locate updatedb with -u, -U]' \ - -e'[exclude directories with -u, -U]:directories:_files -/' \ - -f'[exclude file system types from db with -u, -U]:file system:_file_systems' \ - -l'[security level]:level:(0 1)' \ - -q'[quiet mode]' \ - -n'[limit search results]:file limit: ' \ - -i'[case insensitive search]' \ - {-r,--regexp=}'[use basic regular expression]:regexp: ' \ - {-o,--output=}'[specify database to create]:database:_files' \ - {-d,--database=}'[specify database to search]:database:_files' \ - {-h,--help}'[display help]' \ - {-v,--verbose}'[display files when creating database]' \ - {-V,--version}'[display version]' \ - '*:pattern: ' + args=( -s -S : $args + -u'[create slocate database starting at path /]' + -U'[create slocate database starting at given path]:directory:_files -/' + -c'[parse GNU locate updatedb with -u, -U]' + -e'[exclude directories with -u, -U]:directories:_files -/' + -f'[exclude file system types from db with -u, -U]:file system:_file_systems' + -l'[security level]:level:(0 1)' + -q'[quiet mode]' + -n'[limit search results]:file limit ' + -i'[case insensitive search]' + {-r,--regexp=}'[use basic regular expression]:regexp' + {-o,--output=}'[specify database to create]:database:_files' + {-d,--database=}'[specify database to search]:database:_files' + '(-)'{-h,--help}'[display help information]' + {-v,--verbose}'[display files when creating database]' + ) ;; - (gnu) - _arguments -s : \ - {-d,--database=}'[use alternative database]:database:_files' \ - {-e,--existing}'[restrict display to existing files]' \ - {-E,--non-existing}'[allow display of nonexistent files (default)]' \ - {-i,--ignore-case}'[ignore case distinctions in patterns]' \ - {-w,--wholename}'[match entire file path (default)]' \ - {-b,--basename}'[match only the basename of files in the database]' \ - {-l,-n,--limit=}'[limit search results]:file limit: ' \ - {-S,--statistics}'[show database statistics]' \ - {-0,--null}'[output separated by NUL characters]' \ - {-c,--count}'[output the number of matching entries]' \ - {-P,-H,--nofollow}'[don'\''t follow symbolic links]' \ - {-L,--follow}'[follow symbolic links to find existing files (default)]' \ - {-A,-all}'[match all arguments instead of at least one]' \ - {-p,--print}'[include search results with statistics or count]' \ - {-r,--regex=}'[patterns are regular expressions]:basic regexp: ' \ - --regextype='[select type of regular expression]' \ - {-V,--version}'[show version]' \ - --help'[show help]' \ - '*:pattern: ' + (glocate) + args=( -s : $args + \*{-d,--database=}'[use alternative database]:database:_files' + '(-E --non-existing -e --existing)'{-E,--non-existing}'[restrict display to nonexistent files]' + '(-l --limit)'{-l,--limit=}'[limit search results]:file limit: ' + '--max-database-age[specify database age at which warning should be issued]:age (days) [8]' + '(-p --print)'{-p,--print}'[include search results with statistics or count]' + \*{-r,--regex=}'[patterns are regular expressions]:regexp' + --regextype='[select type of regular expression]:regex type [basic]:(findutils-default awk egrep ed emacs gnu-awk grep posix-awk posix-basic posix-egrep posix-extended posix-minimal-basic sed)' + '(-)'--help'[display help information]' + ) ;; - (bsd) - _arguments -s -S -A '-*' \ - '(-S)-0[separate file names by NUL characters]' \ - '(- *)-S[show database statistics and exit]' \ - '(-S)-c[output the number of matching file names]' \ - '(-S)*-d[specify database to search]:database:_files' \ - '(-S)-i[ignore case distinctions in pattern and database]' \ - '(-S)-l[limit output to specified number of file names]:file limit: ' \ - '(-S)-m[use mmap(2) instead of stdio(3) (default)]' \ - '(-S)-s[use stdio(3) instead of mmap(2)]' \ - '*:pattern: ' - ;; + (freebsd|openbsd|dragonfly|darwin)*) + args=( -s -S -A '-*' + '(-S)-c[output the number of matching file names]' + '(-S)-i[ignore case distinctions in pattern and database]' + '(-S)-l[limit output to specified number of file names]:file limit ' + '(- *)-S[show database statistics and exit]' + ) + ;| + openbsd*) + args+=( '(-S)-b[match only the basename of files in the database]' ) + ;| + (freebsd|dragonfly|darwin)*) + args+=( + '(-S)-0[separate file names by NUL characters]' + '(-S)-m[use mmap(2) instead of stdio(3) (default)]' + '(-S)-s[use stdio(3) instead of mmap(2)]' + ) + ;| + (*) args+=( '(-S)*-d[specify database to search]:database:_files' ) ;; + esac + +_arguments $args '*: :_guard "^-*" pattern' diff --git a/Completion/Unix/Command/_ls b/Completion/Unix/Command/_ls index 74f317ad1..955b0894d 100644 --- a/Completion/Unix/Command/_ls +++ b/Completion/Unix/Command/_ls @@ -11,10 +11,10 @@ if ! _pick_variant gnu=gnu unix --help; then '-R[list subdirectories recursively]' '(-k)-h[print sizes in human readable form]' + '(-h)-k[print sizes in kilobytes]' '-i[print file inode numbers]' '(-l -g -1 -C -m -x)-l[long listing]' - '(-l -1 -C -m -x)-g[long listing but without owner information]' '(-l -g -C -m -x)-1[single column output]' '(-l -g -1 -m -x)-C[list entries in columns sorted vertically]' '(-l -g -1 -C -x)-m[comma separated]' @@ -27,6 +27,7 @@ if ! _pick_variant gnu=gnu unix --help; then '-r[reverse sort order]' + '(-t)-S[sort by size]' '(-S)-t[sort by modification time]' '(-p)-F[append file type indicators]' @@ -34,31 +35,80 @@ if ! _pick_variant gnu=gnu unix --help; then '-n[numeric uid, gid]' - '(-B -b -w -q)-b[as -B, but use C escape codes whenever possible]' '(-B -b -w -q)-q[hide control chars]' '*:files:_files' ) if [[ "$OSTYPE" = (netbsd*|dragonfly*|freebsd*|openbsd*|darwin*) ]]; then arguments+=( - '(-h)-k[print sizes of 1k]' - '(-t)-S[sort by size]' '-T[show complete time information]' - '-o[display file flags]' - '-f[output is not sorted]' - '(-B -b -w -q)-w[print raw characters]' + '(-a -A -r -S -t)-f[output is not sorted]' + ) + fi + if [[ $OSTYPE = (netbsd*|dragonfly*|freebsd*|openbsd*) ]]; then + arguments+=( '-o[display file flags]' ) + fi + if [[ $OSTYPE = (netbsd*|dragonfly*|freebsd*|darwin*) ]]; then + arguments+=( '(-B -b -w -q)-B[print octal escapes for control characters]' + '(-B -b -w -q)-b[as -B, but use C escape codes whenever possible]' + '(-B -b -w -q)-w[print raw characters]' + '-W[display whiteouts when scanning directories]' ) fi - if [[ "$OSTYPE" = (freebsd*|darwin*) ]]; then + if [[ $OSTYPE = (netbsd*|openbsd*|darwin*|solaris*) ]]; then + arguments+=( + '(-l -1 -C -m -x)-g[long listing but without owner information]' + ) + fi + if [[ $OSTYPE = netbsd* ]]; then + arguments+=( + '-M[output file sizes in comma-separated form]' + '-O[output only leaf (non-directory) files]' + '-P[print full pathname for each file]' + "-X[don't cross mount points when recursing]" + ) + fi + if [[ $OSTYPE = (dragonfly*|freebsd*|openbsd*|darwin*) ]]; then + arguments+=( '-H[follow symlinks on the command line]' ) + fi + if [[ $OSTYPE = (dragonfly*|freebsd*|darwin*) ]]; then arguments+=( '-G[enable colorized output]' - '-H[follow symlinks on the command line]' '-P[do not follow symlinks]' ) fi + if [[ $OSTYPE = (dragonfly*|freebsd*) ]]; then + arguments+=( + '(-A)-I[prevent -A from being automatically set for the super-user]' + ) + fi + if [[ $OSTYPE = dragonfly* ]]; then + arguments+=( '-y[display FSMID in long listing]' ) + fi + if [[ $OSTYPE = (freebsd*|darwin*) ]]; then + arguments+=( '(-c -u)-U[file creation time]' ) + fi + if [[ $OSTYPE = freebsd* ]]; then + arguments+=( + '-,[print file sizes grouped and separated by thousands]' + '-D+[specify format for date]:format: _date_formats' + '-y[with -t, sort filenames in the same order as the time]' + '-Z[display MAC label]' + ) + fi + if [[ $OSTYPE = darwin* ]]; then + arguments+=( + '-@[display extended attribute keys and sizes in long listing]' + '-e[display ACL in long listing]' + '(-l -1 -C -m -x)-o[long listing but without group information]' + '-O[display file flags]' + '-v[print raw characters]' + ) + fi if [[ $OSTYPE = solaris* ]]; then arguments+=( + '(-q)-b[print octal escapes for control characters]' '(-l -1 -C -m -x)-o[long listing but without group information]' '(-l -t -s -r -a)-f[interpret each argument as a directory]' '(-E -l)-e[long listing with full and consistent date/time]' @@ -78,14 +128,15 @@ else '(--ignore-backups -B)'{--ignore-backups,-B}"[don't list entries ending with ~]" '(--directory -d)'{--directory,-d}'[list directory entries instead of contents]' '(--dired -D)'{--dired,-D}"[generate output designed for Emacs' dired mode]" - '(--ignore,-I)'{--ignore,-I}"[don't list entire matching pattern]:pattern:" - '(--dereference -L --dereference-command-line --dereference-command-line-symlink-to-dir)'{--dereference,-L}'[list referenced file for sym link]' - '(--dereference -L --dereference-command-line --dereference-command-line-symlink-to-dir)'{--dereference-command-line,--dereference-command-line-symlink-to-dir} + '*'{--ignore=,-I+}"[don't list entries matching pattern]:pattern: " + '(--dereference -L --dereference-command-line -H --dereference-command-line-symlink-to-dir)'{--dereference,-L}'[list referenced file for sym link]' + '(--dereference -L --dereference-command-line -H --dereference-command-line-symlink-to-dir)'{--dereference-command-line,-H}'[follow symlink on the command line]' + '(--dereference -L --dereference-command-line -H)'--dereference-command-line-symlink-to-dir '(--recursive -R)'{--recursive,-R}'[list subdirectories recursively]' '(--no-group -G)'{--no-group,-G}'[inhibit display of group information]' - '(--human-readable -h -H --si)'{--human-readable,-h}'[print sizes in human readable form]' - '(--si -H -h --human-readable)'{--si,-H}'[sizes in human readable form; powers of 1000]' + '(--block-size --human-readable -h --si --kilobytes -k)'{--human-readable,-h}'[print sizes in human readable form]' + '(--block-size --human-readable -h --si --kilobytes -k)--si[sizes in human readable form; powers of 1000]' '(--inode -i)'{--inode,-i}'[print file inode numbers]' '(--format -l -g -o -1 -C -m -x)-l[long listing]' @@ -96,7 +147,7 @@ else '(--format -l -g -o -1 -m -x)-C[list entries in columns sorted vertically]' '(--format -l -g -o -1 -C -x)-m[comma separated]' '(--format -l -g -o -1 -C -m)-x[sort horizontally]' - '(-l -g -o -1 -C -m -x)--format=:format:(verbose long commas horizontal across vertical single-column)' + '(-l -g -o -1 -C -m -x)--format=[specify output format]:format:(verbose long commas horizontal across vertical single-column)' '(--size -s -f)'{--size,-s}'[display size of each file in blocks]' @@ -106,34 +157,35 @@ else '--time-style=[show times using specified style]:style: _alternative "time-styles\:time style\:(full-iso long-iso iso locale)" $datef' '(-a --all -U -l --format -s --size -t --sort --full-time)-f[unsorted, all, short list]' - '(--reverse)'{--reverse,-r}'[reverse sort order]' + '(--reverse -r -U -f)'{--reverse,-r}'[reverse sort order]' '(--sort -t -U -v -X)-S[sort by size]' '(--sort -S -U -v -X)-t[sort by modification time]' '(--sort -S -t -v -X)-U[unsorted]' '(--sort -S -t -U -X)-v[sort by version (filename treated numerically)]' '(--sort -S -t -U -v)-X[sort by extension]' - '(-S -t -U -v -X)--sort=:sort:(size time none version extension)' + '(-S -t -U -v -X)--sort=[specify sort key]:sort key:(size time none version extension)' '--color=-[control use of color]:color:(never always auto)' - "--hide=[don't list entries matching pattern]:pattern" + "*--hide=[like -I, but overridden by -a or -A]:pattern: " '(--classify -F --indicator-style -p --file-type)'{--classify,-F}'[append file type indicators]' - '(--file-type -p --indicator-style -F --classify)'{--file-type,-p}'[append file type indicators except *]' - '(-F --classify -p --file-type)--indicator-style=:indicator style:(none file-type classify slash)' + '(--file-type -p --indicator-style -F --classify)--file-type[append file type indicators except *]' + '(--file-type -p --indicator-style -F --classify)-p[append / to directories]' + '(-F --classify -p --file-type)--indicator-style=[specify indicator style]:indicator style:(none file-type classify slash)' '(-f)--full-time[list both full date and full time]' - '(--kilobytes -k --block-size)'{--kilobytes,-k}'[use block size of 1k]' - '(-k --kilobytes)--block-size=[specify block size]:block size (bytes):(1024)' + '(--block-size --human-readable -h --si --kilobytes -k)'{--kilobytes,-k}'[use block size of 1k]' + '(--human-readable -h --si --kilobytes -k)--block-size=[specify block size]:block size (bytes):(1024)' '(--numeric-uid-gid -n)'{--numeric-uid-gid,-n}'[numeric uid, gid]' '(--tabsize -T)'{--tabsize=,-T+}'[specify tab size]:tab size' '(--width -w)'{--width=,-w+}'[specify screen width]:screen width' '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--escape,-b}'[print octal escapes for control characters]' - '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--literal,-N}'[print raw characters]' + '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--literal,-N}'[print entry names without quoting]' '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--quote-name,-Q}'[quote names]' - '(-b --escape -N --literal -Q --quote-name)--quoting-style=:quoting style:(literal shell shell-always c escape clocale locale)' + '(-b --escape -N --literal -Q --quote-name)--quoting-style=[specify quoting style]:quoting style:(literal shell shell-always c escape clocale locale)' '(--hide-control-chars -q --show-control-chars)'{--hide-control-chars,-q}'[hide control chars]' '(-q --hide-control-chars)--show-control-chars' @@ -148,4 +200,4 @@ else fi fi -_arguments -s $arguments +_arguments -s -S : $arguments diff --git a/Completion/Unix/Command/_lsof b/Completion/Unix/Command/_lsof index c12b9910a..bbb6eab59 100644 --- a/Completion/Unix/Command/_lsof +++ b/Completion/Unix/Command/_lsof @@ -1,6 +1,6 @@ #compdef lsof -local curcontext="$curcontext" state line fields args +local curcontext="$curcontext" state line expl fields args case $OSTYPE in linux*) args=( '-X[skip reporting of info on network connections]' ) ;; diff --git a/Completion/Unix/Command/_man b/Completion/Unix/Command/_man index b2aaeaf7e..67810e1dc 100644 --- a/Completion/Unix/Command/_man +++ b/Completion/Unix/Command/_man @@ -51,7 +51,11 @@ _man() { sect="${sect//:/|}" sect="${sect//,/|}" elif (( CURRENT > 2 )); then - sect=$words[2] + case $words[2] in + (-a) sect='*';; + (-*) ;; + (*) sect=$words[2];; + esac fi if [[ $sect = (<->*|1M|l|n) || $sect = *\|* ]]; then diff --git a/Completion/Unix/Command/_mount b/Completion/Unix/Command/_mount index 7c5605016..03cc01f8d 100644 --- a/Completion/Unix/Command/_mount +++ b/Completion/Unix/Command/_mount @@ -619,7 +619,7 @@ if (( ! $+_fs_any )); then 'longnames[force Windows 95 long filenames to be visible]' 'nowin95[completely ignore Windows 95 extended file information]' ) - if [[ "${OSTYPE}" =~ freebsd.* ]]; then + if [[ "${OSTYPE}" = freebsd* ]]; then _fs_msdosfs=( "$_fs_msdos[@]" ) fi ;; @@ -931,42 +931,7 @@ devordir) esac ;; udevordir) - local dev_tmp dpath_tmp mp_tmp mline - - case "$OSTYPE" in - linux*|irix*) - tmp=( "${(@f)$(< /etc/mtab)}" ) - dev_tmp=( "${(@)${(@)tmp%% *}:#none}" ) - mp_tmp=( "${(@)${(@)tmp#* }%% *}" ) - ;; - freebsd*|dragonfly*) - /sbin/mount | while read mline; do - dev_tmp+=( $mline[(w)1] ) - mp_tmp+=( $mline[(w)3] ) - done - ;; - darwin*) - tmp=( "${(@f)$(/sbin/mount)}" ) - dev_tmp=( "${(@)${(@)tmp%% *}:#map}" ) - mp_tmp=( "${(@)${(@)tmp#* on }%% \(*}" ) - ;; - *) - /sbin/mount | while read mline; do - mp_tmp+=( $mline[(w)1] ) - dev_tmp+=( $mline[(w)3] ) - done - ;; - esac - - local MATCH MBEGIN MEND - mp_tmp=("${(@g::)mp_tmp}") - dpath_tmp=( "${(@Mg::)dev_tmp:#/*}" ) - dev_tmp=( "${(@g::)dev_tmp:#/*}" ) - - _alternative \ - 'device-labels:device label:compadd -a dev_tmp' \ - 'device-paths: device path:_canonical_paths -A dpath_tmp -N -M "r:|/=* r:|=*" device-paths device\ path' \ - 'directories:mount point:_canonical_paths -A mp_tmp -N -M "r:|/=* r:|=*" directories mount\ point' && ret=0 + _umountable ;; labels) _wanted labels expl 'disk label' compadd /dev/disk/by-label/*(:t) && ret=0 diff --git a/Completion/Unix/Command/_mpc b/Completion/Unix/Command/_mpc index 11eab8463..e0c6888b0 100644 --- a/Completion/Unix/Command/_mpc +++ b/Completion/Unix/Command/_mpc @@ -131,7 +131,7 @@ _mpc_helper_songnumbers() { (( $+functions[_mpc_helper_playlists] )) || _mpc_helper_playlists() { local list expl - list=($(mpc lsplaylists)) + list=(${(f)"$(mpc lsplaylists)"}) _wanted list expl playlist compadd -M $MPC_PLAYLIST_MATCHER $expl -a list } diff --git a/Completion/Unix/Command/_mysql_utils b/Completion/Unix/Command/_mysql_utils index 6532d0a7b..f1ad97bcd 100644 --- a/Completion/Unix/Command/_mysql_utils +++ b/Completion/Unix/Command/_mysql_utils @@ -212,7 +212,7 @@ _mysql_utils() { '--defaults-extra-file=[read specified file after the global files]:defaults file:_files' '(-S --socket)'{-S+,--socket=}'[specify socket file to use for connection]:server socket file:_files' '(-h --host)'{-h+,--host=}'[specify server hostname]:hostname:_mysql_hosts' - '(-P,--port)'{-P+,--port=}'[specify port number for connection]:server port:_mysql_ports' + '(-P --port)'{-P+,--port=}'[specify port number for connection]:server port:_mysql_ports' '(-u --user)'{-u+,--user=}'[specify username for login]:server username:_mysql_users' '(-p --password)'{-p-,--password=}'[specify password to use for connection]:server password' '(-C --compress)'{-C,--compress}'[use compression in server/client protocol]' diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm index 73d7508b4..146a69e8a 100644 --- a/Completion/Unix/Command/_nm +++ b/Completion/Unix/Command/_nm @@ -5,79 +5,130 @@ local args files variant files="*:object file:_object_files" args=( '(-A -o --print-file-name)'{-A,-o,--print-file-name}'[print name of input file on each line]' - '(--demangle)-C[decode symbol names]' + '(--demangle --no-demangle)-C[decode symbol names]' '(-D --dynamic)'{-D,--dynamic}'[display dynamic symbols instead of normal ones]' '(-g --extern-only)'{-g,--extern-only}'[display only global symbols]' '(-t --radix -o -x)'{-t,--radix}'[specify radix for numeric values]:radix:((d\:decimal o\:octal x\:hexadecimal))' ) if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfutils unix -V; then - compset -P '@' && files='*:options file:_files' args+=( '(- *)--help[display help information]' - '(- *)--version[display version information]' + '(- *)'{-V,--version}'[display version information]' '(-f --format -P --portability)-B[same as --format=bsd]' - '(-C --no-demangle)--demangle=-[decode symbol names]::style:(auto gnu lucid arm hp edg gnu-v3 java gnat)' - "(-C --demangle)--no-demangle[don't decode symbol names]" '(-u --undefined-only)--defined-only[display only defined symbols]' '(-f --format -P)--format=[specify output format]:format:(bsd sysv posix)' '(-n --numeric-sort -p --no-sort --size-sort -v)'{-n,--numeric-sort}'[sort symbols numerically by address]' - '(-p --no-sort -n --numeric-sort -r -P --reverse-sort --size-sort)'{-p,--no-sort}'[do not sort symbols]' + '(-p --no-sort -n -v --numeric-sort -r --reverse-sort --size-sort)'{-p,--no-sort}'[do not sort symbols]' '(-P --portability -B -f --format)'{-P,--portability}'[same as --format=posix]' - '(-r --reverse-sort -p --no-sort --size-sort -v)'{-r,--reverse-sort}'[reverse sort order]' + '(-r --reverse-sort -p --no-sort)'{-r,--reverse-sort}'[reverse sort order]' '(-u --undefined-only --defined-only)'{-u,--undefined-only}'[display only undefined symbols]' '(-a --debug-syms)'{-a,--debug-syms}'[display debugger-only symbols]' '(-S --print-size)'{-S,--print-size}'[print size of defined symbols]' '(-s --print-armap)'{-s,--print-armap}'[include index for symbols from archive members]' - '(-p --no-sort -n --numeric-sort -r -v)--size-sort[sort symbols by size]' ) case $variant in elftoolchain|binutils) args+=( '(-l --line-numbers)'{-l,--line-numbers}'[display source file and line numbers from debug information]' + "(-C --demangle)--no-demangle[don't decode symbol names]" + '(-p --no-sort -n -v --numeric-sort)--size-sort[sort symbols by size]' + '(-n --numeric-sort -p --no-sort --size-sort)-v[sort symbols numerically by address]' + '(- *)-h[display help information]' ) ;| elftoolchain) - args=( ${args:#*--(portability|extern-only)\[*} - '(- *)-h[display help information]' - '(-t -x)-o[print values in octal]' - '(-t -o)-x[print values in hexadecimal]' - '(--size-sort)-v[sort output by value]' + args=( ${args:#*(-C|-o|--portability)\[*} + '(-C --demangle)'{-C,--demangle=-}'[decode symbol names]::style:(auto gnu-v2 gnu-v3 arm)' + '(-g --extern-only)-e[only display global and static symbols]' + '(--format -P)-F+[specify output format]:format:(bsd sysv posix)' + '-o[with -P, same as -t o; otherwise same as -A]' + '(-t --radix)-x[print values in hexadecimal]' ) ;; elfutils) args+=( '--mark-special[mark special symbols]' '--color=[use color in output]:color:(always auto never)' + '(-C)--demangle[decode symbol names]' + '(--format -P)-f+[specify output format]:format:(bsd sysv posix)' + '(- *)--usage[give a short usage message]' + '(- *)-\\?[display help information]' ) ;; binutils) + compset -P '@' && files='*:options file:_files' args+=( '(-f --format -P)-f+[specify output format]:format:(bsd sysv posix)' + '(-C --no-demangle)--demangle=-[decode symbol names]::style:(auto gnu lucid arm hp edg gnu-v3 java gnat)' '--plugin[load specified plugin]:plugin' '--special-syms[include special symbols in the output]' '--synthetic[display synthetic symbols as well]' "--target=[target object format]:targets:(${${(@M)${(f)$(_call_program targets nm --help)}:#*supported targets:*}##*: })" + '--with-symbol-versions[display version strings after symbol names]' ) ;; esac else - # following flags are accurate for Solaris - args=( ${args:#(|*\)(\*|))-[o-]*} - "-h[don't display column headers]" - '-l[distinguish WEAK symbols with * character]' - '(-t -x)-o[print values in octal]' - '(-v)-n[sort symbols by name]' - '(-P)-p[produce parsable output]' - '(-p)-P[portable output format]' - '(-r)-R[print archive name, object file and symbol name]' - '-r[prepend name of input file to each symbol name]' - '-s[print section name instead of index]' - '-u[print undefined symbols only]' - '(-n)-v[sort external symbols by value]' - '-V[display version of the nm command]' - '(-o -t)-x[print values in hexadecimal]' - ) + case $OSTYPE in + (darwin*|openbsd*) + args=( + '(-A -o)'{-A,-o}'[prepend file name to each output line]' + '(-g)-a[display all symbols including those for debuggers]' + '(-a)-g[display only global symbols]' + '(-U)-u[display only undefined symbols]' + '(-p)-n[sort numerically rather than alphabetically]' + "(-n -r)-p[don't sort; display in symbol-table order]" + '(-p)-r[sort in reverse order]' + '(-j)-P[print information in a portable format]' + '(-j)-t[specify radix for numeric values (used with -P)]:radix:((d\:decimal o\:octal x\:hexadecimal))' + );| + (darwin*) + args+=( + "(-u)-U[don't display undefined symbols]" + '-f[display symbol table of dynamic library flat]' + '(-P -t -m)-j[just display symbol names (no value or type)]' + '-l[display .section_start if no symbol is in the section (used with -s)]' + '(-j)-m[use verbose format for Mach-O symbols]' + '-s[list only symbols in the specified section]:segment name: :section name: ' + "-x[display symbol table entry's fields in hexadecimal]" + '*-arch[select architecture from universal file]:architecture:(all i386 x86_64)' + );; + (openbsd*) + args+=( + '-C[decode low-level symbol names]' + '-D[display dynamic symbol table instead of normal symbol table]' + '-e[output extended information]' + '-s[show archive index]' + '-w[warn about non-object archive members]' + );; + (solaris*) + args=( ${args:#(|*\)(\*|))-[o-]*} + "-h[don't display column headers]" + '-l[distinguish WEAK symbols with * character]' + '(-t -x)-o[print values in octal]' + '(-v)-n[sort symbols by name]' + '(-P)-p[produce parsable output]' + '(-p)-P[portable output format]' + '(-r)-R[print archive name, object file and symbol name]' + '-r[prepend name of input file to each symbol name]' + '-s[print section name instead of index]' + '-u[print undefined symbols only]' + '(-n)-v[sort external symbols by value]' + '-V[display version of the nm command]' + '(-o -t)-x[print values in hexadecimal]' + );; + (*) + # minimal POSIX + args=( + '-A[print name of input file on each line]' + '(-u)-g[display only global symbols]' + '-P[print information in a portable format]' + '-t[specify radix for numeric values]:radix:((d\:decimal o\:octal x\:hexadecimal))' + '(-g)-u[display only undefined symbols]' + '-v[sort symbols by value instead of by name]' + );; + esac fi -_arguments -s "$args[@]" $files +_arguments -s -S : "$args[@]" $files diff --git a/Completion/Unix/Command/_openstack b/Completion/Unix/Command/_openstack index 39fa30c3a..fcb704ac8 100644 --- a/Completion/Unix/Command/_openstack +++ b/Completion/Unix/Command/_openstack @@ -1,4 +1,4 @@ -#compdef openstack aodh barbican ceilometer cinder cloudkitty designate glance gnocchi heat ironic keystone magnum manila mistral monasca murano neutron nova sahara senlin swift trove +#compdef openstack aodh barbican ceilometer cinder cloudkitty designate freezer glance gnocchi heat ironic keystone magnum manila mistral monasca murano neutron nova sahara senlin tacker trove vitrage watcher zun # https://wiki.openstack.org/wiki/OpenStackClients # http://docs.openstack.org/user-guide/common/cli-install-openstack-command-line-clients.html @@ -23,8 +23,8 @@ local -a clnts_compl_new clnts_compl_old clnts_swift_like # # 3) Swift, slightly different from 2) # -clnts_compl_new=( aodh barbican designate gnocchi openstack ) -clnts_compl_old=( ceilometer cinder cloudkitty glance heat ironic keystone magnum manila mistral monasca murano neutron nova sahara senlin trove ) +clnts_compl_new=( aodh barbican designate freezer gnocchi openstack vitrage watcher ) +clnts_compl_old=( ceilometer cinder cloudkitty glance heat ironic keystone magnum manila mistral monasca murano neutron nova sahara senlin tacker trove zun ) clnts_swift_like=( swift ) # Python clients take quite some time to start up and some (openstack(1)) diff --git a/Completion/Unix/Command/_paste b/Completion/Unix/Command/_paste new file mode 100644 index 000000000..6efe8eacb --- /dev/null +++ b/Completion/Unix/Command/_paste @@ -0,0 +1,19 @@ +#compdef paste + +local -a args +local dopt='[specify delimiter list]:delimiter list [tab]' +local sopt='[paste one file at a time instead of in parallel]' + +if _pick_variant gnu=GNU unix --version; then + args=( + '(-z --zero-terminated)'{-z,--zero-terminated}'[use NUL as line delimiter instead of newline]' + "(-d)--delimiters=$dopt" + "(-s)--serial$sopt" + '(- *)--help[display help information]' + '(- *)--version[display version information]' + ) +else + args=( -A "-?*" ) +fi + +_arguments -s $args "(--delimiters)-d+$dopt" "(--serial)-s$sopt" '*:file:_files' diff --git a/Completion/Unix/Command/_patchutils b/Completion/Unix/Command/_patchutils index 323c0a730..50ea3e4c4 100644 --- a/Completion/Unix/Command/_patchutils +++ b/Completion/Unix/Command/_patchutils @@ -43,6 +43,7 @@ case $service in '(-F --files)'{-F+,--files=}'[only list files within specified range]:range' '--strip=[remove specified number of pathname components before displaying]:components' '--addprefix=[insert specified path prefix before displaying path names]:prefix:_directories' + '*:diff file:_files' ) ;| grepdiff|lsdiff) @@ -58,7 +59,6 @@ case $service in \*{-v,--verbose}'[verbose operation]' '(-H --with-filename -h --no-filename)'{-H,--with-filename}'[print the name of the patch file containing each patch]' '!--filter' '!--grep' - '*:diff file:_files' ) ;; grepdiff|filterdiff) @@ -71,7 +71,7 @@ case $service in '--as-numbered-lines=[display lines of selected hunks]:line numbers:(before after)' "--remove-timestamps[don't include timestamps in output]" ) - ;; + ;| filterdiff) args+=( '(-X --exclude-from-file)'{-X+,--exclude-from-file=}'[exclude files matching any pattern listed in specified file]:file:_files' diff --git a/Completion/Unix/Command/_perforce b/Completion/Unix/Command/_perforce index db91e11af..3cd99d519 100644 --- a/Completion/Unix/Command/_perforce +++ b/Completion/Unix/Command/_perforce @@ -3,7 +3,7 @@ # Maintainer: Peter Stephenson <pws@csr.com>. # Increasingly loosely based on _cvs version 1.17. -# Completions currently based on Perforce release 2010.2. +# Completions currently based on Perforce release 2016.1. # Styles, tags and contexts # ========================= @@ -460,7 +460,7 @@ _perforce_call_p4() { # This is for our own use for parsing, and we need English output, # so... local +x P4LANGUAGE - _call_program $cp_tag p4 "${_perforce_global_options[@]}" "$@" + _call_program $cp_tag command p4 "${_perforce_global_options[@]}" "$@" } @@ -1656,11 +1656,12 @@ _perforce_variables() { (( $+functions[_perforce_cmd_add] )) || _perforce_cmd_add() { _arguments -s : \ - '-c+[select by change]:change:_perforce_changes -tc' \ - '-d[reopen removed file for add (downgrade)]' \ + '-c[add files to change]:change:_perforce_changes -tc' \ + '-d[reopen files for add]' \ '-f[allow filenames with wild cards]' \ - '-n[display operation without doing it]' \ - '-t+[set file type]:file type:_perforce_filetypes' \ + '-I[do not perform ignore checking]' \ + '-n[preview add]' \ + '-t[set file type]:file type:_perforce_filetypes' \ '*:file:_perforce_files -tu' } @@ -1682,15 +1683,15 @@ _perforce_cmd_admin() { shift words (( CURRENT-- )) _arguments -s : \ - '-z[gzip journal file]' \ - '1::journal file prefix: ' + '-z[gzip journal file]' \ + '1::journal file prefix: ' ;; (dbstat) shift words (( CURRENT -- )) _arguments -s : \ - '-s[show sizes]' + '-s[show sizes]' esac fi } @@ -1701,11 +1702,17 @@ _perforce_cmd_annotate() { # New in release 2002.2. # -c was new in about 2003.2. _arguments -s : \ - '-a[all, show both added and deleted lines]' \ - '-c[output change numbers instead of revisions]' \ - '-i[follow branches (integration records)]' \ - '-I[follow integrations to get change numbers]' \ - '-q[quiet, suppress one-line file header]' \ + '-a[include deleted files and lines]' \ + '-c[output change numbers]' \ + '-d-[select whitespace option]:whitespace option:(( +b\:ignore\ whitespace\ changes +w\:ignore\ whitespace +l\:ignore\ line\ endings))' \ + '-i[follow branches]' \ + '-I[follow all integrations]' \ + '-q[suppress one-line header]' \ + '-t[display binary files]' \ + '-u[output user and date]' \ '*::file:_perforce_files -tR' } @@ -1718,11 +1725,12 @@ _perforce_cmd_attribute() { # If -f is present, search unopened files, else don't [[ ${words[(I)-f]} -eq 0 ]] && limit=" -to" _arguments -s : \ - '-e[value is in hex]' \ - '-f[set the attribute on a submitted file]' \ - '-n[set name of attribute]:attribute: ' \ - '-p[propagate attribute when opened for edit etc.]' \ - '-v[set value of attribute]:value: ' \ + '-n[attribute name]:name: ' \ + '-v[attribute value]:value: ' \ + '-e[use hex value]' \ + '-f[set attribute on submitted file]' \ + '-p[propagate attribute when opened]' \ + '(-v)-i[read attribute from standard input]' \ "*::file:_perforce_files$limit" } @@ -1730,10 +1738,12 @@ _perforce_cmd_attribute() { (( $+functions[_perforce_cmd_branch] )) || _perforce_cmd_branch() { _arguments -s : \ - '(-o)-f[force operation by superuser]' \ - '(-o -i)-d[delete branch]' \ - '(-d -i -f)-o[write specification to standard output]' \ - '(-d -o)-i[read specification from standard input]' \ + '(-o -S -P)-f[force operation]' \ + '(-o -i -S -P)-d[delete branch]' \ + '(-d -i -f)-o[write branch spec to standard output]' \ + '(-d -o -S -P)-i[read branch spec from standard input]' \ + '(-f -d -i)-S[expose internally generated mapping]:stream: ' \ + '(-f -d -i)-P[treat stream as a child of parent stream]:parent stream: ' \ '(-i)*::branch name:_perforce_branches' } @@ -1741,9 +1751,11 @@ _perforce_cmd_branch() { (( $+functions[_perforce_cmd_branches] )) || _perforce_cmd_branches() { _arguments -s : \ - '-e[limit by wildcard]:wildcard on branches: ' \ - '-u+[select by user]:user:_perforce_users' \ - '-m+[set maximum to show]:max branches: ' + '(-E)-e[list branches that match pattern]:pattern: ' \ + '(-e)-E[list branches that match case-insensitive pattern]:case-insensitive pattern: ' \ + '-u[list branches owned by user]:user:_perforce_users' \ + '-m[limit output to max branches]:max branches: ' \ + '-t[display time and date]' } @@ -1761,14 +1773,18 @@ _perforce_cmd_change() { fi fi _arguments -s : \ - '(-o)-f[allow force by superuser]' \ - '-s[joblist includes the fix status]' \ - '(-o -i)-d[discard newly created pending change]' \ - '(-d -i -f)-o[output specification to standard output]' \ - '(-d -o)-i[read specification from standard input]' \ - '(-d -o)-u[force change of jobs or description by owner]' \ - "(-i)1::change:_perforce_changes$ctype" \ - '-t[specify visibility type]:visibility type:(public restricted)' + '-f[force update of change]' \ + '-s[include fix status in job list]' \ + '(-u -I -o -i -t -U)-d[delete change]' \ + '(-u -d -o -i -t -U --serverid)-o[write change spec to the standard output]' \ + '(-O -I -d -o -i -t -U --serverid)-i[read change spec from the standard input]' \ + '(-s -d -o -i --serverid)-t[set type of change]:type:(public restricted)' \ + '-U[set user of empty change]:user:_perforce_users' \ + '-O[change is original number before submit]' \ + '-I[change is number of Identity field]' \ + '-u[force update of submitted change]' \ + '(-s -u -O -I -o -i -t -U)--serverid[specify server]:server ID: ' \ + "(-i)1::change:_perforce_changes$ctype" } @@ -1782,13 +1798,15 @@ _perforce_cmd_changelist() { _perforce_cmd_changes() { _arguments -s : \ '-i[include integrated changes]' \ - '-t[output time as well as date]' \ - '-l[long output, full change text]' \ - '-L[long output, truncated change text]' \ - '-c+[select by client]:client:_perforce_clients' \ - '-m+[most recent N changes]:max changes: ' \ - '-s+[select by status]:status:(pending shelved submitted)' \ - '-u+[select by user]:user:_perforce_users' \ + '-t[display time and date]' \ + '-l[display full change text]' \ + '-L[display truncated change text]' \ + '-f[view restricted changes]' \ + '-c[display changes submitted by client]:client:_perforce_clients' \ + '-e[display changes above this change]:change:_perforce_changes' \ + '-m[limit to max changes]:max changes: ' \ + '-s[limit output to changes with status]:status:(pending shelved submitted)' \ + '-u[display changes owned by user]:user:_perforce_users' \ '*::file:_perforce_files -tR' } @@ -1799,14 +1817,33 @@ _perforce_cmd_changelists() { } +(( $+functions[_perforce_cmd_clean] )) || +_perforce_cmd_clean() { + _arguments -s : \ + '-e[clean modified files]' \ + '-a[clean added files]' \ + '-d[clean deleted files]' \ + '-I[do not perform ignore checking]' \ + '-l[output relative paths]' \ + '-n[preview clean]' \ + '*:file:_perforce_files -tu' +} + + + (( $+functions[_perforce_cmd_client] )) || _perforce_cmd_client() { _arguments -s : \ - '(-o)-f[force modification by superuser]' \ - '-t[use template]:template client:_perforce_clients' \ - '(-o -i -t)-d[delete client]' \ - '(-d -i -f)-o[print to standard output]' \ - '(-d -o -t)-i[read from standard input]' \ + '-f[force update of client]' \ + '-Fs[force delete with shelved changes]' \ + '(-t -o -S -c -s -i)-d[delete client]' \ + '(-f -d -Fs -s -i --serverid)-o[write client spec to standard output]' \ + '(-t -d -Fs -i --serverid)-S[create new client dedicated to stream]:stream: ' \ + '(-d -Fs -o -c -i --serverid)-s[switch client view without opening editor]' \ + '(-t -d -Fs -o -S -c -s --serverid)-i[read client spec from standard input]' \ + '-t[use client as template]:client:_perforce_clients' \ + '(-f -t -d -Fs -s -i --serverid)-c[yield client spec for stream at moment change was recorded]:change:_perforce_changes -ts' \ + '--serverid[specify server]:server ID: ' \ '1::file:_perforce_clients' } @@ -1814,34 +1851,59 @@ _perforce_cmd_client() { (( $+functions[_perforce_cmd_clients] )) || _perforce_cmd_clients() { _arguments -s : \ - '-e[limit by wildcard]:wildcard on clients: ' \ - '-u+[select by user]:user:_perforce_users' \ - '-m+[set maximum to show]:max clients: ' + '-t[display time and date]' \ + '-u[list clients owned by user]:user:_perforce_users' \ + '(-E)-e[list clients that match pattern]:pattern: ' \ + '(-e)-E[list clients that match case-insensitive pattern]:case-insensitive pattern: ' \ + '-m[limit to max clients]:max clients: ' \ + '-S[limit output to clients dedicated to stream]:stream: ' \ + '-U[list unloaded clients]' \ + '(-s)-a[display all clients]' \ + '(-a)-s[display clients dedicated to server]:server ID: ' } (( $+functions[_perforce_cmd_copy] )) || _perforce_cmd_copy() { - local range - # If -s is present, the first normal argument can't have revRange. - [[ ${words[(I)-s]} -eq 0 ]] && range=" -tR" + local -a fileargs + if [[ ${words[(I)-b*]} -ne 0 ]]; then + if [[ ${words[(I)-*s*]} -eq 0 ]]; then + # with -b and no -s, all files are to-files (but -s may come later) + fileargs=('*::to file:_perforce_files -tR') + else + # with -b and -s we have one from-file and any number of to-files + fileargs=('*::to file:_perforce_files') + fi + elif [[ ${words[(I)-(S|P)]} -ne 0 ]]; then + fileargs=('*::file:_perforce_files -tR') + else + # with no -b we have one from-file and one to-file + fileargs=('1::from file:_perforce_files -tR' + '2::to file:_perforce_files') + fi _arguments -s : \ - '-b[select branch]:branch:_perforce_branches' \ - '-c[select change for copy]:change:_perforce_changes -tc' \ - '-n[no action, dummy run]' \ - '-r[reverse direction of copy with branch]' \ - '-s[select source with -b]:source file:_perforce_files -tR' \ - '-v[leave newly copied files uncopied till sync]' \ - "1:file:_perforce_files$range" \ - '*::file:_perforce_files' + '-b[use branch view'\''s source and target]:branch:_perforce_branches' \ + '-s[select source file, use branch view as target]:source file:_perforce_files -tR' \ + '-r[reverse direction of copy]' \ + '-c[open files in change]:change:_perforce_changes -tc' \ + '-f[force creation of extra revisions]' \ + '-n[preview copy]' \ + '-m[limit copy to max files]:max files: ' \ + '-q[suppress normal output messages]' \ + '-v[do not modify client files]' \ + '(-b -s)-S[copy from stream to its parent]:stream: ' \ + '(-b -s)-P[generate branch view using a parent stream]:parent stream: ' \ + '(-b -s)-F[copy against stream'\''s expected flow]' \ + $fileargs } (( $+functions[_perforce_cmd_counter] )) || _perforce_cmd_counter() { _arguments -s : \ '-d[delete counter]' \ - '-f[force setting of internal counter]' \ - '-i[increment by one atomically]' \ + '-f[set or delete internal counter]' \ + '-i[increment counter by 1]' \ + '-m[allow multiple operations]' \ '1:counter:_perforce_counters' \ '(-d -i)2::numeric value:_perforce_counter_values' } @@ -1849,8 +1911,9 @@ _perforce_cmd_counter() { (( $+functions[_perforce_cmd_counters] )) || _perforce_cmd_counters() { - # No arguments - _arguments -s : + _arguments -s : \ + '-e[list counters that match pattern]:pattern: ' \ + '-m[limit to max counters]:max counters: ' } @@ -1884,8 +1947,10 @@ _perforce_cmd_dbstat() { (( $+functions[_perforce_cmd_delete] )) || _perforce_cmd_delete() { _arguments -s : \ - '-c[select change for deletion]:change:_perforce_changes -tc' \ - '-n[show deletions without doing them]' \ + '-c[delete files for change]:change:_perforce_changes -tc' \ + '-n[preview delete]' \ + '-k[perform delete on server]' \ + '-v[delete unsynced files]' \ '*::file:_perforce_files' } @@ -1893,9 +1958,11 @@ _perforce_cmd_delete() { (( $+functions[_perforce_cmd_depot] )) || _perforce_cmd_depot() { _arguments -s : \ - '-d[delete depot]' \ - '-o[print to stdout]' \ - '-i[read name from stdin]' \ + '(-t -o -i)-d[delete depot]' \ + '(-t -o -i)-f[force delete]' \ + '(-d -o -i)-t[insert value into type]:type: ' \ + '(-t -d -i -f)-o[write depot spec to standard output]' \ + '(-t -d -o -f)-i[read depot spec from standard input]' \ '(-i)*::depot name:_perforce_depots' } @@ -1910,9 +1977,20 @@ _perforce_cmd_depots() { (( $+functions[_perforce_cmd_describe] )) || _perforce_cmd_describe() { _arguments -s : \ - '-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \ - '-s[short form]' \ - '-S[show shelved changes]' \ + '-d-[diff options]:diff options:(( +n\:RCS +c\:context +s\:summary +u\:unified +b\:ignore\ whitespace\ changes +w\:ignore\ whitespace +l\:ignore\ line\ endings))' \ + '-s[omit diffs]' \ + '-S[list shelved files]' \ + '-f[force display of restricted change]' \ + '-O[change is original number before submit]' \ + '-I[change is number of Identity field]' \ + '-m[limit output to max files]:max files: ' \ '*::change:_perforce_changes' } @@ -1920,17 +1998,27 @@ _perforce_cmd_describe() { (( $+functions[_perforce_cmd_diff] )) || _perforce_cmd_diff() { local limit - [[ ${words[(I)-(f|sd|se)]} -eq 0 ]] && limit=" -to" - _arguments -s : \ - '-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context l\:ignore\ line\ endings n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \ + [[ ${words[(I)-(f|sd|se|sl)]} -eq 0 ]] && limit=" -to" + _arguments -s : \ + '-d-[diff options]:diff options:(( +n\:RCS +c\:context +s\:summary +u\:unified +b\:ignore\ whitespace\ changes +w\:ignore\ whitespace +l\:ignore\ line\ endings))' \ '-f[diff every file]' \ - '-m+[set maximum files to show]:max files: ' \ - '(-sd -se -sl -sr)-sa[opened files, different or missing]' \ - '(-sa -se -sl -sr)-sd[unopened files, missing]' \ - '(-sa -sd -sl -sr)-se[unopened files, different]' \ - '(-sa -sd -se -sr)-sl[all unopened files with status]' \ - '(-sa -sd -se -sl)-sr[opened files, same as depot]' \ - '-t[include non-text files]' \ + '-m[limit output to max files]:max files: ' \ + '-Od[limit output to files that differ]' \ + '-s-[filter options]:filter options:(( +a\:list\ opened\ files\ that\ differ\ from\ depot +b\:list\ modified\ integrated\ files +d\:list\ unopened\ missing\ files +e\:list\ unopened\ files\ that\ differ\ from\ depot +l\:list\ all\ unopened\ files\ with\ status +r\:list\ opened\ files\ that\ do\ not\ differ\ from\ depot))' \ + '-t[diff binary files]' \ "*::file:_perforce_files$limit" } @@ -1938,22 +2026,33 @@ _perforce_cmd_diff() { (( $+functions[_perforce_cmd_diff2] )) || _perforce_cmd_diff2() { _arguments -s : \ - '-b[specify branch view]:branch name:_perforce_branches' \ - '-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \ - '-q[only list different files]' \ - '-t[include non-text files]' \ - '-u[use patch-friendly output]' \ - '1::first file:_perforce_files' \ - '2::second file:_perforce_files' + '-b[use branch view'\''s source and target]:branch:_perforce_branches' \ + '-d-[diff options]:diff options:(( +n\:RCS +c\:context +s\:summary +u\:unified +b\:ignore\ whitespace\ changes +w\:ignore\ whitespace +l\:ignore\ line\ endings))' \ + '-Od[limit output to files that differ]' \ + '-q[omit identical files]' \ + '-t[diff binary files]' \ + '-u[use GNU diff -u format]' \ + '(-b)-S[use generated branch view from stream]:stream: ' \ + '(-b)-P[use generated branch view from parent stream]:parent stream: ' \ + '1::from file:_perforce_files' \ + '2::to file:_perforce_files' } (( $+functions[_perforce_cmd_dirs] )) || _perforce_cmd_dirs() { _arguments -s : \ - '-C[only dirs on current client]' \ - '-D[include dirs with deleted files]' \ - '-H[only dirs on the `have'\'' list]' \ + '-C[list only directories in current client]' \ + '-D[include directories with only deleted files]' \ + '-H[list directories with synced files]' \ + '-S[limit output to depot directories mapped to stream'\''s client]:stream: ' \ '*::directory:_perforce_files -td' } @@ -1961,10 +2060,10 @@ _perforce_cmd_dirs() { (( $+functions[_perforce_cmd_edit] )) || _perforce_cmd_edit() { _arguments -s : \ - '-c[set change for edit]:change:_perforce_changes -tc' \ - '-k[no resync from server]' \ - '-n[show files to edit without opening them]' \ - '-t[set filetype]:filetype:_perforce_filetypes' \ + '-c[edit files for change]:change:_perforce_changes -tc' \ + '-t[specify filetype]:filetype:_perforce_filetypes' \ + '-n[preview edit]' \ + '-k[edit files on server]' \ '*::file:_perforce_files' } @@ -1986,14 +2085,15 @@ _perforce_cmd_export() { (( $+functions[_perforce_cmd_filelog] )) || _perforce_cmd_filelog() { _arguments -s : \ - '-c[select by changelist]:change:_perforce_changes -ts' \ - '-h[follow branc/copy from records]' \ - '-i[follow branches]' \ - '-l[long output, full change text]' \ - '-L[long output, truncated change text]' \ - '-m[set maximum number of revisions to show]:max revisions: ' \ - '-s[short output]' \ - '-t[include time with date]' \ + '-c[display files at change]:change:_perforce_changes -ts' \ + '-i[include inherited file history]' \ + '-h[display file content history]' \ + '-t[display time and date]' \ + '-l[display full change text]' \ + '-L[display truncated change text]' \ + '-m[display max number of revisions]:max revisions: ' \ + '-p[do not follow content of promoted task streams]' \ + '-s[display shortened form]' \ '*::file:_perforce_files' } @@ -2001,7 +2101,11 @@ _perforce_cmd_filelog() { (( $+functions[_perforce_cmd_files] )) || _perforce_cmd_files() { _arguments -s : \ - '-a[display all revisions in given range]' \ + '-a[display all revisions in range]' \ + '-A[display files in archive depots]' \ + '-e[do not display deleted, purged or archived files]' \ + '-m[limit output to max files]:max files: ' \ + '-U[display files in unload depot]' \ '*::file:_perforce_files -tR' } @@ -2024,10 +2128,9 @@ _perforce_cmd_fix() { fi _arguments -s : \ - '-d[delete the fix]' \ - '-s[set job status]:status:_perforce_statuses' \ - '1::-c required:(-c)' \ - '2::change:_perforce_changes' \ + '-d[delete fix]' \ + '-s[set status]:status:_perforce_statuses' \ + '-c[display jobs fixed by change]:change:_perforce_changes -ts' \ "*::job:_perforce_jobs$job" } @@ -2035,10 +2138,10 @@ _perforce_cmd_fix() { (( $+functions[_perforce_cmd_fixes] )) || _perforce_cmd_fixes() { _arguments -s : \ + '-j[list fixes for job]:job:_perforce_jobs' \ + '-c[list fixes for change]:change:_perforce_changes -tR' \ '-i[include integrated changes]' \ - '-j[select by job]:job:_perforce_jobs' \ - '-c[select by change]:change:_perforce_changes' \ - '-m[set max fixes to show]:max fixes: ' \ + '-m[limit output to max fixes]:max fixes: ' \ '*::fixed file:_perforce_files -tR' } @@ -2047,8 +2150,12 @@ _perforce_cmd_fixes() { _perforce_cmd_flush() { _arguments -s : \ '-f[force resynchronisation]' \ - '-k[bypass client file update]' \ - '-n[show operations but don'\''t perform them]' \ + '-L[use full depot syntax, including revision number]' \ + '-n[preview flush]' \ + '-N[preview flush with summary]' \ + '-q[suppress normal output messages]' \ + '-r[reopen moved files in new location]' \ + '-m[limit sync to max files]:max files: ' \ '*::file:_perforce_files -tR' } @@ -2058,26 +2165,46 @@ _perforce_cmd_fstat() { local Oattr Aattr if [[ ${_perforce_cmd_list[(r)attribute:*]} != '' ]]; then # Unsupported feature, try not to show if not present - Oattr=' a\:show\ attributes d\:attributes\ digest e\:attributes\ in\ hex' + Oattr=' a\:output\ attributes d\:output\ digest e\:output\ values\ in\ hex' Aattr='-A[restrict attributes by pattern]:attribute pattern: ' fi _arguments -s : \ - '-c+[affected since change]:change:_perforce_changes -ts' \ - '-e+[affected by change]:change:_perforce_changes -ts' \ - '-C[select mapped files (-Rc)]' \ - '-F[pick filter for files]:filter:_perforce_fstat_fields -tv' \ - '-H[select synced files (-Rh)]' \ - '-W[select opened files (-Ro)]' \ - '-l[include fileSize, possibly slow (-Ol)]' \ - '-m[set max files to show]:max files: ' \ - "-O-[select output type]:output type:((f\:all\ revisions l\:fileSize p\:client\ path\ format r\:pending\ integrations s\:exclude\ local\ path$Oattr))" \ - '-P[output clientFile in full Perforce syntax (deprecated: use -Op)]' \ - '-r[show in reverse order]' \ - '-R-[restrict selected files]:restriction:((c\:mapped\ in\ client h\:synced\ to\ client n\:not\ synced\ to\ head o\:opened r\:resolved s\:shelved u\:unresolved))' \ - '-s[shorten, no client-related data (deprecated: use -Os)]' \ - '-S-[changes sort order]:sort criterion:((t\:filetype d\:date r\:head\ revision h\:have\ revision s\:filesize))' \ - '-T[select output fields]:output field:_perforce_fstat_fields' \ $Aattr \ + '-F[list only files satisfying filter]:filter:_perforce_fstat_fields -tv' \ + '-L[use full depot syntax, including revision number]' \ + '-T[return specified fields]:output field:_perforce_fstat_fields' \ + '-m[limits output to max files]:max files: ' \ + '-r[sort output in reverse order]' \ + '-c[display files modified by or after change]:change:_perforce_changes -ts' \ + '-e[list files modified by change]:change:_perforce_changes -ts' \ + "-O-[output options]:output options:(( +f\:all\ revisions +l\:fileSize\ and\ digest +p\:local\ file\ path +r\:pending\ integration +s\:exclude\ local\ path +$Oattr))" \ + '-R-[restrict files]:file restrictions:(( +c\:mapped\ in\ client +h\:synced\ to\ client +n\:opened\ not\ at\ head\ revision +o\:opened +r\:resolved +s\:shelved +u\:unresolved))' \ + '-S-[sort order]:sort by:(( +t\:filetype +d\:date +r\:head\ revision +h\:have\ revision +s\:filesize))' \ + '-U[display info about unload files in unload depot]' \ + '-C[limit output to mapped files (-Rc)]' \ + '-H[limit output to synced files (-Rh)]' \ + '-W[limit output to opened files (-Ro)]' \ + '-l[output fileSize and digest (-Ol)]' \ + '-P[output local file paths (-Op)]' \ + '-s[exclude local file paths (-Os)]' \ '*::file:_perforce_files' } @@ -2085,22 +2212,21 @@ _perforce_cmd_fstat() { (( $+functions[_perforce_cmd_grep] )) || _perforce_cmd_grep() { _arguments -s : \ + '-e[search pattern]:pattern: ' \ '-a[search all revisions]' \ '-i[case insensitive match]' \ - '-n[display matching line]' \ - '-v[display file name]' \ - '-F[interpret as fixed string]' \ - '-G[interpret as regexp (default)]' \ - '-L[list non-matching file/revisions]' \ - '-l[list matching file/revisions]' \ - '-s[suppresses errors on long lines]' \ - '-t[treat all files as text]' \ - '-A[]:trailing context lines: ' \ - '-V[]:leading context lines: ' \ - '-C[]:context lines: ' \ - '1:-e required before pattern:(-e)' \ - '2:pattern: ' \ - '*::file:_perforce_files' + '-n[display matching line number]' \ + '-v[display files with non-matching lines]' \ + '-F[interpret pattern as fixed string]' \ + '-G[interpret pattern as regexp]' \ + '-L[display non-matching files]' \ + '-l[display matching files]' \ + '-s[suppress errors on long lines]' \ + '-t[search binary files]' \ + '-A[display N lines of trailing context]:lines: ' \ + '-B[display N lines of leading context]:lines: ' \ + '-C[display N lines of output context]:lines: ' \ + '*::file:_perforce_files -tR' } @@ -2108,9 +2234,10 @@ _perforce_cmd_grep() { _perforce_cmd_group() { _arguments -s : \ '-d[delete group]' \ - '-o[output to stdout]' \ - '-i[read from stdin]' \ - '(-o)-a[allow non-super owner to modify group]' \ + '-o[write group spec to standard output]' \ + '-i[read group spec from standard input]' \ + '(-o -A)-a[allow owner to modify group]' \ + '(-a -d)-A[allow admin user to add new group]' \ '1::perforce group:_perforce_groups' } @@ -2118,10 +2245,13 @@ _perforce_cmd_group() { (( $+functions[_perforce_cmd_groups] )) || _perforce_cmd_groups() { _arguments -s : \ - '-i[show indirect membership by subgroups]' \ - '-m[set max groups to show]:max groups: ' \ - '-v[show summary data]' \ - '1::user or group name:_perforce_users_or_groups' + '-i[display indirect membership by subgroups]' \ + '-m[limit output to max groups]:max groups: ' \ + '-v[display group data]' \ + '(-u -o)-g[display group with name]:group:_perforce_groups' \ + '(-g -o)-u[display all groups for user]:user:_perforce_users' \ + '(-g -u)-o[display all groups for owner]:owner:_perforce_users' \ + '(-g -u -o)1::user or group name:_perforce_users_or_groups' } @@ -2141,7 +2271,7 @@ _perforce_cmd_help() { _perforce_help_list=($_perforce_cmd_list) _perforce_call_p4 help help | while read -A hline; do if [[ $hline[1] = p4 && $hline[2] = help ]]; then - _perforce_help_list+=("$hline[3]:${hline[4,-1]}") + _perforce_help_list+=("$hline[3]:${hline[4,-1]}") fi done if [[ -z ${_perforce_help_list[(r)undoc:*]} ]]; then @@ -2155,7 +2285,7 @@ _perforce_cmd_help() { (( $+functions[_perforce_cmd_info] )) || _perforce_cmd_info() { _arguments -s : \ - '-s[don'\''t check for unknown users or clients]' + '-s[short output]' } @@ -2165,24 +2295,26 @@ _perforce_cmd_integrate() { # If -s is present, the first normal argument can't have revRange. [[ ${words[(I)-s]} -eq 0 ]] && range=" -tR" _arguments -s : \ - '-b[select branch]:branch:_perforce_branches' \ - '-c[select change for integration]:change:_perforce_changes -tc' \ - '-f[force reintegration]' \ - '-d[reintegrate deleted files]' \ - '-D-[specify allowed deletions]:deletion type:(( -t\:rebranch\ on\ deleted\ file -s\:delete\ modified\ target\ file -i\:ignore\ readded\ source\ file -))' \ - '-h[integrate to revision had on client]' \ - '-i[integrate if no common file base]' \ - '-I[same as -i from 2004.2]' \ - '-n[no action, dummy run]' \ - '-o[display base file name for subsequent resolve]' \ - '-r[reverse direction of integration with branch]' \ - '-s[select source with -b]:source file:_perforce_files -tR' \ - '-t[propagate type changes]' \ - '-v[leave newly branched files uncopied till sync]' \ + '-b[use branch view'\''s source and target]:branch:_perforce_branches' \ + '(-r)-s[select source file, use branch view as target]:source file:_perforce_files -tR' \ + '-f[force integration]' \ + '-O-[output more information]:output options:(( +b\:show\ base\ revision\ for\ merge +r\:show\ scheduled\ resolves))' \ + '-R-[specify resolve schedule]:schedule:(( +b\:branch\ resolves +d\:delete\ resolves +s\:skip\ cherry-picked\ revisions\ already\ integrated))' \ + '-Di[retain revisions of deleted files]' \ + '-h[leave files at revision currently synced]' \ + '-m[limit integration to max files]:max files: ' \ + '-n[preview integration]' \ + '-q[suppress normal output messages]' \ + '-c[open in change]:change:_perforce_changes -tc' \ + '-v[do not modify client files]' \ + '-r[reverse direction of mapping]' \ + '-S[use generated branch view from stream]:stream: ' \ + '-P[use generated branch view from parent stream]:parent stream: ' \ "1:file:_perforce_files$range" \ '*::file:_perforce_files' } @@ -2196,8 +2328,8 @@ _perforce_cmd_integ() { (( $+functions[_perforce_cmd_integrated] )) || _perforce_cmd_integrated() { _arguments -s : \ - '-r[reverse mapping in branch view with -b]' \ - '-b[select files integrated via branch]:branch:_perforce_branches' \ + '-r[reverse mapping in branch view]' \ + '-b[list files integrated from branch view]:branch:_perforce_branches' \ '*::file:_perforce_files -ti' } @@ -2211,34 +2343,51 @@ _perforce_cmd_interchanges() { if [[ ${words[(I)-b*]} -ne 0 ]]; then if [[ ${words[(I)-*s*]} -eq 0 ]]; then # with -b and no -s, all files are to-files (but -s may come later) - fileargs=('-s[specify source file]' - '*::to file:_perforce_files -tR') + fileargs=('*::to file:_perforce_files -tR') else # with -b and -s we have one from-file and any number of to-files - fileargs=('1::from file:_perforce_files -tR' - '*::to file:_perforce_files') + fileargs=('*::to file:_perforce_files') fi + elif [[ ${words[(I)-(S|P)]} -ne 0 ]]; then + fileargs=('*::file:_perforce_files -tR') else # with no -b we have one from-file and one to-file fileargs=('1::from file:_perforce_files -tR' '2::to file:_perforce_files') fi _arguments -s : \ - '-f[show individual files]' \ - '-l[long changelist description]' \ - '-b[select files integrated via branch]:branch:_perforce_branches' \ - '-r[reverse branch mapping]' \ + '-f[list files that require integration]' \ + '-l[display full change text]' \ + '-t[display time and date]' \ + '(-S -P)-b[use branch view'\''s source and target]:branch:_perforce_branches' \ + '(-S -P)-s[select source file, use branch view as target]:source file:_perforce_files -tR' \ + '-u[limit files submitted by user]:user:_perforce_users' \ + '-r[reverse mapping direction]' \ + '-S[use generated branch view from stream]:stream: ' \ + '-P[use generated branch view from parent stream]:parent stream: ' \ + '-F[ignore stream'\''s expected flow]' \ $fileargs } +(( $+functions[_perforce_cmd_istat] )) || +_perforce_cmd_istat() { + _arguments -s : \ + '-a[show status of integration in both directions]' \ + '-c[assume cache is stale]' \ + '-r[show status of integration from parent]' \ + '-s[show cached state without refreshing stale data]' \ + '1::stream: ' +} + + (( $+functions[_perforce_cmd_job] )) || _perforce_cmd_job() { _arguments -s : \ '(-d -o -i)-f[force setting of readonly fields]' \ '(-f -o -i)-d[delete job]' \ - '(-f -d -i)-o[print to stdout]' \ - '(-d -o)-i[read from stdin]' \ + '(-f -d -i)-o[write job spec to standard output]' \ + '(-d -o)-i[read job spec from standard input]' \ '(-i)1::job:_perforce_jobs' } @@ -2246,12 +2395,12 @@ _perforce_cmd_job() { (( $+functions[_perforce_cmd_jobs] )) || _perforce_cmd_jobs() { _arguments -s : \ - '-e[select by jobview]:jobview:_perforce_jobviews' \ - '-i[included integrated changes]' \ - '-l[long output, full job descriptions]' \ - '-r[reverse order of job names]' \ - '-m[limit to most recent N jobs]:number of most recent jobs: ' \ - '(-e -i -l -m)-R[rebuild jobs table on upgrade]' \ + '-e[list jobs matching parameter]::_perforce_jobviews' \ + '-i[include integrated changes]' \ + '-l[display full job text]' \ + '-m[limit output to max jobs]:max jobs: ' \ + '-r[sort in reverse order]' \ + '(-e -i -l -m)-R[rebuild jobs table]' \ '*::file:_perforce_files -tR' } @@ -2264,14 +2413,41 @@ _perforce_cmd_jobspec() { } +(( $+functions[_perforce_cmd_key] )) || +_perforce_cmd_key() { + local -a keyargs + if [[ ${words[(I)-(d|i)]} -ne 0 ]]; then + keyargs=('1::name: ') + elif [[ ${words[(I)-m]} -ne 0 ]]; then + keyargs=('*::name value pairs: ') + else + keyargs=('1::name: ' '2::value: ') + fi + _arguments -s : \ + '(-i -m)-d[delete key]' \ + '(-d -m)-i[increment key value by 1]' \ + '(-d -i)-m[allow mulitple operations]' \ + $keyargs +} + + +(( $+functions[_perforce_cmd_keys] )) || +_perforce_cmd_keys() { + _arguments -s : \ + '-e[list keys that match pattern]:pattern: ' \ + '-m[limit output to max keys]:max keys: ' +} + + (( $+functions[_perforce_cmd_label] )) || _perforce_cmd_label() { _arguments -s : \ '-f[force operation]' \ - '-t+[copy template]:template: ' \ + '-t[copy view and options from label]:label:_perforce_labels' \ '(-o -i -t)-d[delete label]' \ - '(-d -f -i)-o[write to standard output]' \ - '(-o -d -t)-i[read from standard input]' \ + '(-d -f -i -g)-o[write label spec to standard output]' \ + '(-o -d -t)-i[read label spec from standard input]' \ + '-g[update global label]' \ '*::label:_perforce_labels' } @@ -2279,10 +2455,14 @@ _perforce_cmd_label() { (( $+functions[_perforce_cmd_labels] )) || _perforce_cmd_labels() { _arguments -s : \ - '-e[limit by wildcard]:label wildcard: ' \ - '-m+[set maximum to show]:max labels: ' \ - '-t[output time as well as date]' \ - '-u+[select by user]:user:_perforce_users' \ + '-t[display time and date]' \ + '-u[list labels owned by user]:user:_perforce_users' \ + '(-E)-e[list labels that match pattern]:pattern: ' \ + '(-e)-E[list labels that match case-insensitive pattern]:case-insensitive pattern: ' \ + '-m[limit output to max labels]:max labels: ' \ + '(-s)-a[display all labels]' \ + '(-a)-s[display labels from server]:server ID: ' \ + '-U[list unloaded labels]' \ '1::file or revisions which must contain label:_perforce_files -tR' } @@ -2290,11 +2470,23 @@ _perforce_cmd_labels() { (( $+functions[_perforce_cmd_labelsync] )) || _perforce_cmd_labelsync() { _arguments -s : \ + '-l[specify label]:label:_perforce_labels' \ '-a[add files to label]' \ '-d[delete files from label]' \ - '-n[no effect, dummy run]' \ - '-l[specify label]:label:_perforce_labels' \ - '-q[suppress informational messages]' \ + '-n[preview labelsync]' \ + '-q[suppress normal output messages]' \ + '-g[update global label]' \ + '*::file:_perforce_files -tR' +} + + +(( $+functions[_perforce_cmd_list] )) || +_perforce_cmd_list() { + _arguments -s : \ + '-l[use temporary list name]:list name: ' \ + '(-C)-d[delete list]' \ + '-C[limit files to client]' \ + '-M[forward list to master server]' \ '*::file:_perforce_files -tR' } @@ -2310,7 +2502,8 @@ _perforce_cmd_license() { (( $+functions[_perforce_cmd_lock] )) || _perforce_cmd_lock() { _arguments -s : \ - '-c[select by change]:change:_perforce_changes -tc' \ + '-c[lock files for change]:change:_perforce_changes -tc' \ + '-g[lock files globally]' \ '*::file:_perforce_files -to' } @@ -2324,8 +2517,8 @@ _perforce_cmd_lockstat() { (( $+functions[_perforce_cmd_logger] )) || _perforce_cmd_logger() { _arguments -s : \ - '-c[limit by counter no]:number: ' \ - '-t[use counter instead of logger]:counter:_perforce_counters' + '-c[list events after sequence]:sequence: ' \ + '-t[list events after counter]:counter:_perforce_counters' } @@ -2333,9 +2526,11 @@ _perforce_cmd_logger() { (( $+functions[_perforce_cmd_login] )) || _perforce_cmd_login() { _arguments -s : \ - '-a[ticket valid on all machines]' \ + '-a[issue ticket on all host machines]' \ + '-h[issue ticket on host]:host: ' \ '-p[display ticket, do not store]' \ - '-s[show status of ticket]' \ + '-r[forward login to server]:remote spec: ' \ + '(-a -p -h)-s[display status of current ticket]' \ '(-s)1::user:_perforce_users' } @@ -2362,6 +2557,27 @@ _perforce_cmd_logtail() { } +(( $+functions[_perforce_cmd_merge] )) || +_perforce_cmd_merge() { + local -a fileargs + if [[ ${words[(I)--from]} -ne 0 ]]; then + fileargs=('1:to file:_perforce_files -tR') + else + fileargs=('1:from file:_perforce_files -tR' + '2:to file:_perforce_files') + fi + _arguments -s : \ + '-F[merge against stream'\''s expected flow]' \ + '-Ob[show base revision for merge]' \ + '-q[suppress normal output messages]' \ + '--from[merge from stream other than the parent stream]:stream: ' \ + '-m[limit merge to max files]:max files: ' \ + '-n[preview merge]' \ + '-c[open in change]:change:_perforce_changes -tc' \ + $fileargs +} + + (( $+functions[_perforce_cmd_monitor] )) || _perforce_cmd_monitor() { if (( CURRENT > 2 )); then @@ -2397,25 +2613,25 @@ _perforce_cmd_monitor() { (( $+functions[_perforce_cmd_move] )) || _perforce_cmd_move() { _arguments -s : \ - '-c[specify new change list]:change:_perforce_changes -tc' \ - '-f[force move when already synced]' \ - '-k[no resync from server]' \ + '-c[reopen in change]:change:_perforce_changes -tc' \ + '-f[force move]' \ '-t[specify new file type]:filetype:_perforce_filetypes' \ - '-n[show files to move without moving them]' \ - '1::source file, wildcards allowed:_perforce_files -to' \ - '2::destination file, wildcards match source:_perforce_files' + '-n[preview move]' \ + '-k[perform move on server]' \ + '1::from file:_perforce_files -to' \ + '2::to file:_perforce_files -tu' } (( $+functions[_perforce_cmd_obliterate] )) || _perforce_cmd_obliterate() { if [[ ${words[(I)-y]} -gt 0 ]]; then - _message \ + _message \ ": don't complete after -y; run obliterate without, then add the -y" else - _arguments -s : \ - '-y[actually perform the operation]' \ - '*::file:_perforce_files -tR' + _arguments -s : \ + '-y[actually perform the operation]' \ + '*::file:_perforce_files -tR' fi } @@ -2427,11 +2643,14 @@ _perforce_cmd_opened() { # -tp, but currently Perforce doesn't allow that, so -tc is correct. # This is true even if -a is also given. _arguments -s : \ - '-a[list for all clients]' \ - '-c+[select by change]:change:_perforce_changes -tc' \ - '-C[select by client]:client:_perforce_clients' \ - '-m[max files to show]:max files: ' \ - '-u[select by user]:user name:_perforce_users' \ + '-a[list files for all clients]' \ + '-c[list files opened in change]:change:_perforce_changes -tc' \ + '-C[list files open in client]:client:_perforce_clients' \ + '-u[list files opened by user]:user name:_perforce_users' \ + '-m[limit output to max files]:max files: ' \ + '-s[short output]' \ + '-x[list exclusive files]' \ + '-g[list files opened on Commit Server]' \ '*::file:_perforce_files -to' } @@ -2458,12 +2677,49 @@ _perforce_cmd_ping() { } +(( $+functions[_perforce_cmd_populate] )) || +_perforce_cmd_populate() { + local -a fileargs + if [[ ${words[(I)-b*]} -ne 0 ]]; then + if [[ ${words[(I)-*s*]} -eq 0 ]]; then + # with -b and no -s, all files are to-files (but -s may come later) + fileargs=('*::to file:_perforce_files -tR') + else + # with -b and -s we have one from-file and any number of to-files + fileargs=('*::to file:_perforce_files') + fi + elif [[ ${words[(I)-(S|P)]} -ne 0 ]]; then + fileargs=('*::file:_perforce_files -tR') + else + # with no -b we have one from-file and one to-file + fileargs=('1::from file:_perforce_files -tR' + '2::to file:_perforce_files') + fi + _arguments -s : \ + '(-S -P)-b[use branch view'\''s source and target]:branch:_perforce_branches' \ + '(-S -P)-s[select source file, use branch view as target]:source file:_perforce_files -tR' \ + '-r[reverse mapping direction]' \ + '-S[use generated branch view from stream]:stream: ' \ + '-P[use generated branch view from parent stream]:parent stream: ' \ + '-d[description for submitted change]:description: ' \ + '-f[force deleted files to branch into target]' \ + '-n[preview populate]' \ + '-o[display files created by populate]' \ + '-m[limit max actions]:max actions: ' \ + $fileargs +} + + (( $+functions[_perforce_cmd_print] )) || _perforce_cmd_print() { _arguments -s : \ - '-a[display all revisions in a range]' \ - '-o[select output file]:output file:_files' \ + '-a[print all revisions in range]' \ + '-A[print files in archive depots]' \ + '-k[suppress keyword expansion]' \ + '-o[redirect output to file]:file:_files' \ '-q[suppress header]' \ + '-m[limit max files]:max files: ' \ + '-U[print files in unload depot]:unload file:_perforce_files' \ '*::file:_perforce_files -tR' } @@ -2471,23 +2727,31 @@ _perforce_cmd_print() { (( $+functions[_perforce_cmd_protect] )) || _perforce_cmd_protect() { _arguments -s : \ - '-o[write spec to stdout]' \ - '-i[read spec from stdin]' + '-o[write protection table to standard output]' \ + '-i[read protection table from standard input]' } (( $+functions[_perforce_cmd_protects] )) || _perforce_cmd_protects() { _arguments -s : \ - '(-g -u)-a[show for all users]' \ - '(-a -u)-g[select by group]:perforce group:_perforce_groups' \ - '(-a -g)-u[select by user]:perforce user:_perforce_users' \ - '-h[limit to host]:host:_perforce_hosts' \ - '-m[single word summary]' \ + '(-g -u)-a[display protection lines for all users]' \ + '(-a -u)-g[display protection lines for group]:perforce group:_perforce_groups' \ + '(-a -g)-u[display protection lines for user]:perforce user:_perforce_users' \ + '-h[display protection lines for host]:host:_perforce_hosts' \ + '-m[report single word summary]' \ '*:file:_perforce_files' } +(( $+functions[_perforce_cmd_prune] )) || +_perforce_cmd_prune() { + _arguments -s : \ + '-y[execute prune]' \ + '-S[stream to prune]:stream: ' +} + + (( $+functions[_perforce_cmd_pull] )) || _perforce_cmd_pull() { _arguments -s : \ @@ -2497,6 +2761,37 @@ _perforce_cmd_pull() { '-J[specify prefix for journal file]:journal file prefix: ' } + +(( $+functions[_perforce_cmd_reconcile] )) || +_perforce_cmd_reconcile() { + _arguments -s : \ + '-n[preview reconcile]' \ + '-c[open files for change]:change:_perforce_changes -tc' \ + '-e[open modified files for edit]' \ + '-a[open new files for add]' \ + '-d[open removed files for delete]' \ + '-f[reformat filenames with wildcard characters]' \ + '-I[do not perform ignore checking]' \ + '-l[output relative paths]' \ + '-m[check file modification times]' \ + '-w[force client files to be updated to match depot]' \ + '-k[reconcile have list with client]' \ + '*:file:_perforce_files -tu' +} + + +(( $+functions[_perforce_cmd_rec] )) || +_perforce_cmd_rec() { + _perforce_cmd_reconcile "$@" +} + + +(( $+functions[_perforce_cmd_rename] )) || +_perforce_cmd_rename() { + _perforce_cmd_move "$@" +} + + (( $+functions[_perforce_cmd_reopen] )) || _perforce_cmd_reopen() { # Assume user doesn't want to reopen to same changelist. @@ -2508,8 +2803,8 @@ _perforce_cmd_reopen() { fi _arguments -s : \ - '-c+[select change to reopen on]:change:_perforce_changes -tc' \ - '-t+[set file type]:file type:_perforce_filetypes' \ + '-c[reopen files for change]:change:_perforce_changes -tc' \ + '-t[specify new file type]:filetype:_perforce_filetypes' \ '*::file:_perforce_files -to' } @@ -2533,13 +2828,32 @@ _perforce_cmd_replicate() { (( $+functions[_perforce_cmd_resolve] )) || _perforce_cmd_resolve() { _arguments -s : \ - '-a-[select automatic merge type]:automation type:((f\:force\ acceptance m\:skip\ conflicts s\:safe t\:use\ theirs y\:use\ yours))' \ - '-d-[select diff option]:diff option:((b\:ignore\ blanks w\:ignore\ all\ whitespace))' \ - '-f[force re-resolution]' \ - '-n[no action, just list]' \ + '-A-[limit resolve attempts]:resolve attempts:(( +a\:resolve\ attributes +b\:resolve\ file\ branching +c\:resolve\ file\ content\ changes +d\:resolve\ file\ deletions +m\:resolve\ moved\ and\ renamed\ files +t\:resolve\ filetype\ changes +Q\:resolve\ charset\ changes +))' \ + '-a-[set automatic resolve]:resolve:(( +s\:skip\ files\ that\ need\ merging +m\:skip\ files\ with\ conflicts +f\:accept\ merged\ files\ with\ conflicts +t\:use\ theirs +y\:use\ yours))' \ + '-d-[control whitespace merging]:whitespace option:(( +b\:ignore\ whitespace\ changes +w\:ignore\ whitespace\ altogether +l\:ignores\ line\ endings))' \ + '-f[re-resolve files]' \ + '-n[preview resolve]' \ + '-N[preview resolve with summary]' \ '-o[display base file name and revision for merge]' \ - '-t[force textual merge on binary files]' \ - '-v[verbose, mark all changes]' \ + '-t[force textual merge]' \ + '-v[insert markers for all changes]' \ + '-c[limit resolve to change]:change:_perforce_changes -tc' \ '*::file:_perforce_files -to' } @@ -2555,10 +2869,12 @@ _perforce_cmd_resolved() { (( $+functions[_perforce_cmd_revert] )) || _perforce_cmd_revert() { _arguments -s : \ - '-a[revert unaltered files]' \ - '-c[limit reversions to change]:change:_perforce_changes -tc' \ - '-k[bypass client refresh]' \ - '-n[no action, show effect only]' \ + '-a[revert open unchanged files]' \ + '-n[preview revert]' \ + '-k[mark files as reverted on server]' \ + '-w[delete new files]' \ + '-c[revert files opened in change]:change:_perforce_changes -tc' \ + '-C[specify client]:client:_perforce_clients' \ '*::file:_perforce_files -to' } @@ -2566,15 +2882,16 @@ _perforce_cmd_revert() { (( $+functions[_perforce_cmd_review] )) || _perforce_cmd_review() { _arguments -s : \ - '-c[select change for counter]:change:_perforce_changes -ts' \ - '-t[limit change number by counter]:counter:_perforce_counters' + '-c[specify change]:change:_perforce_changes -ts' \ + '-t[specify counter]:counter:_perforce_counters' } (( $+functions[_perforce_cmd_reviews] )) || _perforce_cmd_reviews() { _arguments -s : \ - '-c[show users by change]:change:_perforce_changes -ts' \ + '-c[limit files submitted in change]:change:_perforce_changes -ts' \ + '-C[limit files opened in client]:client:_perforce_clients' \ '*::file:_perforce_files' } @@ -2583,8 +2900,9 @@ _perforce_cmd_reviews() { _perforce_cmd_set() { # Only works under Windoze but maybe we are on Cygwin. _arguments -s : \ + '-q[remove origin]' \ '-s[set for whole system]' \ - '-S[set for specified service]:service: ' \ + '-S[specify service]:service: ' \ "*::environment variable:_perforce_variables" } @@ -2592,26 +2910,80 @@ _perforce_cmd_set() { (( $+functions[_perforce_cmd_shelve] )) || _perforce_cmd_shelve() { _arguments -s : \ - '(-i)-c[specify changelist if not default]:change:_perforce_changes -tc' \ - '(-i -r)-d[delete shelved files]' \ - '(-r)-f[force by admin user or force to overwrite]' \ - '(-c)-i[read from standard input]' \ - '(-d)-r[replace shelved files in changelist]' \ + '-i[read change spec from standard input]' \ + '(-i)-c[shelve files in change]:change:_perforce_changes -tc' \ + '-f[overwrite existing shelved files]' \ + '-r[replace shelved files in change]' \ + '-a[handle unchanged files]:option:(submitunchanged leaveunchanged)' \ + '(-p -a -i -r)-d[delete shelved files]' \ + '-p[promote shelved change to commit server]' \ '(-i -r)*::file:_perforce_files -to' } +(( $+functions[_perforce_cmd_status] )) || +_perforce_cmd_status() { + _arguments -s : \ + '-c[list files in change]:change:_perforce_changes -tc' \ + '-A[list all new, modified, and removed files]' \ + '-e[list modified files]' \ + '-a[list new files]' \ + '-d[list removed files]' \ + '-f[reformat filenames with wildcard characters]' \ + '-s[summarize output for new files]' \ + '-I[do not perform ignore checking]' \ + '-m[check file modification times]' \ + '-k[reconcile have list with client]' \ + '*:file:_perforce_files -tuo' +} + + (( $+functions[_perforce_cmd_sizes] )) || _perforce_cmd_sizes() { _arguments -s : \ - '-a[show for all revisions]' \ - '-b[set blocksize]:blocksize in bytes: ' \ + '-a[list all revisions in range]' \ + '-b[specify blocksize]:blocksize in bytes: ' \ + '(-H)-h[print sizes in human-readable form (GiB)]' \ + '(-h)-H[print sizes in human-readable form (GB)]' \ + '-m[limit max files]:max files: ' \ '-s[sum the file sizes]' \ - '-S[show sizes of shelved files]' \ + '-S[display sizes for shelved files]' \ + '-z[omit lazy copies]' \ + '(-z -S)-A[display files in archive depots]' \ + '-U[display sizes for unload files]' \ '*:file:_perforce_files -tR' } +# TODO Add more logic for subcommands +#p4 stream edit +#p4 stream resolve [-a<flag>] [-n] [-o] +#p4 stream revert +(( $+functions[_perforce_cmd_stream] )) || +_perforce_cmd_stream() { + _arguments -s : \ + '(-o -v)-d[delete stream]' \ + '(-f)-o[write stream spec to standard output]' \ + '(-o -v)-P[insert value into parent field]:parent stream: ' \ + '(-o -v)-t[insert value into type field]:type: ' \ + '(-o -v)-i[read stream spec from standard input]' \ + '(-o -v)-f[force modification]' \ + '(-f)-v[expose client view]' \ + '1:stream name: ' +} + + +(( $+functions[_perforce_cmd_streams] )) || +_perforce_cmd_streams() { + _arguments -s : \ + '-F[limit files to pattern]:file pattern: ' \ + '-T[limit fields to list]:field list: ' \ + '-m[limit max streams]:max streams: ' \ + '-U[list unloaded task streams]' \ + '*:stream path: ' +} + + (( $+functions[_perforce_cmd_spec] )) || _perforce_cmd_spec() { _arguments -s : \ @@ -2623,26 +2995,40 @@ label spec trigger typemap user)" } +# TODO Figure out how --parallel will work +#p4 submit -i [-r -s -f option] --parallel=threads=N[,batch=N][,min=N] (( $+functions[_perforce_cmd_submit] )) || _perforce_cmd_submit() { _arguments -s : \ - '-r[files open for add or edit remain open]' \ - '-s[include fix status in list]' \ + '(-s -d -e -i)-c[submit change]:change:_perforce_changes -tc' \ + '(-r -s -f -d -c -i --noretransfer)-e[submit shelved change]:change:_perforce_changes -tS' \ + '(-s -c -e -i --noretransfer)-d[specify description]:description: ' \ + '(-d -c -e --noretransfer)-i[read change spec from standard input]' \ '-f[override submit option]:submit option:_perforce_submit_options' \ - '(-s -i)-c[submit specific change]:change:_perforce_changes -tc' \ - '(-s -c)-d[specify description on command line]:description: ' \ - '(-c)-i[read change spec from stdin]' \ + '-r[reopen submitted files]' \ + '(-d -c)-s[include fix status in list]' \ + '--parallel[parallel file transfer options]:parallel options: ' \ + '--noretransfer[do not re-transfer submitted files]:no re-transfer?:(0 1)' \ '*::file:_perforce_files -to -tr' } +# TODO Figure out how --parallel will work +#--parallel=threads=N[,batch=N][,batchsize=N][,min=N][,minsize=N] (( $+functions[_perforce_cmd_sync] )) || _perforce_cmd_sync() { _arguments -s : \ '-f[force resynchronisation]' \ - '-n[show operations but don'\''t perform them]' \ - '-k[bypass client file update]' \ - '-q[suppress informational messages]' \ + '-L[use full depot syntax]' \ + '-n[preview sync]' \ + '-N[preview sync with summary]' \ + '(-s -p)-k[update server without syncing files]' \ + '(-f -k -r -s)-p[sync client without updating server]' \ + '-q[suppress normal output messages]' \ + '(-s -p)-r[reopen moved files in new location]' \ + '(-f -k -r -p)-s[do not clobber modified files]' \ + '-m[limit max files to sync]:max files: ' \ + '--parallel[parallel file transfer options]:parallel options: ' \ '*::file:_perforce_files -tR' } @@ -2651,7 +3037,9 @@ _perforce_cmd_sync() { _perforce_cmd_tag() { _arguments -s : \ '-d[delete association between label and files]' \ - '-n[show what files would be tagged]' \ + '-n[preview tag]' \ + '-g[update global label]' \ + '-U[create label with autoreload option]' \ '-l[specify label]:label:_perforce_labels' \ '*::file:_perforce_files -tR' } @@ -2683,8 +3071,10 @@ _perforce_cmd_typemap() { (( $+functions[_perforce_cmd_unlock] )) || _perforce_cmd_unlock() { _arguments -s : \ - '-c[non-default change to unlock]:change:_perforce_changes -tc' \ - '-f[allow superuser to unlock any file]' \ + '-s[unlock files from shelved change]:change:_perforce_changes -tS' \ + '-c[unlock files from change]:change:_perforce_changes -tc' \ + '-x[unlock exclusive files]' \ + '-f[unlock files owned by other users]' \ '*::file:_perforce_files' } @@ -2692,21 +3082,37 @@ _perforce_cmd_unlock() { (( $+functions[_perforce_cmd_unshelve] )) || _perforce_cmd_unshelve() { _arguments -s : \ - '-s[specify shelving change]:change:_perforce_changes -tS' \ - '-c[specify change for unshelve]:change:_perforce_changes -tc' \ + '-s[unshelve files from change]:change:_perforce_changes -tS' \ + '-c[unshelve files to change]:change:_perforce_changes -tc' \ '-f[force clobbering of writeable files]' \ '-n[preview unshelve]' \ + '-b[use branch view for unshelve]:branch:_perforce_branches' \ + '-S[use generated branch view from stream]:stream: ' \ + '-P[use generated branch view from parent stream]:parent stream: ' \ '*::file, pattern allowed:_perforce_files' } +(( $+functions[_perforce_cmd_update] )) || +_perforce_cmd_update() { + _arguments -s : \ + '-f[force resynchronisation]' \ + '-L[use full depot syntax]' \ + '-n[preview update]' \ + '-N[preview update with summary]' \ + '-q[suppress normal output messages]' \ + '-m[limit max files to update]:max files: ' \ + '*::file:_perforce_files -tR' +} + + (( $+functions[_perforce_cmd_user] )) || _perforce_cmd_user() { _arguments -s : \ - '(-o)-f[force edit by superuser]' \ '(-o -i)-d[delete user]' \ - '(-o -d)-i[read form from stdin]' \ - '(-f -i -d)-o[write form to stdout]' \ + '(-f -i -d)-o[write user spec to standard output]' \ + '(-o -d)-i[read user spec from standard input]' \ + '(-o)-f[force edit of user]' \ '(-i)1::username:_perforce_users' } @@ -2714,7 +3120,11 @@ _perforce_cmd_user() { (( $+functions[_perforce_cmd_users] )) || _perforce_cmd_users() { _arguments -s : \ - '-m[set max users to show]:max users: ' \ + '-m[limit output to max users]:max users: ' \ + '-a[output service and operator users]' \ + '-l[long output]' \ + '-r[list only replica users]' \ + '-c[list only central server users]' \ '*::username:_perforce_users' } diff --git a/Completion/Unix/Command/_pgrep b/Completion/Unix/Command/_pgrep index 0b7d23d4d..714bf095b 100644 --- a/Completion/Unix/Command/_pgrep +++ b/Completion/Unix/Command/_pgrep @@ -28,6 +28,7 @@ arguments=('-P[parent process id]:parent process id:->ppid' '-q[do not write anything to standard output]' '-S[search also in system processes]' '-v[negate matching]' + '-w[show thread ids instead of pids]' '-x[match exactly]' '-z[match only in zones]:zone:_zones') @@ -41,7 +42,7 @@ fi local optchars case "$OSTYPE" in linux*) - optchars="cflvxdnoPgsuUGt" + optchars="cflvxdnoPgsuUGtw" ;; freebsd*) optchars="LSafilnoqvxFGMNPUdgjstu" diff --git a/Completion/Unix/Command/_pkg-config b/Completion/Unix/Command/_pkg-config index dd73c79e9..43773967e 100644 --- a/Completion/Unix/Command/_pkg-config +++ b/Completion/Unix/Command/_pkg-config @@ -1,6 +1,6 @@ #compdef pkg-config -local arguments packages curcontext="$curcontext" state line ret=1 +local arguments packages curcontext="$curcontext" state line expl ret=1 declare -A opt_args # Up-to-date as of pkg-config 0.29-4 (debian package) man page synopsis diff --git a/Completion/Unix/Command/_rake b/Completion/Unix/Command/_rake index 7fed949ab..8814edaa5 100644 --- a/Completion/Unix/Command/_rake +++ b/Completion/Unix/Command/_rake @@ -22,7 +22,7 @@ _arguments -C -s -S \ \*{--require,-r}'[require specified module before executing rakefile]:library:->library' \ '(- *)--rules[trace the rules resolution]' \ '(--quiet -q --silent -s --verbose -v)'{--silent,-s}"[like --quiet, but also suppresses the 'in directory' announcement]" \ - '(--system,-g)'{--system,-g}'[using system wide (global) rakefiles (usually '~/.rake/*.rake')]' \ + '(--system -g)'{--system,-g}'[using system wide (global) rakefiles (usually '~/.rake/*.rake')]' \ '(- *)'{--tasks,-T}'[display the tasks (matching the specified pattern) with descriptions, then exit]:pattern::' \ '(--trace -t)'{--trace,-t}'[turn on invoke/execute tracing, enable full backtrace]' \ '(--quiet -q --silent -s --verbose -v)'{--verbose,-v}'[log message to standard output (default)]' \ diff --git a/Completion/Unix/Command/_readelf b/Completion/Unix/Command/_readelf index 15d5145c5..46da00cc4 100644 --- a/Completion/Unix/Command/_readelf +++ b/Completion/Unix/Command/_readelf @@ -34,6 +34,7 @@ case $variant in '(-g --section-groups)'{-g,--section-groups}'[show section groups]' '(-t --section-details)'{-t,--section-details}'[show section details]' '(-e --headers)'{-e,--headers}'[show file, program and sections headers]' + '(-s --syms --symbols)'{-s,--syms,--symbols}'[show symbol table]' '(-u --unwind)'{-u,--unwind}'[show unwind info (if present)]' '(-D --use-dynamic)'{-D,--use-dynamic}'[use dynamic section info when showing symbols]' ) @@ -52,6 +53,8 @@ case $variant in '(-e --exception)'{-e,--exception}'[show sections for exception handling]' '(-N --numeric-addresses)'{-N,--numeric-addresses}"[don't find symbol names for addresses in DWARF data]" '(-z --decompress)'{-z,--decompress}'[show compression information; decompress before dumping data]' + '(--symbols)-s[show symbol table]' + '(-s)--symbols=-[show symbol table]::section:(.dynsym .symtab)' ) ;; esac diff --git a/Completion/Unix/Command/_rrdtool b/Completion/Unix/Command/_rrdtool index 9d097bd77..96bdaf0db 100644 --- a/Completion/Unix/Command/_rrdtool +++ b/Completion/Unix/Command/_rrdtool @@ -1,23 +1,25 @@ #compdef rrdtool -_arguments \ +local curcontext="$curcontext" state line expl ret=1 + +_arguments -C \ ':rrdtool command:(create update updatev graph dump restore last lastupdate first help info fetch tune resize xport)' \ - '*::subcmd:->subcmd' && return 0 + '*:: :->subcmds' && ret=0 +curcontext="${curcontext%:*}-$words[1]:" case "$state" in - (subcmd) - - case "$words[1]" in + (subcmds) + case "$words[1]" in (help) - _wanted -V 'subcommands' expl 'subcommand' compadd \ - create update updatev graph dump restore last lastupdate \ - first help info fetch tune resize xport - ;; + _wanted -V 'subcommands' expl 'subcommand' compadd \ + create update updatev graph dump restore last lastupdate \ + first help info fetch tune resize xport + ;; (*) - _files - ;; - esac + _files + ;; + esac ;; esac diff --git a/Completion/Unix/Command/_ruby b/Completion/Unix/Command/_ruby index 49a1170ef..bb0558fde 100644 --- a/Completion/Unix/Command/_ruby +++ b/Completion/Unix/Command/_ruby @@ -35,11 +35,12 @@ opts=( '(-n)-p[assume loop like -n but print line also like sed]' '-s[enable some switch parsing for switches after script name]' '-S[look for the script using PATH environment variable]' - '-T-[turn on tainting checks]:taint level:((0\:strings\ from\ streams/environment/ARGV\ are\ tainted 1\:no\ dangerous\ operation\ by\ tainted\ value 2\:process/file\ operations\ prohibited 3\:all\ generated\ objects\ are\ tainted 4\:no\ global\ \(non-tainted\)\ variable\ modification/no\ direct\ output))' + '-T-[turn on tainting checks]::taint level [1]:((0\:strings\ from\ streams/environment/ARGV\ are\ tainted 1\:no\ dangerous\ operation\ by\ tainted\ value 2\:process/file\ operations\ prohibited 3\:all\ generated\ objects\ are\ tainted 4\:no\ global\ \(non-tainted\)\ variable\ modification/no\ direct\ output))' '(-v --verbose)'{-v,--verbose}'[print version number, then turn on verbose mode]' '-x-[strip off text before #!ruby line and perhaps cd to directory]:directory:_files -/' '(1 * -)--copyright[print the copyright]' - --{en,dis}able-{gems,rubyopt,all} + --{en,dis}'able=[enable or disable features]:feature:(gems did_you_mean rubyopt frozen_string_literal all)' + \!--{en,dis}able-{gems,rubyopt,all} --{external,internal}'-encoding=:charset:->charsets' '!'{-y,--yydebug} '!--dump=:target:(version copyright usage yydebug syntax parsetree parsetree_with_comment insns)' @@ -113,7 +114,7 @@ case "$state" in charsets=( $(_call_program charsets $RUBY -e 'puts\ Encoding.list' 2>/dev/null) ) # could also add Encoding.aliases.map(&:first) for aliases desc='charset' - if [[ $curcontext = *option-E-1 ]]; then + if [[ $curcontext = *option-(E|-encoding)-1 ]]; then if compset -P '*:'; then desc='internal charset' else diff --git a/Completion/Unix/Command/_sed b/Completion/Unix/Command/_sed index 259477f93..222798b8a 100644 --- a/Completion/Unix/Command/_sed +++ b/Completion/Unix/Command/_sed @@ -23,8 +23,9 @@ elif _pick_variant gnu=GNU unix --version; then '(-i --in-place)'{-i-,--in-place=-}$inplace '(-l --line-length)'{-l,--line-length=-}'[specify line-wrap length for the l command]' '(-r)--posix[disable GNU extensions]' - '(-r --regexp-extended)'{-r,--regexp-extended}$extended + '(-E -r --regexp-extended)'{-E,-r,--regexp-extended}$extended '(-s --separate)'{-s,--separate}'[consider files separately instead of as a combined stream]' + '--sandbox[block commands that can affect the system (r/w/W/e)]' '(-u --unbuffered)'{-u,--unbuffered}'[disable data buffering]' '(-z --null-data)'{-z,--null-data}'[separate lines by NUL characters]' '(- 1 :)--help[print program usage]' diff --git a/Completion/Unix/Command/_sqlite b/Completion/Unix/Command/_sqlite index 05027c603..df673894c 100644 --- a/Completion/Unix/Command/_sqlite +++ b/Completion/Unix/Command/_sqlite @@ -22,7 +22,7 @@ options+=( ) output_modes=( column HTML line list ) -(( $+sqlite3 )) && output_modes+=( csv ) +(( $+sqlite3 )) && output_modes+=( csv quote ) exclusive=( $^dashes-${^output_modes:l} ) for display_opt in $output_modes ; do # finagle the description to match the way SQLite's -help formats them @@ -32,8 +32,8 @@ for display_opt in $output_modes ; do done options+=( - $^dashes'-separator[set output field separator]:string to separate output fields:' - $^dashes'-nullvalue[set null value string]:string for NULL values:' + $^dashes'-separator[set output field separator]:output field separator [|]' + $^dashes'-nullvalue[set text string for null values]:string' '(- :)'$^dashes'-version[show SQLite version]' '(- :)'$^dashes'-help[show help]' '1:SQLite database file:_files' @@ -42,9 +42,12 @@ options+=( (( $+sqlite3 )) && options+=( $^dashes'-bail[stop after hitting an error]' + $^dashes'-cmd[run specified command before reading stdin]:sqlite meta-command' '(-*batch -*interactive)'$^dashes'-batch[force batch I/O]' '(-*batch -*interactive)'$^dashes'-interactive[force interactive I/O]' + $^dashes'-mmap[set default mmap size]:size' $^dashes'-stats[print memory stats before each finalize]' + $^dashes'-vfs[use specified default VFS]:vfs:(unix-dotfile unix-excl unix-none unix-namedsem)' ) _arguments $options diff --git a/Completion/Unix/Command/_ssh b/Completion/Unix/Command/_ssh index 6763e24e7..984c96e93 100644 --- a/Completion/Unix/Command/_ssh +++ b/Completion/Unix/Command/_ssh @@ -51,7 +51,7 @@ _ssh () { '(-1)-m+[specify mac algorithms]:mac spec:->macs' \ '(-1)-N[do not execute a remote command (protocol version 2 only)]' \ '-n[redirect stdin from /dev/null]' \ - '-O:multiplex control command:((check\:"check master process is running" exit\:"request the master to exit" forward\:"request forward without command execution" stop\:"request the master to stop accepting further multiplexing requests" cancel\:"cancel existing forwardings with -L and/or -R"))' \ + '-O[control an active connection multiplexing master process]:multiplex control command:((check\:"check master process is running" exit\:"request the master to exit" forward\:"request forward without command execution" stop\:"request the master to stop accepting further multiplexing requests" cancel\:"cancel existing forwardings with -L and/or -R" proxy))' \ '-P[use non privileged port]' \ '-p+[specify port on remote host]:port number on remote host' \ '(-v)*-q[quiet operation]' \ @@ -150,7 +150,7 @@ _ssh () { "$p1($cmn)-E[specify hash algorithm for displayed fingerprints]:hash algorithim:(md5 sha256)" \ - create \ '(-P -m)-q[silence ssh-keygen]' \ - "(-P -m)-t[specify the type of the key to create]:key type:(rsa1 rsa dsa ecdsa ed25519)" \ + "(-P -m)-t[specify the type of the key to create]:key type:(rsa dsa ecdsa ed25519)" \ - dns \ "($cmn)-r[print DNS resource record]:hostname:_hosts" \ "$p1($cmn)-g[use generic DNS format]" \ @@ -680,17 +680,23 @@ _ssh_hosts () { config="$HOME/.ssh/config" fi if [[ -r $config ]]; then - local key hosts host - while IFS=$'=\t ' read -r key hosts; do - if [[ "$key" == (#i)host ]]; then - for host in ${(z)hosts}; do - case $host in - (*[*?]*) ;; - (*) config_hosts+=("$host") ;; - esac - done - fi - done < "$config" + local key line host + local -a lines=("${(@f)$(<"$config")}") 2>/dev/null + while (($#lines)); do + IFS=$'=\t ' read -r key line <<<"${lines[1]}" + case "$key" in + ((#i)include) + lines[1]=("${(@f)$(cd $HOME/.ssh; cat ${(z)~line})}") 2>/dev/null;; + ((#i)host(|name)) + for host in ${(z)line}; do + case $host in + (*[*?]*) ;; + (*) config_hosts+=("$host") ;; + esac + done ;& + (*) shift lines;; + esac + done if (( ${#config_hosts} )); then _wanted hosts expl 'remote host name' \ compadd -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' "$@" $config_hosts diff --git a/Completion/Unix/Command/_stgit b/Completion/Unix/Command/_stgit index f313f651a..e31af460a 100644 --- a/Completion/Unix/Command/_stgit +++ b/Completion/Unix/Command/_stgit @@ -4,7 +4,7 @@ typeset -a subcmds subcmds=( ${${${(M)${(f)"$(stg help 2> /dev/null)"}## *}# }/#(#b)([^[:space:]]##)[[:space:]]##(*)/$match[1]:$match[2]} ) -local curcontext="$curcontext" +local curcontext="$curcontext" expl local subcmd local ret=1 @@ -18,17 +18,17 @@ else case $subcmd in (push) - _wanted -V "unapplied patches" expl "patch" \ + _wanted -V unapplied-patches expl "patch" \ compadd ${${(M)${(f)"$(stg series 2> /dev/null)"}##- *}#- } \ && ret=0 ;; (pop) - _wanted -V "applied patches" expl "patch" \ + _wanted -V applied-patches expl "patch" \ compadd ${${(M)${(f)"$(stg series 2> /dev/null)"}##[+>] *}#[+>] } \ && ret=0 ;; - (edit|files|goto|rename|log|float|delete|sink|mail|sync|show|pick|hide) - _wanted -V "patches" expl "patch" \ + (edit|files|goto|rename|log|float|delete|sink|mail|sync|show|pick|hide|squash) + _wanted -V patches expl "patch" \ compadd $(stg series --noprefix 2> /dev/null) \ && ret=0 ;; @@ -36,7 +36,7 @@ else last_word="$words[$CURRENT-1]" refresh_patch_options=( -p --patch ) if [[ -n ${refresh_patch_options[(r)$last_word]} ]]; then - _wanted -V "applied patches" expl "patch" \ + _wanted -V applied-patches expl "patch" \ compadd ${${(M)${(f)"$(stg series 2> /dev/null)"}##[+>] *}#[+>] } \ && ret=0 else diff --git a/Completion/Unix/Command/_strip b/Completion/Unix/Command/_strip index 726d87c2b..f244b0ace 100644 --- a/Completion/Unix/Command/_strip +++ b/Completion/Unix/Command/_strip @@ -16,11 +16,12 @@ if _pick_variant gnu=GNU solaris --version; then fi args=( '(-F --target)'{-F+,--target=}'[object code format to use]:bfd name:->bfdnames' - '--help[display usage information and exit]' - '--info[display list of architectures and object formats]' + '(-)--help[display usage information]' + '(-)--info[display list of architectures and object formats]' '(-I --input-target)'{-I+,--input-target=}'[object code format of input]:bfd name:->bfdnames' '(-O --output-target)'{-I+,--output-target=}'[object code format of output]:bfd name:->bfdnames' '*'{-R+,--remove-section=}'[remove given sections]:section name' + '--remove-relocations=[remove relocations from specified section]:section' '(-s --strip-all)'{-s,--strip-all}'[remove all symbols]' '(-g -S -d --strip-debug)'{-g,-S,-d,--strip-debug}'[remove debugging symbols]' '--strip-unneeded[remove symbols not needed for relocation processing]' @@ -33,7 +34,7 @@ if _pick_variant gnu=GNU solaris --version; then '(-X --discard-locals)'{-X,--discard-locals}'[remove compiler-generated local symbols]' '--keep-file-symbols[retain symbols specifying source file names]' '--only-keep-debug[remove everything except debugging information]' - '(-V --version)'{-V,--version}'[display version information and exit]' + '(-)'{-V,--version}'[display version information and exit]' '(-v --verbose)'{-v,--verbose}'[list all object files modified or members of archives]') else args=( diff --git a/Completion/Unix/Command/_subversion b/Completion/Unix/Command/_subversion index b0c032024..b4ccccfae 100644 --- a/Completion/Unix/Command/_subversion +++ b/Completion/Unix/Command/_subversion @@ -36,7 +36,12 @@ _svn () { _svn_cmds=( ${=${(f)${${"$(_comp_locale; _call_program commands svn help)"#l#*Available subcommands:}%%Subversion is a tool*}}/(#s)[[:space:]]#(#b)([a-z]##)[[:space:]]#(\([a-z, ?]##\))#/$match[1] :$match[1]${match[2]:+:${${match[2]//[(),]}// /:}}:} ) - _store_cache svn-cmds _svn_cmds + if (( $? == 0 )); then + _store_cache svn-cmds _svn_cmds + else + # Ensure we enter this block again on the next <TAB>. + unset _svn_cmds + fi fi fi @@ -135,7 +140,7 @@ _svn () { ) ;; (mergeinfo) - args[(r)--show-revs:arg:]=( '--show-revs=:revisions:(merged eligible)' ) + args[(r)--show-revs=:arg:]=( '--show-revs=:revisions:(merged eligible)' ) ;; (propget|propedit|propdel) args+=( @@ -145,7 +150,8 @@ _svn () { ;; (propset) args=( - ':propname:(svn:ignore svn:keywords svn:executable svn:eol-style svn:mime-type svn:externals svn:needs-lock)' + ':propname:(svn:ignore svn:keywords svn:executable svn:eol-style svn:mime-type svn:externals svn:needs-lock svn:global-ignores svn:auto-props)' + ':propval:->propset_propval' ${args/(#b)(*--file*):arg:/$match[1]:file:_files} '*:path or url: _alternative "files:file:_files" "urls:URL:_svn_urls"' ) @@ -174,6 +180,28 @@ _svn () { esac _arguments "$args[@]" && ret=0 + case $state in + (propset_propval) + case $words[2] in + (svn:executable|svn:needs-lock) compadd yes;; + (svn:keywords) + compset -q + # '_values -w' only excludes words in argv[1] or later, so + # install a dummy argv[0]. This affects Foo in [[svn propset + # svn:keywords 'Foo Bar Baz <TAB>]]. + words=( dummy $words ); (( ++CURRENT )) + _values -s ' ' -w "keywords (or custom)" \ + '(URL HeadURL)'{URL,HeadURL}'[URL for the head version of the file]' \ + '(Author LastChangedBy)'{Author,LastChangedBy}'[last person to modify the file]' \ + '(Date LastChangedDate)'{Date,LastChangedDate}'[date/time the file was last modified]' \ + '(Rev Revision LastChangedRevision)'{Rev,Revision,LastChangedRevision}'[last revision the file changed]' \ + Id'[compressed summary of URL,Revision,Date,Author]' \ + Header"[like 'Id' but includes the full URL]";; + (svn:eol-style) compadd - CR LF CRLF native;; + (svn:mime-type) _mime_types;; + (*) _message 'property value';; + esac + esac else _message "unknown svn command: $words[1]" diff --git a/Completion/Unix/Command/_sudo b/Completion/Unix/Command/_sudo index aa7a1a498..ec293d469 100644 --- a/Completion/Unix/Command/_sudo +++ b/Completion/Unix/Command/_sudo @@ -26,6 +26,7 @@ args=( '(-r --role)'{-r+,--role=}'[create SELinux security context with specified role]:role' '(-S --stdin)'{-S,--stdin}'[read password from standard input]' '(-t --type)'{-t+,--type=}'[create SELinux security context with specified type]:type' + '(-T --command-timeout)'{-T+,--command-timeout=}'[terminate command after specified time limit]:timeout' '(-U --other-user)'{-U+,--other-user=}'[in list mode, display privileges for user]:user:_users' '(-u --user)'{-u+,--user=}'[run command (or edit file) as specified user]:user:_users' '(-)'{-V,--version}'[display version information and exit]' diff --git a/Completion/Unix/Command/_swaks b/Completion/Unix/Command/_swaks new file mode 100644 index 000000000..a0ffb53ad --- /dev/null +++ b/Completion/Unix/Command/_swaks @@ -0,0 +1,40 @@ +#compdef swaks + +_arguments \ + '(-s --server -p --port)'{-s+,--server=}'[target host[:port\]]:host[\:port]:_hosts' \ + '(-p --port)'{-p+,--port=}'[target port number]:port number:(25 465 587)' \ + '--copy-routing[derive target host:port from email address domain part]:email address domain part' \ + '(-t --to)'{-t+,--to=}':envelope recipient(s):_sequence _email_addresses -c' \ + '(-f --from)'{-f+,--from=}':envelope sender:_email_addresses -c' \ + '(--ehlo --lhlo -h --helo)'{-h+,--ehlo,--helo,--lhlo}':HELO string:_hosts' \ + '(-q --quit-after)'{-q+,--quit-after=}'[stop transaction early]:stop point:(( + CONNECT\:banner BANNER\:banner + FIRST-HELO\:first\ HELO FIRST-EHLO\:first\ HELO + XCLIENT\:XCLIENT + TLS\:TLS\ negotiation + HELO\:second\ HELO EHLO\:second\ HELO + AUTH\:authentication + MAIL\:MAIL\ FROM FROM\:MAIL\ FROM + RCPT\:RCPT\ TO TO\:RCPT\ TO + ))' \ + '--protocol=:protocol variant:(( + SMTP\:HELO\ 25 + SSMTP\:EHLO\ 465 + SSMTPA\:EHLO\ 465\ authenticated + SMTPS\:HELO\ 465 + ESMTP\:EHLO\ 25 + ESMTPA\:EHLO\ 25\ authenticated + ESMTPS\:EHLO\ STARTTLS\ 25 + ESMTPSA\:EHLO\ STARTTLS\ 25\ authenticated + ))' \ + '-tls[TLS required]' \ + '(-tlsos --tls-optional-strict)'{-tlsos,--tls-optional-strict}'[TLS iff offered by target]' \ + '(-tlsc --tls-on-connect)'{-tlsc,--tls-on-connect}'[TLS on connect (port 465)]' \ + '(-tlsp --tls-protocol)'{-tlsp,--tls-protocol=}':TLS protocol:(sslv2 sslv3 tlsv1 tlsv1_1 tlsv1_2)' \ + '-tls-cipher:OpenSSL cipher string: ' \ + '--tls-verify[verify TLS certificates]' \ + '--tls-ca-path=:OpenSSL CAfile or CAdir:_files' \ + '--tls-get-peer-cert=-:file to write (omit for STDOUT)' \ + '(-d --data)'{-d+,--data=}'[specify DATA payload]:filename (or string with tokens):_files' \ + '*'{-ah,--add-header=}'[add headers]:<Header>\: Value' \ + '*'{-h,--header=}'[replace headers]:<Header>\: Value' diff --git a/Completion/Unix/Command/_swift b/Completion/Unix/Command/_swift new file mode 100644 index 000000000..6776f0dea --- /dev/null +++ b/Completion/Unix/Command/_swift @@ -0,0 +1,123 @@ +#compdef swift swiftc + +# swift(1) and swiftc(1) are part of the Swift programming language. +# https://swift.org/ + +local -a common_options swiftc_mode_options swiftc_additional_options +local -A swiftc_modes + +common_options=( + '-assert-config[specify the assert_configuration replacement]:config:(Debug Release Unchecked DisableReplacement)' + '*-D[marks a conditional compilation flag as true]:flag:' + '*-framework[specifies a framework which should be linked against]:framework:' + '*-F[add directory to framework search path]:path:_files -/' + '(-gnone)-gdwarf-types[emit full DWARF type info]' + '(-gnone)-gline-tables-only[emit minimal debug info for backtraces only]' + '(-gdwarf-types -gline-tables-only -g)-gnone[do not emit debug info]' + '(-gnone)-g[emit debug info]' + '(- : *)-help[display available options]' + '-index-store-path[store indexing data to the specified path]:directory:_files -/' + '*-I[add directory to the import search path]:path:_files -/' + '-j[number of commands to execute in parallel]:count:' + '*-L[add directory to library link search path]:path:_files -/' + '*-l-[specifies a library which should be linked against]:library:' + '-module-cache-path[specifies the Clang module cache path]:path:_files -/' + '-module-link-name[library to link against when using this module]:name:' + '-module-name[name of the module to build]:name:' + '-nostdimport[do not search the standard library import path for modules]' + '-num-threads[enable multi-threading and specify number of threads]:count:' + '(-Ounchecked -O)-Onone[compile without any optimization]' + '(-Onone)-Ounchecked[compile with optimizations and remove runtime safety checks]' + '(-Onone)-O[compile with optimizations]' + '-sdk[compile against SDK]:sdk:_files -/' + '-static-stdlib[statically link the Swift standard library]' + '-suppress-warnings[suppress all warnings]' + '-target-cpu[generate code for a particular CPU variant]:cpu' + '-target[generate code for the given target]:target' + '-use-ld=-[specifies the linker to be used]:linker:_files -/' + '(- : *)-version[print version information and exit]' + '-v[show commands to run and use verbose output]' + '-warnings-as-errors[treat warnings as errors]' + '*-Xcc[pass argument to the C/C++/Objective-C compiler]:arg:' + '*-Xlinker[specifies an option which should be passed to the linker]:option:' +) + +swiftc_modes=( + -dump-ast 'parse and type-check input file(s) and dump AST(s)' + -dump-parse 'parse input file(s) and dump AST(s)' + -dump-type-refinement-contexts + 'type-check input file(s) and dump type refinement contexts(s)' + -emit-assembly 'emit assembly file(s) (-S)' + -emit-bc 'emit LLVM BC file(s)' + -emit-executable 'emit a linked executable' + -emit-ir 'emit LLVM IR file(s)' + -emit-library 'emit a linked library' + -emit-object 'emit object file(s) (-c)' + -emit-sibgen 'emit serialized AST + raw SIL file(s)' + -emit-sib 'emit serialized AST + canonical SIL file(s)' + -emit-silgen 'emit raw SIL file(s)' + -emit-sil 'emit canonical SIL file(s)' + -parse 'parse input file(s)' + -print-ast 'parse and type-check input file(s) and pretty print AST(s)' +) +local mode +for mode in ${(k)swiftc_modes}; do + # Mode options are mutually exclusive + swiftc_mode_options+=("(${(k)swiftc_modes})${mode}[$swiftc_modes[$mode]]") +done + +swiftc_additional_options=( + '-application-extension[restrict code to those available for App Extensions]' + '-embed-bitcode-marker[embed placeholder LLVM IR data as a marker]' + '-embed-bitcode[embed LLVM IR bitcode as data]' + '-emit-dependencies[emit basic Make-compatible dependencies files]' + '-emit-module-path[emit an importable module to the specified path]:path:_files -/' + '-emit-module[emit an importable module]' + '-emit-objc-header-path[emit an Objective-C header file to the specified path]:path:_files -/' + '-emit-objc-header[emit an Objective-C header file]' + '-fixit-all[apply all fixits from diagnostics without any filtering]' + '-fixit-code[get compiler fixits as code edits]' + '-import-underlying-module[implicitly imports the Objective-C half of a module]' + '-output-file-map[a file which specifies the location of outputs]:path:_files' + '-o[write output to specified file]:path:_files' + '-parse-as-library[parse the input file(s) as libraries, not scripts]' + '-parse-sil[parse the input file as SIL code, not Swift source]' + '-parseable-output[emit textual output in a parseable format]' + '-profile-coverage-mapping[generate coverage data for use with profiled execution counts]' + '-profile-generate[generate instrumented code to collect execution counts]' + '-sanitize-coverage=-[specify the type of coverage instrumentation for Sanitizers and additional options separated by commas]:type:' + '*-sanitize=-[turn on runtime checks for erroneous behavior]:check:' + '-save-temps[save intermediate compilation results]' + '-serialize-diagnostics[serialize diagnostics in a binary format]' + '-tools-directory[look for external executables (ld, clang, binutils) in the specified directory]:directory:_files -/' + '-whole-module-optimization[optimize input files together instead of individually]' +) + +case "$words[1]" in + swift) + # The name swift conflicts with the command with the same name from the + # OpenStack project. We delegate completion to _openstack if swift(1) is + # detected to be from OpenStack. + local variant + _pick_variant -r variant openstack=OpenStack swiftlang='Swift compiler' unknown --help + case $variant in + openstack) + _openstack "$@" + ;; + swiftlang) + _arguments \ + "$common_options[@]" \ + '*:input:_files' + ;; + *) + _default "$@" + esac + ;; + swiftc) + _arguments \ + "$swiftc_mode_options[@]" \ + "$common_options[@]" \ + "$swiftc_additional_options[@]" \ + '*:input:_files' + ;; +esac diff --git a/Completion/Unix/Command/_tcpdump b/Completion/Unix/Command/_tcpdump index d73956154..2c1d82226 100644 --- a/Completion/Unix/Command/_tcpdump +++ b/Completion/Unix/Command/_tcpdump @@ -2,10 +2,17 @@ typeset -A opt_args -_interfaces () { - _wanted interfaces expl 'network interface' \ - _net_interfaces - _values "Pseudo-device that captures on all interfaces" "any" +_interfaces() { + local disp expl sep + _description interfaces expl 'network interface' + _net_interfaces "$expl[@]" + if zstyle -t ":completion:${curcontext}:interfaces" verbose; then + zstyle -s ":completion:${curcontext}:interfaces" list-separator sep || sep=-- + disp=( "any $sep capture on all interfaces" ) + compadd "$expl[@]" -ld disp any + else + compadd "$expl[@]" any + fi } _esp_secrets () { diff --git a/Completion/Unix/Command/_texinfo b/Completion/Unix/Command/_texinfo index 7b66d6304..57e13bdc2 100644 --- a/Completion/Unix/Command/_texinfo +++ b/Completion/Unix/Command/_texinfo @@ -227,7 +227,7 @@ esac if [[ -n $state ]]; then local chr cache file q - local -a suf tags + local -a expl suf tags local -i36 hash=5381 local -aU infopath=( /usr/share/info ${commands[info]:h:h}/share/info ${(s.:.)INFOPATH} $infodirs ) infopath=( $^infopath(N) ) diff --git a/Completion/Unix/Command/_tmux b/Completion/Unix/Command/_tmux index 08d80374f..7ef20c666 100644 --- a/Completion/Unix/Command/_tmux +++ b/Completion/Unix/Command/_tmux @@ -526,7 +526,7 @@ _tmux-new-session() { '-t+[specify target session]:session:__tmux-sessions' \ '-x[specify width]:width' \ '-y[specify height]:height' \ - '*:: :_cmdstring' + '*:: :_cmdambivalent' } _tmux-new-window() { @@ -540,7 +540,7 @@ _tmux-new-window() { '-n+[specify a window name]:window name' \ '-P[print information about new window after it is created]' \ '-t+[specify target window]:window:__tmux-windows' \ - '*:: :_cmdstring' + '*:: :_cmdambivalent' } _tmux-next-layout() { @@ -628,7 +628,7 @@ _tmux-respawn-pane() { _arguments -s -A "-*" -S \ '-k[kill window if it is in use]' \ '-t+[specify target pane]:pane:__tmux-pane' \ - ':command:_cmdstring' + ':command:_cmdambivalent' } _tmux-respawn-window() { @@ -636,7 +636,7 @@ _tmux-respawn-window() { _arguments -s -A "-*" -S \ '-k[kill window if it is in use]' \ '-t+[specify target window]:window:__tmux-windows' \ - ':command:_cmdstring' + ':command:_cmdambivalent' } _tmux-rotate-window() { @@ -669,7 +669,7 @@ _tmux-select-layout() { '-o[revert to previous layout]' \ '-p[behave like previous-layout]' \ '-t+[specify a target window]:target window:__tmux-windows' \ - ':layout:(even-horizontal even-vertical main-horizontal main-vertical)' + ':layout:(even-horizontal even-vertical main-horizontal main-vertical tiled)' } _tmux-select-pane() { @@ -855,7 +855,7 @@ _tmux-split-window() { "-l[define new pane's size]:size" \ "-p[define new pane's size in percent]:size (percentage)" \ '-t+[specify target pane]:pane:__tmux-panes' \ - ':command:_cmdstring' + ':command:_cmdambivalent' # Yes, __tmux-panes is correct here. The behaviour was changed # in recent tmux versions and makes more sense. Except that # changing the command's name might annoy users. So it stays like diff --git a/Completion/Unix/Command/_units b/Completion/Unix/Command/_units index d049d22ab..bea77ae67 100644 --- a/Completion/Unix/Command/_units +++ b/Completion/Unix/Command/_units @@ -1,6 +1,6 @@ #compdef units -local curcontext="$curcontext" state line +local curcontext="$curcontext" state line expl integer ret=1 typeset -A opt_args diff --git a/Completion/Unix/Command/_user_admin b/Completion/Unix/Command/_user_admin index f0777729c..7eeec7e9b 100644 --- a/Completion/Unix/Command/_user_admin +++ b/Completion/Unix/Command/_user_admin @@ -125,7 +125,7 @@ case ${service%???}:${(M)service%???}:$OSTYPE in ;| group:*) args+=( - '(-g,--gid)'{-g+,--gid=}'[specify gid]:gid' + '(-g --gid)'{-g+,--gid=}'[specify gid]:gid' '(-o --non-unique)'{-o,--non-unique}'[allow non unique gid]' ) ;| diff --git a/Completion/Unix/Command/_wget b/Completion/Unix/Command/_wget index b89f12353..8a9cc871a 100644 --- a/Completion/Unix/Command/_wget +++ b/Completion/Unix/Command/_wget @@ -32,7 +32,7 @@ _arguments -C -s \ '(--timeout -T)--dns-timeout=[set the DNS lookup timeout]:DNS lookup timeout (seconds)' \ '(--timeout -T)--connect-timeout=[set the connect timeout]:connect timeout (seconds)' \ '(--timeout -T)--read-timeout=[set the read timeout]:read timeout (seconds)' \ - '(--wait,-w)'{--wait=,-w+}'[specify wait between retrievals]:time (seconds)' \ + '(--wait -w)'{--wait=,-w+}'[specify wait between retrievals]:time (seconds)' \ '(--random-wait)--waitretry=:time (seconds)' \ '(--waitretry)--random-wait[random wait time between retrievals]' \ '(--proxy -Y --no-proxy)'{--proxy=,-Y+}'[explicitly turn on proxy]' \ diff --git a/Completion/Unix/Command/_xz b/Completion/Unix/Command/_xz index 028285a35..a4dfea1f5 100644 --- a/Completion/Unix/Command/_xz +++ b/Completion/Unix/Command/_xz @@ -2,7 +2,6 @@ local decompress files expl state line curcontext="$curcontext" ret=1 typeset -A opt_args -local decomp="(-z --compress --decompress -d --test -t --list -l --single-stream --no-sparse)" files=( '(--files --files0)*:files:->files' ) case "$service" in @@ -14,53 +13,55 @@ case "$service" in ;& xz) decompress=no;& unxz) _arguments -C -s -S "$files[@]" \ + '--robot[use machine-parsable messages]' \ + + 'common' \ + '(I -k --keep)'{-k,--keep}"[keep (don't delete) input files]" \ + '(I -f --force)'{-f,--force}'[force overwrite]' \ + '(I -c --stdout)'{-c,--stdout}'[write on standard output]' \ + '(I)*'{-q,--quiet}'[suppress all warnings]' \ + '(I)*'{-v,--verbose}'[verbose mode]' \ + '(I * --files --files0)--files=-[read list of files to process from file]::file:_files' \ + '(I * --files --files0)--files0=-[read null terminated list of files to process from file]::file:_files' \ + '(I -F --format)'{-F,--format}'=[specify file format]:format:(auto xz lzma raw)' \ + '(I -T --threads)'{-T+,--threads=}'[use specified number of threads]:threads [1]' \ + '(I -M --memlimit --memory)'{-M+,--memlimit=,--memory=}'[set memory usage limit]:memory usage' \ + '(I)--no-adjust[give error if settings exceed memory limit]' \ + '(I -Q --no-warn)'{-Q,--no-warn}'[make warnings not affect exit status]' \ + + 'comp' \ + "(I decomp)"{-z,--compress}'[compress]' \ + '(I decomp -e --extreme)'{-e,--extreme}'[try to improve compression ratio by using more CPU time]' \ + '(I decomp -S --suffix)'{-S+,--suffix=}'[use specified suffix for compressed files]:suffix [.xz]' \ + '(I decomp -C --check)'{-C,--check}'=[integrity check type]:check type:(none crc32 crc64 sha256)' \ + '(I decomp)--block-size=[start a new .xz block after specified bytes of input]:size' \ + '(I decomp)--block-list=[start a new .xz block after specified intervals of uncompressed data]:size' \ + '(I decomp)--flush-timeout=[specify maximum time between flushing of output]:time (ms) [0]' \ + '(I decomp)--memlimit-compress=[set memory usage limit for compression]:memory usage' \ + + 'decomp' \ + '(I comp level filters)'{-d,--decompress}'[decompress]' \ + '(I comp level filters)'{-t,--test}'[test compressed file integrity]' \ + '(I comp level filters)'{-l,--list}'[list information about .xz files]' \ + "(I comp level filters)--ignore-check[don't verify integrity when decompressing]" \ + '(I comp level filters)--single-stream[decompress only the first stream]' \ + "(I comp level filters)--no-sparse[don't create sparse files when decompressing]" \ + '(I comp level filters)--memlimit-decompress=[set memory usage limit for decompression]:memory usage' \ + + '(I)' \ + '(* comp decomp level filters common)--info-memory[display amount of RAM and memory usage limits]' \ '(- *)'{-h,--help}'[display help message]' \ '(- *)'{-H,--long-help}'[display the long help (lists also the advanced options)]' \ - '(-d --decompress --compress -z --test -t --list -l)'{-d,--decompress}'[decompress]' \ - "${decomp}"{-z,--compress}'[compress]' \ - '(-k --keep)'{-k,--keep}"[keep (don't delete) input files]" \ - '(-f --force)'{-f,--force}'[force overwrite]' \ - '(-t --test --decompress -d --compress -z --list -l)'{-t,--test}'[test compressed file integrity]' \ - '(-t --test --decompress -d --compress -z --list -l)'{-l,--list}'[list information about .xz files]' \ - '(-c --stdout)'{-c,--stdout}'[write on standard output]' \ - \*{-q,--quiet}'[suppress all warnings]' \ - \*{-v,--verbose}'[verbose mode]' \ - '(- *)'{-V,--version}'[display version number]' \ - '(-e --extreme)'{-e,--extreme}'[try to improve compression ratio by using more CPU time]' \ - '(-1 -2 -3 -4 -5 -6 -7 -8 -9 --fast )--best' \ - '(-1 -2 -3 -4 -5 -6 -7 -8 -9 --best)--fast' \ - '( -2 -3 -4 -5 -6 -7 -8 -9 --fast --best)-1' \ - '(-1 -3 -4 -5 -6 -7 -8 -9 --fast --best)-2' \ - '(-1 -2 -4 -5 -6 -7 -8 -9 --fast --best)-3' \ - '(-1 -2 -3 -5 -6 -7 -8 -9 --fast --best)-4' \ - '(-1 -2 -3 -4 -6 -7 -8 -9 --fast --best)-5' \ - '(-1 -2 -3 -4 -5 -7 -8 -9 --fast --best)-6' \ - '(-1 -2 -3 -4 -5 -6 -8 -9 --fast --best)-7' \ - '(-1 -2 -3 -4 -5 -6 -7 -9 --fast --best)-8' \ - '(-1 -2 -3 -4 -5 -6 -7 -8 --fast --best)-9' \ - "${decomp}--single-stream[decompress only the first stream]" \ - "${decomp}--no-sparse[do not create sparse files when decompressing]" \ - '(* --files --files0)--files=-[read list of files to process from file]::file:_files' \ - '(* --files --files0)--files0=-[read null terminated list of files to process from file]::file:_files' \ - '(-F --format)'{-F,--format}'=[specify file format]:format;(auto xz lzma raw)' \ - '(-C --check)'{-C,--check}'=[integrity check type]:check type:(none crc32 crc64 sha256)' \ - '--memlimit-compress=[set memory usage limit for compression]:memory usage' \ - '--memlimit-decompress=[set memory usage limit for decompression]:memory usage' \ - '(-M --memlimit --memory)'{-M+,--memlimit=,--memory=}'[set memory usage limit]:memory usage' \ - '--no-adjust[give error if settings exceed memory limit]' \ - '(-Q --no-warn)'{-Q,--no-warn}'[make warnings not affect exit status]' \ - '--robot[use machine-parsable messages]' \ - --{x86,powerpc,ia64,arm,armthumb,sparc}=-'[add a branch/call/jump filter]::option:->bcj-options' \ - --lzma{1,2}=-'[add lzma filter]::option:->lzma-options' \ - '--delta=-[add delta filter]::option:->delta-options' \ - '(- *)--info-memory[display amount of RAM and memory usage limits]' && ret=0 + '(* comp decomp level filters common)'{-V,--version}'[display version number]' \ + + '(level)' \ + '(I filters decomp)-'{-best,-fast,1,2,3,4,5,6,7,8,9} \ + + filters \ + '(I level decomp --extreme)'--{x86,powerpc,ia64,arm,armthumb,sparc}=-'[add a branch/call/jump filter]::option:->bcj-options' \ + '(I level decomp --extreme)'--lzma{1,2}=-'[add lzma filter]::option:->lzma-options' \ + '(I level decomp --extreme)--delta=-[add delta filter]::option:->delta-options' && ret=0 ;; esac case $state in files) (( $+opt_args[-z] || $+opt_args[--compress] )) && decompress=no - [[ -n $opt_args[(i)-([dtl]|-decompress|-test|-list)] ]] && unset decompress + [[ -n ${(k)opt_args[(i)decomp*]} ]] && unset decompress if [[ -z "$decompress" ]]; then _description files expl 'compressed file' _files "$expl[@]" -g '*.(xz|txz|lzma|tlz)(-.)' && return @@ -71,7 +72,7 @@ case $state in ;; lzma-options) _values -s , options 'preset:preset' 'dict:size' 'lc:context bits' \ - 'lp:position bits' 'mf:matchfinder:(hc3 hc4 bt2 bt3 bt4)' \ + 'lp:position bits' 'pb:position bites' 'mf:matchfinder:(hc3 hc4 bt2 bt3 bt4)' \ 'mode:mode:(fast normal)' 'nice:length' 'depth:depth' && ret=0 ;; bcj-options) diff --git a/Completion/Unix/Command/_yafc b/Completion/Unix/Command/_yafc index edc7c417f..1e0a601a1 100644 --- a/Completion/Unix/Command/_yafc +++ b/Completion/Unix/Command/_yafc @@ -30,7 +30,7 @@ _yafc_bookmarks() { local bkmfile=~/.yafc/bookmarks if [[ -f $bkmfile ]]; then - local -a bkms + local -a bkms expl bkms=(${${${(M)"${(f)$(<$bkmfile)}":#machine*alias ##\'*\' #}##machine*alias ##\'}%%\' #}) #" vim syntax goes crazy _wanted bookmarks expl 'bookmarks' compadd "$@" -a - bkms fi diff --git a/Completion/Unix/Command/_zpool b/Completion/Unix/Command/_zpool index 950266896..4d4793eea 100644 --- a/Completion/Unix/Command/_zpool +++ b/Completion/Unix/Command/_zpool @@ -237,7 +237,7 @@ _zpool() { _arguments -A "-*" \ '-D[Destroyed pools]' \ '(-d)*-c[Use cache file]:cache file:_files' \ - '(-c,-D)*-d[Search for devices or files in directory]:directory:_files -/' \ + '(-c -D)*-d[Search for devices or files in directory]:directory:_files -/' \ '-F[Recovery mode: discard transactions if required]' \ '-f[Force import]' \ '-l[Display configuration in /dev/chassis location form]' \ diff --git a/Completion/Unix/Type/_absolute_command_paths b/Completion/Unix/Type/_absolute_command_paths index e08ca56df..0d52ff851 100644 --- a/Completion/Unix/Type/_absolute_command_paths +++ b/Completion/Unix/Type/_absolute_command_paths @@ -9,7 +9,7 @@ _hashed_absolute_command_paths() { do local -a matches=( "${(@)commands[(R)${~i}[^/]#]}" ) local -a descs=( $matches:t ) - compadd -M "l:|=$i" -d descs "$expl[@]" -a matches + compadd -M "l:|=$i" -d descs "$@" -a matches ret=0 done return ret diff --git a/Completion/Unix/Type/_cmdambivalent b/Completion/Unix/Type/_cmdambivalent new file mode 100644 index 000000000..1f15d11ab --- /dev/null +++ b/Completion/Unix/Type/_cmdambivalent @@ -0,0 +1,17 @@ +#autoload + +if (( CURRENT == 1 && ${#words} == 1 )); then + # Heuristics to decide whether to complete for system() or for execl(). + local space=' ' + if (( ${${words[CURRENT]}[(I)$space]} )); then + _cmdstring + elif [[ ${${compstate[all_quotes]}[1]} == (\'|\") ]]; then + _cmdstring + else + _command_names -e + fi +elif (( CURRENT == 1 )); then + _command_names -e +else + _normal +fi diff --git a/Completion/Unix/Type/_hosts b/Completion/Unix/Type/_hosts index 56540865e..d9e1090a4 100644 --- a/Completion/Unix/Type/_hosts +++ b/Completion/Unix/Type/_hosts @@ -50,12 +50,13 @@ if ! zstyle -a ":completion:${curcontext}:hosts" hosts _hosts; then # entries. () { local host + local -a match mbegin mend khosts=() for host; do if [[ $host == *[*?]* ]]; then continue - elif [[ $host =~ "\[(.*)\]:\d*" ]]; then - khosts+=$match + elif [[ $host = (#b)*\[(*)\]:[[:digit:]]#* ]]; then + khosts+=${match[1]} else khosts+=$host fi diff --git a/Completion/Unix/Type/_remote_files b/Completion/Unix/Type/_remote_files index 1e9fed15e..a5fce9afd 100644 --- a/Completion/Unix/Type/_remote_files +++ b/Completion/Unix/Type/_remote_files @@ -58,11 +58,13 @@ if zstyle -T ":completion:${curcontext}:files" remote-access; then else rempat="${(q)PREFIX%%[^./][^/]#}\*" fi + # remote filenames remfiles=(${(M)${(f)"$(_call_program files $cmd $cmd_args $host ls -d1FL -- "$rempat" 2>/dev/null)"}%%[^/]#(|/)}) compset -P '*/' compset -S '/*' || (( ${args[(I)-/]} )) || suf='remote file' + # display strings for remote files and directories remdispf=(${remfiles:#*/}) remdispd=(${(M)remfiles:#*/}) @@ -77,9 +79,9 @@ if zstyle -T ":completion:${curcontext}:files" remote-access; then while _tags; do while _next_label files expl ${suf:-remote directory}; do [[ -n $suf ]] && - compadd "$args[@]" "$expl[@]" -d remdispf ${(q)remdispf%[*=|]} && ret=0 + compadd "$args[@]" "$expl[@]" -d remdispf -- ${(q)remdispf%[*=|]} && ret=0 compadd ${suf:+-S/} -r "/ \t\n\-" "$args[@]" "$expl[@]" -d remdispd \ - ${(q)remdispd%/} && ret=0 + -- ${(q)remdispd%/} && ret=0 done (( ret )) || return 0 done diff --git a/Completion/Unix/Type/_umountable b/Completion/Unix/Type/_umountable new file mode 100644 index 000000000..2b2567478 --- /dev/null +++ b/Completion/Unix/Type/_umountable @@ -0,0 +1,44 @@ +#autoload +local tmp +local dev_tmp dpath_tmp mp_tmp mline + +case "$OSTYPE" in +linux*|irix*) + tmp=( "${(@f)$(< /etc/mtab)}" ) + dev_tmp=( "${(@)${(@)tmp%% *}:#none}" ) + mp_tmp=( "${(@)${(@)tmp#* }%% *}" ) + ;; +freebsd*|dragonfly*) + /sbin/mount | while read mline; do + dev_tmp+=( $mline[(w)1] ) + mp_tmp+=( $mline[(w)3] ) + done +;; +darwin*) + tmp=( "${(@f)$(/sbin/mount)}" ) + dev_tmp=( "${(@)${(@)tmp%% *}:#map}" ) + mp_tmp=( "${(@)${(@)tmp#* on }%% \(*}" ) + ;; +*) + /sbin/mount | while read mline; do + mp_tmp+=( $mline[(w)1] ) + dev_tmp+=( $mline[(w)3] ) + done + ;; +esac + +local MATCH MBEGIN MEND +# The complicated substitution for mount point names is required because +# characters in /etc/mtab that might confuse programs reading the names +# are encoded as exactly 3 octal digits, like for example \040 for space. +# The cleaner-looking ${(g::)mp_tmp} might consume too many digits. +# Both mp_tmp and dev_tmp are derived from /etc/mtab or "mount" output. +mp_tmp=("${(@)mp_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}") +dev_tmp=("${(@)dev_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}") +dpath_tmp=( "${(@M)dev_tmp:#/*}" ) +dev_tmp=( "${(@)dev_tmp:#/*}" ) + +_alternative \ + 'device-labels:device label:compadd -a dev_tmp' \ + 'device-paths: device path:_canonical_paths -A dpath_tmp -N -M "r:|/=* r:|=*" device-paths device\ path' \ + 'directories:mount point:_canonical_paths -A mp_tmp -N -M "r:|/=* r:|=*" directories mount\ point' && ret=0 diff --git a/Completion/X/Command/_setxkbmap b/Completion/X/Command/_setxkbmap index d192cc17a..f7310ecdd 100644 --- a/Completion/X/Command/_setxkbmap +++ b/Completion/X/Command/_setxkbmap @@ -55,7 +55,7 @@ _setxkbmap_files () { local dir="$1" local label="$2" - local -a fullpath shortpath + local -a fullpath shortpath expl fullpath=($sourcedir/$dir/**/*~*README(.)) shortpath=(${fullpath#$sourcedir\/$dir\/}) @@ -82,7 +82,7 @@ _setxkbmap_geometry () { (( $+functions[_setxkbmap_variant] )) || _setxkbmap_variant () { local file=$sourcedir/symbols/${1} - local -a variants lines + local -a variants lines expl if [ ! -f $file ]; then _message "no such layout: ${1}" diff --git a/Completion/X/Command/_xclip b/Completion/X/Command/_xclip index ff131f3b1..509a15b79 100644 --- a/Completion/X/Command/_xclip +++ b/Completion/X/Command/_xclip @@ -10,6 +10,7 @@ _arguments \ '(-)'{-h,-help}'[display usage information]' \ '(-selection)-selection[selection to access]:selection:(primary secondary clipboard buffer-cut)' \ "-noutf8[operate in legacy, non-Unicode, mode]" \ + '(-r -rmlastnl)'{-r,-rmlastnl}'[remove the last newline character if present]' \ '(-)-version[display version information]' \ '(-quiet -verbose)-silent[errors only, run in background]' \ "(-silent -verbose)-quiet[run in foreground, show what's happening]" \ diff --git a/Completion/X/Type/_xft_fonts b/Completion/X/Type/_xft_fonts index 535b9b5ae..991838d67 100644 --- a/Completion/X/Type/_xft_fonts +++ b/Completion/X/Type/_xft_fonts @@ -1,6 +1,6 @@ #compdef fc-list fc-match -local -a suf +local -a expl suf local font=${${PREFIX//-[0-9]##:/:}%:*}: ret=1 local attr diff --git a/Completion/Zsh/Command/_fc b/Completion/Zsh/Command/_fc index 6cc01f32d..dd014e7d7 100644 --- a/Completion/Zsh/Command/_fc +++ b/Completion/Zsh/Command/_fc @@ -1,6 +1,6 @@ #compdef fc history r -local curcontext="$curcontext" state state_descr line ret=1 +local curcontext="$curcontext" state state_descr line expl ret=1 local num cmd sep local -a events typeset -A opt_args diff --git a/Completion/Zsh/Command/_typeset b/Completion/Zsh/Command/_typeset index 94f63cf7e..160150234 100644 --- a/Completion/Zsh/Command/_typeset +++ b/Completion/Zsh/Command/_typeset @@ -21,6 +21,7 @@ allargs=( X '+X[immediately autoload function]' Z "($fopts -A -E -F -i)-Z+[right justify and fill with leading zeros]:width" a "($fopts -A -E -F -T -i)-a[specify that arguments refer to arrays]" + df "-d[default absolute path autoload to fpath]" f "($popts)-f[specify that arguments refer to functions]" g "($fopts -T)-+g[do not restrict parameter to local scope]" h "($fopts -T)-+h[hide specialness of parameter]" @@ -31,6 +32,8 @@ allargs=( m '(-A -E -F -T -i)-m[treat arguments as patterns]' p '-p[output parameters in form of calls to typeset]' r '(-f)-+r[mark parameters as readonly]' + rf '-r[remember autoload path]' + Rf '-R[remember autoload path, error if not found]' t '(-T)-+t[tag parameters and turn on execution tracing for functions]' tf '(-T)-+t[turn on execution tracing for functions]' tp '(-T)-+t[tag parameters]' @@ -46,7 +49,7 @@ use="AEFHLRTUZafghiklmprtuxz" case ${service} in autoload) - use="UTXktwz" + use="URTXdkrtwz" func=f ;; float) use="EFHghlprtux";; @@ -74,7 +77,7 @@ onopts=${(j..)${${words[1,CURRENT-1]:#^-*}##-}} offopts=${(j..)${${words[1,CURRENT-1]:#^+*}##+}} for ((i=1;i<=$#use;++i)); do - args+=( ${allargs[${use[$i]}${${(s::)use[$i]}[(r)[UutT]]:+$func}]} ) + args+=( ${allargs[${use[$i]}${${(s::)use[$i]}[(r)[dUurRtT]]:+$func}]} ) done _arguments -C -s -A "-*" -S "${args[@]}" '*::vars:= ->vars_eq' @@ -90,12 +93,17 @@ if [[ "$state" = vars_eq ]]; then elif (( $+opt_args[-w] )); then _wanted files expl 'zwc file' _files -g '*.zwc(-.)' elif [[ $service = autoload || -n $opt_args[(i)-[uU]] ]]; then - args=(${^fpath}/*(-.:t)) - # Filter out functions already loaded or marked for autoload. - local -a funckeys - funckeys=(${(k)functions}) - args=(${args:|funckeys}) - _wanted functions expl 'shell function' compadd -a args + if [[ $PREFIX[1] = [/~] ]]; then + # Autoload by absolute path + _files + else + args=(${^fpath}/*(-.:t)) + # Filter out functions already loaded or marked for autoload. + local -a funckeys + funckeys=(${(k)functions}) + args=(${args:|funckeys}) + _wanted functions expl 'shell function' compadd -a args + fi elif [[ -n $onopts$offopts ]]; then if [[ -n $offopts ]]; then args=(${(f)"$(functions +${offopts//[^UXkmtTuz]/})"}) diff --git a/Completion/Zsh/Context/_brace_parameter b/Completion/Zsh/Context/_brace_parameter index aa1572176..f22db8895 100644 --- a/Completion/Zsh/Context/_brace_parameter +++ b/Completion/Zsh/Context/_brace_parameter @@ -141,7 +141,7 @@ if [[ $PREFIX = *'${('[^\)]# ]]; then flags+=( "#:evaluate as numeric expression" "@:double-quoted splitting of scalars" - "A:create array parameter" + "A:assign as an array parameter" "a:sort in array index order (with O to reverse)" "b:backslash quote pattern characters only" "c:count characters in an array (with \${(c)#...})" diff --git a/Completion/Zsh/Context/_value b/Completion/Zsh/Context/_value index 47fbc1749..22372ab36 100644 --- a/Completion/Zsh/Context/_value +++ b/Completion/Zsh/Context/_value @@ -24,6 +24,7 @@ else if [[ "$compstate[parameter]" != *-* && "$compstate[context]" = *value && "${(Pt)${compstate[parameter]}}" = assoc* ]]; then + local expl if (( CURRENT & 1 )); then _wanted association-keys expl 'association key' \ compadd -k "$compstate[parameter]" diff --git a/Completion/Zsh/Function/_add-zle-hook-widget b/Completion/Zsh/Function/_add-zle-hook-widget index 93954a2bb..f108d1868 100644 --- a/Completion/Zsh/Function/_add-zle-hook-widget +++ b/Completion/Zsh/Function/_add-zle-hook-widget @@ -11,6 +11,7 @@ _add-zle-hook-widget_types() { } _add-zle-hook-widget_widgets() { + local expl if (( $+opt_args[-d] )); then local -a tmp zstyle -g tmp $line[1] widgets diff --git a/Completion/Zsh/Function/_add-zsh-hook b/Completion/Zsh/Function/_add-zsh-hook index fb5403a60..e8ae97052 100644 --- a/Completion/Zsh/Function/_add-zsh-hook +++ b/Completion/Zsh/Function/_add-zsh-hook @@ -1,6 +1,7 @@ #compdef add-zsh-hook _add-zsh-hook_hooks() { + local expl if (( $+opt_args[-d] )); then _wanted functions expl "installed hooks" compadd -a - "$line[1]_functions" && return 0 else diff --git a/Completion/compinit b/Completion/compinit index 6612baca0..c345ceb43 100644 --- a/Completion/compinit +++ b/Completion/compinit @@ -142,6 +142,7 @@ _comp_options=( NO_cshnullglob NO_cshjunkiequotes NO_errexit + NO_errreturn NO_globassign NO_globsubst NO_histsubstpattern @@ -153,8 +154,10 @@ _comp_options=( NO_markdirs NO_octalzeroes NO_posixbuiltins + NO_posixidentifiers NO_shwordsplit NO_shglob + NO_warnnestedvar NO_warncreateglobal ) @@ -168,7 +171,7 @@ typeset -gH _comp_setup='local -A _comp_caller_options; _comp_caller_options=(${(kv)options[@]}); setopt localoptions localtraps localpatterns ${_comp_options[@]}; local IFS=$'\'\ \\t\\r\\n\\0\''; - builtin enable -p \| \~ \( \? \* \[ \< \^ \# 2>/dev/null; + builtin enable -p \| \~ \( \? \* \[ \< \^ \# 2>&-; exec </dev/null; trap - ZERR; local -a reply; diff --git a/Config/version.mk b/Config/version.mk index 5f6bd4efa..363618aca 100644 --- a/Config/version.mk +++ b/Config/version.mk @@ -27,5 +27,5 @@ # This must also serve as a shell script, so do not add spaces around the # `=' signs. -VERSION=5.3.1 -VERSION_DATE='December 21, 2016' +VERSION=5.4.1 +VERSION_DATE='August 8, 2017' diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 7b04d0648..3afe990ba 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -147,20 +147,42 @@ ifnzman(noderef(Aliasing)). findex(autoload) cindex(functions, autoloading) cindex(autoloading functions) -item(tt(autoload) [ {tt(PLUS())|tt(-)}tt(TUXkmtz) ] [ tt(-w) ] [ var(name) ... ])( +item(tt(autoload) [ {tt(PLUS())|tt(-)}tt(RTUXdkmrtWz) ] [ tt(-w) ] [ var(name) ... ])( vindex(fpath, searching) -Equivalent to tt(functions -u), with the exception of tt(-X)/tt(+X) and -tt(-w). See the section `Autoloading Functions' in ifzman(zmanref(zshmisc))\ +See the section `Autoloading Functions' in ifzman(zmanref(zshmisc))\ ifnzman(noderef(Functions)) for full details. The tt(fpath) parameter will be searched to find the function definition when the function is first referenced. -The flag tt(-X) may be used only inside a shell function, and may not be -followed by a var(name). It causes the calling function to be marked for -autoloading and then immediately loaded and executed, with the current -array of positional parameters as arguments. This replaces the previous -definition of the function. If no function definition is found, an error -is printed and the function remains undefined and marked for autoloading. +If var(name) consists of an absolute path, the function is defined to +load from the file given (searching as usual for dump files in the given +location). The name of the function is the basename (non-directory +part) of the file. It is normally an error if the function is not found +in the given location; however, if the option tt(-d) is given, searching +for the function defaults to tt($fpath). If a function is loaded by +absolute path, any functions loaded from it that are marked for +tt(autoload) without an absolute path have the load path of the parent +function temporarily prepended to tt($fpath). + +If the option tt(-r) or tt(-R) is given, the function is searched for +immediately and the location is recorded internally for use when the +function is executed; a relative path is expanded using the value of +tt($PWD). This protects against a change to tt($fpath) after the call +to tt(autoload). With tt(-r), if the function is not found, it is +silently left unresolved until execution; with tt(-R), an error message +is printed and command processing aborted immediately the search fails, +i.e. at the tt(autoload) command rather than at function execution.. + +The flag tt(-X) may be used only inside a shell function. It causes the +calling function to be marked for autoloading and then immediately +loaded and executed, with the current array of positional parameters as +arguments. This replaces the previous definition of the function. If +no function definition is found, an error is printed and the function +remains undefined and marked for autoloading. If an argument is given, +it is used as a directory (i.e. it does not include the name of the +function) in which the function is to be found; this may be combined +with the tt(-d) option to allow the function search to default to tt($fpath) +if it is not in the given location. The flag tt(+X) attempts to load each var(name) as an autoloaded function, but does em(not) execute it. The exit status is zero (success) if the @@ -176,6 +198,13 @@ If the tt(-m) flag is also given each var(name) is treated as a pattern and all functions already marked for autoload that match the pattern are loaded. +With the tt(-t) flag, turn on execution tracing; with tt(-T), turn on +execution tracing only for the current function, turning it off on entry +to any called functions that do not also have tracing enabled. + +With the tt(-U) flag, alias expansion is suppressed when the function is +loaded. + With the tt(-w) flag, the var(name)s are taken as names of files compiled with the tt(zcompile) builtin, and all functions defined in them are marked for autoloading. @@ -193,6 +222,10 @@ example(emulate zsh -c 'autoload -Uz var(func)') arranges that when var(func) is loaded the shell is in native tt(zsh) emulation, and this emulation is also applied when var(func) is run. + +Some of the functions of tt(autoload) are also provided by tt(functions +-u) or tt(functions -U), but tt(autoload) is a more comprehensive +interface. ) findex(bg) cindex(jobs, backgrounding) @@ -453,7 +486,7 @@ tt(echo) recognizes the following escape sequences: startsitem() sitem(tt(\a))(bell character) sitem(tt(\b))(backspace) -sitem(tt(\c))(suppress final newline) +sitem(tt(\c))(suppress subsequent characters and final newline) sitem(tt(\e))(escape) sitem(tt(\f))(form feed) sitem(tt(\n))(linefeed (newline)) @@ -634,7 +667,10 @@ if there are no var(args) or they contain no commands (i.e. are an empty string or whitespace) the return status is zero. ) item(tt(exec) [ tt(-cl) ] [ tt(-a) var(argv0) ] [ var(command) [ var(arg) ... ] ])( -Replace the current shell with an external var(command) rather than forking. +Replace the current shell with var(command) rather than forking. +If var(command) is a shell builtin command or a shell function, +the shell executes it, then immediately exits. + With tt(-c) clear the environment; with tt(-l) prepend tt(-) to the tt(argv[0]) string of the command executed (to simulate a login shell); with tt(-a) var(argv0) set the tt(argv[0]) string of the command @@ -642,6 +678,12 @@ executed. See ifzman(the section `Precommand Modifiers' in zmanref(zshmisc))\ ifnzman(noderef(Precommand Modifiers)). +If the option tt(POSIX_BUILTINS) is set, var(command) is never +interpreted as a shell builtin command or shell function. This +means further precommand modifiers such as tt(builtin) and +tt(noglob) are also not interpreted within the shell. Hence +var(command) is always found by searching the command path. + cindex(redirection, current shell's I/O) If var(command) is omitted but any redirections are specified, then the redirections will take effect in the current shell. @@ -806,18 +848,24 @@ Equivalent to tt(typeset -E), except that options irrelevant to floating point numbers are not permitted. ) findex(functions) -xitem(tt(functions) [ {tt(PLUS())|tt(-)}tt(UkmtTuz) ] [ tt(-x) var(num) ] [ var(name) ... ]) -xitem(tt(functions -M) var(mathfn) [ var(min) [ var(max) [ var(shellfn) ] ] ]) +xitem(tt(functions) [ {tt(PLUS())|tt(-)}tt(UkmtTuWz) ] [ tt(-x) var(num) ] [ var(name) ... ]) +xitem(tt(functions -M) [tt(-s)] var(mathfn) [ var(min) [ var(max) [ var(shellfn) ] ] ]) xitem(tt(functions -M) [ tt(-m) var(pattern) ... ]) item(tt(functions +M) [ tt(-m) ] var(mathfn) ... )( -Equivalent to tt(typeset -f), with the exception of the tt(-x) and -tt(-M) options. +Equivalent to tt(typeset -f), with the exception of the tt(-x), +tt(-M) and tt(-W) options. For tt(functions -u) and tt(functions -U), +see tt(autoload), which provides additional options. The tt(-x) option indicates that any functions output will have each leading tab for indentation, added by the shell to show syntactic structure, expanded to the given number var(num) of spaces. var(num) can also be 0 to suppress all indentation. +The tt(-W) option turns on the option tt(WARN_NESTED_VAR) for the named +function or functions only. The option is turned off at the start of +nested functions (apart from anonoymous functions) unless the called +function also has the tt(-W) attribute. + Use of the tt(-M) option may not be combined with any of the options handled by tt(typeset -f). @@ -843,6 +891,13 @@ The result of the last arithmetical expression evaluated inside the shell function (even if it is a form that normally only returns a status) gives the result of the mathematical function. +If the additional option tt(-s) is given to tt(functions -M), the +argument to the function is a single string: anything between the +opening and matching closing parenthesis is passed to the function as a +single argument, even if it includes commas or white space. The minimum +and maximum argument specifiers must therefore be 1 if given. An empty +argument list is passed as a zero-length string. + tt(functions -M) with no arguments lists all such user-defined functions in the same form as a definition. With the additional option tt(-m) and a list of arguments, all functions whose var(mathfn) matches one of @@ -850,15 +905,22 @@ the pattern arguments are listed. tt(function +M) removes the list of mathematical functions; with the additional option tt(-m) the arguments are treated as patterns and -all functions whose tt(mathfn) matches the pattern are removed. Note +all functions whose var(mathfn) matches the pattern are removed. Note that the shell function implementing the behaviour is not removed -(regardless of whether its name coincides with tt(mathfn)). +(regardless of whether its name coincides with var(mathfn)). For example, the following prints the cube of 3: example(zmath_cube+LPAR()RPAR() { (( $1 * $1 * $1 )) } functions -M cube 1 1 zmath_cube print $(( cube+LPAR()3+RPAR() ))) + +The following string function takes a single argument, including +the commas, so prints 11: + +example(stringfn+LPAR()RPAR() { (( $#1 )) } +functions -Ms stringfn +print $(( stringfn+LPAR()foo,bar,rod+RPAR() ))) ) module(getcap)(zsh/cap) findex(getln) @@ -1199,6 +1261,9 @@ Perform prompt expansion (see ifzman(EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\ ifnzman(noderef(Prompt Expansion))\ ). +In combination with `tt(-f)', +prompt escape sequences are parsed only within interpolated arguments, +not within the format string. ) item(tt(-r))( Ignore the escape conventions of tt(echo). @@ -2034,7 +2099,9 @@ expansion to be suppressed when the function is loaded. See the description of the `tt(autoload)' builtin for details. Note that the builtin tt(functions) provides the same basic capabilities -as tt(typeset -f) but gives access to a few extra options. +as tt(typeset -f) but gives access to a few extra options; tt(autoload) +gives further additional options for the case tt(typeset -fu) and +tt(typeset -fU). ) item(tt(-h))( Hide: only useful for special parameters (those marked `<S>' in the table in @@ -2496,7 +2563,7 @@ zlecmd(zle) findex(zmodload) cindex(modules, loading) cindex(loading modules) -xitem(tt(zmodload) [ tt(-dL) ] [ ... ]) +xitem(tt(zmodload) [ tt(-dL) ] [ tt(-s) ] [ ... ]) xitem(tt(zmodload -F) [ tt(-alLme) tt(-P) var(param) ] var(module) [ [tt(PLUS()-)]var(feature) ... ]) xitem(tt(zmodload -e) [ tt(-A) ] [ ... ]) xitem(tt(zmodload) [ tt(-a) [ tt(-bcpf) [ tt(-I) ] ] ] [ tt(-iL) ] ...) @@ -2515,7 +2582,7 @@ printed. The tt(-L) option causes this list to be in the form of a series of tt(zmodload) commands. Forms with arguments are: startitem() -xitem(tt(zmodload) [ tt(-i) ] var(name) ... ) +xitem(tt(zmodload) [ tt(-is) ] var(name) ... ) item(tt(zmodload) tt(-u) [ tt(-i) ] var(name) ...)( In the simplest case, tt(zmodload) loads a binary module. The module must be in a file with a name consisting of the specified var(name) followed by @@ -2523,9 +2590,7 @@ a standard suffix, usually `tt(.so)' (`tt(.sl)' on HPUX). If the module to be loaded is already loaded the duplicate module is ignored. If tt(zmodload) detects an inconsistency, such as an invalid module name or circular dependency list, the current code block is -aborted. Hence `tt(zmodload) var(module) tt(2>/dev/null)' is sufficient -to test whether a module is available. -If it is available, the module is loaded if necessary, while if it +aborted. If it is available, the module is loaded if necessary, while if it is not available, non-zero status is silently returned. The option tt(-i) is accepted for compatibility but has no effect. @@ -2538,6 +2603,11 @@ If the module supports features (see below), tt(zmodload) tries to enable all features when loading a module. If the module was successfully loaded but not all features could be enabled, tt(zmodload) returns status 2. +If the option tt(-s) is given, no error is printed if the module was not +available (though other errors indicating a problem with the module are +printed). The return status indicates if the module was loaded. This +is appropriate if the caller considers the module optional. + With tt(-u), tt(zmodload) unloads modules. The same var(name) must be given that was given when the module was loaded, but it is not necessary for the module to exist in the file system. diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 953d51c4c..36afd7305 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -1158,6 +1158,12 @@ directory is accepted without any attempt to complete it further. Hence, in the given example, the path tt(/usr/bin/) is accepted immediately and completion tried in that directory. +This style is also useful when completing after directories that +magically appear when referenced, such as ZFS tt(.zfs) directories +or NetApp tt(.snapshot) directories. When the style is set the +shell does not check for the existence of the directory within the +parent directory. + If you wish to inhibit this behaviour entirely, set the tt(path-completion) style (see below) to `false'. ) @@ -1428,9 +1434,10 @@ or colons in var(dir) should be quoted with a backslash to be treated literally. This can be useful on systems that support special file systems whose -top-level pathnames can not be listed or generated with glob patterns. -It can also be used for directories for which one does not have read -permission. +top-level pathnames can not be listed or generated with glob patterns +(but see tt(accept-exact-dirs) for a more general way of dealing +with this problem). It can also be used for directories for which one +does not have read permission. The pattern form can be used to add a certain `magic' entry to all directories on a particular file system. @@ -2196,7 +2203,7 @@ matches does not fit on the screen by using the value `tt(select=long)'. To start menu selection even if the current widget only performs listing, use the value `tt(select=long-list)'. -To turn on menu completion or menu selection when a there are a certain +To turn on menu completion or menu selection when there are a certain number of matches em(or) the list of matches does not fit on the screen, both of `tt(yes=)' and `tt(select=)' may be given twice, once with a number and once with `tt(long)' or `tt(long-list)'. @@ -3007,6 +3014,22 @@ tt(-n), tt(-F), tt(-X) are passed to tt(compadd). See tt(_description) for a description of var(tag) and var(descr). ) +findex(_cmdambivalent) +item(tt(_cmdambivalent))( +Completes the remaining positional arguments as an external command. +The external command and its arguments are completed as separate arguments +(in a manner appropriate for completing tt(/usr/bin/env)) +if there are two or more remaining positional arguments on the command line, +and as a quoted command string (in the manner of tt(system+LPAR()...+RPAR())) otherwise. +See also tt(_cmdstring) and tt(_precommand). + +This function takes no arguments. +) +findex(_cmdstring) +item(tt(_cmdstring))( +Completes an external command as a single argument, as for +tt(system+LPAR()...+RPAR()). +) findex(_complete) item(tt(_complete))( This completer generates all possible completions in a context-sensitive @@ -3207,6 +3230,11 @@ tt(old-menu), see ifzman(the section `Completion System Configuration' above)\ ifnzman(noderef(Completion System Configuration)). ) +findex(_precommand) +item(tt(_precommand))( +Complete an external command in word-separated arguments, as for +tt(exec) and tt(/usr/bin/env). +) findex(_prefix) item(tt(_prefix))( This completer can be used to try completion with the suffix (everything @@ -3573,13 +3601,11 @@ This function can be used to give a complete specification for completion for a command whose arguments follow standard UNIX option and argument conventions. -em(Options overview) +em(Options Overview) Options to tt(_arguments) itself must be in separate words, i.e. tt(-s -w), not tt(-sw). The options are followed by var(spec)s that describe options and -arguments of the analyzed command. var(spec)s that describe option flags must -precede var(spec)s that describe non-option ("positional" or "normal") -arguments of the analyzed line. To avoid ambiguity, all +arguments of the analyzed command. To avoid ambiguity, all options to tt(_arguments) itself may be separated from the var(spec) forms by a single colon. @@ -3997,18 +4023,48 @@ example(local curcontext="$curcontext") This is useful where it is not possible for multiple states to be valid together. -em(Specifying multiple sets of options) +em(Grouping Options) -It is possible to specify multiple sets of options and -arguments with the sets separated by single hyphens. The specifications -before the first hyphen (if any) are shared by all the remaining sets. -The first word in every other set provides a name for the -set which may appear in exclusion lists in specifications, -either alone or before one of the possible values described above. -In the second case a `tt(-)' should appear between this name and the -remainder. +Options can be grouped to simplify exclusion lists. A group is +introduced with `tt(PLUS())' followed by a name for the group in the +subsequent word. Whole groups can then be referenced in an exclusion +list or a group name can be used to disambiguate between two forms of +the same option. For example: -For example: +example(_arguments \ + '(group2--x)-a' \ + PLUS() group1 \ + -m \ + '(group2)-n' \ + PLUS() group2 \ + -x -y) + +If the name of a group is specified in the form +`tt(LPAR())var(name)tt(RPAR())' then only one value from that group +will ever be completed; more formally, all specifications are mutually +exclusive to all other specifications in that group. This is useful for +defining options that are aliases for each other. For example: + +example(_arguments \ + -a -b \ + PLUS() '(operation)' \ + {-c,--compress}'[compress]' \ + {-d,--decompress}'[decompress]' \ + {-l,--list}'[list]') + +If an option in a group appears on the command line, it is stored in the +associative array `tt(opt_args)' with 'var(group)tt(-)var(option)' +as a key. In the example above, a key `tt(operation--c)' is used if the option +`tt(-c)' is present on the command line. + +em(Specifying Multiple Sets of Arguments) + +It is possible to specify multiple sets of options and arguments with +the sets separated by single hyphens. This differs from groups in that +sets are considered to be mutually exclusive of each other. + +Specifications before the first set and from any group are common to +all sets. For example: example(_arguments \ -a \ @@ -4024,28 +4080,11 @@ possible completions. When it contains `tt(-d)' or an argument, the option `tt(-c)' will not be considered. However, after `tt(-a)' both sets will still be considered valid. -If an option in a set appears on the command line, it is stored in the -associative array `tt(opt_args)' with 'var(set)tt(-)var(option)' -as a key. In the example above, a key `tt(set1--c)' is used if the option -`tt(-c)' is on the command line. - -If the name given for one of the mutually exclusive sets is of the form -`tt(LPAR())var(name)tt(RPAR())' then only one value from each set will ever -be completed; more formally, all specifications are mutually -exclusive to all other specifications in the same set. This is -useful for defining multiple sets of options which are mutually -exclusive and in which the options are aliases for each other. For -example: - -example(_arguments \ - -a -b \ - - '(compress)' \ - {-c,--compress}'[compress]' \ - - '(uncompress)' \ - {-d,--decompress}'[decompress]') +As for groups, the name of a set may appear in exclusion lists, either +alone or preceding a normal option or argument specification. -As the completion code has to parse the command line separately for each -set this form of argument is slow and should only be used when necessary. +The completion code has to parse the command line separately for each +set. This can be slow so sets should only be used when necessary. A useful alternative is often an option specification with rest-arguments (as in `tt(-foo:*:...)'); here the option tt(-foo) swallows up all remaining arguments as described by the var(optarg) definitions. diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index f764eb7c6..35ce91575 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -862,7 +862,8 @@ sitem(SVK (tt(svk)))(uref(http://svk.bestpractical.com/)) endsitem() There is also support for the patch management system tt(quilt) -(uref(http://savannah.nongnu.org/projects/quilt)). See tt(Quilt Support) +(uref(http://savannah.nongnu.org/projects/quilt)). See +ifzman(bf(Quilt Support))ifnzman(noderef(vcs_info Quilt Support)) below for details. To load tt(vcs_info): @@ -872,6 +873,18 @@ example(autoload -Uz vcs_info) It can be used in any existing prompt, because it does not require any specific tt($psvar) entries to be available. +startmenu() +menu(vcs_info Quickstart) +menu(vcs_info Configuration) +menu(vcs_info Oddities) +menu(vcs_info Quilt Support) +menu(vcs_info API) +menu(vcs_info Variables) +menu(vcs_info Hooks) +menu(vcs_info Examples) +endmenu() + +texinode(vcs_info Quickstart)(vcs_info Configuration)()(Version Control Information) subsect(Quickstart) To get this feature working quickly (including colors), you can do the @@ -935,6 +948,7 @@ That means the detection of these systems is skipped em(completely). No wasted time there. +texinode(vcs_info Configuration)(vcs_info Oddities)(vcs_info Quickstart)(Version Control Information) subsect(Configuration) The tt(vcs_info) feature can be configured via tt(zstyle). @@ -944,11 +958,17 @@ example(:vcs_info:var(vcs-string):var(user-context):var(repo-root-name)) startitem() item(var(vcs-string))( -is one of: bf(git), bf(git-svn), bf(git-p4), bf(hg), bf(hg-git), -bf(hg-hgsubversion), bf(hg-hgsvn), bf(darcs), bf(bzr), bf(cdv), bf(mtn), -bf(svn), bf(cvs), bf(svk), bf(tla), bf(p4) or bf(fossil). When hooks are -active the hooks name is added after a `+'. (See bf(Hooks in vcs_info) -below.) +is one of: tt(git), tt(git-svn), tt(git-p4), tt(hg), tt(hg-git), +tt(hg-hgsubversion), tt(hg-hgsvn), tt(darcs), tt(bzr), tt(cdv), tt(mtn), +tt(svn), tt(cvs), tt(svk), tt(tla), tt(p4) or tt(fossil). +This is followed by `tt(.quilt-)var(quilt-mode)' in Quilt mode +(see ifzman(bf(Quilt Support))ifnzman(noderef(vcs_info Quilt Support)) for details) +and by `tt(+)var(hook-name)' while hooks are active +(see ifzman(bf(Hooks in vcs_info))ifnzman(noderef(vcs_info Hooks)) for details). + +COMMENT(users/20807) +Currently, hooks in quilt mode don't add the `tt(.quilt-)var(quilt-mode)' information. +This may change in the future. ) item(var(user-context))( is a freely configurable string, assignable by @@ -1056,17 +1076,17 @@ example(zstyle ':vcs_info:*' disable-patterns "${+LPAR()b+RPAR()HOME}/.zsh+LPAR( kindex(use-quilt) item(tt(use-quilt))( If enabled, the tt(quilt) support code is active in `addon' mode. -See tt(Quilt Support) for details. +See ifzman(bf(Quilt Support))ifnzman(noderef(vcs_info Quilt Support)) for details. ) kindex(quilt-standalone) item(tt(quilt-standalone))( If enabled, `standalone' mode detection is attempted if no VCS is active -in a given directory. See tt(Quilt Support) for details. +in a given directory. See ifzman(bf(Quilt Support))ifnzman(noderef(vcs_info Quilt Support)) for details. ) kindex(quilt-patch-dir) item(tt(quilt-patch-dir))( Overwrite the value of the tt($QUILT_PATCHES) environment variable. See -tt(Quilt Support) for details. +ifzman(bf(Quilt Support))ifnzman(noderef(vcs_info Quilt Support)) for details. ) kindex(quiltcommand) item(tt(quiltcommand))( @@ -1197,7 +1217,8 @@ is only used by tt(vcs_info)'s hooks system. ) kindex(hooks) item(tt(hooks))( -A list style that defines hook-function names. See bf(Hooks in vcs_info) +A list style that defines hook-function names. See ifzman(bf(Hooks in vcs_info))\ +ifnzman(noderef(vcs_info Hooks)) below for details. ) kindex(patch-format) @@ -1207,6 +1228,8 @@ item(tt(nopatch-format))( This pair of styles format the patch information used by the tt(%m) expando in formats and actionformats for the tt(git) and tt(hg) backends. The value is subject to certain tt(%)-expansions described below. +The expanded value is made available in the global tt(backend_misc) array as +tt(${backend_misc[patches]}) (also if a tt(set-patch-format) hook is used). ) kindex(get-unapplied) item(tt(get-unapplied))( @@ -1277,8 +1300,8 @@ A "misc" replacement. It is at the discretion of the backend to decide what this replacement expands to. The tt(hg) and tt(git) backends use this expando to display patch information. -tt(hg) sources patch information from the tt(mq) extensions; tt(git) from the -tt(rebase) command and from the and tt(stgit) extension. The tt(patch-format) +tt(hg) sources patch information from the tt(mq) extensions; tt(git) from in-progress +tt(rebase) and tt(cherry-pick) operations and from the tt(stgit) extension. The tt(patch-format) and tt(nopatch-format) styles control the generated string. The former is used when at least one patch from the patch queue has been applied, and the latter otherwise. @@ -1288,6 +1311,17 @@ to tt(mq) information). See the tt(get-mq) and tt(get-bookmarks) styles. Both of these styles may be enabled at the same time. If both are enabled, both resulting strings will be shown separated by a semicolon (that cannot currently be customized). + +The tt(quilt) `standalone' backend sets this expando to the same value as the +tt(%Q) expando. +) +item(tt(%Q))( +Quilt series information. +When quilt is used (either in `addon' mode or as a `standalone' backend), +this expando is set to quilt series' tt(patch-format) string. +The tt(set-patch-format) hook and tt(nopatch-format) style are honoured. + +See ifzman(tt(Quilt Support))ifnzman(noderef(vcs_info Quilt Support)) below for details. ) enditem() @@ -1321,6 +1355,7 @@ endsitem() Not all VCS backends have to support all replacements. For tt(nvcsformats) no replacements are performed at all, it is just a string. +texinode(vcs_info Oddities)(vcs_info Quilt Support)(vcs_info Configuration)(Version Control Information) subsect(Oddities) If you want to use the tt(%b) (bold off) prompt expansion in tt(formats), @@ -1331,7 +1366,14 @@ tt(branchformat), use tt(%%%%b). Sorry for this inconvenience, but it cannot be easily avoided. Luckily we do not clash with a lot of prompt expansions and this only needs to be done for those. +When one of the tt(gen-applied-string), tt(gen-unapplied-string), and +tt(set-patch-format) hooks is defined, +applying tt(%)-escaping (`tt(foo=${foo//'%'/%%})') to the interpolated values +for use in the prompt is the responsibility of those hooks (jointly); +when neither of those hooks is defined, tt(vcs_info) handles escaping by itself. +We regret this coupling, but it was required for backwards compatibility. +texinode(vcs_info Quilt Support)(vcs_info API)(vcs_info Oddities)(Version Control Information) subsect(Quilt Support) bf(Quilt) is not a version control system, therefore this is not implemented @@ -1346,13 +1388,22 @@ The tt(vcs_info) integration tries to support both ways of using quilt by having two slightly different modes of operation: `addon' mode and `standalone' mode). +Quilt integration is off by default; to enable it, set the tt(use-quilt) style, +and add tt(%Q) to your tt(formats) or tt(actionformats) style: +example(zstyle ':vcs_info:*' use-quilt true) + +Styles looked up from the Quilt support code include `tt(.quilt-)var(quilt-mode)' +in the var(vcs-string) part of the context, where var(quilt-mode) is either +tt(addon) or tt(standalone). +Example: tt(:vcs_info:git.quilt-addon:default:)var(repo-root-name). + For `addon' mode to become active tt(vcs_info) must have already detected a real version control system controlling the directory. If that is the case, a directory that holds quilt's patches needs to be found. That directory is configurable via the `tt(QUILT_PATCHES)' environment variable. If that variable exists its value is used, otherwise the value `tt(patches)' is assumed. The value from tt($QUILT_PATCHES) can be overwritten using the -tt(`quilt-patches') style. (Note: you can use tt(vcs_info) to keep the value +`tt(quilt-patches)' style. (Note: you can use tt(vcs_info) to keep the value of tt($QUILT_PATCHES) correct all the time via the tt(post-quilt) hook). When the directory in question is found, quilt is assumed to be active. To @@ -1366,8 +1417,10 @@ to know which patches of a series are not yet applied, you need to activate the tt(get-unapplied) style in the appropriate context. tt(vcs_info) allows for very detailed control over how the gathered -information is presented (see the below sections, bf(Styles) and bf(Hooks in -vcs_info)), all of which are documented below. Note there are a number of +information is presented (see +ifzman(the bf(Configuration) and bf(Hooks in vcs_info) sections)\ +ifnzman(noderef(vcs_info Configuration) and noderef(vcs_info Hooks))), +all of which are documented below. Note there are a number of other patch tracking systems that work on top of a certain version control system (like tt(stgit) for bf(git), or tt(mq) for bf(hg)); the configuration for systems like that are generally configured the same way as the bf(quilt) @@ -1421,6 +1474,7 @@ Note, if there is both a function and a variable by the name of tt(quilt-standalone), the function will take precedence. +texinode(vcs_info API)(vcs_info Variables)(vcs_info Quilt Support)(Version Control Information) subsect(Function Descriptions (Public API)) startitem() @@ -1429,7 +1483,8 @@ item(tt(vcs_info) [var(user-context)])( The main function, that runs all backends and assembles all data into tt(${vcs_info_msg_*_}). This is the function you want to call from tt(precmd) if you want to include up-to-date information in your prompt (see -tt(Variable description) below). If an argument is given, that string will be +ifzman(bf(Variable Description))ifnzman(noderef(vcs_info Variables)) +below). If an argument is given, that string will be used instead of tt(default) in the var(user-context) field of the style context. ) @@ -1438,7 +1493,8 @@ item(tt(vcs_info_hookadd))( Statically registers a number of functions to a given hook. The hook needs to be given as the first argument; what follows is a list of hook-function names to register to the hook. The `tt(+vi-)' prefix needs to be left out -here. See bf(Hooks in vcs_info) below for details. +here. See ifzman(bf(Hooks in vcs_info))ifnzman(noderef(vcs_info Hooks)) +below for details. ) findex(vcs_info_hookdel) item(tt(vcs_info_hookdel))( @@ -1447,8 +1503,9 @@ first non-option argument; what follows is a list of hook-function names to un-register from the hook. If `tt(-a)' is used as the first argument, tt(all) occurrences of the functions are unregistered. Otherwise only the last occurrence is removed (if a function was registered to a hook -more than once) . The `tt(+vi-)' prefix needs to be left out here. See -bf(Hooks in vcs_info) below for details. +more than once). The `tt(+vi-)' prefix needs to be left out here. +See ifzman(bf(Hooks in vcs_info))ifnzman(noderef(vcs_info Hooks)) +below for details. ) findex(vcs_info_lastmsg) item(tt(vcs_info_lastmsg))( @@ -1473,6 +1530,7 @@ enditem() All functions named tt(VCS_INFO_*) are for internal use only. +texinode(vcs_info Variables)(vcs_info Hooks)(vcs_info API)(Version Control Information) subsect(Variable Description) startitem() @@ -1490,6 +1548,7 @@ enditem() All variables named tt(VCS_INFO_*) are for internal use only. +texinode(vcs_info Hooks)(vcs_info Examples)(vcs_info Variables)(Version Control Information) subsect(Hooks in vcs_info) Hooks are places in tt(vcs_info) where you can run your own code. That @@ -1597,10 +1656,11 @@ so far in the opposite order, which means that the first argument is the top-most patch and so forth. When setting tt(ret) to non-zero, the string in -tt(${hook_com[applied-string]}) will be used in the tt(%m) escape in -tt(formats) and tt(actionformats); it will be available in the global -tt(backend_misc) array as tt($backend_misc[patches]}); and it will be +tt(${hook_com[applied-string]}) will be available as tt(%p) in the tt(patch-format) and tt(nopatch-format) styles. +This hook is, in concert with tt(set-patch-format), responsible for +tt(%)-escaping that value for use in the prompt. +(See ifzman(the bf(Oddities) section)ifnzman(noderef(vcs_info Oddities)).) ) item(tt(gen-unapplied-string))( Called in the tt(git) (with tt(stgit) or during rebase), and tt(hg) (with @@ -1614,6 +1674,9 @@ the patch next-in-line to be applied and so forth. When setting tt(ret) to non-zero, the string in tt(${hook_com[unapplied-string]}) will be available as tt(%u) in the tt(patch-format) and tt(nopatch-format) styles. +This hook is, in concert with tt(set-patch-format), responsible for +tt(%)-escaping that value for use in the prompt. +(See ifzman(the bf(Oddities) section)ifnzman(noderef(vcs_info Oddities)).) ) item(tt(gen-mqguards-string))( Called in the tt(hg) backend when tt(guards-string) is generated; the @@ -1691,6 +1754,11 @@ controllable in addition to that. If tt(ret) is set to non-zero, the string in tt(${hook_com[patch-replace]}) will be used unchanged instead of an expanded format from tt(patch-format) or tt(nopatch-format). + +This hook is, in concert with the tt(gen-applied-string) or +tt(gen-unapplied-string) hooks if they are defined, responsible for +tt(%)-escaping the final tt(patch-format) value for use in the prompt. +(See ifzman(the bf(Oddities) section)ifnzman(noderef(vcs_info Oddities)).) ) item(tt(set-message))( Called each time before a `tt(vcs_info_msg_)var(N)tt(_)' message is set. @@ -1719,10 +1787,12 @@ tt(vcs_info). ) enditem() -If all of this sounds rather confusing, take a look at the bf(Examples) -section below and also in the tt(Misc/vcs_info-examples) file in the Zsh source. +If all of this sounds rather confusing, take a look at +ifzman(the bf(Examples) section below)ifnzman(noderef(vcs_info Examples)) +and also in the tt(Misc/vcs_info-examples) file in the Zsh source. They contain some explanatory code. +texinode(vcs_info Examples)()(vcs_info Hooks)(Version Control Information) subsect(Examples) Don't use tt(vcs_info) at all (even though it's in your prompt): @@ -1850,8 +1920,9 @@ subsect(Installation) You should make sure all the functions from the tt(Functions/Prompts) directory of the source distribution are available; they all begin with the string `tt(prompt_)' except for the special function`tt(promptinit)'. -You also need the `tt(colors)' function from tt(Functions/Misc). All of -these functions may already have been installed on your system; if not, +You also need the `tt(colors)' and `tt(add-zsh-hook)' functions from +tt(Functions/Misc). +All these functions may already be installed on your system; if not, you will need to find them and copy them. The directory should appear as one of the elements of the tt(fpath) array (this should already be the case if they were installed), and at least the function tt(promptinit) @@ -1905,6 +1976,75 @@ normally call a theme's setup function directly. ) enditem() +subsect(Utility Themes) + +startitem() +item(tt(prompt off))( +The theme `tt(off)' sets all the prompt variables to minimal values with +no special effects. +) +item(tt(prompt default))( +The theme `tt(default)' sets all prompt variables to the same state as +if an interactive zsh was started with no initialization files. +) +item(tt(prompt restore))( +The special theme `tt(restore)' erases all theme settings and sets prompt +variables to their state before the first time the `tt(prompt)' function +was run, provided each theme has properly defined its cleanup (see below). + +Note that you can undo `tt(prompt off)' and `tt(prompt default)' with +`tt(prompt restore)', but a second restore does not undo the first. +) +enditem() + +subsect(Writing Themes) + +The first step for adding your own theme is to choose a name for it, +and create a file `tt(prompt_var(name)_setup)' in a directory in your +tt(fpath), such as tt(~/myfns) in the example above. The file should +at minimum contain assignments for the prompt variables that your +theme wishes to modify. By convention, themes use tt(PS1), tt(PS2), +tt(RPS1), etc., rather than the longer tt(PROMPT) and tt(RPROMPT). + +The file is autoloaded as a function in the current shell context, so +it may contain any necessary commands to customize your theme, including +defining additional functions. To make some complex tasks easier, your +setup function may also do any of the following: + +startitem() +item(Assign tt(prompt_opts))( +The array tt(prompt_opts) may be assigned any of tt("bang"), tt("cr"), +tt("percent"), tt("sp"), and/or tt("subst") as values. The corresponding +setopts (tt(promptbang), etc.) are turned on, all other prompt-related +options are turned off. The tt(prompt_opts) array preserves setopts even +beyond the scope of tt(localoptions), should your function need that. +) +item(Modify precmd and preexec)( +Use of tt(add-zsh-hook) is recommended. The tt(precmd) and tt(preexec) +hooks are automatically adjusted if the prompt theme changes or is +disabled. +) +item(Declare cleanup)( +If your function makes any other changes that should be undone when the +theme is disabled, your setup function may call +example(prompt_cleanup var(command)) +where var(command) should be suitably quoted. If your theme is ever +disabled or replaced by another, var(command) is executed with tt(eval). +You may declare more than one such cleanup hook. +) +item(Define preview)( +Define or autoload a function tt(prompt_var(name)_preview) to display +a simulated version of your prompt. A simple default previewer is +defined by tt(promptinit) for themes that do not define their own. +This preview function is called by `tt(prompt -p)'. +) +item(Provide help)( +Define or autoload a function tt(prompt_var(name)_help) to display +documentation or help text for your theme. +This help function is called by `tt(prompt -h)'. +) +enditem() + texinode(ZLE Functions)(Exception Handling)(Prompt Themes)(User Contributions) sect(ZLE Functions) diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index cf4f69ea2..a61738f84 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -21,9 +21,12 @@ xitem(em(Parameter Expansion)) xitem(em(Command Substitution)) xitem(em(Arithmetic Expansion)) item(em(Brace Expansion))( -These five are performed in one step in left-to-right fashion. After -these expansions, all unquoted occurrences of the characters `tt(\)', -`tt(')' and `tt(")' are removed. +These five are performed in left-to-right fashion. On each argument, +any of the five steps that are needed are performed one after the other. +Hence, for example, all the parts of parameter expansion are completed +before command substitution is started. After these expansions, all +unquoted occurrences of the characters `tt(\)',`tt(')' and `tt(")' are +removed. ) item(em(Filename Expansion))( If the tt(SH_FILE_EXPANSION) option is set, the order of expansion is @@ -856,8 +859,9 @@ all arguments to be removed. Internally, each such expansion is converted into the equivalent list for brace expansion. E.g., tt(${^var}) becomes tt({$var[1],$var[2],)...tt(}), and is processed as described in -noderef(Brace Expansion) below. -If word splitting is also in effect the +noderef(Brace Expansion) below: note, however, the expansion +happens immediately, with any explicit brace expansion +happening later. If word splitting is also in effect the tt($var[)var(N)tt(]) may themselves be split into different list elements. ) @@ -955,15 +959,25 @@ This is distinct from em(field splitting) by the tt(f), tt(s) or tt(z) flags, which still applies within each array element. ) item(tt(A))( -Create an array parameter with `tt(${)...tt(=)...tt(})', +Convert the substitution into an array expression, even if it otherwise +would be scalar. This has lower precedence than subscripting, so one +level of nested expansion is required in order that subscripts apply +to array elements. Thus tt(${${LPAR()A)tt(RPAR())var(name)tt(}[1]}) +yields the full value of var(name) when var(name) is scalar. + +This assigns an array parameter with `tt(${)...tt(=)...tt(})', `tt(${)...tt(:=)...tt(})' or `tt(${)...tt(::=)...tt(})'. -If this flag is repeated (as in `tt(AA)'), create an associative +If this flag is repeated (as in `tt(AA)'), assigns an associative array parameter. Assignment is made before sorting or padding; if field splitting is active, the var(word) part is split before assignment. The var(name) part may be a subscripted range for -ordinary arrays; the var(word) part em(must) be converted to -an array, for example by using `tt(${(AA)=)var(name)tt(=)...tt(})' -to activate field splitting, when creating an associative array. +ordinary arrays; when assigning an associative array, the var(word) +part em(must) be converted to an array, for example by using +`tt(${(AA)=)var(name)tt(=)...tt(})' to activate field splitting. + +Surrounding context such as additional nesting or use of the value +in a scalar assignment may cause the array to be joined back into +a single string again. ) item(tt(a))( Sort in array index order; when combined with `tt(O)' sort in reverse @@ -1039,7 +1053,9 @@ If var(name) refers to an associative array, substitute the em(keys) (element names) rather than the values of the elements. Used with subscripts (including ordinary arrays), force indices or keys to be substituted even if the subscript form refers to values. However, -this flag may not be combined with subscript ranges. +this flag may not be combined with subscript ranges. With the +tt(KSH_ARRAYS) option a subscript `tt([*])' or `tt([@])' is needed +to operate on the whole array, as usual. ) item(tt(L))( Convert all letters in the result to lower case. @@ -2100,6 +2116,7 @@ Matches either var(x) or var(y). This operator has lower precedence than any other. The `tt(|)' character must be within parentheses, to avoid interpretation as a pipeline. +The alternatives are tried in order from left to right. ) item(tt(^)var(x))( (Requires tt(EXTENDED_GLOB) to be set.) diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo index 2a76964f3..463ac8831 100644 --- a/Doc/Zsh/grammar.yo +++ b/Doc/Zsh/grammar.yo @@ -461,6 +461,9 @@ item(tt(select) var(name) [ tt(in) var(word) ... var(term) ] var(sublist))( where var(term) is at least one newline or tt(;). A short form of tt(select). ) +item(tt(function) var(word) ... [ tt(+LPAR()+RPAR()) ] [ var(term) ] var(sublist))( +This is a short form of tt(function). +) enditem() texinode(Reserved Words)(Errors)(Alternate Forms For Complex Commands)(Shell Grammar) sect(Reserved Words) diff --git a/Doc/Zsh/jobs.yo b/Doc/Zsh/jobs.yo index 6262dd244..70559f2d8 100644 --- a/Doc/Zsh/jobs.yo +++ b/Doc/Zsh/jobs.yo @@ -49,6 +49,12 @@ in the parent shell. Thus the behaviour is different from the case where the function was never suspended. Zsh is different from many other shells in this regard. +One additional side effect is that use of tt(disown) with a job +created by suspending shell code in this fashion is delayed: the +job can only be disowned once any process started from the parent +shell has terminated. At that point, the disowned job disappears +silently from the job list. + The same behaviour is found when the shell is executing code as the right hand side of a pipeline or any complex shell construct such as tt(if), tt(for), etc., in order that the entire block of code diff --git a/Doc/Zsh/mod_complist.yo b/Doc/Zsh/mod_complist.yo index 31aa656f1..463486ff9 100644 --- a/Doc/Zsh/mod_complist.yo +++ b/Doc/Zsh/mod_complist.yo @@ -134,7 +134,10 @@ matches beginning with `tt(m)' in groups whose names begin with Note also that all patterns are tried in the order in which they appear in the parameter value until the first one matches which is -then used. +then used. Patterns may be matched against completions, descriptions +(possibly with spaces appended for padding), or lines consisting of a +completion followed by a description. For consistent coloring it may be +necessary to use more than one pattern or a pattern with backreferences. When printing a match, the code prints the value of tt(lc), the value for the file-type or the last matching specification with a `tt(*)', diff --git a/Doc/Zsh/mod_curses.yo b/Doc/Zsh/mod_curses.yo index 72dc4094a..6e4831abe 100644 --- a/Doc/Zsh/mod_curses.yo +++ b/Doc/Zsh/mod_curses.yo @@ -27,7 +27,8 @@ xitem(tt(zcurses) tt(scroll) var(targetwin) [ tt(on) | tt(off) | [tt(+)|tt(-)]va xitem(tt(zcurses) tt(input) var(targetwin) [ var(param) [ var(kparam) [ var(mparam) ] ] ]) xitem(tt(zcurses) tt(mouse) [ tt(delay) var(num) | [tt(+)|tt(-)]tt(motion) ]) xitem(tt(zcurses) tt(timeout) var(targetwin) var(intval)) -item(tt(zcurses) tt(querychar) var(targetwin) [ var(param) ])( +xitem(tt(zcurses) tt(querychar) var(targetwin) [ var(param) ]) +item(tt(zcurses) tt(resize) var(height) var(width) [ tt(endwin) | tt(nosave) | tt(endwin_nosave) ])( Manipulate curses windows. All uses of this command should be bracketed by `tt(zcurses init)' to initialise use of curses, and `tt(zcurses end)' to end it; omitting `tt(zcurses end)' can cause @@ -211,6 +212,21 @@ second is the color pair in the usual var(fg_col)tt(/)var(bg_col) notation, or tt(0) if color is not supported. Any attributes other than color that apply to the character, as set with the subcommand tt(attr), appear as additional elements. + +The subcommand tt(resize) resizes tt(stdscr) and all windows to given +dimensions (windows that stick out from the new dimensions are resized +down). The underlying curses extension (tt(resize_term call)) can be +unavailable. To verify, zeroes can be used for var(height) and +var(width). If the result of the subcommand is tt(0), resize_term is +available (tt(2) otherwise). Tests show that resizing can be normally +accomplished by calling tt(zcurses end) and tt(zcurses refresh). The +tt(resize) subcommand is provided for versatility. Multiple system +configurations have been checked and tt(zcurses end) and tt(zcurses +refresh) are still needed for correct terminal state after resize. To +invoke them with tt(resize), use var(endwin) argument. Using +var(nosave) argument will cause new terminal state to not be saved +internally by tt(zcurses). This is also provided for versatility and +should normally be not needed. ) enditem() diff --git a/Doc/Zsh/mod_db_gdbm.yo b/Doc/Zsh/mod_db_gdbm.yo index 90974297c..699e9ab93 100644 --- a/Doc/Zsh/mod_db_gdbm.yo +++ b/Doc/Zsh/mod_db_gdbm.yo @@ -43,6 +43,17 @@ local scope (function) ends. Note that a readonly parameter may not be explicitly unset, so the only way to unset a global parameter created with `tt(ztie -r)' is to use `tt(zuntie -u)'. ) +findex(zgdbmpath) +cindex(database file path, reading) +item(tt(zgdbmpath) var(parametername))( +Put path to database file assigned to var(parametername) into tt(REPLY) +scalar. +) +findex(zgdbm_tied) +cindex(database tied arrays, enumerating) +item(tt(zgdbm_tied))( +Array holding names of all tied parameters. +) enditem() The fields of an associative array tied to GDBM are neither cached nor diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo index 3d260f8e9..942e4c5b6 100644 --- a/Doc/Zsh/mod_parameter.yo +++ b/Doc/Zsh/mod_parameter.yo @@ -37,6 +37,30 @@ vindex(dis_functions) item(tt(dis_functions))( Like tt(functions) but for disabled functions. ) +vindex(functions_source) +item(tt(functions_source))( +This readonly associative array maps names of enabled functions to the +name of the file containing the source of the function. + +For an autoloaded function that has already been loaded, or marked for +autoload with an absolute path, or that has had its path resolved with +`tt(functions -r)', this is the file found for autoloading, resolved +to an absolute path. + +For a function defined within the body of a script or sourced file, +this is the name of that file. In this case, this is the exact path +originally used to that file, which may be a relative path. + +For any other function, including any defined at an interactive prompt or +an autoload function whose path has not yet been resolved, this is +the empty string. However, the hash element is reported as defined +just so long as the function is present: the keys to this hash are +the same as those to tt($funcions). +) +vindex(dis_functions_source) +item(tt(dis_functions_source))( +Like tt(functions_source) but for disabled functions. +) vindex(builtins) item(tt(builtins))( This associative array gives information about the builtin commands @@ -202,10 +226,13 @@ defined. The line number is the line where the `tt(function) var(name)' or `var(name) tt(LPAR()RPAR())' started. In the case of an autoloaded function the line number is reported as zero. The format of each element is var(filename)tt(:)var(lineno). + For functions autoloaded from a file in native zsh format, where only the body of the function occurs in the file, or for files that have been executed by the tt(source) or `tt(.)' builtins, the trace information is -shown as var(filename)tt(:)var(0), since the entire file is the definition. +shown as var(filename)tt(:)var(0), since the entire file is the +definition. The source file name is resolved to an absolute path when +the function is loaded or the path to it otherwise resolved. Most users will be interested in the information in the tt(funcfiletrace) array instead. diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index dc17161f1..8331eabb7 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -179,7 +179,7 @@ item(tt(zregexparse))( This implements some internals of the tt(_regex_arguments) function. ) findex(zparseopts) -item(tt(zparseopts) [ tt(-D) tt(-K) tt(-M) tt(-E) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] var(spec) ...)( +item(tt(zparseopts) [ tt(-D) tt(-K) tt(-M) tt(-E) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] [ 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 diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index f68a945ec..70092d681 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -395,8 +395,9 @@ pindex(RECEXACT) pindex(NORECEXACT) cindex(completion, exact matches) item(tt(REC_EXACT) (tt(-S)))( -In completion, recognize exact matches even -if they are ambiguous. +If the string on the command line exactly matches one of the possible +completions, it is accepted, even if there is another completion (i.e. that +string with something else added) that also matches. ) enditem() @@ -722,9 +723,10 @@ pindex(REMATCHPCRE) pindex(NOREMATCHPCRE) cindex(regexp, PCRE) cindex(PCRE, regexp) -item(tt(REMATCH_PCRE) <Z>)( +item(tt(REMATCH_PCRE))( If set, regular expression matching with the tt(=~) operator will use -Perl-Compatible Regular Expressions from the PCRE library, if available. +Perl-Compatible Regular Expressions from the PCRE library. +(The tt(zsh/pcre) module must be available.) If not set, regular expressions will use the extended regexp syntax provided by the system libraries. ) @@ -768,6 +770,37 @@ global from within a function using tt(typeset -g) do not cause a warning. Note that there is no warning when a local parameter is assigned to in a nested function, which may also indicate an error. ) +pindex(WARN_NESTED_VAR) +pindex(NO_WARN_NESTED_VAR) +pindex(WARNNESTEDVAR) +pindex(NO_WARNNESTEDVAR) +cindex(parameters, warning when setting in enclosing scope) +item(tt(WARN_NESTED_VAR))( +Print a warning message when an existing parameter from an +enclosing function scope, or global, is set in a function +by an assignment or in math context. Assignment to shell +special parameters does not cause a warning. This is the companion +to tt(WARN_CREATE_GLOBAL) as in this case the warning is only +printed when a parameter is em(not) created. Where possible, +use of tt(typeset -g) to set the parameter suppresses the error, +but note that this needs to be used every time the parameter is set. +To restrict the effect of this option to a single function scope, +use `tt(functions -W)'. + +For example, the following code produces a warning for the assignment +inside the function tt(nested) as that overrides the value within +tt(toplevel) + +example(toplevel+LPAR()RPAR() { + local foo="in fn" + nested +} +nested+LPAR()RPAR() { + foo="in nested" +} +setopt warn_nested_var +toplevel) +) enditem() subsect(History) @@ -1539,6 +1572,36 @@ enditem() subsect(Scripts and Functions) startitem() +pindex(ALIAS_FUNC_DEF) +pindex(NO_ALIAS_FUNC_DEF) +pindex(ALIASFUNCDEF) +pindex(NOALIASFUNCDEF) +cindex(functions, defining with expanded aliases) +cindex(aliases, expanding in function definition) +item(tt(ALIAS_FUNC_DEF) <S>)( +By default, zsh does not allow the definition of functions using +the `var(name) tt(LPAR()RPAR())' syntax if var(name) was expanded as an +alias: this causes an error. This is usually the desired behaviour, as +otherwise the combination of an alias and a function based on the same +definition can easily cause problems. + +When this option is set, aliases can be used for defining functions. + +For example, consider the following definitions as they might +occur in a startup file. + +example(alias foo=bar +foo+LPAR()RPAR() { + print This probably does not do what you expect. +}) + +Here, tt(foo) is expanded as an alias to tt(bar) before the +tt(LPAR()RPAR()) is encountered, so the function defined would be named +tt(bar). By default this is instead an error in native mode. Note that +quoting any part of the function name, or using the keyword +tt(function), avoids the problem, so is recommended when the function +name can also be an alias. +) pindex(C_BASES) pindex(NO_C_BASES) pindex(CBASES) @@ -2077,6 +2140,10 @@ In addition, various error conditions associated with the above builtins or tt(exec) cause a non-interactive shell to exit and an interactive shell to return to its top-level processing. +Furthermore, functions and shell builtins are not executed after +an tt(exec) prefix; the command to be executed must be an external +command found in the path. + Furthermore, the tt(getopts) builtin behaves in a POSIX-compatible fashion in that the associated variable tt(OPTIND) is not made local to functions. diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 905e92d22..817496b8a 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -952,8 +952,8 @@ of zsh. ) vindex(ZSH_PATCHLEVEL) item(tt(ZSH_PATCHLEVEL))( -The revision string for the version number of the ChangeLog file -in the zsh distribution. This is most useful in order to keep +The output of `tt(git describe --tags --long)' for the zsh repository +used to build the shell. This is most useful in order to keep track of versions of the shell during development between releases; hence most users should not use it and should instead rely on tt($ZSH_VERSION). diff --git a/Doc/Zsh/roadmap.yo b/Doc/Zsh/roadmap.yo index bd064e2b2..94ef74d1f 100644 --- a/Doc/Zsh/roadmap.yo +++ b/Doc/Zsh/roadmap.yo @@ -139,6 +139,9 @@ startitem() item(tt(**))( for matching over multiple directories ) +item(tt(|))( +for matching either of two alternatives +) item(tt(~), tt(^))( the ability to exclude patterns from matching when the tt(EXTENDED_GLOB) option is set diff --git a/Doc/Zsh/seealso.yo b/Doc/Zsh/seealso.yo index 73c7fa673..7a78c481b 100644 --- a/Doc/Zsh/seealso.yo +++ b/Doc/Zsh/seealso.yo @@ -8,15 +8,21 @@ manref(bash)(1), manref(ksh)(1)\ ifzshone(\ , +zmanref(zshall), zmanref(zshbuiltins), +zmanref(zshcalsys), zmanref(zshcompwid), zmanref(zshcompsys), zmanref(zshcompctl), +zmanref(zshcontrib), zmanref(zshexpn), zmanref(zshmisc), zmanref(zshmodules), zmanref(zshoptions), zmanref(zshparam), +zmanref(zshroadmap), +zmanref(zshtcpsys), +zmanref(zshzftpsys), zmanref(zshzle)\ )\ diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index d68365b94..bd0252f6e 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -750,12 +750,12 @@ sect(User-Defined Widgets) cindex(widgets, user-defined) User-defined widgets, being implemented as shell functions, can execute any normal shell command. They can also run other widgets -(whether built-in or user-defined) using the tt(zle) builtin command. -The standard input of the function is closed to prevent external commands -from unintentionally blocking ZLE by reading from the terminal, but -tt(read -k) or tt(read -q) can be used to read characters. Finally, -they can examine and edit the ZLE buffer being edited by -reading and setting the special parameters described below. +(whether built-in or user-defined) using the tt(zle) builtin command. The +standard input of the function is redirected from /dev/null to prevent +external commands from unintentionally blocking ZLE by reading from the +terminal, but tt(read -k) or tt(read -q) can be used to read characters. +Finally, they can examine and edit the ZLE buffer being edited by reading +and setting the special parameters described below. cindex(parameters, editor) cindex(parameters, zle) @@ -864,6 +864,12 @@ vindex(KEYS) item(tt(KEYS) (scalar))( The keys typed to invoke this widget, as a literal string; read-only. ) +vindex(KEYS_QUEUED_COUNT) +item(tt(KEYS_QUEUED_COUNT) (integer))( +The number of bytes pushed back to the input queue and therefore +available for reading immediately before any I/O is done; read-only. +See also tt(PENDING); the two values are distinct. +) vindex(killring) item(tt(killring) (array))( The array of previously killed items, with the most recently killed first. @@ -919,7 +925,8 @@ item(tt(PENDING) (integer))( The number of bytes pending for input, i.e. the number of bytes which have already been typed and can immediately be read. On systems where the shell is not able to get this information, this parameter will always have a -value of zero. Read-only. +value of zero. Read-only. See also tt(KEYS_QUEUED_COUNT); the two +values are distinct. ) vindex(PREBUFFER) item(tt(PREBUFFER) (scalar))( @@ -12,6 +12,17 @@ the nonomatch and nullglob options. ------------------------------------------------------------------------ It is currently impossible to time builtins. ------------------------------------------------------------------------ -The comp* completion-related builtins (compadd, compset, etc) are run with -$_comp_options in effect, rather than the user's options. +40106: The comp* completion-related builtins (compadd, compset, etc) are +run with $_comp_options in effect, rather than the user's options. +------------------------------------------------------------------------ +users/20807: vcs_info quilt 'addon' mode: hook lookup context specifies +the underlying VCS but not whether quilt is used. + +Workaround: test (( ${+funcstack[(r)VCS_INFO_quilt]} )). +------------------------------------------------------------------------ +41184: 'exec' optimization for last command in a subshell should be +skipped when STTY=... is set for that command +------------------------------------------------------------------------ +41203 and others: Make it easier to maintain C modules out of tree. +(May require defining a stable API for modules, see 41254) ------------------------------------------------------------------------ diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo index 6b635ea3e..689b90022 100644 --- a/Etc/FAQ.yo +++ b/Etc/FAQ.yo @@ -306,7 +306,7 @@ sect(On what machines will it run?) sect(What's the latest version?) - Zsh 5.3.1 is the latest production version. For details of all the + Zsh 5.4.1 is the latest production version. For details of all the changes, see the NEWS file in the source distribution. A beta of the next version is sometimes available. Development of zsh is diff --git a/Etc/completion-style-guide b/Etc/completion-style-guide index e91e92307..a6fc737a7 100644 --- a/Etc/completion-style-guide +++ b/Etc/completion-style-guide @@ -64,7 +64,7 @@ tells _wanted where to put options specifying the `directory' description. Where two matches have identical meaning, give them the same description so that the completion system can group them together. Conventionally a brace expansion of this form is used: - '(--context,-C)'{--context=,-C-}'[specify lines of context]:lines' + '(--context -C)'{--context=,-C-}'[specify lines of context]:lines' You won't need the exclusion list if the option can be specified multiple times. It can also be useful to use the same description for matches which are completely opposite in their meaning if it shortens diff --git a/Functions/Misc/run-help-ip b/Functions/Misc/run-help-ip index 740af52b5..8807f9ef1 100644 --- a/Functions/Misc/run-help-ip +++ b/Functions/Misc/run-help-ip @@ -19,8 +19,8 @@ while [[ $# != 0 && $1 == -* ]]; do done case $1 in - (addr*) man ip-address ;; - (addrlabel) man ip-addrlabel ;; + (addrl*) man ip-addrlabel ;; + (a*) man ip-address ;; (l2*) man ip-l2tp ;; (li*) man ip-link ;; (ma*) man ip-maddress ;; diff --git a/Functions/Misc/zed b/Functions/Misc/zed index 77d392bc3..33bd1025b 100644 --- a/Functions/Misc/zed +++ b/Functions/Misc/zed @@ -39,6 +39,24 @@ local curcontext=zed::: zstyle -m ":completion:zed:*" insert-tab '*' || zstyle ":completion:zed:*" insert-tab yes +zmodload zsh/terminfo 2>/dev/null + +__zed_pg_up() +{ + integer count=$(( LINES / 2 - 1 )) + while (( count -- )); do + zle up-line + done +} + +__zed_pg_down() +{ + integer count=$(( LINES / 2 - 1 )) + while (( count -- )); do + zle down-line + done +} + if (( bind )) || ! bindkey -M zed >&/dev/null; then # Make the zed keymap a copy of the current main. bindkey -N zed main @@ -54,6 +72,11 @@ if (( bind )) || ! bindkey -M zed >&/dev/null; then bindkey -M zed '^x^w' accept-line bindkey -M zed '^M' self-insert-unmeta + zle -N __zed_pg_up + zle -N __zed_pg_down + [[ ${+terminfo} = 1 && -n "$terminfo[kpp]" ]] && bindkey -M zed "$terminfo[kpp]" __zed_pg_up + [[ ${+terminfo} = 1 && -n "$terminfo[knp]" ]] && bindkey -M zed "$terminfo[knp]" __zed_pg_down + # Make zed-set-file-name available. # Assume it's in fpath; there's no error at this point if it isn't autoload -Uz zed-set-file-name diff --git a/Functions/Prompts/prompt_bart_setup b/Functions/Prompts/prompt_bart_setup index cb032de8a..6de412231 100644 --- a/Functions/Prompts/prompt_bart_setup +++ b/Functions/Prompts/prompt_bart_setup @@ -16,9 +16,13 @@ prompt_bart_help () { blue, and the default foreground) are used if no arguments are given. The defaults look best on a light background. - The "off" token temporarily disables the theme; "on" restores it. No background colors or hardwired cursor motion escapes are used, and it is not necessary to setopt promptsubst. + + The "off" token temporarily disables the theme; "on" restores it. + Note, this does NOT fully reset to the original prompt state, it + only hides/reveals the extra lines above the command line and + removes the supporting hooks. EOF [[ $(read -sek 1 "?${(%):-%S[press return]%s}") == [Qq] ]] && print -nP '\r%E' && return @@ -183,7 +187,7 @@ prompt_bart_setup () { add-zsh-hook -D preexec "prompt_*_preexec" functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_bart_winch}" [[ $prompt_theme[1] = bart ]] && PS1=${${(f)PS1}[-1]} - return 1 + return 1 # Prevent change of $prompt_theme ;; (on|enable) shift @@ -224,6 +228,8 @@ prompt_bart_setup () { add-zsh-hook precmd prompt_bart_precmd add-zsh-hook preexec prompt_bart_preexec + prompt_cleanup \ + 'functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_bart_winch}"' functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_bart_winch} prompt_bart_winch" diff --git a/Functions/Prompts/prompt_default_setup b/Functions/Prompts/prompt_default_setup new file mode 100644 index 000000000..aed74eb67 --- /dev/null +++ b/Functions/Prompts/prompt_default_setup @@ -0,0 +1,7 @@ +PS1='%m%# ' +PS2='%_> ' +PS3='?# ' +PS4='+%N:%i> ' +unset RPS1 RPS2 RPROMPT RPROMPT2 + +prompt_opts=( cr percent sp ) diff --git a/Functions/Prompts/prompt_off_setup b/Functions/Prompts/prompt_off_setup index f604b477f..e6d16bfd9 100644 --- a/Functions/Prompts/prompt_off_setup +++ b/Functions/Prompts/prompt_off_setup @@ -1,9 +1,10 @@ # Very simple prompt -prompt_off_setup () { - PS1="%# " - PS2="> " - prompt_opts=( cr percent ) -} +prompt_default_setup 2>/dev/null -prompt_off_setup "$@" +PS1="%# " +PS2="> " +PS3='?# ' +PS4='+> ' + +prompt_opts=( cr percent sp ) diff --git a/Functions/Prompts/prompt_restore_setup b/Functions/Prompts/prompt_restore_setup new file mode 100644 index 000000000..54c4adbf9 --- /dev/null +++ b/Functions/Prompts/prompt_restore_setup @@ -0,0 +1,2 @@ +# Damn that was easy +zstyle -t :prompt-theme cleanup diff --git a/Functions/Prompts/prompt_walters_setup b/Functions/Prompts/prompt_walters_setup index 7948254d8..9fea574d0 100644 --- a/Functions/Prompts/prompt_walters_setup +++ b/Functions/Prompts/prompt_walters_setup @@ -14,10 +14,10 @@ EOF prompt_walters_setup () { if [[ "$TERM" != "dumb" ]]; then - PROMPT='%B%(?..[%?] )%b%n@%U%m%u> ' - RPROMPT="%F{${1:-green}}%~%f" + PS1='%B%(?..[%?] )%b%n@%U%m%u> ' + RPS1="%F{${1:-green}}%~%f" else - PROMPT="%(?..[%?] )%n@%m:%~> " + PS1="%(?..[%?] )%n@%m:%~> " fi prompt_opts=(cr percent) diff --git a/Functions/Prompts/promptinit b/Functions/Prompts/promptinit index 587248997..e27b8779a 100644 --- a/Functions/Prompts/promptinit +++ b/Functions/Prompts/promptinit @@ -47,20 +47,36 @@ prompt_preview_safely() { return fi - local -a psv; psv=($psvar); local -a +h psvar; psvar=($psv) # Ick - local +h PS1=$PS1 PS2=$PS2 PS3=$PS3 PS4=$PS4 RPS1=$RPS1 - local -a precmd_functions preexec_functions - - # The next line is a bit ugly. It (perhaps unnecessarily) - # runs the prompt theme setup function to ensure that if - # the theme has a _preview function that it's been autoloaded. - prompt_${1}_setup - - if typeset +f prompt_${1}_preview >&/dev/null; then - prompt_${1}_preview "$@[2,-1]" - else - prompt_preview_theme "$@" - fi + # This handles all the stuff from the default :prompt-theme cleanup + local +h PS1=$PS1 PS2=$PS2 PS3=$PS3 PS4=$PS4 RPS1=$RPS1 RPS2=$RPS2 + local +h PROMPT=$PROMPT RPROMPT=$RPOMPT RPROMPT2=$RPROMPT2 PSVAR=$PSVAR + local -a precmd_functions preexec_functions prompt_preview_cleanup + local -aLl +h zle_highlight + + { + # Save and clear current restore-point if any + zstyle -g prompt_preview_cleanup :prompt-theme cleanup + { + zstyle -d :prompt-theme cleanup + + # The next line is a bit ugly. It (perhaps unnecessarily) + # runs the prompt theme setup function to ensure that if + # the theme has a _preview function that it's been autoloaded. + prompt_${1}_setup + + if typeset +f prompt_${1}_preview >&/dev/null; then + prompt_${1}_preview "$@[2,-1]" + else + prompt_preview_theme "$@" + fi + } always { + # Run any theme-specific cleanup, then reset restore point + zstyle -t :prompt-theme cleanup + } + } always { + (( $#prompt_preview_cleanup )) && + zstyle -e :prompt-theme cleanup "${prompt_preview_cleanup[@]}" + } } set_prompt() { @@ -84,9 +100,9 @@ Use prompt -h <theme> for help on specific themes.' setopt localtraps if [[ -z "$prompt_theme[1]" ]]; then # Not using a prompt theme; save settings - local -a psv; psv=($psvar); local -a +h psvar; psvar=($psv) # Ick - local +h PS1=$PS1 PS2=$PS2 PS3=$PS3 PS4=$PS4 RPS1=$RPS1 - local precmd_functions preexec_functions + local +h PS1=$PS1 PS2=$PS2 PS3=$PS3 PS4=$PS4 RPS1=$RPS1 RPS2=$RPS2 + local +h PROMPT=$PROMPT RPROMPT=$RPOMPT RPROMPT2=$RPROMPT2 PSVAR=$PSVAR + local -a precmd_functions preexec_functions else trap 'prompt_${prompt_theme[1]}_setup "${(@)prompt_theme[2,-1]}"' 0 fi @@ -104,11 +120,11 @@ Use prompt -h <theme> for help on specific themes.' ;; h) if [[ -n "$2" && -n $prompt_themes[(r)$2] ]]; then if functions prompt_$2_setup >/dev/null; then - # The next line is a bit ugly. It (perhaps unnecessarily) - # runs the prompt theme setup function to ensure that if - # the theme has a _help function that it's been autoloaded. - prompt_$2_setup - fi + # The next line is a bit ugly. It (perhaps unnecessarily) + # runs the prompt theme setup function to ensure that if + # the theme has a _help function that it's been autoloaded. + prompt_$2_setup + fi if functions prompt_$2_help >/dev/null; then print "Help for $2 theme:\n" prompt_$2_help @@ -168,28 +184,74 @@ Use prompt -h <theme> for help on specific themes.' esac } +prompt_cleanup () { + local -a cleanup_hooks + if zstyle -g cleanup_hooks :prompt-theme cleanup + then + cleanup_hooks+=(';' "$@") + zstyle -e :prompt-theme cleanup "${cleanup_hooks[@]}" + elif (( $+prompt_preview_cleanup == 0 )) + then + print -u2 "prompt_cleanup: no prompt theme active" + return 1 + fi +} + prompt () { - local prompt_opts + local -a prompt_opts theme_active + zstyle -g theme_active :prompt-theme cleanup || { + # This is done here rather than in set_prompt so that it + # is safe and sane for set_prompt to setopt localoptions, + # which will be cleared before we arrive back here again. + # This is also why we pass around the prompt_opts array. + [[ -o promptbang ]] && prompt_opts+=(bang) + [[ -o promptcr ]] && prompt_opts+=(cr) + [[ -o promptpercent ]] && prompt_opts+=(percent) + [[ -o promptsp ]] && prompt_opts+=(sp) + [[ -o promptsubst ]] && prompt_opts+=(subst) + zstyle -e :prompt-theme cleanup \ + 'zstyle -d :prompt-theme cleanup;' \ + 'prompt_default_setup;' \ + ${PS1+PS1="${(q)PS1}"} \ + ${PS2+PS2="${(q)PS2}"} \ + ${PS3+PS3="${(q)PS3}"} \ + ${PS4+PS4="${(q)PS4}"} \ + ${RPS1+RPS1="${(q)RPS1}"} \ + ${RPS2+RPS2="${(q)RPS2}"} \ + ${RPROMPT+RPROMPT="${(q)RPROMPT}"} \ + ${RPROMPT2+RPROMPT2="${(q)RPROMPT2}"} \ + ${PSVAR+PSVAR="${(q)PSVAR}"} \ + "precmd_functions=(${(q)precmd_functions[@]})" \ + "preexec_functions=(${(q)preexec_functions[@]})" \ + "prompt_opts=( ${prompt_opts[*]} )" \ + 'reply=(yes)' + } set_prompt "$@" - (( $#prompt_opts )) && - setopt noprompt{bang,cr,percent,subst} "prompt${^prompt_opts[@]}" + (( ${#prompt_opts} )) && + setopt noprompt{bang,cr,percent,sp,subst} "prompt${^prompt_opts[@]}" true } prompt_preview_theme () { emulate -L zsh - local -a psv; psv=($psvar); local -a +h psvar; psvar=($psv) # Ick - local +h PS1=$PS1 PS2=$PS2 PS3=$PS3 PS4=$PS4 RPS1=$RPS1 - local precmd_functions preexec_functions prompt_opts - local -aLl +h zle_highlight + # Check for proper state handling + (( $+prompt_preview_cleanup )) || { + prompt_preview_safely "$@" + return + } + + # Minimal preview for prompts that don't supply one + local -a prompt_opts print -n "$1 theme" (( $#* > 1 )) && print -n " with parameters \`$*[2,-1]'" print ":" prompt_${1}_setup "$@[2,-1]" + (( ${#prompt_opts} )) && + setopt noprompt{bang,cr,percent,sp,subst} "prompt${^prompt_opts[@]}" [[ -n ${precmd_functions[(r)prompt_${1}_precmd]} ]] && prompt_${1}_precmd [[ -o promptcr ]] && print -n $'\r'; : diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git index 63109aa46..f3dd95dcb 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git @@ -120,41 +120,15 @@ VCS_INFO_git_getbranch () { } VCS_INFO_git_handle_patches () { - local git_applied_s git_unapplied_s gitmsg git_all + local git_applied_s git_unapplied_s gitmsg git_patches_applied=(${(Oa)git_patches_applied}) git_patches_unapplied=(${(Oa)git_patches_unapplied}) - (( git_all = ${#git_patches_applied} + ${#git_patches_unapplied} )) - if VCS_INFO_hook 'gen-applied-string' "${git_patches_applied[@]}"; then - if (( ${#git_patches_applied} )); then - git_applied_s=${git_patches_applied[1]} - else - git_applied_s="" - fi - else - git_applied_s=${hook_com[applied-string]} - fi - hook_com=() - if VCS_INFO_hook 'gen-unapplied-string' "${git_patches_unapplied[@]}"; then - git_patches_unapplied=${#git_patches_unapplied} - else - git_patches_unapplied=${hook_com[unapplied-string]} - fi - - if (( ${#git_patches_applied} )); then - zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" patch-format gitmsg || gitmsg="%p (%n applied)" - else - zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" nopatch-format gitmsg || gitmsg="no patch applied" - fi - hook_com=( applied "${git_applied_s}" unapplied "${git_patches_unapplied}" - applied-n ${#git_patches_applied} unapplied-n ${#git_patches_unapplied} all-n ${git_all} ) - if VCS_INFO_hook 'set-patch-format' "${gitmsg}"; then - zformat -f gitmisc "${gitmsg}" "p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \ - "n:${#git_patches_applied}" "c:${#git_patches_unapplied}" "a:${git_all}" - else - gitmisc=${hook_com[patch-replace]} - fi - hook_com=() + VCS_INFO_set-patch-format 'git_patches_applied' 'git_applied_s' \ + 'git_patches_unapplied' 'git_unapplied_s' \ + ":vcs_info:${vcs}:${usercontext}:${rrn}" gitmsg \ + '' '' + gitmisc=$REPLY } gitdir=${vcs_comm[gitdir]} @@ -182,7 +156,7 @@ if (( querystaged || queryunstaged )) && \ [[ "$(${vcs_comm[cmd]} rev-parse --is-inside-work-tree 2> /dev/null)" == 'true' ]] ; then # Default: off - these are potentially expensive on big repositories if (( queryunstaged )) ; then - ${vcs_comm[cmd]} diff --no-ext-diff --ignore-submodules=dirty --quiet --exit-code || + ${vcs_comm[cmd]} diff --no-ext-diff --ignore-submodules=dirty --quiet --exit-code 2> /dev/null || gitunstaged=1 fi if (( querystaged )) ; then @@ -205,6 +179,7 @@ local patchdir=${gitdir}/patches/${gitbranch} if [[ -d $patchdir ]] && [[ -f $patchdir/applied ]] \ && [[ -f $patchdir/unapplied ]] then + # stgit git_patches_applied=(${(f)"$(< "${patchdir}/applied")"}) git_patches_unapplied=(${(f)"$(< "${patchdir}/unapplied")"}) VCS_INFO_git_handle_patches diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg index 69b7db304..d4030125c 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg @@ -13,7 +13,7 @@ local hgbase bmfile branchfile rebasefile dirstatefile mqseriesfile \ hgbmstring hgmqstring applied_string unapplied_string guards_string local -a hgid_args defrevformat defbranchformat \ - hgbmarks mqpatches mqseries mqguards mqunapplied hgmisc \ + hgbmarks mqpatches mqguards mqunapplied hgmisc \ i_patchguards i_negguards i_posguards local -A hook_com @@ -175,9 +175,6 @@ if zstyle -T ":vcs_info:${vcs}:${usercontext}:${rrn}" get-mq \ # Skip commented lines [[ ${i_patch} == [[:space:]]#"#"* ]] && continue - # Keep list of all patches - mqseries+=( $i_patch ) - # Separate negative and positive guards to more easily find the # intersection of active guards with patch guards i_patchguards=( ${(s: :)i_patchguards} ) @@ -203,50 +200,21 @@ if zstyle -T ":vcs_info:${vcs}:${usercontext}:${rrn}" get-mq \ done < ${mqseriesfile} fi - if VCS_INFO_hook 'gen-applied-string' "${mqpatches[@]}"; then - (( ${#mqpatches} )) && applied_string=${mqpatches[1]} - else - applied_string=${hook_com[applied-string]} - fi - - hook_com=() - - if VCS_INFO_hook 'gen-unapplied-string' "${mqunapplied[@]}"; then - unapplied_string=${#mqunapplied} - else - unapplied_string=${hook_com[unapplied-string]} - fi - - hook_com=() - if VCS_INFO_hook 'gen-mqguards-string' "${mqguards[@]}"; then guards_string=${(j:,:)mqguards} + # TODO: %-escape extra_zformats[g:...] value else guards_string=${hook_com[guards-string]} fi - if (( ${#mqpatches} )); then - zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" patch-format \ - hgmqstring || hgmqstring="%p (%n applied)" - else - zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" nopatch-format \ - hgmqstring || hgmqstring="no patch applied" - fi - - hook_com=( applied "${applied_string}" unapplied "${unapplied_string}" - applied-n ${#mqpatches} unapplied-n ${#mqunapplied} all-n ${#mqseries} - guards "${guards_string}" guards-n ${#mqguards} ) + local -A extra_hook_com=( guards "${guards_string}" guards-n ${#mqguards} ) + local -a extra_zformats=( "g:${extra_hook_com[guards]}" "G:${#mqguards}" ) - if VCS_INFO_hook 'set-patch-format' ${qstring}; then - zformat -f hgmqstring "${hgmqstring}" \ - "p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \ - "n:${#mqpatches}" "c:${#mqunapplied}" "a:${#mqseries}" \ - "g:${hook_com[guards]}" "G:${#mqguards}" - else - hgmqstring=${hook_com[patch-replace]} - fi - - hook_com=() + VCS_INFO_set-patch-format 'mqpatches' 'applied_string' \ + 'mqunapplied' 'unapplied_string' \ + ":vcs_info:${vcs}:${usercontext}:${rrn}" hgmqstring \ + extra_hook_com extra_zformats + hgmqstring=$REPLY fi diff --git a/Functions/VCS_Info/VCS_INFO_patch2subject b/Functions/VCS_Info/VCS_INFO_patch2subject index 583467bc8..e222e8382 100644 --- a/Functions/VCS_Info/VCS_INFO_patch2subject +++ b/Functions/VCS_Info/VCS_INFO_patch2subject @@ -1,6 +1,7 @@ # This function takes as an argument a filename of a patch and sets $REPLY to # a single-line "subject", or unsets it if no subject could be extracted. { + setopt localoptions extendedglob integer i integer -r LIMIT=10 local -a lines @@ -34,6 +35,22 @@ elif [[ ${lines[1]} == '# HG changeset patch' ]] && { needle=${${lines:#([#]*)}[1]}; [[ -n $needle ]] }; then # Mercurial patch REPLY=$needle + elif [[ ${lines[1]} == "commit "[0-9a-f](#c40) ]] && + [[ ${lines[2]} == "Author:"* && ${lines[3]} == "Date:"* ]] && + (( ! ${+lines[4]} )); then + # `git show` output. + # + # The log message is after the first blank line, so open() the file + # again. Also check whether the following line (second line of the + # log message itself) is empty. + { + repeat 4 { IFS= read -r } + IFS= read -r needle; needle=${needle#' '} + if IFS= read -r; REPLY=${REPLY#' '}; [[ -n $REPLY ]]; then + needle+='...' + fi + } < "$1" + REPLY=$needle elif (( ${+lines[1]} )); then # The first line of the file is not part of the diff. REPLY=${lines[1]} diff --git a/Functions/VCS_Info/VCS_INFO_quilt b/Functions/VCS_Info/VCS_INFO_quilt index 4c61506cd..381b58489 100644 --- a/Functions/VCS_Info/VCS_INFO_quilt +++ b/Functions/VCS_Info/VCS_INFO_quilt @@ -91,7 +91,7 @@ function VCS_INFO_quilt() { local patches pc tmp qstring root local -i ret local context - local -a applied unapplied all applied_string unapplied_string quiltcommand quilt_env + local -a applied unapplied applied_string unapplied_string quiltcommand quilt_env local -A hook_com context=":vcs_info:${vcs}.quilt-${mode}:${usercontext}:${rrn}" @@ -171,41 +171,15 @@ function VCS_INFO_quilt() { } fi - all=( ${(Oa)applied} ${unapplied} ) - - if VCS_INFO_hook 'gen-applied-string' "${applied[@]}"; then - if (( ${#applied} )); then - applied_string=${applied[1]} - else - applied_string="" - fi - else - applied_string=${hook_com[applied-string]} - fi - hook_com=() - if VCS_INFO_hook 'gen-unapplied-string' "${unapplied[@]}"; then - unapplied_string="${#unapplied}" - else - unapplied_string=${hook_com[unapplied-string]} - fi - - if (( ${#applied} )); then - zstyle -s "${context}" patch-format qstring || qstring="%p (%n applied)" - else - zstyle -s "${context}" nopatch-format qstring || qstring="no patch applied" - fi - hook_com=( applied "${applied_string}" unapplied "${unapplied_string}" - applied-n ${#applied} unapplied-n ${#unapplied} all-n ${#all} ) - if VCS_INFO_hook 'set-patch-format' ${qstring}; then - zformat -f qstring "${qstring}" "p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \ - "n:${#applied}" "c:${#unapplied}" "a:${#all}" - else - qstring=${hook_com[patch-replace]} - fi - hook_com=() + VCS_INFO_set-patch-format 'applied' 'applied_string' \ + 'unapplied' 'unapplied_string' \ + ${context} qstring \ + '' '' + qstring=$REPLY case ${mode} in (standalone) + backend_misc[patches]=${qstring} VCS_INFO_formats '' '' "${root}" '' '' '' "${qstring}" VCS_INFO_set ;; diff --git a/Functions/VCS_Info/VCS_INFO_set-patch-format b/Functions/VCS_Info/VCS_INFO_set-patch-format new file mode 100644 index 000000000..cdf2d303e --- /dev/null +++ b/Functions/VCS_Info/VCS_INFO_set-patch-format @@ -0,0 +1,79 @@ +# This function is the common guts of the gen-applied-string / +# gen-unapplied-string / set-patch-format dance of several backends. +# +# Parameters: +# $1 - name of an array parameter to be the argument to gen-applied-string +# $2 - name of a parameter to store the applied-string in +# $3 - name of an array parameter to be the argument to gen-unapplied-string +# $4 - name of a parameter to store the unapplied-string in +# $5 - context argument for use in zstyle getters +# $6 - name of a parameter to store a patch-format format string in +# $7 - name of an assoc parameter with extra $hook_com key-value pairs for the +# set-patch-format hook invocation, or '' for none +# $8 - name of an array parameter with extra arguments for the patch-format zformat call, or '' for empty +# +# The expanded patch-format string is returned in $REPLY. +# +# Output: +# - $hook_com is overwritten and the keys 'applied', 'applied-n', +# 'unapplied', 'unapplied-n', 'all-n' are set. +{ + local applied_needs_escaping='unknown' + local unapplied_needs_escaping='unknown' + if VCS_INFO_hook 'gen-applied-string' "${(@P)1}"; then + if (( ${(P)#1} )); then + REPLY=${(P)1[1]} + else + REPLY="" + fi + applied_needs_escaping='yes' + else + REPLY=${hook_com[applied-string]} + fi + : ${(P)2::=$REPLY} + hook_com=() + + if VCS_INFO_hook 'gen-unapplied-string' "${(@P)3}"; then + REPLY=${(P)#3} + unapplied_needs_escaping='yes' + else + REPLY=${hook_com[unapplied-string]} + fi + : ${(P)4::=$REPLY} + hook_com=() + + if (( ${(P)#1} )); then + zstyle -s "${5}" patch-format REPLY || REPLY="%p (%n applied)" + else + zstyle -s "${5}" nopatch-format REPLY || REPLY="no patch applied" + fi + : ${(P)6::=$REPLY} + + hook_com=( + applied-n ${(P)#1} + applied "${(P)2}" + unapplied-n ${(P)#3} + unapplied "${(P)4}" + ) + hook_com[all-n]=$(( ${hook_com[applied-n]} + ${hook_com[unapplied-n]} )) + hook_com+=( ${7:+"${(@kvP)7}"} ) + if VCS_INFO_hook 'set-patch-format' "${(P)6}"; then + # Escape the value for use in $PS1 + if [[ $applied_needs_escaping == 'yes' ]]; then + hook_com[applied]=${hook_com[applied]//'%'/%%} + fi + if [[ $unapplied_needs_escaping == 'yes' ]]; then + hook_com[unapplied]=${hook_com[unapplied]//'%'/%%} + fi + + zformat -f REPLY "${(P)6}" "p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \ + "n:${hook_com[applied-n]}" "c:${hook_com[unapplied-n]}" \ + "a:${hook_com[all-n]}" \ + ${8:+"${(@P)8}"} + else + unset applied_needs_escaping unapplied_needs_escaping # the hook deals with escaping + REPLY=${hook_com[patch-replace]} + fi + hook_com=() + +} diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info index 24ae98e52..4e9ac6c6a 100644 --- a/Functions/VCS_Info/vcs_info +++ b/Functions/VCS_Info/vcs_info @@ -21,6 +21,7 @@ static_functions=( VCS_INFO_get_cmd VCS_INFO_hexdump VCS_INFO_hook + VCS_INFO_set-patch-format VCS_INFO_maxexports VCS_INFO_nvcsformats VCS_INFO_patch2subject diff --git a/Functions/Zle/bracketed-paste-magic b/Functions/Zle/bracketed-paste-magic index c46f741d5..4baae823e 100644 --- a/Functions/Zle/bracketed-paste-magic +++ b/Functions/Zle/bracketed-paste-magic @@ -145,27 +145,26 @@ bracketed-paste-magic() { done fi - # Save context, create a clean slate for the paste - integer bpm_mark=$MARK bpm_cursor=$CURSOR bpm_region=$REGION_ACTIVE - integer bpm_numeric=${NUMERIC:-1} - local bpm_buffer=$BUFFER - fc -p -a /dev/null 0 0 - BUFFER= - zstyle -a :bracketed-paste-magic inactive-keys bpm_inactive if zstyle -s :bracketed-paste-magic active-widgets bpm_active '|'; then - # There are active widgets. Reprocess $PASTED as keystrokes. - NUMERIC=1 - zle -U - $PASTED - + # Save context, create a clean slate for the paste + integer bpm_mark=$MARK bpm_region=$REGION_ACTIVE + integer bpm_numeric=${NUMERIC:-1} + integer bpm_limit=$UNDO_LIMIT_NO bpm_undo=$UNDO_CHANGE_NO + zle .split-undo + UNDO_LIMIT_NO=$UNDO_CHANGE_NO + BUFFER= + CURSOR=1 + fc -p -a /dev/null 0 0 if [[ $bmp_keymap = vicmd ]]; then zle -K viins fi + # There are active widgets. Reprocess $PASTED as keystrokes. + NUMERIC=1 + zle -U - $PASTED + # Just in case there are active undo widgets - zle .split-undo - integer bpm_limit=$UNDO_LIMIT_NO bpm_undo=$UNDO_CHANGE_NO - UNDO_LIMIT_NO=$UNDO_CHANGE_NO while [[ -n $PASTED ]] && zle .read-command; do PASTED=${PASTED#$KEYS} @@ -183,21 +182,16 @@ bracketed-paste-magic() { done PASTED=$BUFFER - # Reset the undo state + # Restore state + zle -K $bpm_keymap + fc -P + MARK=$bpm_mark + REGION_ACTIVE=$bpm_region + NUMERIC=$bpm_numeric zle .undo $bpm_undo UNDO_LIMIT_NO=$bpm_limit - - zle -K $bpm_keymap fi - # Restore state - BUFFER=$bpm_buffer - MARK=$bpm_mark - CURSOR=$bpm_cursor - REGION_ACTIVE=$bpm_region - NUMERIC=$bpm_numeric - fc -P - # PASTED has been updated, run the paste-finish functions if zstyle -a :bracketed-paste-magic paste-finish bpm_hooks; then for bpm_func in $bpm_hooks; do diff --git a/Functions/Zle/insert-files b/Functions/Zle/insert-files index 10f90ed4a..2d13d82d2 100644 --- a/Functions/Zle/insert-files +++ b/Functions/Zle/insert-files @@ -12,7 +12,7 @@ setopt nobadpattern local key str files -files=( *(N) ) +files=( *(N:q) ) if (( $#files )); then zle -R "files: ${str}_" "$files[@]" else @@ -26,7 +26,7 @@ while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' && else str="$str$key" fi - eval "files=( \${~str}*(N) )" + eval "files=( \${~str}*(N:q) )" if (( $#files )); then zle -R "files: ${str}_" "$files[@]" else diff --git a/Functions/Zle/insert-unicode-char b/Functions/Zle/insert-unicode-char index af9aad914..b943fb7f7 100644 --- a/Functions/Zle/insert-unicode-char +++ b/Functions/Zle/insert-unicode-char @@ -12,11 +12,11 @@ then local -i 16 -Z 10 arg=$NUMERIC # ...and use print to turn this into a Unicode character. LBUFFER+="$(print -n "\U${arg##0x}")" - _insert_unicode_ready=0 + integer -g _insert_unicode_ready=0 else # Set the base to 16... zle argument-base 16 # ...wait for user to type hex keys then call this widget again. zle universal-argument - _insert_unicode_ready=1 + integer -g _insert_unicode_ready=1 fi diff --git a/Functions/Zle/url-quote-magic b/Functions/Zle/url-quote-magic index 7ee281ea4..cb7bf727a 100644 --- a/Functions/Zle/url-quote-magic +++ b/Functions/Zle/url-quote-magic @@ -10,7 +10,7 @@ # As of zsh-5.1, the following may also be necessary in order to apply # quoting to copy-pasted URLs: -# autload -Uz bracketed-paste-magic +# autoload -Uz bracketed-paste-magic # zle -N bracketed-paste bracketed-paste-magic # See also backward-extend-paste in bracketed-paste-magic source file. @@ -10,7 +10,7 @@ simply be omitted. -- -The Z Shell is copyright (c) 1992-2009 Paul Falstad, Richard Coleman, +The Z Shell is copyright (c) 1992-2017 Paul Falstad, Richard Coleman, Zoltán Hidvégi, Andrew Main, Peter Stephenson, Sven Wischnowsky, and others. All rights reserved. Individual authors, whether or not specifically named, retain copyright in all changes; in what follows, they diff --git a/Makefile.in b/Makefile.in index cb74e94ef..ae18855ff 100644 --- a/Makefile.in +++ b/Makefile.in @@ -151,8 +151,7 @@ config.modules: $(sdir)/config.h.in config.status config.modules.sh $(SHELL) ./config.modules.sh $(sdir)/config.h.in: $(sdir)/stamp-h.in -$(sdir)/stamp-h.in: $(sdir)/configure.ac \ - $(sdir)/aclocal.m4 $(sdir)/aczsh.m4 +$(sdir)/stamp-h.in: $(sdir)/configure cd $(sdir) && autoheader echo > $(sdir)/stamp-h.in diff --git a/Misc/vcs_info-examples b/Misc/vcs_info-examples index 766eb82a4..58dd8cf98 100644 --- a/Misc/vcs_info-examples +++ b/Misc/vcs_info-examples @@ -31,7 +31,7 @@ precmd() { psvar=() vcs_info - [[ -n $vcs_info_msg_0_ ]] && psvar[1]="$vcs_info_msg_0_" + [[ -n $vcs_info_msg_0_ ]] && print -v 'psvar[1]' -Pr -- "$vcs_info_msg_0_" } # You can now use `%1v' to drop the $vcs_info_msg_0_ contents in your prompt; @@ -4,6 +4,29 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH Note also the list of incompatibilities in the README file. +Changes from 5.3.1 to 5.4 +------------------------- + +The 'exec' and 'command' precommand modifiers, and options to them, are +now parsed after parameter expansion. Previously, both the modifier and +any options to it were parsed between alias expansion and parameter +expansion (see zshexpn(1)), so they could neither be quoted nor be the +result of parameter expansion. Examples: 's=command; $s -V ls' and +'\command -V ls' now work as expected. + +Functions executed by ZLE widgets no longer have their standard input +closed, but redirected from /dev/null instead. That still guards +against user defined widgets inadvertently reading from the tty device. + +There is an option WARN_NESTED_VAR, a companion to the existing +WARN_CREATE_GLOBAL that causes a warning if a function updates a +variable from an enclosing scope without using typeset -g. It can be +turned on for an individual function with "functions -W". + +zmodload now has an option -s to be silent on a failure to find a module +but still print other errors. + + Changes from 5.2 to 5.3.1 ------------------------- @@ -5,10 +5,11 @@ THE Z SHELL (ZSH) Version ------- -This is version 5.3.1 of the shell. This is a stable release. There are -a few visible improvements since 5.2 as well as many bugfixes. Note -in particular the changs highlighted under "Incompatibilites -between 5.2 and 5.3.1" below. See NEWS for more information. +This is version 5.4,1 of the shell. This is a stable release. There +are a few visible improvements since 5.3.1, the last widely released +version, as well as many bugfixes. Note in particular the changs +highlighted under "Incompatibilites since 5.3.1" below. See NEWS for +more information. Installing Zsh -------------- @@ -29,8 +30,59 @@ Zsh is a shell with lots of features. For a list of some of these, see the file FEATURES, and for the latest changes see NEWS. For more details, see the documentation. -Incompatibilities between 5.2 and 5.3.1 ---------------------------------------- +Incompatibilities since 5.3.1 +----------------------------- + +1) The default behaviour of code like the following has changed: + + alias foo='noglob foo' + foo() { print function body; } + +When this is encountered in a start-up file, or other place where input +was read line by line, "foo" is in command position and is expanded as +an alias before the function definition takes place. In previous +versions of the shell, this caused two functions "noglob" and "foo" to +be defined. Any expansion of an alias in a function definition is +nearly always an unintended effect, as well as hard to detect, so has +been made an error. (The option setting NO_MULTI_FUNC_DEF turned this +case into an error, but did not help with other cases and is off by +default.) The alternative, of not expanding the alias, was rejected as +it was more difficult to achieve in the parser and also would silently +change the shell's behaviur between versions. A new option, +ALIAS_FUNC_DEF, has been added, which can be set to make the shell +behave as in previous versions. It is in any case recommended to use +the "function" keyword, as aliases are not expanded afterwards. + +2) It was an undocumented, and largely useless, feature that a function +autoloaded with an absolute path was searched for along the normal fpath +(as if the leading / was missing) and, if found, loaded under the full +name including the leading slash. This has been replaced with the more +useful feature that the function is searched for only at the given +absolute path; the name of the function is the base name of the file. +Note that functions including a non-leading / behave as before, +e.g. if `dir/name' is found anywhere under a directory in $fpath it is +loaded as a function named `dir/name'. + +3) vcs_info: When neither a set-patch-format nor a gen-applied-string +(resp. gen-unapplied-string) hook is set, vcs_info now '%'-escapes the +applied-string (resp. unapplied-string) before interpolating it into the +patch-format string, to prevent literal `%' signs in the interpolated +value from being interpreted as prompt escape sequences. If you use +${vcs_info_msg_0_} in a context other than the shell prompt, you may need +to undo the escaping with: + + print -v vcs_info_msg_0_ -Pr -- "${vcs_info_msg_0_}" + +This is also needed if $vcs_info_msg_0_ is used to set $psvar. + +4) functions executed by ZLE widgets no longer have their standard input +closed, but redirected from /dev/null instead. That still guards +against user defined widgets inadvertently reading from the tty device, +and addresses the antisocial behaviour of running a command with its +stdin closed. + +Incompatibilities between 5.0.8 and 5.3 +---------------------------------------- 1) In character classes delimited by "[" and "]" within patterns, whether used for filename generation (globbing) or other forms of pattern @@ -159,10 +211,6 @@ following example illustrates how this differs from past versions. 4 4 => 1 | 4 4 => 0 ** 4 5 => 1 | 4 5 => 1 - -Incompatibilities between 5.0.8 and 5.2 ---------------------------------------- - The behaviour of the parameter flag (P) has changed when it appears in a nested parameter group, in order to make it more useful in such cases. A (P) in the outermost parameter group behaves as diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c index 63c6748f5..a60dfcbf8 100644 --- a/Src/Modules/curses.c +++ b/Src/Modules/curses.c @@ -1082,15 +1082,7 @@ zccmd_input(const char *nam, char **args) #endif /* - * Some documentation for wgetch() says: - - The behavior of getch and friends in the presence of handled signals - is unspecified in the SVr4 and XSI Curses documentation. Under his- - torical curses implementations, it varied depending on whether the - operating system's implementation of handled signal receipt interrupts - a read(2) call in progress or not, and also (in some implementations) - depending on whether an input timeout or non-blocking mode has been - set. + * Linux, OS X, FreeBSD documentation for wgetch() mentions: Programmers concerned about portability should be prepared for either of two cases: (a) signal receipt does not interrupt getch; (b) signal @@ -1098,21 +1090,16 @@ zccmd_input(const char *nam, char **args) EINTR. Under the ncurses implementation, handled signals never inter- rupt getch. - * The observed behavior, however, is different: wgetch() consistently - * returns ERR with EINTR when a signal is handled by the shell "trap" - * command mechanism. Further, it consistently returns ERR twice, the - * second time without even attempting to repeat the interrupted read, - * which has the side-effect of NOT updating errno. A third call will - * then begin reading again. - * - * Therefore, to properly implement signal trapping, we must (1) call - * wgetch() in a loop as long as errno remains EINTR, and (2) clear - * errno only before beginning the loop, not on every pass. + * Some observed behavior: wgetch() returns ERR with EINTR when a signal is + * handled by the shell "trap" command mechanism. Observed that it returns + * ERR twice, the second time without even attempting to repeat the + * interrupted read. Third call will then begin reading again. * - * There remains a potential bug here in that, if the caller has set - * a timeout for the read [see zccmd_timeout()] the countdown is very - * likely restarted on every call to wgetch(), so an interrupted call - * might wait much longer than desired. + * Because of widespread of previous implementation that called wget*ch + * possibly indefinitely many times after ERR/EINTR, and because of the + * above observation, wget_wch call is repeated after each ERR/EINTR, but + * errno is being reset (it wasn't) and the loop to all means should break. + * Problem: the timeout may be waited twice. */ errno = 0; @@ -1120,6 +1107,7 @@ zccmd_input(const char *nam, char **args) while ((ret = wget_wch(w->win, &wi)) == ERR) { if (errno != EINTR || errflag || retflag || breaks || exit_pending) break; + errno = 0; } switch (ret) { case OK: @@ -1146,6 +1134,7 @@ zccmd_input(const char *nam, char **args) while ((ci = wgetch(w->win)) == ERR) { if (errno != EINTR || errflag || retflag || breaks || exit_pending) return 1; + errno = 0; } if (ci >= 256) { keypadnum = ci; @@ -1501,6 +1490,74 @@ zccmd_touch(const char *nam, char **args) return ret; } +static int +zccmd_resize(const char *nam, char **args) +{ +#ifdef HAVE_RESIZE_TERM + int y, x, do_endwin=0, do_save=1; + LinkNode stdscr_win = zcurses_getwindowbyname("stdscr"); + + if (stdscr_win) { + y = atoi(args[0]); + x = atoi(args[1]); + if (args[2]) { + if (0 == strcmp(args[2], "endwin")) { + do_endwin=1; + } else if (0 == strcmp(args[2], "endwin_nosave")) { + do_endwin=1; + do_save=0; + } else if (0 == strcmp(args[2], "nosave")) { + do_save=0; + } else { + zwarnnam(nam, "`resize' expects `endwin', `nosave' or `endwin_nosave' for third argument, if given"); + } + } + + if (y == 0 && x == 0 && args[2] == NULL) { + // Special case to just test that curses has resize_term. #ifdef + // HAVE_RESIZE_TERM will result in return value 2 if resize_term + // is not available. + return 0; + } else { + // Without this call some window moves are innacurate. Tested on + // OS X ncurses 5.4, Homebrew ncursesw 6.0-2, Arch Linux ncursesw + // 6.0, Ubuntu 14.04 ncurses 5.9, FreeBSD ncursesw.so.8 + // + // On the other hand, the whole resize goal can be (from tests) + // accomplished by calling endwin and refresh. But to secure any + // future problems, resize_term is provided, and it is featured + // with endwin, so that users have multiple options. + if (do_endwin) { + endwin(); + } + + if( resize_term( y, x ) == OK ) { + // Things work without this, but we need to get out from + // endwin (i.e. call refresh), and in theory store new + // curses state (the resize might have changed it), which + // should be presented to terminal only after refresh. + if (do_endwin || do_save) { + ZCWin w; + w = (ZCWin)getdata(stdscr_win); + wnoutrefresh(w->win); + doupdate(); + } + + if (do_save) { + gettyinfo(&curses_tty_state); + } + return 0; + } else { + return 1; + } + } + } else { + return 1; + } +#else + return 2; +#endif +} /********************* Main builtin handler @@ -1534,6 +1591,7 @@ bin_zcurses(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) {"mouse", zccmd_mouse, 0, -1}, {"querychar", zccmd_querychar, 1, 2}, {"touch", zccmd_touch, 1, -1}, + {"resize", zccmd_resize, 2, 3}, {NULL, (zccmd_t)0, 0, 0} }; diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c index bb82c542f..6e9047bc5 100644 --- a/Src/Modules/datetime.c +++ b/Src/Modules/datetime.c @@ -133,11 +133,15 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func)) len = 0; for (x=0; x < 4; x++) { - if ((len = ztrftime(buffer, bufsize, argv[0], t, 0L)) >= 0) + if ((len = ztrftime(buffer, bufsize, argv[0], t, 0L)) >= 0 || x==3) break; buffer = zrealloc(buffer, bufsize *= 2); } - DPUTS(len < 0, "bad output from ztrftime"); + if (len < 0) { + zwarnnam(nam, "bad/unsupported format: '%s'", argv[0]); + zfree(buffer, bufsize); + return 1; + } if (scalar) { setsparam(scalar, metafy(buffer, len, META_DUP)); diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c index 8dd60fc0d..cf1322459 100644 --- a/Src/Modules/db_gdbm.c +++ b/Src/Modules/db_gdbm.c @@ -6,6 +6,9 @@ * Copyright (c) 2008 Clint Adams * All rights reserved. * + * Modifications copyright (c) 2017 Sebastian Gniazdowski + * All rights reserved. + * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and to distribute modified versions of this software for any @@ -31,6 +34,18 @@ #include "db_gdbm.mdh" #include "db_gdbm.pro" +#ifndef PM_UPTODATE +#define PM_UPTODATE (1<<19) /* Parameter has up-to-date data (e.g. loaded from DB) */ +#endif + +static Param createhash( char *name, int flags ); +static int append_tied_name( const char *name ); +static int remove_tied_name( const char *name ); +static char *unmetafy_zalloc(const char *to_copy, int *new_len); +static void myfreeparamnode(HashNode hn); + +static int no_database_action = 0; + /* * Make sure we have all the bits I'm using for memory mapping, otherwise * I don't know what I'm doing. @@ -41,8 +56,34 @@ static char *backtype = "db/gdbm"; -static const struct gsu_scalar gdbm_gsu = -{ gdbmgetfn, gdbmsetfn, gdbmunsetfn }; +/* + * Longer GSU structure, to carry GDBM_FILE of owning + * database. Every parameter (hash value) receives GSU + * pointer and thus also receives GDBM_FILE - this way + * parameters can access proper database. + * + * Main HashTable parameter has the same instance of + * the custom GSU struct in u.hash->tmpdata field. + * When database is closed, `dbf` field is set to NULL + * and hash values know to not access database when + * being unset (total purge at zuntie). + * + * When database closing is ended, custom GSU struct + * is freed. Only new ztie creates new custom GSU + * struct instance. + */ + +struct gsu_scalar_ext { + struct gsu_scalar std; /* Size of three pointers */ + GDBM_FILE dbf; + char *dbfile_path; +}; + +/* Source structure - will be copied to allocated one, + * with `dbf` filled. `dbf` allocation <-> gsu allocation. */ +static const struct gsu_scalar_ext gdbm_gsu_ext = +{ { gdbmgetfn, gdbmsetfn, gdbmunsetfn }, 0, 0 }; + /**/ static const struct gsu_hash gdbm_hash_gsu = { hashgetfn, gdbmhashsetfn, gdbmhashunsetfn }; @@ -50,12 +91,24 @@ static const struct gsu_hash gdbm_hash_gsu = static struct builtin bintab[] = { BUILTIN("ztie", 0, bin_ztie, 1, -1, 0, "d:f:r", NULL), BUILTIN("zuntie", 0, bin_zuntie, 1, -1, 0, "u", NULL), + BUILTIN("zgdbmpath", 0, bin_zgdbmpath, 1, -1, 0, "", NULL), +}; + +#define ROARRPARAMDEF(name, var) \ + { name, PM_ARRAY | PM_READONLY, (void *) var, NULL, NULL, NULL, NULL } + +/* Holds names of all tied parameters */ +char **zgdbm_tied; + +static struct paramdef patab[] = { + ROARRPARAMDEF( "zgdbm_tied", &zgdbm_tied ), }; /**/ static int bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) { + struct gsu_scalar_ext *dbf_carrier; char *resource_name, *pmname; GDBM_FILE dbf = NULL; int read_write = GDBM_SYNC, pmflags = PM_REMOVABLE; @@ -77,8 +130,7 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) } /* Here should be a lookup of the backend type against - * a registry. - */ + * a registry, if generam DB mechanism is to be added */ if (strcmp(OPT_ARG(ops, 'd'), backtype) != 0) { zwarnnam(nam, "unsupported backend type `%s'", OPT_ARG(ops, 'd')); return 1; @@ -92,7 +144,8 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) /* * Unset any existing parameter. Note there's no implicit * "local" here, but if the existing parameter is local - * that will be reflected in the new one. + * then new parameter will be also local without following + * unset. * * We need to do this before attempting to open the DB * in case this variable is already tied to a DB. @@ -105,24 +158,40 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) return 1; } + gdbm_errno=0; dbf = gdbm_open(resource_name, 0, read_write, 0666, 0); - if(dbf) - addmodulefd(gdbm_fdesc(dbf), FDT_INTERNAL); - else { - zwarnnam(nam, "error opening database file %s", resource_name); + if(dbf == NULL) { + zwarnnam(nam, "error opening database file %s (%s)", resource_name, gdbm_strerror(gdbm_errno)); return 1; } - if (!(tied_param = createspecialhash(pmname, &getgdbmnode, &scangdbmkeys, - pmflags))) { + if (!(tied_param = createhash(pmname, pmflags))) { zwarnnam(nam, "cannot create the requested parameter %s", pmname); - fdtable[gdbm_fdesc(dbf)] = FDT_UNUSED; gdbm_close(dbf); return 1; } tied_param->gsu.h = &gdbm_hash_gsu; - tied_param->u.hash->tmpdata = (void *)dbf; + + /* Allocate parameter sub-gsu, fill dbf field. + * dbf allocation is 1 to 1 accompanied by + * gsu_scalar_ext allocation. */ + + dbf_carrier = (struct gsu_scalar_ext *) zalloc(sizeof(struct gsu_scalar_ext)); + dbf_carrier->std = gdbm_gsu_ext.std; + dbf_carrier->dbf = dbf; + tied_param->u.hash->tmpdata = (void *)dbf_carrier; + + /* Fill also file path field */ + if (*resource_name != '/') { + /* Code copied from check_autoload() */ + resource_name = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", resource_name); + resource_name = xsymlink(resource_name, 1); + } + dbf_carrier->dbfile_path = ztrdup(resource_name); + + addmodulefd(gdbm_fdesc(dbf), FDT_INTERNAL); + append_tied_name(pmname); return 0; } @@ -149,8 +218,9 @@ bin_zuntie(char *nam, char **args, Options ops, UNUSED(int func)) } queue_signals(); - if (OPT_ISSET(ops,'u')) - gdbmuntie(pm); /* clear read-only-ness */ + if (OPT_ISSET(ops,'u')) { + pm->node.flags &= ~PM_READONLY; + } if (unsetparam_pm(pm, 0, 1)) { /* assume already reported */ ret = 1; @@ -162,25 +232,112 @@ bin_zuntie(char *nam, char **args, Options ops, UNUSED(int func)) } /**/ +static int +bin_zgdbmpath(char *nam, char **args, Options ops, UNUSED(int func)) +{ + Param pm; + char *pmname; + + pmname = *args; + + if (!pmname) { + zwarnnam(nam, "parameter name (whose path is to be written to $REPLY) is required"); + return 1; + } + + pm = (Param) paramtab->getnode(paramtab, pmname); + if(!pm) { + zwarnnam(nam, "no such parameter: %s", pmname); + return 1; + } + + if (pm->gsu.h != &gdbm_hash_gsu) { + zwarnnam(nam, "not a tied gdbm parameter: %s", pmname); + return 1; + } + + /* Paranoia, it *will* be always set */ + if (((struct gsu_scalar_ext *)pm->u.hash->tmpdata)->dbfile_path) { + setsparam("REPLY", ztrdup(((struct gsu_scalar_ext *)pm->u.hash->tmpdata)->dbfile_path)); + } else { + setsparam("REPLY", ztrdup("")); + } + + return 0; +} + +/* + * The param is actual param in hash – always, because + * getgdbmnode creates every new key seen. However, it + * might be not PM_UPTODATE - which means that database + * wasn't yet queried. + * + * It will be left in this state if database doesn't + * contain such key. That might be a drawback, maybe + * setting to empty value has sense. + */ + +/**/ static char * gdbmgetfn(Param pm) { datum key, content; - int ret; + int ret, umlen; + char *umkey; GDBM_FILE dbf; - key.dptr = pm->node.nam; - key.dsize = strlen(key.dptr) + 1; + /* Key already retrieved? There is no sense of asking the + * database again, because: + * - there can be only multiple readers + * - so, no writer + reader use is allowed + * + * Thus: + * - if we are writers, we for sure have newest copy of data + * - if we are readers, we for sure have newest copy of data + */ + if ( pm->node.flags & PM_UPTODATE ) { + return pm->u.str ? pm->u.str : ""; + } + + /* Unmetafy key. GDBM fits nice into this + * process, as it uses length of data */ + umlen = 0; + umkey = unmetafy_zalloc(pm->node.nam,¨en); + + key.dptr = umkey; + key.dsize = umlen; + + dbf = ((struct gsu_scalar_ext *)pm->gsu.s)->dbf; + + if((ret = gdbm_exists(dbf, key))) { + /* We have data – store it, return it */ + pm->node.flags |= PM_UPTODATE; - dbf = (GDBM_FILE)(pm->u.hash->tmpdata); - ret = gdbm_exists(dbf, key); - if(ret) { content = gdbm_fetch(dbf, key); - } else { - content.dptr = dupstring(""); + + /* Ensure there's no leak */ + if (pm->u.str) { + zsfree(pm->u.str); + pm->u.str = NULL; + } + + /* Metafy returned data. All fits - metafy + * can obtain data length to avoid using \0 */ + pm->u.str = metafy(content.dptr, content.dsize, META_DUP); + /* gdbm allocates with malloc */ + free(content.dptr); + + /* Free key */ + zfree(umkey, umlen+1); + + /* Can return pointer, correctly saved inside hash */ + return pm->u.str; } - return content.dptr; + /* Free key */ + zfree(umkey, umlen+1); + + return ""; } /**/ @@ -190,78 +347,128 @@ gdbmsetfn(Param pm, char *val) datum key, content; GDBM_FILE dbf; - key.dptr = pm->node.nam; - key.dsize = strlen(key.dptr) + 1; - content.dptr = val; - content.dsize = strlen(content.dptr) + 1; + /* Set is done on parameter and on database. + * See the allowed workers / readers comment + * at gdbmgetfn() */ - dbf = (GDBM_FILE)(pm->u.hash->tmpdata); - (void)gdbm_store(dbf, key, content, GDBM_REPLACE); + /* Parameter */ + if (pm->u.str) { + zsfree(pm->u.str); + pm->u.str = NULL; + pm->node.flags &= ~(PM_UPTODATE); + } + + if (val) { + pm->u.str = ztrdup(val); + pm->node.flags |= PM_UPTODATE; + } + + /* Database */ + dbf = ((struct gsu_scalar_ext *)pm->gsu.s)->dbf; + if (dbf && no_database_action == 0) { + int umlen = 0; + char *umkey = unmetafy_zalloc(pm->node.nam,¨en); + + key.dptr = umkey; + key.dsize = umlen; + + if (val) { + /* Unmetafy with exact zalloc size */ + char *umval = unmetafy_zalloc(val,¨en); + + /* Store */ + content.dptr = umval; + content.dsize = umlen; + (void)gdbm_store(dbf, key, content, GDBM_REPLACE); + + /* Free */ + zfree(umval, umlen+1); + } else { + (void)gdbm_delete(dbf, key); + } + + /* Free key */ + zfree(umkey, key.dsize+1); + } } /**/ static void gdbmunsetfn(Param pm, UNUSED(int um)) { - datum key; - GDBM_FILE dbf; - - key.dptr = pm->node.nam; - key.dsize = strlen(key.dptr) + 1; - - dbf = (GDBM_FILE)(pm->u.hash->tmpdata); - (void)gdbm_delete(dbf, key); + /* Set with NULL */ + gdbmsetfn(pm, NULL); } /**/ static HashNode getgdbmnode(HashTable ht, const char *name) { - int len; - char *nameu; - Param pm = NULL; - - nameu = dupstring(name); - unmetafy(nameu, &len); - - pm = (Param) hcalloc(sizeof(struct param)); - pm->node.nam = nameu; - pm->node.flags = PM_SCALAR; - pm->gsu.s = &gdbm_gsu; - pm->u.hash = ht; + HashNode hn = gethashnode2( ht, name ); + Param val_pm = (Param) hn; + + /* Entry for key doesn't exist? Create it now, + * it will be interfacing between the database + * and Zsh - through special gdbm_gsu. So, any + * seen key results in new interfacing parameter. + * + * Previous code was returning heap arena Param + * that wasn't actually added to the hash. It was + * plainly name / database-key holder. Here we + * add the Param to its hash, it is not PM_UPTODATE. + * It will be loaded from database *and filled* + * or left in that state if the database doesn't + * contain it. + * + * No heap arena memory is used, memory usage is + * now limited - by number of distinct keys seen, + * not by number of key *uses*. + * */ + + if ( ! val_pm ) { + val_pm = (Param) zshcalloc( sizeof (*val_pm) ); + val_pm->node.flags = PM_SCALAR | PM_HASHELEM; /* no PM_UPTODATE */ + val_pm->gsu.s = (GsuScalar) ht->tmpdata; + ht->addnode( ht, ztrdup( name ), val_pm ); /* sets pm->node.nam */ + } - return &pm->node; + return (HashNode) val_pm; } /**/ static void scangdbmkeys(HashTable ht, ScanFunc func, int flags) { - Param pm = NULL; - datum key, content; - GDBM_FILE dbf = (GDBM_FILE)(ht->tmpdata); - - pm = (Param) hcalloc(sizeof(struct param)); - - pm->node.flags = PM_SCALAR; - pm->gsu.s = &nullsetscalar_gsu; + datum key, prev_key; + GDBM_FILE dbf = ((struct gsu_scalar_ext *)ht->tmpdata)->dbf; + /* Iterate keys adding them to hash, so + * we have Param to use in `func` */ key = gdbm_firstkey(dbf); while(key.dptr) { - content = gdbm_fetch(dbf, key); - - pm->node.nam = key.dptr; - pm->u.str = content.dptr; - pm->gsu.s = &nullsetscalar_gsu; - - func(&pm->node, flags); - + /* This returns database-interfacing Param, + * it will return u.str or first fetch data + * if not PM_UPTODATE (newly created) */ + char *zkey = metafy(key.dptr, key.dsize, META_DUP); + HashNode hn = getgdbmnode(ht, zkey); + zsfree( zkey ); + + func(hn, flags); + + /* Iterate - no problem as interfacing Param + * will do at most only fetches, not stores */ + prev_key = key; key = gdbm_nextkey(dbf, key); + free(prev_key.dptr); } } +/* + * Replace database with new hash + */ + /**/ static void gdbmhashsetfn(Param pm, HashTable ht) @@ -274,7 +481,7 @@ gdbmhashsetfn(Param pm, HashTable ht) if (!pm->u.hash || pm->u.hash == ht) return; - if (!(dbf = (GDBM_FILE)(pm->u.hash->tmpdata))) + if (!(dbf = ((struct gsu_scalar_ext *)pm->u.hash->tmpdata)->dbf)) return; key = gdbm_firstkey(dbf); @@ -286,48 +493,78 @@ gdbmhashsetfn(Param pm, HashTable ht) key = gdbm_firstkey(dbf); } - /* just deleted everything, clean up */ - (void)gdbm_reorganize(dbf); + /* Just deleted everything, clean up if no new data. + * User can also reorganize via gdbmtool. */ + if (!ht || ht->hsize == 0) { + (void)gdbm_reorganize(dbf); + } + + no_database_action = 1; + emptyhashtable(pm->u.hash); + no_database_action = 0; if (!ht) return; - for (i = 0; i < ht->hsize; i++) + /* Put new strings into database, waiting + * for their interfacing-Params to be created */ + + for (i = 0; i < ht->hsize; i++) { for (hn = ht->nodes[i]; hn; hn = hn->next) { struct value v; + int umlen = 0; + char *umkey, *umval; v.isarr = v.flags = v.start = 0; v.end = -1; v.arr = NULL; v.pm = (Param) hn; - key.dptr = v.pm->node.nam; - key.dsize = strlen(key.dptr) + 1; + /* Unmetafy key */ + umkey = unmetafy_zalloc(v.pm->node.nam,¨en); + + key.dptr = umkey; + key.dsize = umlen; queue_signals(); - content.dptr = getstrvalue(&v); - content.dsize = strlen(content.dptr) + 1; + /* Unmetafy */ + umval = unmetafy_zalloc(getstrvalue(&v),¨en); + /* Store */ + content.dptr = umval; + content.dsize = umlen; (void)gdbm_store(dbf, key, content, GDBM_REPLACE); + /* Free - unmetafy_zalloc allocates + * exact required space + 1 null byte */ + zfree(umval, content.dsize+1); + zfree(umkey, key.dsize+1); + unqueue_signals(); } + } + /* We reuse our hash, the input is to be deleted */ + deleteparamtable(ht); } /**/ static void gdbmuntie(Param pm) { - GDBM_FILE dbf = (GDBM_FILE)(pm->u.hash->tmpdata); + GDBM_FILE dbf = ((struct gsu_scalar_ext *)pm->u.hash->tmpdata)->dbf; HashTable ht = pm->u.hash; if (dbf) { /* paranoia */ fdtable[gdbm_fdesc(dbf)] = FDT_UNUSED; - gdbm_close(dbf); - } + gdbm_close(dbf); + + /* Let hash fields know there's no backend */ + ((struct gsu_scalar_ext *)ht->tmpdata)->dbf = NULL; - ht->tmpdata = NULL; + /* Remove from list of tied parameters */ + remove_tied_name(pm->node.nam); + } /* for completeness ... createspecialhash() should have an inverse */ ht->getnode = ht->getnode2 = gethashnode2; @@ -341,21 +578,31 @@ gdbmuntie(Param pm) static void gdbmhashunsetfn(Param pm, UNUSED(int exp)) { + struct gsu_scalar_ext * gsu_ext; + gdbmuntie(pm); - /* hash table is now normal, so proceed normally... */ + + /* Remember custom GSU structure assigned to + * u.hash->tmpdata before hash gets deleted */ + gsu_ext = pm->u.hash->tmpdata; + + /* Uses normal unsetter (because gdbmuntie is called above). + * Will delete all owned field-parameters and also hashtable. */ pm->gsu.h->setfn(pm, NULL); + + /* Don't need custom GSU structure with its + * GDBM_FILE pointer anymore */ + zsfree( gsu_ext->dbfile_path ); + zfree( gsu_ext, sizeof(struct gsu_scalar_ext)); + pm->node.flags |= PM_UNSET; } -#else -# error no gdbm -#endif /* have gdbm */ - static struct features module_features = { bintab, sizeof(bintab)/sizeof(*bintab), NULL, 0, NULL, 0, - NULL, 0, + patab, sizeof(patab)/sizeof(*patab), 0 }; @@ -385,6 +632,7 @@ enables_(Module m, int **enables) int boot_(UNUSED(Module m)) { + zgdbm_tied = zshcalloc((1) * sizeof(char *)); return 0; } @@ -392,6 +640,7 @@ boot_(UNUSED(Module m)) int cleanup_(Module m) { + /* This frees `zgdbm_tied` */ return setfeatureenables(m, &module_features, NULL); } @@ -401,3 +650,169 @@ finish_(UNUSED(Module m)) { return 0; } + +/********************* + * Utility functions * + *********************/ + +static Param createhash( char *name, int flags ) { + Param pm; + HashTable ht; + + pm = createparam(name, flags | PM_SPECIAL | PM_HASHED); + if (!pm) { + return NULL; + } + + if (pm->old) + pm->level = locallevel; + + /* This creates standard hash. */ + ht = pm->u.hash = newparamtable(17, name); + if (!pm->u.hash) { + paramtab->removenode(paramtab, name); + paramtab->freenode(&pm->node); + zwarnnam(name, "out of memory when allocating hash"); + return NULL; + } + + /* Does free Param (unsetfn is called) */ + ht->freenode = myfreeparamnode; + + /* These provide special features */ + ht->getnode = ht->getnode2 = getgdbmnode; + ht->scantab = scangdbmkeys; + + return pm; +} + +/* + * Adds parameter name to `zgdbm_tied` + */ + +static int append_tied_name( const char *name ) { + int old_len = arrlen(zgdbm_tied); + char **new_zgdbm_tied = zshcalloc( (old_len+2) * sizeof(char *)); + + /* Copy */ + char **p = zgdbm_tied; + char **dst = new_zgdbm_tied; + while (*p) { + *dst++ = *p++; + } + + /* Append new one */ + *dst = ztrdup(name); + + /* Substitute, free old one */ + zfree(zgdbm_tied, sizeof(char *) * (old_len + 1)); + zgdbm_tied = new_zgdbm_tied; + + return 0; +} + +/* + * Removes parameter name from `zgdbm_tied` + */ + +static int remove_tied_name( const char *name ) { + int old_len = arrlen(zgdbm_tied); + int new_len; + + /* Two stage, to always have arrlen() == zfree-size - 1. + * Could do allocation and revert when `not found`, but + * what would be better about that. */ + + /* Find one to remove */ + char **p = zgdbm_tied; + while (*p) { + if (0==strcmp(name,*p)) { + break; + } + p++; + } + + /* Copy x+1 to x */ + while (*p) { + *p=*(p+1); + p++; + } + + /* Second stage. Size changed? Only old_size-1 + * change is possible, but.. paranoia way */ + new_len = arrlen(zgdbm_tied); + if (new_len != old_len) { + char **dst; + char **new_zgdbm_tied = zshcalloc((new_len+1) * sizeof(char *)); + + /* Copy */ + p = zgdbm_tied; + dst = new_zgdbm_tied; + while (*p) { + *dst++ = *p++; + } + *dst = NULL; + + /* Substitute, free old one */ + zfree(zgdbm_tied, sizeof(char *) * (old_len + 1)); + zgdbm_tied = new_zgdbm_tied; + } + + return 0; +} + +/* + * Unmetafy that: + * - duplicates bufer to work on it, + * - does zalloc of exact size for the new string, + * - restores work buffer to original content, to restore strlen + */ +static char * +unmetafy_zalloc(const char *to_copy, int *new_len) { + char *work, *to_return; + int my_new_len = 0; + + work = ztrdup(to_copy); + work = unmetafy(work,&my_new_len); + + if (new_len) + *new_len = my_new_len; + + /* This string can be correctly zsfree()-d */ + to_return = (char *) zalloc((my_new_len+1)*sizeof(char)); + memcpy(to_return, work, sizeof(char)*my_new_len); /* memcpy handles $'\0' */ + to_return[my_new_len]='\0'; + + /* Restore original strlen and correctly free */ + strcpy(work, to_copy); + zsfree(work); + + return to_return; +} + +static void +myfreeparamnode(HashNode hn) +{ + Param pm = (Param) hn; + + /* Upstream: The second argument of unsetfn() is used by modules to + * differentiate "exp"licit unset from implicit unset, as when + * a parameter is going out of scope. It's not clear which + * of these applies here, but passing 1 has always worked. + */ + + /* if (delunset) */ + pm->gsu.s->unsetfn(pm, 1); + + zsfree(pm->node.nam); + /* If this variable was tied by the user, ename was ztrdup'd */ + if (pm->node.flags & PM_TIED && pm->ename) { + zsfree(pm->ename); + pm->ename = NULL; + } + zfree(pm, sizeof(struct param)); +} + +#else +# error no gdbm +#endif /* have gdbm */ diff --git a/Src/Modules/db_gdbm.mdd b/Src/Modules/db_gdbm.mdd index ce7926bd9..210c22177 100644 --- a/Src/Modules/db_gdbm.mdd +++ b/Src/Modules/db_gdbm.mdd @@ -7,6 +7,6 @@ fi ' load=no -autofeatures="b:ztie b:zuntie" +autofeatures="b:ztie b:zuntie b:zgdbmpath p:zgdbm_tied" objects="db_gdbm.o" diff --git a/Src/Modules/example.c b/Src/Modules/example.c index 45ca2cffa..c80c9e7b2 100644 --- a/Src/Modules/example.c +++ b/Src/Modules/example.c @@ -69,7 +69,8 @@ bin_example(char *nam, char **args, Options ops, UNUSED(int func)) intparam = i; zsfree(strparam); strparam = ztrdup(*oargs ? *oargs : ""); - freearray(arrparam); + if (arrparam) + freearray(arrparam); arrparam = zarrdup(oargs); return 0; } diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 98bcaba6e..10c47d214 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -167,7 +167,7 @@ unsetpmcommand(Param pm, UNUSED(int exp)) /**/ static void -setpmcommands(UNUSED(Param pm), HashTable ht) +setpmcommands(Param pm, HashTable ht) { int i; HashNode hn; @@ -190,7 +190,15 @@ setpmcommands(UNUSED(Param pm), HashTable ht) cmdnamtab->addnode(cmdnamtab, ztrdup(hn->nam), &cn->node); } - deleteparamtable(ht); + /* + * On full-array assignment ht is a temporary hash with the default + * get/set functions, whereas pm->u.hash has the special $commands + * get/set functions. Do not assign ht to pm, just delete it. + * + * On append, ht and pm->u.hash are the same table, don't delete. + */ + if (ht != pm->u.hash) + deleteparamtable(ht); } static const struct gsu_scalar pmcommand_gsu = @@ -330,7 +338,7 @@ unsetpmfunction(Param pm, UNUSED(int exp)) /**/ static void -setfunctions(UNUSED(Param pm), HashTable ht, int dis) +setfunctions(Param pm, HashTable ht, int dis) { int i; HashNode hn; @@ -349,7 +357,9 @@ setfunctions(UNUSED(Param pm), HashTable ht, int dis) setfunction(hn->nam, ztrdup(getstrvalue(&v)), dis); } - deleteparamtable(ht); + /* See setpmcommands() above */ + if (ht != pm->u.hash) + deleteparamtable(ht); } /**/ @@ -515,6 +525,98 @@ scanpmdisfunctions(HashTable ht, ScanFunc func, int flags) scanfunctions(ht, func, flags, DISABLED); } +/* Functions for the functions_source special parameter. */ + +/* Retrieve the source file for a function by explicit name */ + +/**/ +static HashNode +getfunction_source(UNUSED(HashTable ht), const char *name, int dis) +{ + Shfunc shf; + Param pm = NULL; + + pm = (Param) hcalloc(sizeof(struct param)); + pm->node.nam = dupstring(name); + pm->node.flags = PM_SCALAR|PM_READONLY; + pm->gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu; + + if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) && + (dis ? (shf->node.flags & DISABLED) : !(shf->node.flags & DISABLED))) { + pm->u.str = getshfuncfile(shf); + if (!pm->u.str) + pm->u.str = dupstring(""); + } + return &pm->node; +} + +/* Retrieve the source file for functions by scanning the table */ + +/**/ +static void +scanfunctions_source(UNUSED(HashTable ht), ScanFunc func, int flags, int dis) +{ + struct param pm; + int i; + HashNode hn; + + memset((void *)&pm, 0, sizeof(struct param)); + pm.node.flags = PM_SCALAR|PM_READONLY; + pm.gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu; + + for (i = 0; i < shfunctab->hsize; i++) { + for (hn = shfunctab->nodes[i]; hn; hn = hn->next) { + if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) { + pm.node.nam = hn->nam; + if (func != scancountparams && + ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) || + !(flags & SCANPM_WANTKEYS))) { + pm.u.str = getshfuncfile((Shfunc)hn); + if (!pm.u.str) + pm.u.str = dupstring(""); + } + func(&pm.node, flags); + } + } + } +} + +/* Param table entry for retrieving functions_source element */ + +/**/ +static HashNode +getpmfunction_source(HashTable ht, const char *name) +{ + return getfunction_source(ht, name, 0); +} + +/* Param table entry for retrieving ds_functions_source element */ + +/**/ +static HashNode +getpmdisfunction_source(HashTable ht, const char *name) +{ + return getfunction_source(ht, name, 1); +} + +/* Param table entry for scanning functions_source table */ + +/**/ +static void +scanpmfunction_source(HashTable ht, ScanFunc func, int flags) +{ + scanfunctions_source(ht, func, flags, 0); +} + +/* Param table entry for scanning dis_functions_source table */ + +/**/ +static void +scanpmdisfunction_source(HashTable ht, ScanFunc func, int flags) +{ + scanfunctions_source(ht, func, flags, 1); +} + /* Functions for the funcstack special parameter. */ /**/ @@ -845,7 +947,7 @@ unsetpmoption(Param pm, UNUSED(int exp)) /**/ static void -setpmoptions(UNUSED(Param pm), HashTable ht) +setpmoptions(Param pm, HashTable ht) { int i; HashNode hn; @@ -870,7 +972,9 @@ setpmoptions(UNUSED(Param pm), HashTable ht) (val && strcmp(val, "off")), 0, opts)) zwarn("can't change option: %s", hn->nam); } - deleteparamtable(ht); + /* See setpmcommands() above */ + if (ht != pm->u.hash) + deleteparamtable(ht); } static const struct gsu_scalar pmoption_gsu = @@ -1409,7 +1513,7 @@ unsetpmnameddir(Param pm, UNUSED(int exp)) /**/ static void -setpmnameddirs(UNUSED(Param pm), HashTable ht) +setpmnameddirs(Param pm, HashTable ht) { int i; HashNode hn, next, hd; @@ -1451,7 +1555,9 @@ setpmnameddirs(UNUSED(Param pm), HashTable ht) i = opts[INTERACTIVE]; opts[INTERACTIVE] = 0; - deleteparamtable(ht); + /* See setpmcommands() above */ + if (ht != pm->u.hash) + deleteparamtable(ht); opts[INTERACTIVE] = i; } @@ -1632,7 +1738,7 @@ unsetpmsalias(Param pm, UNUSED(int exp)) /**/ static void -setaliases(HashTable alht, UNUSED(Param pm), HashTable ht, int flags) +setaliases(HashTable alht, Param pm, HashTable ht, int flags) { int i; HashNode hn, next, hd; @@ -1668,7 +1774,9 @@ setaliases(HashTable alht, UNUSED(Param pm), HashTable ht, int flags) alht->addnode(alht, ztrdup(hn->nam), createaliasnode(ztrdup(val), flags)); } - deleteparamtable(ht); + /* See setpmcommands() above */ + if (ht != pm->u.hash) + deleteparamtable(ht); } /**/ @@ -2095,6 +2203,8 @@ static struct paramdef partab[] = { NULL, getpmdisbuiltin, scanpmdisbuiltins), SPECIALPMDEF("dis_functions", 0, &pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions), + SPECIALPMDEF("dis_functions_source", PM_READONLY, NULL, + getpmdisfunction_source, scanpmdisfunction_source), SPECIALPMDEF("dis_galiases", 0, &pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases), SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY, @@ -2111,6 +2221,8 @@ static struct paramdef partab[] = { &funcstack_gsu, NULL, NULL), SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction, scanpmfunctions), + SPECIALPMDEF("functions_source", PM_READONLY, NULL, + getpmfunction_source, scanpmfunction_source), SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY, &functrace_gsu, NULL, NULL), SPECIALPMDEF("galiases", 0, diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c index 5fd67963d..27191d709 100644 --- a/Src/Modules/pcre.c +++ b/Src/Modules/pcre.c @@ -75,7 +75,7 @@ zpcre_utf8_enabled(void) static int bin_pcre_compile(char *nam, char **args, Options ops, UNUSED(int func)) { - int pcre_opts = 0, pcre_errptr; + int pcre_opts = 0, pcre_errptr, target_len; const char *pcre_error; char *target; @@ -89,15 +89,19 @@ bin_pcre_compile(char *nam, char **args, Options ops, UNUSED(int func)) pcre_opts |= PCRE_UTF8; pcre_hints = NULL; /* Is this necessary? */ - + if (pcre_pattern) pcre_free(pcre_pattern); target = ztrdup(*args); - unmetafy(target, NULL); + unmetafy(target, &target_len); + + if ((int)strlen(target) != target_len) { + zwarnnam(nam, "embedded NULs in PCRE pattern terminate pattern"); + } pcre_pattern = pcre_compile(target, pcre_opts, &pcre_error, &pcre_errptr, NULL); - + free(target); if (pcre_pattern == NULL) @@ -167,7 +171,12 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar, sprintf(offset_all, "%d %d", ovec[0], ovec[1]); setsparam("ZPCRE_OP", ztrdup(offset_all)); } - match_all = metafy(captures[0], -1, META_DUP); + /* + * Result strings can contain embedded NULs; the length of each is the + * difference between the two values in each paired entry in ovec. + * ovec is length 2*(1+capture_list_length) + */ + match_all = metafy(captures[0], ovec[1] - ovec[0], META_DUP); setsparam(matchvar, match_all); /* * If we're setting match, mbegin, mend we only do @@ -176,13 +185,16 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar, */ if (!want_begin_end || nelem) { char **x, **y; + int vec_off; y = &captures[capture_start]; matches = x = (char **) zalloc(sizeof(char *) * (arrlen(y) + 1)); + vec_off = 2; do { if (*y) - *x++ = metafy(*y, -1, META_DUP); + *x++ = metafy(*y, ovec[vec_off+1]-ovec[vec_off], META_DUP); else *x++ = NULL; + vec_off += 2; } while (*y++); setaparam(substravar, matches); } @@ -318,8 +330,7 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func)) ovec = zalloc(ovecsize*sizeof(int)); plaintext = ztrdup(*args); - unmetafy(plaintext, NULL); - subject_len = (int)strlen(plaintext); + unmetafy(plaintext, &subject_len); if (offset_start > 0 && offset_start >= subject_len) ret = PCRE_ERROR_NOMATCH; @@ -351,6 +362,7 @@ cond_pcre_match(char **a, int id) const char *pcre_err; char *lhstr, *rhre, *lhstr_plain, *rhre_plain, *avar=NULL; int r = 0, pcre_opts = 0, pcre_errptr, capcnt, *ov, ovsize; + int lhstr_plain_len, rhre_plain_len; int return_value = 0; if (zpcre_utf8_enabled()) @@ -362,8 +374,8 @@ cond_pcre_match(char **a, int id) rhre = cond_str(a,1,0); lhstr_plain = ztrdup(lhstr); rhre_plain = ztrdup(rhre); - unmetafy(lhstr_plain, NULL); - unmetafy(rhre_plain, NULL); + unmetafy(lhstr_plain, &lhstr_plain_len); + unmetafy(rhre_plain, &rhre_plain_len); pcre_pat = NULL; ov = NULL; ovsize = 0; @@ -373,6 +385,9 @@ cond_pcre_match(char **a, int id) switch(id) { case CPCRE_PLAIN: + if ((int)strlen(rhre_plain) != rhre_plain_len) { + zwarn("embedded NULs in PCRE pattern terminate pattern"); + } pcre_pat = pcre_compile(rhre_plain, pcre_opts, &pcre_err, &pcre_errptr, NULL); if (pcre_pat == NULL) { zwarn("failed to compile regexp /%s/: %s", rhre, pcre_err); @@ -381,7 +396,7 @@ cond_pcre_match(char **a, int id) pcre_fullinfo(pcre_pat, NULL, PCRE_INFO_CAPTURECOUNT, &capcnt); ovsize = (capcnt+1)*3; ov = zalloc(ovsize*sizeof(int)); - r = pcre_exec(pcre_pat, NULL, lhstr_plain, strlen(lhstr_plain), 0, 0, ov, ovsize); + r = pcre_exec(pcre_pat, NULL, lhstr_plain, lhstr_plain_len, 0, 0, ov, ovsize); /* r < 0 => error; r==0 match but not enough size in ov * r > 0 => (r-1) substrings found; r==1 => no substrings */ diff --git a/Src/Modules/regex.c b/Src/Modules/regex.c index edb7234d4..d02769ef0 100644 --- a/Src/Modules/regex.c +++ b/Src/Modules/regex.c @@ -111,7 +111,7 @@ zcond_regex_match(char **a, int id) *x = NULL; } if (isset(BASHREMATCH)) { - setaparam("BASH_REMATCH", arr); + assignaparam("BASH_REMATCH", arr, 0); } else { zlong offs; char *ptr; @@ -119,7 +119,7 @@ zcond_regex_match(char **a, int id) m = matches; s = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP); - setsparam("MATCH", s); + assignsparam("MATCH", s, 0); /* * Count the characters before the match. */ @@ -133,7 +133,7 @@ zcond_regex_match(char **a, int id) ptr += clen; leftlen -= clen; } - setiparam("MBEGIN", offs + !isset(KSHARRAYS)); + assigniparam("MBEGIN", offs + !isset(KSHARRAYS), 0); /* * Add on the characters in the match. */ @@ -144,7 +144,7 @@ zcond_regex_match(char **a, int id) ptr += clen; leftlen -= clen; } - setiparam("MEND", offs + !isset(KSHARRAYS) - 1); + assigniparam("MEND", offs + !isset(KSHARRAYS) - 1, 0); if (nelem) { char **mbegin, **mend, **bptr, **eptr; bptr = mbegin = (char **)zalloc(sizeof(char *)*(nelem+1)); diff --git a/Src/Modules/system.c b/Src/Modules/system.c index afaec262a..3eecd7e95 100644 --- a/Src/Modules/system.c +++ b/Src/Modules/system.c @@ -313,7 +313,7 @@ bin_sysopen(char *nam, char **args, Options ops, UNUSED(int func)) int flags = O_NOCTTY | append | ((append || write) ? (read ? O_RDWR : O_WRONLY) : O_RDONLY); char *opt, *ptr, *nextopt, *fdvar; - int o, fd, explicit = -1; + int o, fd, moved_fd, explicit = -1; mode_t perms = 0666; #if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) int fdflags; @@ -376,22 +376,32 @@ bin_sysopen(char *nam, char **args, Options ops, UNUSED(int func)) zwarnnam(nam, "can't open file %s: %e", *args, errno); return 1; } - fd = (explicit > -1) ? redup(fd, explicit) : movefd(fd); - if (fd == -1) { + moved_fd = (explicit > -1) ? redup(fd, explicit) : movefd(fd); + if (moved_fd == -1) { zwarnnam(nam, "can't open file %s", *args); return 1; } -#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) +#ifdef FD_CLOEXEC +#ifdef O_CLOEXEC + /* + * the O_CLOEXEC is a flag attached to the *file descriptor*, not the + * *open file description* so it doesn't survive a dup(). If that flag was + * requested and the fd was moved, we need to reapply it to the moved fd + * even if the original one was open with O_CLOEXEC + */ + if ((flags & O_CLOEXEC) && fd != moved_fd) +#else if (fdflags) - fcntl(fd, F_SETFD, FD_CLOEXEC); -#endif +#endif /* O_CLOEXEC */ + fcntl(moved_fd, F_SETFD, FD_CLOEXEC); +#endif /* FD_CLOEXEC */ if (explicit == -1) { - fdtable[fd] = FDT_EXTERNAL; - setiparam(fdvar, fd); - /* if setting the variable failed, close fd to avoid leak */ + fdtable[moved_fd] = FDT_EXTERNAL; + setiparam(fdvar, moved_fd); + /* if setting the variable failed, close moved_fd to avoid leak */ if (errflag) - zclose(fd); + zclose(moved_fd); } return 0; diff --git a/Src/Modules/tcp.c b/Src/Modules/tcp.c index dec12142b..0bbce5d49 100644 --- a/Src/Modules/tcp.c +++ b/Src/Modules/tcp.c @@ -343,7 +343,8 @@ bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func)) { int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0; ZSOCKLEN_T len; - char **addrp, *desthost, *localname, *remotename; + char **addrp, *desthost; + const char *localname, *remotename; struct hostent *zthost = NULL, *ztpeer = NULL; struct servent *srv; Tcp_session sess = NULL; diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index deed35e2f..24f4b4200 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -3177,7 +3177,7 @@ static struct features module_features = { int setup_(UNUSED(Module m)) { - return (require_module("zsh/net/tcp", NULL) == 1); + return (require_module("zsh/net/tcp", NULL, 0) == 1); } /**/ diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 0ef753915..3c1bef58f 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -331,6 +331,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock) /* This code copied from the clone module, except for getting * * the descriptor from get_pty() and duplicating it to 0/1/2. */ + deletehookfunc("exit", ptyhook); clearjobtab(0); ppid = getppid(); mypid = getpid(); @@ -544,7 +545,8 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch) p = dupstring(args[1]); tokenize(p); remnulargs(p); - if (!(prog = patcompile(p, PAT_STATIC, NULL))) { + /* Signals handlers might stomp PAT_STATIC */ + if (!(prog = patcompile(p, PAT_ZDUP, NULL))) { zwarnnam(nam, "bad pattern: %s", args[1]); return 1; } @@ -682,9 +684,14 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch) write_loop(1, buf, used); } - if (seen && (!prog || matchok || !mustmatch)) - return 0; - return cmd->fin + 1; + { + int ret = cmd->fin + 1; + if (seen && (!prog || matchok || !mustmatch)) + ret = 0; + if (prog) + freepatprog(prog); + return ret; + } } static int @@ -846,6 +853,7 @@ bin_zpty(char *nam, char **args, Options ops, UNUSED(int func)) } } +/**/ static int ptyhook(UNUSED(Hookdef d), UNUSED(void *dummy)) { diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index d95c0c254..19a8306b5 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -510,25 +510,33 @@ bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) zwarnnam(nam, "too many arguments"); return 1; } + + queue_signals(); /* Protect PAT_STATIC */ + if (context) { tokenize(context); zstyle_contprog = patcompile(context, PAT_STATIC, NULL); - if (!zstyle_contprog) + if (!zstyle_contprog) { + unqueue_signals(); return 1; + } } else zstyle_contprog = NULL; if (stylename) { s = (Style)zstyletab->getnode2(zstyletab, stylename); - if (!s) + if (!s) { + unqueue_signals(); return 1; + } zstyletab->printnode(&s->node, list); } else { scanhashtable(zstyletab, 1, 0, 0, zstyletab->printnode, list); } + unqueue_signals(); return 0; } switch (args[0][1]) { @@ -675,14 +683,20 @@ bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) char **vals; Patprog prog; + queue_signals(); /* Protect PAT_STATIC */ + tokenize(args[3]); if ((vals = lookupstyle(args[1], args[2])) && (prog = patcompile(args[3], PAT_STATIC, NULL))) { while (*vals) - if (pattry(prog, *vals++)) + if (pattry(prog, *vals++)) { + unqueue_signals(); return 0; + } } + + unqueue_signals(); return 1; } break; diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index d1cf7a08a..52b0c173f 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -3135,7 +3135,9 @@ matchcmp(Cmatch *a, Cmatch *b) if ((*b)->disp && !((*b)->flags & CMF_MORDER)) return 1; - return zstrbcmp((*a)->str, (*b)->str); + return zstrcmp((*a)->str, (*b)->str, (SORTIT_IGNORING_BACKSLASHES| + (isset(NUMERICGLOBSORT) ? + SORTIT_NUMERICALLY : 0))); } /* This tests whether two matches are equal (would produce the same diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 52c6f1233..5414b8ff6 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -99,7 +99,7 @@ freecompctlp(HashNode hn) } /**/ -void +static void freecompctl(Compctl cc) { if (cc == &cc_default || @@ -142,7 +142,7 @@ freecompctl(Compctl cc) } /**/ -void +static void freecompcond(void *a) { Compcond cc = (Compcond) a; @@ -186,7 +186,7 @@ freecompcond(void *a) } /**/ -int +static int compctlread(char *name, char **args, Options ops, char *reply) { char *buf, *bptr; @@ -1564,6 +1564,8 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) Compctl cc = NULL; int ret = 0; + queue_signals(); + /* clear static flags */ cclist = 0; showmask = 0; @@ -1571,12 +1573,15 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) /* Parse all the arguments */ if (*argv) { /* Let's see if this is a global matcher definition. */ - if ((ret = get_gmatcher(name, argv))) + if ((ret = get_gmatcher(name, argv))) { + unqueue_signals(); return ret - 1; + } cc = (Compctl) zshcalloc(sizeof(*cc)); if (get_compctl(name, &argv, cc, 1, 0, 0)) { freecompctl(cc); + unqueue_signals(); return 1; } @@ -1604,6 +1609,7 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) printcompctl((cclist & COMP_LIST) ? "" : "DEFAULT", &cc_default, 0, 0); printcompctl((cclist & COMP_LIST) ? "" : "FIRST", &cc_first, 0, 0); print_gmatcher((cclist & COMP_LIST)); + unqueue_signals(); return ret; } @@ -1642,6 +1648,7 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) printcompctl("", &cc_first, 0, 0); if (cclist & COMP_LISTMATCH) print_gmatcher(COMP_LIST); + unqueue_signals(); return ret; } @@ -1656,6 +1663,7 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) compctl_process_cc(argv, cc); } + unqueue_signals(); return ret; } @@ -1667,12 +1675,18 @@ bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) static int bin_compcall(char *name, UNUSED(char **argv), Options ops, UNUSED(int func)) { + int ret; + if (incompfunc != 1) { zwarnnam(name, "can only be called from completion function"); return 1; } - return makecomplistctl((OPT_ISSET(ops,'T') ? 0 : CFN_FIRST) | - (OPT_ISSET(ops,'D') ? 0 : CFN_DEFAULT)); + + queue_signals(); + ret = makecomplistctl((OPT_ISSET(ops,'T') ? 0 : CFN_FIRST) | + (OPT_ISSET(ops,'D') ? 0 : CFN_DEFAULT)); + unqueue_signals(); + return ret; } /* @@ -1756,6 +1770,8 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) int onm = nmatches, odm = diffmatches, osi = movefd(0); LinkNode n; + queue_signals(); + /* We build a copy of the list of matchers to use to make sure that this * works even if a shell function called from the completion code changes * the global matchers. */ @@ -1851,6 +1867,7 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) redup(osi, 0); dat->lst = 0; + unqueue_signals(); return 0; } if (lastmatches) { @@ -1874,6 +1891,7 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) redup(osi, 0); dat->lst = 0; + unqueue_signals(); return 0; } if (!m || !(m = m->next)) @@ -1883,6 +1901,8 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) } redup(osi, 0); dat->lst = 1; + + unqueue_signals(); return 0; } @@ -2044,7 +2064,7 @@ maketildelist(void) /* This does the check for compctl -x `n' and `N' patterns. */ /**/ -int +static int getcpat(char *str, int cpatindex, char *cpat, int class) { char *s, *t, *p; diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index 48fcd4751..68bdf2332 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -901,7 +901,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod) return 0; singsub(&sa); - pp = patcompile(sa, PAT_STATIC, NULL); + pp = patcompile(sa, PAT_HEAPDUP, NULL); for (i--, p = compwords + i; i >= 0; p--, i--) { if (pattry(pp, *p)) { @@ -955,7 +955,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod) if (!na) return 0; - if (!(pp = patcompile(sa, PAT_STATIC, 0))) + if (!(pp = patcompile(sa, PAT_HEAPDUP, 0))) return 0; if (test == CVT_PREPAT) { diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 2edaf6eca..a83daeff9 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -1993,7 +1993,8 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) if (noselect > 0) noselect = 0; - if ((minfo.asked == 2 && mselect < 0) || nlnct >= zterm_lines) { + if ((minfo.asked == 2 && mselect < 0) || nlnct >= zterm_lines || + errflag) { showinglist = 0; amatches = oamatches; return (noselect = 1); @@ -2333,11 +2334,6 @@ msearch(Cmatch **ptr, char *ins, int back, int rep, int *wrapp) } } if (x == ex && y == ey) { - if (wrap) { - msearchstate = MS_FAILED | owrap; - break; - } - msearchstate |= MS_WRAPPED; if (back) { x = mcols - 1; @@ -2349,6 +2345,13 @@ msearch(Cmatch **ptr, char *ins, int back, int rep, int *wrapp) } ex = mcol; ey = mline; + + if (wrap || (x == ex && y == ey)) { + msearchstate = MS_FAILED | owrap; + break; + } + + msearchstate |= MS_WRAPPED; wrap = 1; *wrapp = 1; } diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c index aedf463fc..1cdbb8a48 100644 --- a/Src/Zle/compmatch.c +++ b/Src/Zle/compmatch.c @@ -1548,27 +1548,11 @@ pattern_match(Cpattern p, char *s, Cpattern wp, char *ws) { convchar_t c, wc; convchar_t ind, wind; - int len = 0, wlen, mt, wmt; -#ifdef MULTIBYTE_SUPPORT - mbstate_t lstate, wstate; - - memset(&lstate, 0, sizeof(lstate)); - memset(&wstate, 0, sizeof(wstate)); -#endif + int len = 0, wlen = 0, mt, wmt; while (p && wp && *s && *ws) { /* First test the word character */ -#ifdef MULTIBYTE_SUPPORT - wlen = mb_metacharlenconv_r(ws, &wc, &wstate); -#else - if (*ws == Meta) { - wc = STOUC(ws[1]) ^ 32; - wlen = 2; - } else { - wc = STOUC(*ws); - wlen = 1; - } -#endif + wc = unmeta_one(ws, &wlen); wind = pattern_match1(wp, wc, &wmt); if (!wind) return 0; @@ -1576,18 +1560,7 @@ pattern_match(Cpattern p, char *s, Cpattern wp, char *ws) /* * Now the line character. */ -#ifdef MULTIBYTE_SUPPORT - len = mb_metacharlenconv_r(s, &c, &lstate); -#else - /* We have the character itself. */ - if (*s == Meta) { - c = STOUC(s[1]) ^ 32; - len = 2; - } else { - c = STOUC(*s); - len = 1; - } -#endif + c = unmeta_one(s, &len); /* * If either is "?", they match each other; no further tests. * Apply this even if the character wasn't convertable; @@ -1627,17 +1600,7 @@ pattern_match(Cpattern p, char *s, Cpattern wp, char *ws) } while (p && *s) { -#ifdef MULTIBYTE_SUPPORT - len = mb_metacharlenconv_r(s, &c, &lstate); -#else - if (*s == Meta) { - c = STOUC(s[1]) ^ 32; - len = 2; - } else { - c = STOUC(*s); - len = 1; - } -#endif + c = unmeta_one(s, &len); if (!pattern_match1(p, c, &mt)) return 0; p = p->next; @@ -1645,17 +1608,7 @@ pattern_match(Cpattern p, char *s, Cpattern wp, char *ws) } while (wp && *ws) { -#ifdef MULTIBYTE_SUPPORT - wlen = mb_metacharlenconv_r(ws, &wc, &wstate); -#else - if (*ws == Meta) { - wc = STOUC(ws[1]) ^ 32; - wlen = 2; - } else { - wc = STOUC(*ws); - wlen = 1; - } -#endif + wc = unmeta_one(ws, &wlen); if (!pattern_match1(wp, wc, &wmt)) return 0; wp = wp->next; diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index 192ddeab9..e704f9ffa 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -917,7 +917,6 @@ struct cadef { int argsactive; /* if normal arguments are still allowed */ /* used while parsing a command line */ char *set; /* set name prefix (<name>-), shared */ - char *sname; /* set name */ int flags; /* see CDF_* below */ char *nonarg; /* pattern for non-args (-A argument) */ }; @@ -935,7 +934,7 @@ struct caopt { Caarg args; /* option arguments */ int active; /* still allowed on command line */ int num; /* it's the num'th option */ - char *set; /* set name, shared */ + char *gsname; /* group or set name, shared */ int not; /* don't complete this option (`!...') */ }; @@ -956,10 +955,10 @@ struct caarg { char *end; /* end-pattern for ::<pat>:... */ char *opt; /* option name if for an option */ int num; /* it's the num'th argument */ - int min; /* it's also this argument, using opt. args */ + int min; /* earliest possible arg pos, given optional args */ int direct; /* true if argument number was given explicitly */ int active; /* still allowed on command line */ - char *set; /* set name, shared */ + char *gsname; /* group or set name, shared */ }; #define CAA_NORMAL 1 @@ -1020,7 +1019,6 @@ freecadef(Cadef d) s = d->snext; zsfree(d->match); zsfree(d->set); - zsfree(d->sname); if (d->defs) freearray(d->defs); @@ -1098,7 +1096,7 @@ parse_caarg(int mult, int type, int num, int opt, char *oname, char **def, ret->type = type; ret->opt = ztrdup(oname); ret->direct = 0; - ret->set = set; + ret->gsname = set; /* Get the description. */ @@ -1147,8 +1145,11 @@ alloc_cadef(char **args, int single, char *match, char *nonarg, int flags) ret->defs = NULL; ret->ndefs = 0; } + ret->nopts = 0; + ret->ndopts = 0; + ret->nodopts = 0; ret->lastt = time(0); - ret->set = ret->sname = NULL; + ret->set = NULL; if (single) { ret->single = (Caopt *) zalloc(256 * sizeof(Caopt)); memset(ret->single, 0, 256 * sizeof(Caopt)); @@ -1182,12 +1183,10 @@ parse_cadef(char *nam, char **args) Cadef all, ret; Caopt *optp; char **orig_args = args, *p, *q, *match = "r:|[_-]=* r:|=*", **xor, **sargs; - char *adpre, *adsuf, *axor = NULL, *doset = NULL, **setp = NULL; + char *adpre, *adsuf, *axor = NULL, *doset = NULL, **pendset = NULL, **curset = NULL; char *nonarg = NULL; - int single = 0, anum = 1, xnum, nopts, ndopts, nodopts, flags = 0; - int state = 0, not = 0; - - nopts = ndopts = nodopts = 0; + int single = 0, anum = 1, xnum, flags = 0; + int foreignset = 0, not = 0; /* First string is the auto-description definition. */ @@ -1250,51 +1249,72 @@ parse_cadef(char *nam, char **args) if (nonarg) tokenize(nonarg = dupstring(nonarg)); - /* Looks good. Optimistically allocate the cadef structure. */ all = ret = alloc_cadef(orig_args, single, match, nonarg, flags); optp = &(ret->opts); - anum = 1; - sargs = args; /* Get the definitions. */ - for (; *args; args++) { + for (; *args || pendset; args++) { + if (!*args) { + /* start new set */ + args = sargs; /* go back and repeat parse of common options */ + doset = NULL; + set_cadef_opts(ret); + ret = ret->snext = alloc_cadef(NULL, single, match, nonarg, flags); + optp = &(ret->opts); + anum = 1; + foreignset = 0; + curset = pendset; + pendset = 0; + } if (args[0][0] == '-' && !args[0][1] && args[1]) { - if (!state) { - char *p; - int l; - - if (setp) - args = setp; - p = *++args; - l = strlen(p) - 1; + if ((foreignset = curset && args != curset)) { + if (!pendset && args > curset) + pendset = args; /* mark pointer to next pending set */ + ++args; + } else { + /* Carrying on: this is the current set */ + char *p = *++args; + int l = strlen(p) - 1; + if (*p == '(' && p[l] == ')') { axor = p = dupstring(p + 1); p[l - 1] = '\0'; } else axor = NULL; + if (!*p) { + freecadef(all); + zwarnnam(nam, "empty set name"); + return NULL; + } ret->set = doset = tricat(p, "-", ""); - ret->sname = ztrdup(p); - state = 1; - } else { - setp = args; - state = 0; - args = sargs - 1; - doset = NULL; - ret->nopts = nopts; - ret->ndopts = ndopts; - ret->nodopts = nodopts; - set_cadef_opts(ret); - ret = ret->snext = alloc_cadef(NULL, single, NULL, nonarg, flags); - optp = &(ret->opts); - nopts = ndopts = nodopts = 0; - anum = 1; + curset = args; /* needed for the first set */ } continue; - } + } else if (args[0][0] == '+' && !args[0][1] && args[1]) { + char *p; + int l; + + foreignset = 0; /* group not in any set, don't want to skip it */ + p = *++args; + l = strlen(p) - 1; + if (*p == '(' && p[l] == ')') { + axor = p = dupstring(p + 1); + p[l - 1] = '\0'; + } else + axor = NULL; + if (!*p) { + freecadef(all); + zwarnnam(nam, "empty group name"); + return NULL; + } + doset = tricat(p, "-", ""); + continue; + } else if (foreignset) /* skipping over a different set */ + continue; p = dupstring(*args); xnum = 0; if ((not = (*p == '!'))) @@ -1506,7 +1526,7 @@ parse_cadef(char *nam, char **args) optp = &((*optp)->next); opt->next = NULL; - opt->set = doset; + opt->gsname = doset; opt->name = ztrdup(rembslashcolon(name)); if (descr) opt->descr = ztrdup(descr); @@ -1526,13 +1546,13 @@ parse_cadef(char *nam, char **args) opt->xor = (again == 1 && xor ? zarrdup(xor) : xor); opt->type = otype; opt->args = oargs; - opt->num = nopts++; + opt->num = ret->nopts++; opt->not = not; if (otype == CAO_DIRECT || otype == CAO_EQUAL) - ndopts++; + ret->ndopts++; else if (otype == CAO_ODIRECT || otype == CAO_OEQUAL) - nodopts++; + ret->nodopts++; /* If this is for single-letter option we also store a * pointer for the definition in the array for fast lookup. @@ -1584,7 +1604,7 @@ parse_cadef(char *nam, char **args) continue; if ((direct = idigit(*p))) { - /* Argment number is given. */ + /* Argument number is given. */ int num = 0; while (*p && idigit(*p)) @@ -1630,9 +1650,6 @@ parse_cadef(char *nam, char **args) ret->args = arg; } } - ret->nopts = nopts; - ret->ndopts = ndopts; - ret->nodopts = nodopts; set_cadef_opts(ret); return all; @@ -1751,6 +1768,27 @@ ca_get_sopt(Cadef d, char *line, char **end, LinkList *lp) return pp; } +/* Search for an option in all sets except the current one. + * Return true if found */ + +static int +ca_foreign_opt(Cadef curset, Cadef all, char *option) +{ + Cadef d; + Caopt p; + + for (d = all; d; d = d->snext) { + if (d == curset) + continue; + + for (p = d->opts; p; p = p->next) { + if (!strcmp(p->name, option)) + return 1; + } + } + return 0; +} + /* Return the n'th argument definition. */ static Caarg @@ -1776,77 +1814,95 @@ ca_get_arg(Cadef d, int n) * d: option definitions for a set * pass either: * xor: a list if exclusions - * opts: if set, all options excluded leaving only nornal/rest arguments - * if ca_xor list initialised, exclusions are added to it */ - -static LinkList ca_xor; + * opts: if set, all options excluded leaving only nornal/rest arguments */ -static int -ca_inactive(Cadef d, char **xor, int cur, int opts, char *optname) +static void +ca_inactive(Cadef d, char **xor, int cur, int opts) { if ((xor || opts) && cur <= compcurrent) { Caopt opt; char *x; - int sl = (d->set ? (int)strlen(d->set) : -1), set = 0; + /* current word could be a prefix of a longer one so only do + * exclusions for single-letter options (for option clumping) */ + int single = (cur == compcurrent); for (; (x = (opts ? "-" : *xor)); xor++) { - if (optname && optname[0] == x[0] && strcmp(optname, x)) - continue; - if (ca_xor) - addlinknode(ca_xor, x); - set = 0; - if (sl > 0) { - if (strpfx(d->set, x)) { - x += sl; - set = 1; - } else if (!strncmp(d->set, x, sl - 1)) { - Caopt p; - - for (p = d->opts; p; p = p->next) - if (p->set) - p->active = 0; - - x = ":"; - set = 1; + int excludeall = 0; + char *grp = NULL; + size_t grplen; + char *next, *sep = x; + + while (*sep != '+' && *sep != '-' && *sep != ':' && *sep != '*' && !idigit(*sep)) { + if (!(next = strchr(sep, '-')) || !*++next) { + /* exclusion is just the name of a set or group */ + excludeall = 1; /* excluding options and args */ + sep += strlen(sep); + /* A trailing '-' is included in the various gsname fields but is not + * there for this branch. This is why we add excludeall to grplen + * when checking for the null in a few places below */ + break; } + sep = next; + } + if (sep > x) { /* exclusion included a set or group name */ + grp = x; + grplen = sep - grp; + x = sep; } - if (x[0] == ':' && !x[1]) { - if (set) { + + if (excludeall || (x[0] == ':' && !x[1])) { + if (grp) { Caarg a; for (a = d->args; a; a = a->next) - if (a->set) + if (a->gsname && !strncmp(a->gsname, grp, grplen) && + !a->gsname[grplen + excludeall]) a->active = 0; - if (d->rest && (!set || d->rest->set)) + if (d->rest && d->rest->gsname && + !strncmp(d->rest->gsname, grp, grplen) && + !d->rest->gsname[grplen + excludeall]) d->rest->active = 0; } else d->argsactive = 0; - } else if (x[0] == '-' && !x[1]) { + } + + if (excludeall || (x[0] == '-' && !x[1])) { Caopt p; for (p = d->opts; p; p = p->next) - if (!set || p->set) + if ((!grp || (p->gsname && !strncmp(p->gsname, grp, grplen) && + !p->gsname[grplen + excludeall])) && + !(single && *p->name && p->name[1] && p->name[2])) p->active = 0; - } else if (x[0] == '*' && !x[1]) { - if (d->rest && (!set || d->rest->set)) - d->rest->active = 0; - } else if (idigit(x[0])) { - int n = atoi(x); - Caarg a = d->args; - - while (a && a->num < n) - a = a->next; + } - if (a && a->num == n && (!set || a->set)) - a->active = 0; - } else if ((opt = ca_get_opt(d, x, 1, NULL)) && (!set || opt->set)) - opt->active = 0; + if (excludeall || (x[0] == '*' && !x[1])) { + if (d->rest && (!grp || (d->rest->gsname && + !strncmp(d->rest->gsname, grp, grplen) && + !d->rest->gsname[grplen + excludeall]))) + d->rest->active = 0; + } - if (opts) - break; + if (!excludeall) { + if (idigit(x[0])) { + int n = atoi(x); + Caarg a = d->args; + + while (a && a->num < n) + a = a->next; + + if (a && a->num == n && (!grp || (a->gsname && + !strncmp(a->gsname, grp, grplen)))) + a->active = 0; + } else if ((opt = ca_get_opt(d, x, 1, NULL)) && + (!grp || (opt->gsname && !strncmp(opt->gsname, grp, grplen))) && + !(single && *opt->name && opt->name[1] && opt->name[2])) + opt->active = 0; + if (opts) + break; + } } } - return 0; } /* State when parsing a command line. */ @@ -1875,7 +1931,6 @@ struct castate { int curpos; /* current word position */ int argend; /* total number of words */ int inopt; /* set to current word pos if word is a recognised option */ - int inrest; /* unused */ int inarg; /* in a normal argument */ int nth; /* number of current normal arg */ int doff; /* length of current option */ @@ -1934,7 +1989,7 @@ ca_opt_arg(Caopt opt, char *line) * existing options on the line. */ static int -ca_parse_line(Cadef d, int multi, int first) +ca_parse_line(Cadef d, Cadef all, int multi, int first) { Caarg adef, ddef; Caopt ptr, wasopt = NULL, dopt; @@ -1978,7 +2033,7 @@ ca_parse_line(Cadef d, int multi, int first) state.argbeg = state.optbeg = state.nargbeg = state.restbeg = state.actopts = state.nth = state.inopt = state.inarg = state.opt = state.arg = 1; state.argend = argend = arrlen(compwords) - 1; - state.inrest = state.doff = state.singles = state.oopt = 0; + state.doff = state.singles = state.oopt = 0; state.curpos = compcurrent; state.args = znewlinklist(); state.oargs = (LinkList *) zalloc(d->nopts * sizeof(LinkList)); @@ -2025,10 +2080,9 @@ ca_parse_line(Cadef d, int multi, int first) remnulargs(line); untokenize(line); - if (ca_inactive(d, argxor, cur, 0, NULL) || - ((d->flags & CDF_SEP) && cur != compcurrent && !strcmp(line, "--"))) { - if (ca_inactive(d, NULL, cur, 1, NULL)) - return 1; + ca_inactive(d, argxor, cur, 0); + if ((d->flags & CDF_SEP) && cur != compcurrent && !strcmp(line, "--")) { + ca_inactive(d, NULL, cur, 1); continue; } @@ -2104,9 +2158,7 @@ ca_parse_line(Cadef d, int multi, int first) if (!state.oargs[state.curopt->num]) state.oargs[state.curopt->num] = znewlinklist(); - if (ca_inactive(d, state.curopt->xor, cur, 0, - (cur == compcurrent ? state.curopt->name : NULL))) - return 1; + ca_inactive(d, state.curopt->xor, cur, 0); /* Collect the argument strings. Maybe. */ @@ -2159,9 +2211,7 @@ ca_parse_line(Cadef d, int multi, int first) if (!state.oargs[tmpopt->num]) state.oargs[tmpopt->num] = znewlinklist(); - if (ca_inactive(d, tmpopt->xor, cur, 0, - (cur == compcurrent ? tmpopt->name : NULL))) - return 1; + ca_inactive(d, tmpopt->xor, cur, 0); } } if (state.def && @@ -2183,20 +2233,13 @@ ca_parse_line(Cadef d, int multi, int first) else state.curopt = NULL; } else if (multi && (*line == '-' || *line == '+') && cur != compcurrent -#if 0 - /**** Ouch. Using this will disable the mutual exclusion - of different sets. Not using it will make the -A - pattern be effectively ignored with multiple sets. */ - && (!napat || !pattry(napat, line)) -#endif - ) + && (ca_foreign_opt(d, all, line))) return 1; else if (state.arg && (!napat || cur <= compcurrent || !pattry(napat, line))) { /* Otherwise it's a normal argument. */ - if (napat && cur <= compcurrent && - ca_inactive(d, NULL, cur + 1, 1, NULL)) - return 1; + if (napat && cur <= compcurrent) + ca_inactive(d, NULL, cur + 1, 1); arglast = 1; /* if this is the first normal arg after an option, may have been @@ -2231,7 +2274,6 @@ ca_parse_line(Cadef d, int multi, int first) if (ca_laststate.def) break; - state.inrest = 0; state.opt = (cur == state.nargbeg + 1 && (!multi || !*line || *line == '-' || *line == '+')); @@ -2421,19 +2463,19 @@ ca_set_data(LinkList descr, LinkList act, LinkList subc, restrict_range(ca_laststate.argbeg, ca_laststate.argend); } if (arg->opt) { - buf = (char *) zhalloc((arg->set ? strlen(arg->set) : 0) + + buf = (char *) zhalloc((arg->gsname ? strlen(arg->gsname) : 0) + strlen(arg->opt) + 40); if (arg->num > 0 && arg->type < CAA_REST) sprintf(buf, "%soption%s-%d", - (arg->set ? arg->set : ""), arg->opt, arg->num); + (arg->gsname ? arg->gsname : ""), arg->opt, arg->num); else sprintf(buf, "%soption%s-rest", - (arg->set ? arg->set : ""), arg->opt); + (arg->gsname ? arg->gsname : ""), arg->opt); } else if (arg->num > 0) { sprintf(nbuf, "argument-%d", arg->num); - buf = (arg->set ? dyncat(arg->set, nbuf) : dupstring(nbuf)); + buf = (arg->gsname ? dyncat(arg->gsname, nbuf) : dupstring(nbuf)); } else - buf = (arg->set ? dyncat(arg->set, "argument-rest") : + buf = (arg->gsname ? dyncat(arg->gsname, "argument-rest") : dupstring("argument-rest")); addlinknode(subc, buf); @@ -2537,47 +2579,29 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) * auto-description string, the optional -s, -S, -A and -M options * given to _arguments and the specs. */ if (compcurrent > 1 && compwords[0]) { - Cadef def; + Cadef def, all; int cap = ca_parsed, multi, first = 1, use, ret = 0; - LinkList cax = ca_xor, nx; - LinkNode node; Castate states = NULL, sp; - char *xor[2]; ca_parsed = 0; - xor[1] = NULL; - if (!(def = get_cadef(nam, args + 1))) + if (!(def = all = get_cadef(nam, args + 1))) return 1; multi = !!def->snext; /* if we have sets */ ca_parsed = cap; - ca_xor = (multi ? newlinklist() : NULL); while (def) { /* for each set */ - use = !ca_parse_line(def, multi, first); - nx = ca_xor; - ca_xor = NULL; /* don't want to duplicate the xors in the list */ - while ((def = def->snext)) { - if (nx) { - for (node = firstnode(nx); node; incnode(node)) { - xor[0] = (char *) getdata(node); - if (!strcmp(xor[0], def->sname) || - ca_inactive(def, xor, compcurrent, 0, NULL)) - break; /* exclude this whole set */ - } - if (!node) /* continue with this set */ - break; - } - /* entire set was excluded, continue to next set */ - } - ca_xor = nx; + use = !ca_parse_line(def, all, multi, first); + def = def->snext; if (use && def) { + /* entry needed so save it into list */ sp = (Castate) zalloc(sizeof(*sp)); memcpy(sp, &ca_laststate, sizeof(*sp)); sp->snext = states; states = sp; } else if (!use && !def) { + /* final entry not needed */ if (states) { freecastate(&ca_laststate); memcpy(&ca_laststate, states, sizeof(*sp)); @@ -2589,7 +2613,6 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } first = 0; } - ca_xor = cax; ca_parsed = 1; ca_laststate.snext = states; @@ -2602,7 +2625,7 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) * things _arguments has to execute at this place on the line (the * sub-contexts are used as tags). * The return value is particularly important here, it says if - * there are arguments to completely at all. */ + * there are arguments to complete at all. */ { LinkList descr, act, subc; Caarg arg; @@ -2805,7 +2828,7 @@ bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) for (s = lstate; s; s = s->snext) for (o = s->d->opts, a = s->oargs; o; o = o->next, a++) if (*a) { - *p++ = (o->set ? tricat(o->set, o->name, "") : + *p++ = (o->gsname ? tricat(o->gsname, o->name, "") : ztrdup(o->name)); *p++ = ca_colonlist(*a); } @@ -3546,8 +3569,8 @@ bin_compvalues(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) Cvval val = cv_get_val(cv_laststate.d, args[1]); if (val && val->arg) { - setsparam(args[2], val->arg->descr); - setsparam(args[3], val->arg->action); + setsparam(args[2], ztrdup(val->arg->descr)); + setsparam(args[3], ztrdup(val->arg->action)); if (args[4]) setsparam(args[4], ztrdup(val->name)); @@ -3905,6 +3928,8 @@ bin_comptry(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) if (*q) { char *qq, *qqq; + queue_signals(); + if (c) *c = '\0'; @@ -3976,6 +4001,8 @@ bin_comptry(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } if (c) *c = ':'; + + unqueue_signals(); } } if (num) { @@ -4438,17 +4465,24 @@ cfp_matcher_pats(char *matcher, char *add) if (m && m != pcm_err) { char *tmp; int al = strlen(add), zl = ztrlen(add), tl, cl; - VARARR(Cmatcher, ms, zl); + VARARR(Cmatcher, ms, zl); /* One Cmatcher per character */ Cmatcher *mp; Cpattern stopp; int stopl = 0; + /* zl >= (number of wide characters) is guaranteed */ memset(ms, 0, zl * sizeof(Cmatcher)); for (; m && *add; m = m->next) { stopp = NULL; if (!(m->flags & (CMF_LEFT|CMF_RIGHT))) { if (m->llen == 1 && m->wlen == 1) { + /* + * In this loop and similar loops below we step + * through tmp one (possibly wide) character at a + * time. pattern_match() compares only the first + * character using unmeta_one() so keep in step. + */ for (tmp = add, tl = al, mp = ms; tl; ) { if (pattern_match(m->line, tmp, NULL, NULL)) { if (*mp) { @@ -4458,10 +4492,10 @@ cfp_matcher_pats(char *matcher, char *add) } else *mp = m; } - cl = (*tmp == Meta) ? 2 : 1; + (void) unmeta_one(tmp, &cl); tl -= cl; tmp += cl; - mp += cl; + mp++; } } else { stopp = m->line; @@ -4478,10 +4512,10 @@ cfp_matcher_pats(char *matcher, char *add) } else *mp = m; } - cl = (*tmp == Meta) ? 2 : 1; + (void) unmeta_one(tmp, &cl); tl -= cl; tmp += cl; - mp += cl; + mp++; } } else if (m->llen) { stopp = m->line; @@ -4504,7 +4538,7 @@ cfp_matcher_pats(char *matcher, char *add) al = tmp - add; break; } - cl = (*tmp == Meta) ? 2 : 1; + (void) unmeta_one(tmp, &cl); tl -= cl; tmp += cl; } @@ -4685,6 +4719,8 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, if (!*p) continue; + queue_signals(); /* Protect PAT_STATIC */ + tokenize(f); pprog = patcompile(f, PAT_STATIC, NULL); untokenize(f); @@ -4717,6 +4753,8 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, } } } + + unqueue_signals(); } } } diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c index 3db0781ff..bf83906f2 100644 --- a/Src/Zle/textobjects.c +++ b/Src/Zle/textobjects.c @@ -48,9 +48,10 @@ int selectword(UNUSED(char **args)) { int n = zmult; - int all = (bindk == t_selectaword || bindk == t_selectablankword); - int (*viclass)(ZLE_CHAR_T) = (bindk == t_selectaword || - bindk == t_selectinword) ? wordclass : blankwordclass; + int all = IS_THINGY(bindk, selectaword) || + IS_THINGY(bindk, selectablankword); + int (*viclass)(ZLE_CHAR_T) = (IS_THINGY(bindk, selectaword) || + IS_THINGY(bindk, selectinword)) ? wordclass : blankwordclass; int sclass = viclass(zleline[zlecs]); int doblanks = all && sclass; @@ -288,7 +289,7 @@ selectargument(UNUSED(char **args)) free(stringaszleline(linein, wstarts[wcur], &zlecs, &tmpsz, &mark)); free(linein); - if (bindk == t_selectinshellword) { + if (IS_THINGY(bindk, selectinshellword)) { ZLE_CHAR_T *match = ZWS("`\'\""); ZLE_CHAR_T *lmatch = ZWS("\'({"), *rmatch = ZWS("\')}"); ZLE_CHAR_T *ematch = match, *found; diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index 8f92e5611..07b310180 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -230,6 +230,13 @@ struct thingy { /* DISABLED is (1<<0) */ #define TH_IMMORTAL (1<<1) /* can't refer to a different widget */ +/* + * Check if bindk refers to named thingy (a set of bare characters), + * also checking the special .thingy widget. + */ +#define IS_THINGY(bindk, name) \ + ((bindk) == t_ ## name || (bindk) == t_D ## name) + /* command modifier prefixes */ struct modifier { diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index abd6e1749..581ca4979 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -1220,13 +1220,14 @@ doisearch(char **args, int dir, int pattern) char *patbuf = ztrdup(sbuf); char *patstring; /* - * Use static pattern buffer since we don't need - * to maintain it and won't call other pattern functions - * meanwhile. - * Use PAT_NOANCH because we don't need the match - * anchored to the end, even if it is at the start. + * Do not use static pattern buffer (PAT_STATIC) since we + * call zle hooks, which might call other pattern + * functions. Use PAT_ZDUP because we re-use the pattern + * in subsequent loops, so we can't pushheap/popheap. + * Use PAT_NOANCH because we don't need the match anchored + * to the end, even if it is at the start. */ - int patflags = PAT_STATIC|PAT_NOANCH; + int patflags = PAT_ZDUP|PAT_NOANCH; if (sbuf[0] == '^') { /* * We'll handle the anchor later when @@ -1521,6 +1522,7 @@ doisearch(char **args, int dir, int pattern) if (only_one || !top_spot || old_sbptr != sbptr) break; } + freepatprog(patprog); patprog = NULL; nosearch = 1; skip_pos = 0; @@ -1632,6 +1634,7 @@ doisearch(char **args, int dir, int pattern) } strcpy(sbuf + sbptr, paste); sbptr += pastelen; + freepatprog(patprog); patprog = NULL; free(paste); } else if (cmd == Th(z_acceptsearch)) { @@ -1682,6 +1685,7 @@ doisearch(char **args, int dir, int pattern) * always valid at this point. */ sbptr += zlecharasstring(LASTFULLCHAR, sbuf + sbptr); + freepatprog(patprog); patprog = NULL; } if (feep) @@ -1702,6 +1706,7 @@ doisearch(char **args, int dir, int pattern) zsfree(okeymap); if (matchlist) freematchlist(matchlist); + freepatprog(patprog); isearch_active = 0; /* * Don't allow unused characters provided as a string to the diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 04eb70675..2e96ac780 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -961,7 +961,7 @@ bin_bindkey_meta(char *name, char *kmname, Keymap km, UNUSED(char **argv), UNUSE m[0] = i; metafy(m, 1, META_NOALLOC); fn = keybind(km, m, &str); - if(fn == t_selfinsert || fn == t_undefinedkey) + if(IS_THINGY(fn, selfinsert) || fn == t_undefinedkey) bindkey(km, m, refthingy(Th(metabind[i - 128])), NULL); } return 0; diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 15ea79643..be2b062b0 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1245,6 +1245,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) resetneeded = 0; fetchttyinfo = 0; trashedzle = 0; + clearflag = 0; raw_lp = lp; lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL, &pmpt_attr); raw_rp = rp; @@ -1484,6 +1485,13 @@ execzlefunc(Thingy func, char **args, int set_bindk) int inuse = w->flags & WIDGET_INUSE; w->flags |= WIDGET_INUSE; + if (osi > 0) { + /* + * Many commands don't like having a closed stdin, open on + * /dev/null instead + */ + open("/dev/null", O_RDWR | O_NOCTTY); /* ignore failure */ + } if (*args) { largs = newlinklist(); addlinknode(largs, dupstring(w->u.fnnam)); diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index 1e4c5b832..0a922d2d6 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -85,6 +85,8 @@ static const struct gsu_integer cursor_gsu = { get_cursor, set_cursor, zleunsetfn }; static const struct gsu_integer histno_gsu = { get_histno, set_histno, zleunsetfn }; +static const struct gsu_integer keys_queued_count_gsu = +{ get_keys_queued_count, NULL, zleunsetfn }; static const struct gsu_integer mark_gsu = { get_mark, set_mark, zleunsetfn }; static const struct gsu_integer numeric_gsu = @@ -146,6 +148,8 @@ static struct zleparam { { "HISTNO", PM_INTEGER, GSU(histno_gsu), NULL }, { "KEYMAP", PM_SCALAR | PM_READONLY, GSU(keymap_gsu), NULL }, { "KEYS", PM_SCALAR | PM_READONLY, GSU(keys_gsu), NULL }, + { "KEYS_QUEUED_COUNT", PM_INTEGER | PM_READONLY, GSU(keys_queued_count_gsu), + NULL}, { "killring", PM_ARRAY, GSU(killring_gsu), NULL }, { "LASTABORTEDSEARCH", PM_SCALAR | PM_READONLY, GSU(lastabortedsearch_gsu), NULL }, @@ -458,6 +462,13 @@ get_keys(UNUSED(Param pm)) } /**/ +static zlong +get_keys_queued_count(UNUSED(Param pm)) +{ + return kungetct; +} + +/**/ static void set_numeric(UNUSED(Param pm), zlong x) { diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 8d173cda1..d0dd1ef06 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -1278,7 +1278,7 @@ zrefresh(void) #ifdef __STDC_ISO_10646__ !ZSH_INVALID_WCHAR_TEST(*t) && #endif - iswprint(*t) && (width = WCWIDTH(*t)) > 0) { + WC_ISPRINT(*t) && (width = WCWIDTH(*t)) > 0) { int ichars; if (width > rpms.sen - rpms.s) { int started = 0; @@ -1460,7 +1460,7 @@ zrefresh(void) u = outputline; for (; u < outputline + outll; u++) { #ifdef MULTIBYTE_SUPPORT - if (iswprint(*u)) { + if (WC_ISPRINT(*u)) { int width = WCWIDTH(*u); /* Handle wide characters as above */ if (width > rpms.sen - rpms.s) { @@ -2434,8 +2434,8 @@ redisplay(UNUSED(char **args)) moveto(0, 0); zputc(&zr_cr); /* extra care */ tc_upcurs(lprompth - 1); - resetneeded = !showinglist; - clearflag = showinglist; + resetneeded = 1; + clearflag = 0; return 0; } @@ -2468,7 +2468,7 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) if (tmpline[t0] == ZWC('\t')) vsiz = (vsiz | 7) + 2; #ifdef MULTIBYTE_SUPPORT - else if (iswprint(tmpline[t0]) && ((width = WCWIDTH(tmpline[t0])) > 0)) { + else if (WC_ISPRINT(tmpline[t0]) && ((width = WCWIDTH(tmpline[t0])) > 0)) { vsiz += width; if (isset(COMBININGCHARS) && IS_BASECHAR(tmpline[t0])) { while (t0 < tmpll-1 && IS_COMBINING(tmpline[t0+1])) @@ -2556,7 +2556,7 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs) vp->atr = all_atr_on | all_atr_off; vp++; #ifdef MULTIBYTE_SUPPORT - } else if (iswprint(tmpline[t0]) && + } else if (WC_ISPRINT(tmpline[t0]) && (width = WCWIDTH(tmpline[t0])) > 0) { int ichars; if (isset(COMBININGCHARS) && IS_BASECHAR(tmpline[t0])) { diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index c7092854a..f7e9829c2 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -602,7 +602,7 @@ bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func) Thingy t; Widget w, cw; - if (require_module("zsh/complete", NULL) == 1) { + if (require_module("zsh/complete", NULL, 0) == 1) { zwarnnam(name, "can't load complete module"); return 1; } @@ -703,7 +703,7 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) { Thingy t; struct modifier modsave = zmod; - int ret, saveflag = 0, setbindk = 0; + int ret, saveflag = 0, setbindk = 0, remetafy; char *wname = *args++, *keymap_restore = NULL, *keymap_tmp; if (!wname) @@ -714,7 +714,15 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) return 1; } - UNMETACHECK(); + /* + * zle is callable in traps, so we can't be sure the line is + * in its normal state. + */ + if (zlemetaline) { + unmetafy_line(); + remetafy = 1; + } else + remetafy = 0; while (*args && **args == '-') { char *num; @@ -728,6 +736,8 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) num = args[0][1] ? args[0]+1 : args[1]; if (!num) { zwarnnam(name, "number expected after -%c", **args); + if (remetafy) + metafy_line(); return 1; } if (!args[0][1]) @@ -745,19 +755,26 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) keymap_tmp = args[0][1] ? args[0]+1 : args[1]; if (!keymap_tmp) { zwarnnam(name, "keymap expected after -%c", **args); + if (remetafy) + metafy_line(); return 1; } if (!args[0][1]) *++args = "" - 1; keymap_restore = dupstring(curkeymapname); - if (selectkeymap(keymap_tmp, 0)) + if (selectkeymap(keymap_tmp, 0)) { + if (remetafy) + metafy_line(); return 1; + } break; case 'w': setbindk = 1; break; default: zwarnnam(name, "unknown option: %s", *args); + if (remetafy) + metafy_line(); return 1; } } @@ -775,6 +792,8 @@ bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) zmod = modsave; if (keymap_restore) selectkeymap(keymap_restore, 0); + if (remetafy) + metafy_line(); return ret; } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 3d8679119..5a9cccb6f 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -2407,53 +2407,6 @@ sfxlen(char *s, char *t) } #endif -/* This is zstrcmp with ignoring backslashes. */ - -/**/ -mod_export int -zstrbcmp(const char *a, const char *b) -{ - const char *astart = a; - - while (*a && *b) { - if (*a == '\\') - a++; - if (*b == '\\') - b++; - if (*a != *b || !*a) - break; - a++; - b++; - } - if (isset(NUMERICGLOBSORT) && (idigit(*a) || idigit(*b))) { - for (; a > astart && idigit(a[-1]); a--, b--); - if (idigit(*a) && idigit(*b)) { - while (*a == '0') - a++; - while (*b == '0') - b++; - for (; idigit(*a) && *a == *b; a++, b++); - if (idigit(*a) || idigit(*b)) { - int cmp = (int) STOUC(*a) - (int) STOUC(*b); - - while (idigit(*a) && idigit(*b)) - a++, b++; - if (idigit(*a) && !idigit(*b)) - return 1; - if (idigit(*b) && !idigit(*a)) - return -1; - - return cmp; - } - } - } -#ifndef HAVE_STRCOLL - return (int)(*a - *b); -#else - return strcoll(a,b); -#endif -} - /* This is used to print the strings (e.g. explanations). * * It returns the number of lines printed. */ diff --git a/Src/builtin.c b/Src/builtin.c index 0f04d149f..2e72ba20a 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -46,7 +46,7 @@ static struct builtin builtins[] = BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL), BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL), BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmrs", NULL), - BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "mktTUwXz", "u"), + BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "dmktrRTUwWXz", "u"), BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL), BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL), BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL), @@ -72,7 +72,7 @@ static struct builtin builtins[] = BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL), BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"), - BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUx:z", NULL), + BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMstTuUWx:z", NULL), BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"), BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL), BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv", NULL), @@ -131,7 +131,7 @@ static struct builtin builtins[] = BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSwx:", NULL), BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsSwx:", "ca"), BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsSwx:", "c"), - BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpue", NULL), + BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpsue", NULL), BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL), }; @@ -539,18 +539,18 @@ bin_enable(char *name, char **argv, Options ops, int func) /* With -m option, treat arguments as glob patterns. */ if (OPT_ISSET(ops,'m')) { for (; *argv; argv++) { + queue_signals(); + /* parse pattern */ tokenize(*argv); - if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { - queue_signals(); + if ((pprog = patcompile(*argv, PAT_STATIC, 0))) match += scanmatchtable(ht, pprog, 0, 0, 0, scanfunc, 0); - unqueue_signals(); - } else { untokenize(*argv); zwarnnam(name, "bad pattern : %s", *argv); returnval = 1; } + unqueue_signals(); } /* If we didn't match anything, we return 1. */ if (!match) @@ -796,8 +796,8 @@ set_pwd_env(void) unsetparam_pm(pm, 0, 1); } - setsparam("PWD", ztrdup(pwd)); - setsparam("OLDPWD", ztrdup(oldpwd)); + assignsparam("PWD", ztrdup(pwd), 0); + assignsparam("OLDPWD", ztrdup(oldpwd), 0); pm = (Param) paramtab->getnode(paramtab, "PWD"); if (!(pm->node.flags & PM_EXPORTED)) @@ -880,8 +880,13 @@ cd_get_dest(char *nam, char **argv, int hard, int func) dir = nextnode(firstnode(dirstack)); if (dir) zinsertlinknode(dirstack, dir, getlinknode(dirstack)); - else if (func != BIN_POPD) + else if (func != BIN_POPD) { + if (!home) { + zwarnnam(nam, "HOME not set"); + return NULL; + } zpushnode(dirstack, ztrdup(home)); + } } else if (!argv[1]) { int dd; char *end; @@ -936,6 +941,10 @@ cd_get_dest(char *nam, char **argv, int hard, int func) if (!dir) { dir = firstnode(dirstack); } + if (!dir || !getdata(dir)) { + DPUTS(1, "Directory not set, not detected early enough"); + return NULL; + } if (!(dest = cd_do_chdir(nam, getdata(dir), hard))) { if (!target) zsfree(getlinknode(dirstack)); @@ -2922,9 +2931,61 @@ eval_autoload(Shfunc shf, char *name, Options ops, int func) } return !loadautofn(shf, (OPT_ISSET(ops,'k') ? 2 : - (OPT_ISSET(ops,'z') ? 0 : 1)), 1); + (OPT_ISSET(ops,'z') ? 0 : 1)), 1, + OPT_ISSET(ops,'d')); } +/* Helper for bin_functions() for -X and -r options */ + +/**/ +static int +check_autoload(Shfunc shf, char *name, Options ops, int func) +{ + if (OPT_ISSET(ops,'X')) + { + return eval_autoload(shf, name, ops, func); + } + if ((OPT_ISSET(ops,'r') || OPT_ISSET(ops,'R')) && + (shf->node.flags & PM_UNDEFINED)) + { + char *dir_path; + if (shf->filename && (shf->node.flags & PM_LOADDIR)) { + char *spec_path[2]; + spec_path[0] = shf->filename; + spec_path[1] = NULL; + if (getfpfunc(shf->node.nam, NULL, &dir_path, spec_path, 1)) { + /* shf->filename is already correct. */ + return 0; + } + if (!OPT_ISSET(ops,'d')) { + if (OPT_ISSET(ops,'R')) { + zerr("%s: function definition file not found", + shf->node.nam); + return 1; + } + return 0; + } + } + if (getfpfunc(shf->node.nam, NULL, &dir_path, NULL, 1)) { + dircache_set(&shf->filename, NULL); + if (*dir_path != '/') { + dir_path = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), + "/", dir_path); + dir_path = xsymlink(dir_path, 1); + } + dircache_set(&shf->filename, dir_path); + shf->node.flags |= PM_LOADDIR; + return 0; + } + if (OPT_ISSET(ops,'R')) { + zerr("%s: function definition file not found", + shf->node.nam); + return 1; + } + /* with -r, we don't flag an error, just let it be found later. */ + } + return 0; +} /* List a user-defined math function. */ static void @@ -2941,7 +3002,7 @@ listusermathfunc(MathFunc p) else showargs = 0; - printf("functions -M %s", p->name); + printf("functions -M%s %s", (p->flags & MFF_STR) ? "s" : "", p->name); if (showargs) { printf(" %d", p->minargs); showargs--; @@ -2962,6 +3023,66 @@ listusermathfunc(MathFunc p) } +static void +add_autoload_function(Shfunc shf, char *funcname) +{ + char *nam; + if (*funcname == '/' && funcname[1] && + (nam = strrchr(funcname, '/')) && nam[1] && + (shf->node.flags & PM_UNDEFINED)) { + char *dir; + nam = strrchr(funcname, '/'); + if (nam == funcname) { + dir = "/"; + } else { + *nam++ = '\0'; + dir = funcname; + } + dircache_set(&shf->filename, NULL); + dircache_set(&shf->filename, dir); + shf->node.flags |= PM_LOADDIR; + shf->node.flags |= PM_ABSPATH_USED; + shfunctab->addnode(shfunctab, ztrdup(nam), shf); + } else { + Shfunc shf2; + Funcstack fs; + const char *calling_f = NULL; + char buf[PATH_MAX+1]; + + /* Find calling function */ + for (fs = funcstack; fs; fs = fs->prev) { + if (fs->tp == FS_FUNC && fs->name && (!shf->node.nam || 0 != strcmp(fs->name,shf->node.nam))) { + calling_f = fs->name; + break; + } + } + + /* Get its directory */ + if (calling_f) { + /* Should contain load directory, and be loaded via absolute path */ + if ((shf2 = (Shfunc) shfunctab->getnode2(shfunctab, calling_f)) + && (shf2->node.flags & PM_LOADDIR) && (shf2->node.flags & PM_ABSPATH_USED) + && shf2->filename) + { + if (strlen(shf2->filename) + strlen(funcname) + 1 < PATH_MAX) + { + sprintf(buf, "%s/%s", shf2->filename, funcname); + /* Set containing directory if the function file + * exists (do normal FPATH processing otherwise) */ + if (!access(buf, R_OK)) { + dircache_set(&shf->filename, NULL); + dircache_set(&shf->filename, shf2->filename); + shf->node.flags |= PM_LOADDIR; + shf->node.flags |= PM_ABSPATH_USED; + } + } + } + } + + shfunctab->addnode(shfunctab, ztrdup(funcname), shf); + } +} + /* Display or change the attributes of shell functions. * * If called as autoload, it will define a new autoloaded * * (undefined) shell function. */ @@ -2992,6 +3113,10 @@ bin_functions(char *name, char **argv, Options ops, int func) on |= PM_TAGGED_LOCAL; else if (OPT_PLUS(ops,'T')) off |= PM_TAGGED_LOCAL; + if (OPT_MINUS(ops,'W')) + on |= PM_WARNNESTED; + else if (OPT_PLUS(ops,'W')) + off |= PM_WARNNESTED; roff = off; if (OPT_MINUS(ops,'z')) { on |= PM_ZSHSTORED; @@ -3007,10 +3132,17 @@ bin_functions(char *name, char **argv, Options ops, int func) off |= PM_KSHSTORED; roff |= PM_KSHSTORED; } + if (OPT_MINUS(ops,'d')) { + on |= PM_CUR_FPATH; + off |= PM_CUR_FPATH; + } else if (OPT_PLUS(ops,'d')) { + off |= PM_CUR_FPATH; + roff |= PM_CUR_FPATH; + } if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) || (OPT_ISSET(ops,'x') && !OPT_HASARG(ops,'x')) || - (OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || *argv || !scriptname))) { + (OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || !scriptname))) { zwarnnam(name, "invalid option(s)"); return 1; } @@ -3049,9 +3181,9 @@ bin_functions(char *name, char **argv, Options ops, int func) } else if (OPT_ISSET(ops,'m')) { /* List matching functions. */ for (; *argv; argv++) { + queue_signals(); tokenize(*argv); if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { - queue_signals(); for (p = mathfuncs, q = NULL; p; q = p) { MathFunc next; do { @@ -3070,12 +3202,12 @@ bin_functions(char *name, char **argv, Options ops, int func) if (p) p = p->next; } - unqueue_signals(); } else { untokenize(*argv); zwarnnam(name, "bad pattern : %s", *argv); returnval = 1; } + unqueue_signals(); } } else if (OPT_PLUS(ops,'M')) { /* Delete functions. -m is allowed but is handled above. */ @@ -3097,11 +3229,18 @@ bin_functions(char *name, char **argv, Options ops, int func) } } else { /* Add a function */ - int minargs = 0, maxargs = -1; + int minargs, maxargs; char *funcname = *argv++; char *modname = NULL; char *ptr; + if (OPT_ISSET(ops,'s')) { + minargs = maxargs = 1; + } else { + minargs = 0; + maxargs = -1; + } + ptr = itype_end(funcname, IIDENT, 0); if (idigit(*funcname) || funcname == ptr || *ptr) { zwarnnam(name, "-M %s: bad math function name", funcname); @@ -3115,6 +3254,10 @@ bin_functions(char *name, char **argv, Options ops, int func) *argv); return 1; } + if (OPT_ISSET(ops,'s') && minargs != 1) { + zwarnnam(name, "-Ms: must take a single string argument"); + return 1; + } maxargs = minargs; argv++; } @@ -3128,6 +3271,10 @@ bin_functions(char *name, char **argv, Options ops, int func) *argv); return 1; } + if (OPT_ISSET(ops,'s') && maxargs != 1) { + zwarnnam(name, "-Ms: must take a single string argument"); + return 1; + } argv++; } if (*argv) @@ -3140,6 +3287,8 @@ bin_functions(char *name, char **argv, Options ops, int func) p = (MathFunc)zshcalloc(sizeof(struct mathfunc)); p->name = ztrdup(funcname); p->flags = MFF_USERFUNC; + if (OPT_ISSET(ops,'s')) + p->flags |= MFF_STR; p->module = modname ? ztrdup(modname) : NULL; p->minargs = minargs; p->maxargs = maxargs; @@ -3165,47 +3314,58 @@ bin_functions(char *name, char **argv, Options ops, int func) return returnval; } - /* If no arguments given, we will print functions. If flags * - * are given, we will print only functions containing these * - * flags, else we'll print them all. */ - if (!*argv) { - int ret = 0; - + if (OPT_MINUS(ops,'X')) { + Funcstack fs; + char *funcname = NULL; + int ret; + if (*argv && argv[1]) { + zwarnnam(name, "-X: too many arguments"); + return 1; + } queue_signals(); - if (OPT_MINUS(ops,'X')) { - Funcstack fs; - char *funcname = NULL; - for (fs = funcstack; fs; fs = fs->prev) { - if (fs->tp == FS_FUNC) { - /* - * dupstring here is paranoia but unlikely to be - * problematic - */ - funcname = dupstring(fs->name); - break; - } + for (fs = funcstack; fs; fs = fs->prev) { + if (fs->tp == FS_FUNC) { + /* + * dupstring here is paranoia but unlikely to be + * problematic + */ + funcname = dupstring(fs->name); + break; } - if (!funcname) - { - zerrnam(name, "bad autoload"); - ret = 1; + } + if (!funcname) + { + zerrnam(name, "bad autoload"); + ret = 1; + } else { + if ((shf = (Shfunc) shfunctab->getnode(shfunctab, funcname))) { + DPUTS(!shf->funcdef, + "BUG: Calling autoload from empty function"); } else { - if ((shf = (Shfunc) shfunctab->getnode(shfunctab, funcname))) { - DPUTS(!shf->funcdef, - "BUG: Calling autoload from empty function"); - } else { - shf = (Shfunc) zshcalloc(sizeof *shf); - shfunctab->addnode(shfunctab, ztrdup(funcname), shf); - } - shf->node.flags = on; - ret = eval_autoload(shf, funcname, ops, func); + shf = (Shfunc) zshcalloc(sizeof *shf); + shfunctab->addnode(shfunctab, ztrdup(funcname), shf); } - } else { - if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u')) + if (*argv) { + dircache_set(&shf->filename, NULL); + dircache_set(&shf->filename, *argv); + on |= PM_LOADDIR; + } + shf->node.flags = on; + ret = eval_autoload(shf, funcname, ops, func); + } + unqueue_signals(); + return ret; + } else if (!*argv) { + /* If no arguments given, we will print functions. If flags * + * are given, we will print only functions containing these * + * flags, else we'll print them all. */ + int ret = 0; + + queue_signals(); + if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u')) on &= ~PM_UNDEFINED; scanshfunc(1, on|off, DISABLED, shfunctab->printnode, pflags, expand); - } unqueue_signals(); return ret; } @@ -3214,11 +3374,11 @@ bin_functions(char *name, char **argv, Options ops, int func) if (OPT_ISSET(ops,'m')) { on &= ~PM_UNDEFINED; for (; *argv; argv++) { + queue_signals(); /* expand argument */ tokenize(*argv); if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { /* with no options, just print all functions matching the glob pattern */ - queue_signals(); if (!(on|off) && !OPT_ISSET(ops,'X')) { scanmatchshfunc(pprog, 1, 0, DISABLED, shfunctab->printnode, pflags, expand); @@ -3231,19 +3391,19 @@ bin_functions(char *name, char **argv, Options ops, int func) !(shf->node.flags & DISABLED)) { shf->node.flags = (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off; - if (OPT_ISSET(ops,'X') && - eval_autoload(shf, shf->node.nam, ops, func)) { + if (check_autoload(shf, shf->node.nam, + ops, func)) { returnval = 1; } } } } - unqueue_signals(); } else { untokenize(*argv); zwarnnam(name, "bad pattern : %s", *argv); returnval = 1; } + unqueue_signals(); } return returnval; } @@ -3258,8 +3418,7 @@ bin_functions(char *name, char **argv, Options ops, int func) if (on|off) { /* turn on/off the given flags */ shf->node.flags = (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off; - if (OPT_ISSET(ops,'X') && - eval_autoload(shf, shf->node.nam, ops, func)) + if (check_autoload(shf, shf->node.nam, ops, func)) returnval = 1; } else /* no flags, so just print */ @@ -3276,13 +3435,38 @@ bin_functions(char *name, char **argv, Options ops, int func) removetrapnode(signum); } + if (**argv == '/') { + char *base = strrchr(*argv, '/') + 1; + if (*base && + (shf = (Shfunc) shfunctab->getnode(shfunctab, base))) { + char *dir; + /* turn on/off the given flags */ + shf->node.flags = + (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off; + if (shf->node.flags & PM_UNDEFINED) { + /* update path if not yet loaded */ + if (base == *argv + 1) + dir = "/"; + else { + dir = *argv; + base[-1] = '\0'; + } + dircache_set(&shf->filename, NULL); + dircache_set(&shf->filename, dir); + } + if (check_autoload(shf, shf->node.nam, ops, func)) + returnval = 1; + continue; + } + } + /* Add a new undefined (autoloaded) function to the * * hash table with the corresponding flags set. */ shf = (Shfunc) zshcalloc(sizeof *shf); shf->node.flags = on; shf->funcdef = mkautofn(shf); shfunc_set_sticky(shf); - shfunctab->addnode(shfunctab, ztrdup(*argv), shf); + add_autoload_function(shf, *argv); if (signum != -1) { if (settrap(signum, NULL, ZSIG_FUNC)) { @@ -3293,8 +3477,7 @@ bin_functions(char *name, char **argv, Options ops, int func) } } - if (ok && OPT_ISSET(ops,'X') && - eval_autoload(shf, shf->node.nam, ops, func)) + if (ok && check_autoload(shf, shf->node.nam, ops, func)) returnval = 1; } else returnval = 1; @@ -3348,11 +3531,11 @@ bin_unset(char *name, char **argv, Options ops, int func) /* with -m option, treat arguments as glob patterns */ if (OPT_ISSET(ops,'m')) { while ((s = *argv++)) { + queue_signals(); /* expand */ tokenize(s); if ((pprog = patcompile(s, PAT_STATIC, NULL))) { /* Go through the parameter table, and unset any matches */ - queue_signals(); for (i = 0; i < paramtab->hsize; i++) { for (pm = (Param) paramtab->nodes[i]; pm; pm = next) { /* record pointer to next, since we may free this one */ @@ -3365,12 +3548,12 @@ bin_unset(char *name, char **argv, Options ops, int func) } } } - unqueue_signals(); } else { untokenize(s); zwarnnam(name, "bad pattern : %s", s); returnval = 1; } + unqueue_signals(); } /* If we didn't match anything, we return 1. */ if (!match) @@ -3534,6 +3717,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) pushheap(); matchednodes = newlinklist(); } + queue_signals(); for (; *argv; argv++) { /* parse the pattern */ tokenize(*argv); @@ -3543,7 +3727,6 @@ bin_whence(char *nam, char **argv, Options ops, int func) returnval = 1; continue; } - queue_signals(); if (!OPT_ISSET(ops,'p')) { /* -p option is for path search only. * * We're not using it, so search for ... */ @@ -3574,9 +3757,9 @@ bin_whence(char *nam, char **argv, Options ops, int func) scanmatchtable(cmdnamtab, pprog, 1, 0, 0, (all ? fetchcmdnamnode : cmdnamtab->printnode), printflags); - - unqueue_signals(); + run_queued_signals(); } + unqueue_signals(); if (all) { allmatched = argv = zlinklist2array(matchednodes); matchednodes = NULL; @@ -3653,9 +3836,11 @@ bin_whence(char *nam, char **argv, Options ops, int func) if (wd) { printf("%s: command\n", *argv); } else { - if (v && !csh) + if (v && !csh) { zputs(*argv, stdout), fputs(" is ", stdout); - zputs(buf, stdout); + quotedzputs(buf, stdout); + } else + zputs(buf, stdout); if (OPT_ISSET(ops,'s') || OPT_ISSET(ops, 'S')) print_if_link(buf, OPT_ISSET(ops, 'S')); fputc('\n', stdout); @@ -3685,9 +3870,11 @@ bin_whence(char *nam, char **argv, Options ops, int func) if (wd) { printf("%s: command\n", *argv); } else { - if (v && !csh) + if (v && !csh) { zputs(*argv, stdout), fputs(" is ", stdout); - zputs(cnam, stdout); + quotedzputs(cnam, stdout); + } else + zputs(cnam, stdout); if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'S')) print_if_link(cnam, OPT_ISSET(ops,'S')); fputc('\n', stdout); @@ -3899,11 +4086,11 @@ bin_unhash(char *name, char **argv, Options ops, int func) * "unhash -m '*'" is legal, but not recommended. */ if (OPT_ISSET(ops,'m')) { for (; *argv; argv++) { + queue_signals(); /* expand argument */ tokenize(*argv); if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) { /* remove all nodes matching glob pattern */ - queue_signals(); for (i = 0; i < ht->hsize; i++) { for (hn = ht->nodes[i]; hn; hn = nhn) { /* record pointer to next, since we may free this one */ @@ -3914,12 +4101,12 @@ bin_unhash(char *name, char **argv, Options ops, int func) } } } - unqueue_signals(); } else { untokenize(*argv); zwarnnam(name, "bad pattern : %s", *argv); returnval = 1; } + unqueue_signals(); } /* If we didn't match anything, we return 1. */ if (!match) @@ -4002,18 +4189,18 @@ bin_alias(char *name, char **argv, Options ops, UNUSED(int func)) * glob patterns of aliases to display. */ if (OPT_ISSET(ops,'m')) { for (; *argv; argv++) { + queue_signals(); tokenize(*argv); /* expand argument */ if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) { /* display the matching aliases */ - queue_signals(); scanmatchtable(ht, pprog, 1, flags1, flags2, ht->printnode, printflags); - unqueue_signals(); } else { untokenize(*argv); zwarnnam(name, "bad pattern : %s", *argv); returnval = 1; } + unqueue_signals(); } return returnval; } @@ -4223,10 +4410,12 @@ bin_print(char *name, char **args, Options ops, int func) zwarnnam(name, "no pattern specified"); return 1; } + queue_signals(); tokenize(*args); if (!(pprog = patcompile(*args, PAT_STATIC, NULL))) { untokenize(*args); zwarnnam(name, "bad pattern: %s", *args); + unqueue_signals(); return 1; } for (t = p = ++args; *p; p++) @@ -4234,6 +4423,7 @@ bin_print(char *name, char **args, Options ops, int func) *t++ = *p; *t = NULL; first = args; + unqueue_signals(); if (fmt && !*args) return 0; } /* compute lengths, and interpret according to -P, -D, -e, etc. */ @@ -5319,7 +5509,7 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func) } /*FALLTHROUGH*/ case BIN_EXIT: - if (locallevel > forklevel) { + if (locallevel > forklevel && shell_exiting != -1) { /* * We don't exit directly from functions to allow tidying * up, in particular EXIT traps. We still need to perform @@ -5328,6 +5518,9 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func) * * If we are forked, we exit the shell at the function depth * at which we became a subshell, hence the comparison. + * + * If we are already exiting... give this all up as + * a bad job. */ if (stopmsg || (zexit(0,2), !stopmsg)) { retflag = 1; @@ -5374,6 +5567,14 @@ checkjobs(void) } } +/* + * -1 if the shell is already committed to exit. + * positive if zexit() was already called. + */ + +/**/ +int shell_exiting; + /* exit the shell. val is the return value of the shell. * * from_where is * 1 if zexit is called because of a signal @@ -5385,10 +5586,8 @@ checkjobs(void) mod_export void zexit(int val, int from_where) { - static int in_exit; - /* Don't do anything recursively: see below */ - if (in_exit == -1) + if (shell_exiting == -1) return; if (isset(MONITOR) && !stopmsg && from_where != 1) { @@ -5401,14 +5600,14 @@ zexit(int val, int from_where) } } /* Positive in_exit means we have been here before */ - if (from_where == 2 || (in_exit++ && from_where)) + if (from_where == 2 || (shell_exiting++ && from_where)) return; /* - * We're now committed to exiting. Set in_exit to -1 to + * We're now committed to exiting. Set shell_exiting to -1 to * indicate we shouldn't do any recursive processing. */ - in_exit = -1; + shell_exiting = -1; /* * We want to do all remaining processing regardless of preceding * errors, even user interrupts. diff --git a/Src/compat.c b/Src/compat.c index a2956946f..a130d9264 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -672,7 +672,7 @@ strtoul(nptr, endptr, base) /**/ int -mk_wcwidth(wchar_t ucs) +u9_wcwidth(wchar_t ucs) { int w = wcwidth9(ucs); if (w < -1) @@ -681,326 +681,16 @@ mk_wcwidth(wchar_t ucs) } /**/ -#elif defined(BROKEN_WCWIDTH) && (defined(__STDC_ISO_10646__) || defined(__APPLE__)) - -/* - * This is an implementation of wcwidth() and wcswidth() (defined in - * IEEE Std 1002.1-2001) for Unicode. - * - * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html - * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html - * - * In fixed-width output devices, Latin characters all occupy a single - * "cell" position of equal width, whereas ideographic CJK characters - * occupy two such cells. Interoperability between terminal-line - * applications and (teletype-style) character terminals using the - * UTF-8 encoding requires agreement on which character should advance - * the cursor by how many cell positions. No established formal - * standards exist at present on which Unicode character shall occupy - * how many cell positions on character terminals. These routines are - * a first attempt of defining such behavior based on simple rules - * applied to data provided by the Unicode Consortium. - * - * For some graphical characters, the Unicode standard explicitly - * defines a character-cell width via the definition of the East Asian - * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. - * In all these cases, there is no ambiguity about which width a - * terminal shall use. For characters in the East Asian Ambiguous (A) - * class, the width choice depends purely on a preference of backward - * compatibility with either historic CJK or Western practice. - * Choosing single-width for these characters is easy to justify as - * the appropriate long-term solution, as the CJK practice of - * displaying these characters as double-width comes from historic - * implementation simplicity (8-bit encoded characters were displayed - * single-width and 16-bit ones double-width, even for Greek, - * Cyrillic, etc.) and not any typographic considerations. - * - * Much less clear is the choice of width for the Not East Asian - * (Neutral) class. Existing practice does not dictate a width for any - * of these characters. It would nevertheless make sense - * typographically to allocate two character cells to characters such - * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be - * represented adequately with a single-width glyph. The following - * routines at present merely assign a single-cell width to all - * neutral characters, in the interest of simplicity. This is not - * entirely satisfactory and should be reconsidered before - * establishing a formal standard in this area. At the moment, the - * decision which Not East Asian (Neutral) characters should be - * represented by double-width glyphs cannot yet be answered by - * applying a simple rule from the Unicode database content. Setting - * up a proper standard for the behavior of UTF-8 character terminals - * will require a careful analysis not only of each Unicode character, - * but also of each presentation form, something the author of these - * routines has avoided to do so far. - * - * http://www.unicode.org/unicode/reports/tr11/ - * - * Markus Kuhn -- 2007-05-26 (Unicode 5.0) - * - * Permission to use, copy, modify, and distribute this software - * for any purpose and without fee is hereby granted. The author - * disclaims all warranties with regard to this software. - * - * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ - -struct interval { - int first; - int last; -}; - -/* auxiliary function for binary search in interval table */ -static int bisearch(wchar_t ucs, const struct interval *table, int max) { - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) - return 0; - while (max >= min) { - mid = (min + max) / 2; - if (ucs > table[mid].last) - min = mid + 1; - else if (ucs < table[mid].first) - max = mid - 1; - else - return 1; - } - - return 0; -} - - -/* The following two functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - SOFT HYPHEN (U+00AD) has a column width of 1. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * Full-width (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that wchar_t characters are encoded - * in ISO 10646. - */ - -/**/ int -mk_wcwidth(wchar_t ucs) -{ - /* sorted list of non-overlapping intervals of non-spacing characters */ - /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ - static const struct interval combining[] = { - { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, - { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, - { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, - { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, - { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, - { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, - { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, - { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, - { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, - { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, - { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, - { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, - { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, - { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, - { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, - { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, - { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, - { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, - { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, - { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, - { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, - { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, - { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, - { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, - { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, - { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, - { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, - { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, - { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, - { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, - { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, - { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, - { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, - { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, - { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, - { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, - { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, - { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, - { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, - { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, - { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, - { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, - { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, - { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, - { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, - { 0xE0100, 0xE01EF } - }; - - /* test for 8-bit control characters */ - if (ucs == 0) - return 0; - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) - return -1; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, combining, - sizeof(combining) / sizeof(struct interval) - 1)) - return 0; - - /* if we arrive here, ucs is not a combining or C0/C1 control character */ - - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - ucs == 0x2329 || ucs == 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && - ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); -} - - -/* - * The following functions are part of the original wcwidth.c: - * we don't use them but I've kept them in case - pws. - */ -#if 0 -int mk_wcswidth(const wchar_t *pwcs, size_t n) -{ - int w, width = 0; - - for (;*pwcs && n-- > 0; pwcs++) - if ((w = mk_wcwidth(*pwcs)) < 0) - return -1; - else - width += w; - - return width; -} - - -/* - * The following functions are the same as mk_wcwidth() and - * mk_wcswidth(), except that spacing characters in the East Asian - * Ambiguous (A) category as defined in Unicode Technical Report #11 - * have a column width of 2. This variant might be useful for users of - * CJK legacy encodings who want to migrate to UCS without changing - * the traditional terminal character-width behaviour. It is not - * otherwise recommended for general use. - */ -int mk_wcwidth_cjk(wchar_t ucs) +u9_iswprint(wint_t ucs) { - /* sorted list of non-overlapping intervals of East Asian Ambiguous - * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ - static const struct interval ambiguous[] = { - { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, - { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, - { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, - { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, - { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, - { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, - { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, - { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, - { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, - { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, - { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, - { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, - { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, - { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, - { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, - { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, - { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, - { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, - { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, - { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, - { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, - { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, - { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, - { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, - { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, - { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, - { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, - { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, - { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, - { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, - { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, - { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, - { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, - { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, - { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, - { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, - { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, - { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, - { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, - { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, - { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, - { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, - { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, - { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, - { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, - { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, - { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, - { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, - { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, - { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, - { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, - { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } - }; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, ambiguous, - sizeof(ambiguous) / sizeof(struct interval) - 1)) - return 2; - - return mk_wcwidth(ucs); + if (ucs == 0) + return 0; + return wcwidth9(ucs) != -1; } - -int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n) -{ - int w, width = 0; - - for (;*pwcs && n-- > 0; pwcs++) - if ((w = mk_wcwidth_cjk(*pwcs)) < 0) - return -1; - else - width += w; - - return width; -} -#endif /* 0 */ - /**/ -#endif /* BROKEN_WCWIDTH && (__STDC_ISO_10646__ || __APPLE__) */ +#endif /* ENABLE_UNICODE9 */ /**/ #if defined(__APPLE__) && defined(BROKEN_ISPRINT) diff --git a/Src/cond.c b/Src/cond.c index 42e9de30f..b9a47cea5 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -138,13 +138,13 @@ evalcond(Estate state, char *fromtest) strs = arrdup(sbuf); l = 2; } - if (name && name[0] == '-') - errname = name; - else if (strs[0] && *strs[0] == '-') - errname = strs[0]; + if (name && IS_DASH(name[0])) + untokenize(errname = dupstring(name)); + else if (strs[0] && IS_DASH(*strs[0])) + untokenize(errname = strs[0]); else errname = "<null>"; - if (name && name[0] == '-' && + if (name && IS_DASH(name[0]) && (cd = getconddef((ctype == COND_MODI), name + 1, 1))) { if (ctype == COND_MOD && (l < cd->min || (cd->max >= 0 && l > cd->max))) { @@ -171,7 +171,7 @@ evalcond(Estate state, char *fromtest) strs[0] = dupstring(name); name = s; - if (name && name[0] == '-' && + if (name && IS_DASH(name[0]) && (cd = getconddef(0, name + 1, 1))) { if (l < cd->min || (cd->max >= 0 && l > cd->max)) { zwarnnam(fromtest, "unknown condition: %s", @@ -295,6 +295,8 @@ evalcond(Estate state, char *fromtest) int test, npat = state->pc[1]; Patprog pprog = state->prog->pats[npat]; + queue_signals(); + if (pprog == dummy_patprog1 || pprog == dummy_patprog2) { char *opat; int save; @@ -308,6 +310,7 @@ evalcond(Estate state, char *fromtest) if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC), NULL))) { zwarnnam(fromtest, "bad pattern: %s", right); + unqueue_signals(); return 2; } else if (save) @@ -316,6 +319,8 @@ evalcond(Estate state, char *fromtest) state->pc += 2; test = (pprog && pattry(pprog, left)); + unqueue_signals(); + return !(ctype == COND_STRNEQ ? !test : test); } case COND_STRLT: diff --git a/Src/exec.c b/Src/exec.c index a439aec7f..f339dd6d0 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -975,9 +975,8 @@ entersubsh(int flags) int sig, monitor, job_control_ok; if (!(flags & ESUB_KEEPTRAP)) - for (sig = 0; sig < VSIGCOUNT; sig++) - if (!(sigtrapped[sig] & ZSIG_FUNC) && - sig != SIGDEBUG && sig != SIGZERR) + for (sig = 0; sig < SIGCOUNT; sig++) + if (!(sigtrapped[sig] & ZSIG_FUNC)) unsettrap(sig); monitor = isset(MONITOR); job_control_ok = monitor && (flags & ESUB_JOB_CONTROL) && isset(POSIXJOBS); @@ -1068,6 +1067,18 @@ entersubsh(int flags) } if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED)) signal_default(SIGQUIT); + /* + * sigtrapped[sig] == ZSIG_IGNORED for signals that remain ignored, + * but other trapped signals are temporarily blocked when intrap, + * and must be unblocked before continuing into the subshell. This + * is orthogonal to what the default handler for the signal may be. + * + * Start loop at 1 because 0 is SIGEXIT + */ + if (intrap) + for (sig = 1; sig < SIGCOUNT; sig++) + if (sigtrapped[sig] && sigtrapped[sig] != ZSIG_IGNORED) + signal_unblock(signal_mask(sig)); if (!job_control_ok) opts[MONITOR] = 0; opts[USEZLE] = 0; @@ -1601,6 +1612,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) zclose(opipe[0]); } if (how & Z_DISOWN) { + pipecleanfilelist(jobtab[thisjob].filelist, 0); deletejob(jobtab + thisjob, 1); thisjob = -1; } @@ -1848,7 +1860,7 @@ execpline2(Estate state, wordcode pcode, lineno = WC_PIPE_LINENO(pcode) - 1; if (pline_level == 1) { - if ((how & Z_ASYNC) || (!sfcontext && !sourcelevel)) + if ((how & Z_ASYNC) || !sfcontext) strcpy(list_pipe_text, getjobtext(state->prog, state->pc + (WC_PIPE_TYPE(pcode) == WC_PIPE_END ? @@ -2379,9 +2391,7 @@ addvars(Estate state, Wordcode pc, int addflags) * to be restored after the command, since then the assignment * is implicitly scoped. */ - flags = (!(addflags & ADDVAR_RESTORE) && - locallevel > forklevel && isset(WARNCREATEGLOBAL)) ? - ASSPM_WARN_CREATE : 0; + flags = !(addflags & ADDVAR_RESTORE) ? ASSPM_WARN : 0; xtr = isset(XTRACE); if (xtr) { printprompt4(); @@ -2633,6 +2643,27 @@ execcmd_analyse(Estate state, Execcmd_params eparams) } /* + * Transfer the first node of args to preargs, performing + * prefork expansion on the way if necessary. + */ +static void execcmd_getargs(LinkList preargs, LinkList args, int expand) +{ + if (!firstnode(args)) { + return; + } else if (expand) { + local_list0(svl); + init_list0(svl); + /* not init_list1, as we need real nodes */ + addlinknode(&svl, uremnode(args, firstnode(args))); + /* Analysing commands, so vanilla options to prefork */ + prefork(&svl, 0, NULL); + joinlists(preargs, &svl); + } else { + addlinknode(preargs, uremnode(args, firstnode(args))); + } +} + +/* * Execute a command at the lowest level of the hierarchy. */ @@ -2649,7 +2680,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, char *text; int save[10]; int fil, dfil, is_cursh, do_exec = 0, redir_err = 0, i; - int nullexec = 0, assign = 0, forked = 0; + int nullexec = 0, magic_assign = 0, forked = 0; int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0; /* Various flags to the command. */ int cflags = 0, orig_cflags = 0, checked = 0, oautocont = -1; @@ -2662,6 +2693,11 @@ execcmd_exec(Estate state, Execcmd_params eparams, LinkList redir = eparams->redir; Wordcode varspc = eparams->varspc; int type = eparams->type; + /* + * preargs comes from expanding the head of the args list + * in order to check for prefix commands. + */ + LinkList preargs; doneps4 = 0; @@ -2716,9 +2752,19 @@ execcmd_exec(Estate state, Execcmd_params eparams, * command if it contains some tokens (e.g. x=ex; ${x}port), so this * * only works in simple cases. has_token() is called to make sure * * this really is a simple case. */ - if (type == WC_SIMPLE || type == WC_TYPESET) { - while (args && nonempty(args)) { - char *cmdarg = (char *) peekfirst(args); + if ((type == WC_SIMPLE || type == WC_TYPESET) && args) { + /* + * preargs contains args that have been expanded by prefork. + * Running execcmd_getargs() causes the any argument available + * in args to be exanded where necessary and transferred to + * preargs. We call execcmd_getargs() every time we need to + * analyse an argument not available in preargs, though there is + * no guarantee a further argument will be available. + */ + preargs = newlinklist(); + execcmd_getargs(preargs, args, eparams->htok); + while (nonempty(preargs)) { + char *cmdarg = (char *) peekfirst(preargs); checked = !has_token(cmdarg); if (!checked) break; @@ -2732,6 +2778,12 @@ execcmd_exec(Estate state, Execcmd_params eparams, * Reserved words take precedence over shell functions. */ checked = 1; + } else if (isset(POSIXBUILTINS) && (cflags & BINF_EXEC)) { + /* + * POSIX doesn't allow "exec" to operate on builtins + * or shell functions. + */ + break; } else { if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) && (hn = shfunctab->getnode(shfunctab, cmdarg))) { @@ -2752,11 +2804,24 @@ execcmd_exec(Estate state, Execcmd_params eparams, /* autoload the builtin if necessary */ if (!(hn = resolvebuiltin(cmdarg, hn))) return; - assign = (hn->flags & BINF_MAGICEQUALS); + if (type != WC_TYPESET) + magic_assign = (hn->flags & BINF_MAGICEQUALS); break; } checked = 0; - if ((cflags & BINF_COMMAND) && nextnode(firstnode(args))) { + /* + * We usually don't need the argument containing the + * precommand modifier itself. Exception: when "command" + * will implemented by a call to "whence", in which case + * we'll simply re-insert the argument. + */ + uremnode(preargs, firstnode(preargs)); + if (!firstnode(preargs)) { + execcmd_getargs(preargs, args, eparams->htok); + if (!firstnode(preargs)) + break; + } + if ((cflags & BINF_COMMAND)) { /* * Check for options to "command". * If just -p, this is handled here: use the default @@ -2766,13 +2831,15 @@ execcmd_exec(Estate state, Execcmd_params eparams, * Otherwise, just leave marked as BINF_COMMAND * modifier with no additional action. */ - LinkNode argnode = nextnode(firstnode(args)); - char *argdata = (char *) getdata(argnode); - char *cmdopt; + LinkNode argnode, oldnode, pnode = NULL; + char *argdata, *cmdopt; int has_p = 0, has_vV = 0, has_other = 0; - while (*argdata == '-') { + argnode = firstnode(preargs); + argdata = (char *) getdata(argnode); + while (IS_DASH(*argdata)) { /* Just to be definite, stop on single "-", too, */ - if (!argdata[1] || (argdata[1] == '-' && !argdata[2])) + if (!argdata[1] || + (IS_DASH(argdata[1]) && !argdata[2])) break; for (cmdopt = argdata+1; *cmdopt; cmdopt++) { switch (*cmdopt) { @@ -2785,6 +2852,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, * also traditional behaviour. */ has_p = 1; + pnode = argnode; break; case 'v': case 'V': @@ -2801,42 +2869,53 @@ execcmd_exec(Estate state, Execcmd_params eparams, break; } + oldnode = argnode; argnode = nextnode(argnode); - if (!argnode) - break; + if (!argnode) { + execcmd_getargs(preargs, args, eparams->htok); + if (!(argnode = nextnode(oldnode))) + break; + } argdata = (char *) getdata(argnode); } if (has_vV) { - /* Leave everything alone, dispatch to whence */ + /* + * Leave everything alone, dispatch to whence. + * We need to put the name back in the list. + */ + pushnode(preargs, "command"); hn = &commandbn.node; is_builtin = 1; break; } else if (has_p) { - /* Use default path; absorb command and option. */ - uremnode(args, firstnode(args)); + /* Use default path */ use_defpath = 1; - if ((argnode = nextnode(firstnode(args)))) - argdata = (char *) getdata(argnode); + /* + * We don't need this node as we're not treating + * "command" as a builtin this time. + */ + if (pnode) + uremnode(preargs, pnode); } /* - * Else just absorb command and any trailing + * Else just any trailing * end-of-options marker. This can only occur * if we just had -p or something including more * than just -p, -v and -V, in which case we behave * as if this is command [non-option-stuff]. This * isn't a good place for standard option handling. */ - if (!strcmp(argdata, "--")) - uremnode(args, firstnode(args)); - } - if ((cflags & BINF_EXEC) && nextnode(firstnode(args))) { + if (IS_DASH(argdata[0]) && IS_DASH(argdata[1]) && !argdata[2]) + uremnode(preargs, argnode); + } else if (cflags & BINF_EXEC) { /* * Check for compatibility options to exec builtin. * It would be nice to do these more generically, * but currently we don't have a mechanism for * precommand modifiers. */ - char *next = (char *) getdata(nextnode(firstnode(args))); + LinkNode argnode = firstnode(preargs), oldnode; + char *argdata = (char *) getdata(argnode); char *cmdopt, *exec_argv0 = NULL; /* * Careful here: we want to make sure a final dash @@ -2846,17 +2925,23 @@ execcmd_exec(Estate state, Execcmd_params eparams, * people aren't likely to mix the option style * with the zsh style. */ - while (next && *next == '-' && strlen(next) >= 2) { - if (!firstnode(args)) { + while (argdata && IS_DASH(*argdata) && strlen(argdata) >= 2) { + oldnode = argnode; + argnode = nextnode(oldnode); + if (!argnode) { + execcmd_getargs(preargs, args, eparams->htok); + argnode = nextnode(oldnode); + } + if (!argnode) { zerr("exec requires a command to execute"); lastval = 1; errflag |= ERRFLAG_ERROR; goto done; } - uremnode(args, firstnode(args)); - if (!strcmp(next, "--")) + uremnode(preargs, oldnode); + if (IS_DASH(argdata[0]) && IS_DASH(argdata[1]) && !argdata[2]) break; - for (cmdopt = &next[1]; *cmdopt; ++cmdopt) { + for (cmdopt = &argdata[1]; *cmdopt; ++cmdopt) { switch (*cmdopt) { case 'a': /* argument is ARGV0 string */ @@ -2865,21 +2950,25 @@ execcmd_exec(Estate state, Execcmd_params eparams, /* position on last non-NULL character */ cmdopt += strlen(cmdopt+1); } else { - if (!firstnode(args)) { + if (!argnode) { zerr("exec requires a command to execute"); lastval = 1; errflag |= ERRFLAG_ERROR; goto done; } - if (!nextnode(firstnode(args))) { + if (!nextnode(argnode)) + execcmd_getargs(preargs, args, + eparams->htok); + if (!nextnode(argnode)) { zerr("exec flag -a requires a parameter"); lastval = 1; errflag |= ERRFLAG_ERROR; goto done; } - exec_argv0 = (char *) - getdata(nextnode(firstnode(args))); - uremnode(args, firstnode(args)); + exec_argv0 = (char *) getdata(argnode); + oldnode = argnode; + argnode = nextnode(argnode); + uremnode(args, oldnode); } break; case 'c': @@ -2895,8 +2984,9 @@ execcmd_exec(Estate state, Execcmd_params eparams, return; } } - if (firstnode(args) && nextnode(firstnode(args))) - next = (char *) getdata(nextnode(firstnode(args))); + if (!argnode) + break; + argdata = (char *) getdata(argnode); } if (exec_argv0) { char *str, *s; @@ -2908,21 +2998,41 @@ execcmd_exec(Estate state, Execcmd_params eparams, zputenv(str); } } - uremnode(args, firstnode(args)); hn = NULL; if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS)) break; + if (!nonempty(preargs)) + execcmd_getargs(preargs, args, eparams->htok); } - } + } else + preargs = NULL; /* if we get this far, it is OK to pay attention to lastval again */ if (noerrexit == 2 && !is_shfunc) noerrexit = 0; - /* Do prefork substitutions */ - esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0; - if (args && eparams->htok) - prefork(args, esprefork, NULL); + /* Do prefork substitutions. + * + * Decide if we need "magic" handling of ~'s etc. in + * assignment-like arguments. + * - If magic_assign is set, we are using a builtin of the + * tyepset family, but did not recognise this as a keyword, + * so need guess-o-matic behaviour. + * - Otherwise, if we did recognise the keyword, we never need + * guess-o-matic behaviour as the argument was properly parsed + * as such. + * - Otherwise, use the behaviour specified by the MAGIC_EQUAL_SUBST + * option. + */ + esprefork = (magic_assign || + (isset(MAGICEQUALSUBST) && type != WC_TYPESET)) ? + PREFORK_TYPESET : 0; + if (args) { + if (eparams->htok) + prefork(args, esprefork, NULL); + if (preargs) + args = joinlists(preargs, args); + } if (type == WC_SIMPLE || type == WC_TYPESET) { int unglobbed = 0; @@ -3019,10 +3129,14 @@ execcmd_exec(Estate state, Execcmd_params eparams, * - we have determined there are options which would * require us to use the "command" builtin); or * - we aren't using POSIX and so BINF_COMMAND indicates a zsh - * precommand modifier is being used in place of the builtin + * precommand modifier is being used in place of the + * builtin + * - we are using POSIX and this is an EXEC, so we can't + * execute a builtin or function. */ if (errflag || checked || is_builtin || - (unset(POSIXBUILTINS) && (cflags & BINF_COMMAND))) + (isset(POSIXBUILTINS) ? + (cflags & BINF_EXEC) : (cflags & BINF_COMMAND))) break; cmdarg = (char *) peekfirst(args); @@ -3065,7 +3179,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, /* Get the text associated with this command. */ if ((how & Z_ASYNC) || - (!sfcontext && !sourcelevel && (jobbing || (how & Z_TIMED)))) + (!sfcontext && (jobbing || (how & Z_TIMED)))) text = getjobtext(state->prog, eparams->beg); else text = NULL; @@ -3124,7 +3238,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, if (is_shfunc) shf = (Shfunc)hn; else { - shf = loadautofn(state->prog->shf, 1, 0); + shf = loadautofn(state->prog->shf, 1, 0, 0); if (shf) state->prog->shf = shf; else { @@ -3700,7 +3814,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, * Save if it's got "command" in front or it's * not a magic-equals assignment. */ - if ((cflags & (BINF_COMMAND|BINF_ASSIGN)) || !assign) + if ((cflags & (BINF_COMMAND|BINF_ASSIGN)) || !magic_assign) do_save = 1; } if (do_save && varspc) @@ -3987,6 +4101,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, * classify as a builtin) we treat all errors as fatal. * The "command" builtin is not special so resets this behaviour. */ + forked |= zsh_subshell; fatal: if (redir_err || errflag) { if (!isset(INTERACTIVE)) { @@ -4465,7 +4580,7 @@ getoutputfile(char *cmd, char **eptr) } if (!(prog = parsecmd(cmd, eptr))) return NULL; - if (!(nam = gettempname(NULL, 0))) + if (!(nam = gettempname(NULL, 1))) return NULL; if ((s = simple_redir_name(prog, REDIR_HERESTR))) { @@ -4496,7 +4611,7 @@ getoutputfile(char *cmd, char **eptr) suffix = dyncat(nam, unmeta(suffix)); if (link(nam, suffix) == 0) { addfilelist(nam, 0); - nam = ztrdup(suffix); + nam = suffix; } } } @@ -4902,6 +5017,7 @@ execfuncdef(Estate state, Eprog redir_prog) shf = (Shfunc) zalloc(sizeof(*shf)); shf->funcdef = prog; shf->node.flags = 0; + /* No dircache here, not a directory */ shf->filename = ztrdup(scriptfilename); shf->lineno = lineno; /* @@ -4934,7 +5050,7 @@ execfuncdef(Estate state, Eprog redir_prog) freeeprog(shf->funcdef); if (shf->redir) /* shouldn't be */ freeeprog(shf->redir); - zsfree(shf->filename); + dircache_set(&shf->filename, NULL); zfree(shf, sizeof(*shf)); state->pc = end; return 1; @@ -4965,7 +5081,7 @@ execfuncdef(Estate state, Eprog redir_prog) freeeprog(shf->funcdef); if (shf->redir) /* shouldn't be */ freeeprog(shf->redir); - zsfree(shf->filename); + dircache_set(&shf->filename, NULL); zfree(shf, sizeof(*shf)); break; } else { @@ -4974,7 +5090,7 @@ execfuncdef(Estate state, Eprog redir_prog) (signum = getsignum(s + 4)) != -1) { if (settrap(signum, NULL, ZSIG_FUNC)) { freeeprog(shf->funcdef); - zsfree(shf->filename); + dircache_set(&shf->filename, NULL); zfree(shf, sizeof(*shf)); state->pc = end; return 1; @@ -5123,12 +5239,12 @@ execautofn_basic(Estate state, UNUSED(int do_exec)) * defined yet. */ if (funcstack && !funcstack->filename) - funcstack->filename = dupstring(shf->filename); + funcstack->filename = getshfuncfile(shf); oldscriptname = scriptname; oldscriptfilename = scriptfilename; scriptname = dupstring(shf->node.nam); - scriptfilename = dupstring(shf->filename); + scriptfilename = getshfuncfile(shf); execode(shf->funcdef, 1, 0, "loadautofunc"); scriptname = oldscriptname; scriptfilename = oldscriptfilename; @@ -5142,25 +5258,71 @@ execautofn(Estate state, UNUSED(int do_exec)) { Shfunc shf; - if (!(shf = loadautofn(state->prog->shf, 1, 0))) + if (!(shf = loadautofn(state->prog->shf, 1, 0, 0))) return 1; state->prog->shf = shf; return execautofn_basic(state, 0); } +/* + * Helper function to install the source file name of a shell function + * just autoloaded. + * + * We attempt to do this efficiently as the typical case is the + * directory part is a well-known directory, which is cached, and + * the non-directory part is the same as the node name. + */ + +/**/ +static void +loadautofnsetfile(Shfunc shf, char *fdir) +{ + /* + * If shf->filename is already the load directory --- + * keep it as we can still use it to get the load file. + * This makes autoload with an absolute path particularly efficient. + */ + if (!(shf->node.flags & PM_LOADDIR) || + strcmp(shf->filename, fdir) != 0) { + /* Old directory name not useful... */ + dircache_set(&shf->filename, NULL); + if (fdir) { + /* ...can still cache directory */ + shf->node.flags |= PM_LOADDIR; + dircache_set(&shf->filename, fdir); + } else { + /* ...no separate directory part to cache, for some reason. */ + shf->node.flags &= ~PM_LOADDIR; + shf->filename = ztrdup(shf->node.nam); + } + } +} + /**/ Shfunc -loadautofn(Shfunc shf, int fksh, int autol) +loadautofn(Shfunc shf, int fksh, int autol, int current_fpath) { int noalias = noaliases, ksh = 1; Eprog prog; - char *fname; + char *fdir; /* Directory path where func found */ pushheap(); noaliases = (shf->node.flags & PM_UNALIASED); - prog = getfpfunc(shf->node.nam, &ksh, &fname); + if (shf->filename && shf->filename[0] == '/' && + (shf->node.flags & PM_LOADDIR)) + { + char *spec_path[2]; + spec_path[0] = dupstring(shf->filename); + spec_path[1] = NULL; + prog = getfpfunc(shf->node.nam, &ksh, &fdir, spec_path, 0); + if (prog == &dummy_eprog && + (current_fpath || (shf->node.flags & PM_CUR_FPATH))) + prog = getfpfunc(shf->node.nam, &ksh, &fdir, NULL, 0); + } + else + prog = getfpfunc(shf->node.nam, &ksh, &fdir, NULL, 0); noaliases = noalias; if (ksh == 1) { @@ -5179,7 +5341,6 @@ loadautofn(Shfunc shf, int fksh, int autol) return NULL; } if (!prog) { - zsfree(fname); popheap(); return NULL; } @@ -5193,7 +5354,7 @@ loadautofn(Shfunc shf, int fksh, int autol) else shf->funcdef = dupeprog(prog, 0); shf->node.flags &= ~PM_UNDEFINED; - shf->filename = fname; + loadautofnsetfile(shf, fdir); } else { VARARR(char, n, strlen(shf->node.nam) + 1); strcpy(n, shf->node.nam); @@ -5205,7 +5366,6 @@ loadautofn(Shfunc shf, int fksh, int autol) zwarn("%s: function not defined by file", n); locallevel++; popheap(); - zsfree(fname); return NULL; } } @@ -5216,7 +5376,7 @@ loadautofn(Shfunc shf, int fksh, int autol) else shf->funcdef = dupeprog(stripkshdef(prog, shf->node.nam), 0); shf->node.flags &= ~PM_UNDEFINED; - shf->filename = fname; + loadautofnsetfile(shf, fdir); } popheap(); @@ -5386,6 +5546,14 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) else opts[XTRACE] = 0; } + if (flags & PM_WARNNESTED) + opts[WARNNESTEDVAR] = 1; + else if (oflags & PM_WARNNESTED) { + if (shfunc->node.nam == ANONYMOUS_FUNCTION_NAME) + flags |= PM_WARNNESTED; + else + opts[WARNNESTEDVAR] = 0; + } ooflags = oflags; /* * oflags is static, because we compare it on the next recursive @@ -5436,7 +5604,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) funcstack = &fstack; fstack.flineno = shfunc->lineno; - fstack.filename = dupstring(shfunc->filename); + fstack.filename = getshfuncfile(shfunc); prog = shfunc->funcdef; if (prog->flags & EF_RUN) { @@ -5504,6 +5672,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE]; opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS]; opts[LOCALLOOPS] = saveopts[LOCALLOOPS]; + opts[WARNNESTEDVAR] = saveopts[WARNNESTEDVAR]; } if (opts[LOCALLOOPS]) { @@ -5537,8 +5706,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) * the only likely case where we need that second test is * when we have an "always" block. The endparamscope() has * already happened, hence the "+1" here. + * + * If we are in an exit trap, finish it first... we wouldn't set + * exit_pending if we were already in one. */ - if (exit_pending && exit_level >= locallevel+1) { + if (exit_pending && exit_level >= locallevel+1 && !in_exit_trap) { if (locallevel > forklevel) { /* Still functions to return: force them to do so. */ retflag = 1; @@ -5602,12 +5774,21 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) unqueue_signals(); } -/* Search fpath for an undefined function. Finds the file, and returns the * - * list of its contents. */ +/* + * Search fpath for an undefined function. Finds the file, and returns the + * list of its contents. + * + * If test is 0, load the function. + * + * If test_only is 1, don't load function, just test for it: + * Non-null return means function was found + * + * *fdir points to path at which found (as passed in, not duplicated) + */ /**/ Eprog -getfpfunc(char *s, int *ksh, char **fname) +getfpfunc(char *s, int *ksh, char **fdir, char **alt_path, int test_only) { char **pp, buf[PATH_MAX+1]; off_t len; @@ -5616,7 +5797,7 @@ getfpfunc(char *s, int *ksh, char **fname) Eprog r; int fd; - pp = fpath; + pp = alt_path ? alt_path : fpath; for (; *pp; pp++) { if (strlen(*pp) + strlen(s) + 1 >= PATH_MAX) continue; @@ -5624,9 +5805,9 @@ getfpfunc(char *s, int *ksh, char **fname) sprintf(buf, "%s/%s", *pp, s); else strcpy(buf, s); - if ((r = try_dump_file(*pp, s, buf, ksh))) { - if (fname) - *fname = ztrdup(buf); + if ((r = try_dump_file(*pp, s, buf, ksh, test_only))) { + if (fdir) + *fdir = *pp; return r; } unmetafy(buf, NULL); @@ -5634,6 +5815,12 @@ getfpfunc(char *s, int *ksh, char **fname) struct stat st; if (!fstat(fd, &st) && S_ISREG(st.st_mode) && (len = lseek(fd, 0, 2)) != -1) { + if (test_only) { + close(fd); + if (fdir) + *fdir = *pp; + return &dummy_eprog; + } d = (char *) zalloc(len + 1); lseek(fd, 0, 0); if ((rlen = read(fd, d, len)) >= 0) { @@ -5647,8 +5834,8 @@ getfpfunc(char *s, int *ksh, char **fname) r = parse_string(d, 1); scriptname = oldscriptname; - if (fname) - *fname = ztrdup(buf); + if (fdir) + *fdir = *pp; zfree(d, len + 1); @@ -5661,7 +5848,7 @@ getfpfunc(char *s, int *ksh, char **fname) close(fd); } } - return &dummy_eprog; + return test_only ? NULL : &dummy_eprog; } /* Handle the most common type of ksh-style autoloading, when doing a * diff --git a/Src/glob.c b/Src/glob.c index 623e6f1d6..c9ec97e0e 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -1314,6 +1314,7 @@ zglob(LinkList list, LinkNode np, int nountok) sense ^= 1; break; case '-': + case Dash: /* Toggle matching of symbolic links */ sense ^= 2; break; @@ -1608,7 +1609,7 @@ zglob(LinkList list, LinkNode np, int nountok) ++s; } /* See if it's greater than, equal to, or less than */ - if ((g_range = *s == '+' ? 1 : *s == '-' ? -1 : 0)) + if ((g_range = *s == '+' ? 1 : IS_DASH(*s) ? -1 : 0)) ++s; data = qgetnum(&s); break; @@ -2025,13 +2026,13 @@ hasbraces(char *str) if (bracechardots(str-1, NULL, NULL)) return 1; lbr = str - 1; - if (*str == '-') + if (IS_DASH(*str)) str++; while (idigit(*str)) str++; if (*str == '.' && str[1] == '.') { str++; str++; - if (*str == '-') + if (IS_DASH(*str)) str++; while (idigit(*str)) str++; @@ -2040,7 +2041,7 @@ hasbraces(char *str) return 1; else if (*str == '.' && str[1] == '.') { str++; str++; - if (*str == '-') + if (IS_DASH(*str)) str++; while (idigit(*str)) str++; @@ -2123,7 +2124,7 @@ xpandredir(struct redir *fn, LinkList redirtab) fn->name = s; untokenize(s); if (fn->type == REDIR_MERGEIN || fn->type == REDIR_MERGEOUT) { - if (s[0] == '-' && !s[1]) + if (IS_DASH(s[0]) && !s[1]) fn->type = REDIR_CLOSE; else if (s[0] == 'p' && !s[1]) fn->fd2 = -2; @@ -2193,6 +2194,8 @@ bracechardots(char *str, convchar_t *c1p, convchar_t *c2p) pnext[0] != '.' || pnext[1] != '.') return 0; pnext += 2; + if (!*pnext) + return 0; if (itok(*pnext)) { if (*pnext == Inbrace) return 0; @@ -2329,12 +2332,14 @@ xpandbraces(LinkList list, LinkNode *np) * str+1 is the first number in the range, dots+2 the last, * and dots2+2 is the increment if that's given. */ /* TODO: sorry about this */ - int minw = (str[1] == '0' || (str[1] == '-' && str[2] == '0')) + int minw = (str[1] == '0' || + (IS_DASH(str[1]) && str[2] == '0')) ? wid1 - : (dots[2] == '0' || (dots[2] == '-' && dots[3] == '0')) + : (dots[2] == '0' || + (IS_DASH(dots[2]) && dots[3] == '0')) ? wid2 : (dots2 && (dots2[2] == '0' || - (dots2[2] == '-' && dots2[3] == '0'))) + (IS_DASH(dots2[2]) && dots2[3] == '0'))) ? wid3 : 0; if (rincr < 0) { @@ -2392,7 +2397,8 @@ xpandbraces(LinkList list, LinkNode *np) c2 = ztokens[c2 - STOUC(Pound)]; if ((char) c2 == Meta) c2 = 32 ^ p[1]; - if (c1 == '-' && lastch >= 0 && p < str2 && lastch <= (int)c2) { + if (IS_DASH((char)c1) && lastch >= 0 && + p < str2 && lastch <= (int)c2) { while (lastch < (int)c2) ccl[lastch++] = 1; lastch = -1; @@ -2462,13 +2468,20 @@ xpandbraces(LinkList list, LinkNode *np) int matchpat(char *a, char *b) { - Patprog p = patcompile(b, PAT_STATIC, NULL); + Patprog p; + int ret; - if (!p) { + queue_signals(); /* Protect PAT_STATIC */ + + if (!(p = patcompile(b, PAT_STATIC, NULL))) { zerr("bad pattern: %s", b); - return 0; - } - return pattry(p, a); + ret = 0; + } else + ret = pattry(p, a); + + unqueue_signals(); + + return ret; } /* do the ${foo%%bar}, ${foo#bar} stuff */ @@ -2918,7 +2931,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * move forward along string until we get a match. * * Again there's no optimisation. */ mb_charinit(); - for (ioff = 0, t = s, umlen = umltot; t < send ; ioff++) { + for (ioff = 0, t = s, umlen = umltot; t <= send ; ioff++) { set_pat_start(p, t-s); if (pattrylen(p, t, umlen, 0, &patstralloc, ioff)) { *sp = get_match_ret(&imd, t-s, umltot); @@ -2926,6 +2939,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, } if (fl & SUB_START) break; + if (t == send) + break; umlen -= iincchar(&t, send - t); } if (!(fl & SUB_START) && pattrylen(p, send, 0, 0, @@ -2958,7 +2973,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, do { /* loop over all matches for global substitution */ matched = 0; - for (; t < send; ioff++) { + for (; t <= send; ioff++) { /* Find the longest match from this position. */ set_pat_start(p, t-s); if (pattrylen(p, t, umlen, 0, &patstralloc, ioff)) { @@ -3007,15 +3022,19 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * which is already marked for replacement. */ matched = 1; + if (t == send) + break; while (t < mpos) { ioff++; umlen -= iincchar(&t, send - t); } break; } + if (t == send) + break; umlen -= iincchar(&t, send - t); } - } while (matched); + } while (matched && t < send); /* * check if we can match a blank string, if so do it * at the start. Goodness knows if this is a good idea @@ -3521,7 +3540,7 @@ zshtokenize(char *s, int flags) } t = s; while (idigit(*++s)); - if (*s != '-') + if (!IS_DASH(*s)) goto cont; while (idigit(*++s)); if (*s != '>') diff --git a/Src/hashtable.c b/Src/hashtable.c index 7c3367568..6ec2ed220 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -889,7 +889,7 @@ freeshfuncnode(HashNode hn) freeeprog(shf->funcdef); if (shf->redir) freeeprog(shf->redir); - zsfree(shf->filename); + dircache_set(&shf->filename, NULL); if (shf->sticky) { if (shf->sticky->n_on_opts) zfree(shf->sticky->on_opts, @@ -926,10 +926,13 @@ printshfuncnode(HashNode hn, int printflags) (f->node.flags & PM_UNDEFINED) ? " is an autoload shell function" : " is a shell function"); - if (f->filename && (printflags & PRINT_WHENCE_VERBOSE) && - strcmp(f->filename, f->node.nam) != 0) { + if ((printflags & PRINT_WHENCE_VERBOSE) && f->filename) { printf(" from "); quotedzputs(f->filename, stdout); + if (f->node.flags & PM_LOADDIR) { + printf("/"); + quotedzputs(f->node.nam, stdout); + } } putchar('\n'); return; @@ -949,16 +952,20 @@ printshfuncnode(HashNode hn, int printflags) zoutputtab(stdout); } if (!t) { - char *fopt = "UtTkz"; + char *fopt = "UtTkzc"; int flgs[] = { PM_UNALIASED, PM_TAGGED, PM_TAGGED_LOCAL, - PM_KSHSTORED, PM_ZSHSTORED, 0 + PM_KSHSTORED, PM_ZSHSTORED, PM_CUR_FPATH, 0 }; int fl;; zputs("builtin autoload -X", stdout); for (fl=0;fopt[fl];fl++) if (f->node.flags & flgs[fl]) putchar(fopt[fl]); + if (f->filename && (f->node.flags & PM_LOADDIR)) { + putchar(' '); + zputs(f->filename, stdout); + } } else { zputs(t, stdout); zsfree(t); @@ -1037,6 +1044,24 @@ printshfuncexpand(HashNode hn, int printflags, int expand) text_expand_tabs = save_expand; } +/* + * Get a heap-duplicated name of the shell function, for + * use in tracing. + */ + +/**/ +mod_export char * +getshfuncfile(Shfunc shf) +{ + if (shf->node.flags & PM_LOADDIR) { + return zhtricat(shf->filename, "/", shf->node.nam); + } else if (shf->filename) { + return dupstring(shf->filename); + } else { + return NULL; + } +} + /**************************************/ /* Reserved Word Hash Table Functions */ /**************************************/ @@ -1420,6 +1445,9 @@ freehistdata(Histent he, int unlink) if (!he) return; + if (he == &curline) + return; + if (!(he->node.flags & (HIST_DUP | HIST_TMPSTORE))) removehashnode(histtab, he->node.nam); @@ -1438,3 +1466,150 @@ freehistdata(Histent he, int unlink) } } } + + +/*********************************************************************** + * Directory name cache mechanism + * + * The idea of this is that there are various shell structures, + * notably functions, that record the directories with which they + * are associated. Rather than store the full string each time, + * we store a pointer to the same location and count the references. + * This is optimised so that retrieval is quick at the expense of + * searching the list when setting up the structure, which is a much + * rarer operation. + * + * There is nothing special about the fact that the strings are + * directories, except for the assumptions for efficiency that many + * structures will point to the same one, and that there are not too + * many different directories associated with the shell. + **********************************************************************/ + +struct dircache_entry +{ + /* Name of directory in cache */ + char *name; + /* Number of references to it */ + int refs; +}; + +/* + * dircache is the cache, of length dircache_size. + * dircache_lastentry is the last entry used, an optimisation + * for multiple references to the same directory, e.g + * "autoload /blah/blah/\*". + */ +static struct dircache_entry *dircache, *dircache_lastentry; +static int dircache_size; + +/* + * Set *name to point to a cached version of value. + * value is copied so may come from any source. + * + * If value is NULL, look for the existing value of *name (safe if this + * too is NULL) and remove a reference to it from the cache. If it's + * not found in the cache, it's assumed to be an allocated string and + * freed --- this currently occurs for a shell function that's been + * loaded as the filename is now a full path, not just a directory, + * though we may one day optimise this to a cached directory plus a + * name, too. Note --- the function does *not* otherwise check + * if *name points to something already cached, so this is + * necessary any time *name may already be in the cache. + */ + +/**/ +mod_export void +dircache_set(char **name, char *value) +{ + struct dircache_entry *dcptr, *dcnew; + + if (!value) { + if (!*name) + return; + if (!dircache_size) { + zsfree(*name); + *name = NULL; + return; + } + + for (dcptr = dircache; dcptr < dircache + dircache_size; dcptr++) + { + /* Must be a pointer much, not a string match */ + if (*name == dcptr->name) + { + --dcptr->refs; + if (!dcptr->refs) { + ptrdiff_t ind = dcptr - dircache; + zsfree(dcptr->name); + --dircache_size; + + if (!dircache_size) { + zfree(dircache, sizeof(*dircache)); + dircache = NULL; + dircache_lastentry = NULL; + *name = NULL; + return; + } + dcnew = (struct dircache_entry *) + zalloc(dircache_size * sizeof(*dcnew)); + if (ind) + memcpy(dcnew, dircache, ind * sizeof(*dcnew)); + if (ind < dircache_size) + memcpy(dcnew + ind, dcptr + 1, + (dircache_size - ind) * sizeof(*dcnew)); + zfree(dircache, (dircache_size+1)*sizeof(*dcnew)); + dircache = dcnew; + dircache_lastentry = NULL; + } + *name = NULL; + return; + } + } + zsfree(*name); + *name = NULL; + } else { + /* + * As the function path has been resolved to a particular + * location, we'll store it as an absolute path. + */ + if (*value != '/') { + value = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), + "/", value); + value = xsymlink(value, 1); + } + /* + * We'll maintain the cache at exactly the right size rather + * than overallocating. The rationale here is that typically + * we'll get a lot of functions in a small number of directories + * so the complexity overhead of maintaining a separate count + * isn't really matched by the efficiency gain. + */ + if (dircache_lastentry && + !strcmp(value, dircache_lastentry->name)) { + *name = dircache_lastentry->name; + ++dircache_lastentry->refs; + return; + } else if (!dircache_size) { + dircache_size = 1; + dcptr = dircache = + (struct dircache_entry *)zalloc(sizeof(*dircache)); + } else { + for (dcptr = dircache; dcptr < dircache + dircache_size; dcptr++) + { + if (!strcmp(value, dcptr->name)) { + *name = dcptr->name; + ++dcptr->refs; + return; + } + } + ++dircache_size; + dircache = (struct dircache_entry *) + zrealloc(dircache, sizeof(*dircache) * dircache_size); + dcptr = dircache + dircache_size - 1; + } + dcptr->name = ztrdup(value); + *name = dcptr->name; + dcptr->refs = 1; + dircache_lastentry = dcptr; + } +} diff --git a/Src/hist.c b/Src/hist.c index 97fd34039..da5a8b29f 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -253,6 +253,7 @@ hist_context_save(struct hist_stack *hs, int toplevel) hs->hwend = hwend; hs->addtoline = addtoline; hs->hlinesz = hlinesz; + hs->defev = defev; /* * We save and restore the command stack with history * as it's visible to the user interactively, so if @@ -296,6 +297,7 @@ hist_context_restore(const struct hist_stack *hs, int toplevel) hwend = hs->hwend; addtoline = hs->addtoline; hlinesz = hs->hlinesz; + defev = hs->defev; if (cmdstack) zfree(cmdstack, CMDSTACKSZ); cmdstack = hs->cstack; @@ -1418,7 +1420,7 @@ hend(Eprog prog) DPUTS(hptr < chline, "History end pointer off start of line"); *hptr = '\0'; } - { + if (*chline) { LinkList hookargs = newlinklist(); int save_errflag = errflag; errflag = 0; @@ -1427,6 +1429,7 @@ hend(Eprog prog) addlinknode(hookargs, chline); callhookfunc("zshaddhistory", hookargs, 1, &hookret); + errflag &= ~ERRFLAG_ERROR; errflag |= save_errflag; } /* For history sharing, lock history file once for both read and write */ diff --git a/Src/init.c b/Src/init.c index c12043b88..d8c26aca2 100644 --- a/Src/init.c +++ b/Src/init.c @@ -376,12 +376,12 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, *argv = "--"; while (*++*argv) { if (**argv == '-') { - if(!argv[0][1]) { + if (!argv[0][1]) { /* The pseudo-option `--' signifies the end of options. */ argv++; goto doneoptions; } - if(*argv != args+1 || **argv != '-') + if (nam || *argv != args+1 || **argv != '-') goto badoptionstring; /* GNU-style long options */ ++*argv; @@ -790,7 +790,7 @@ init_term(void) tcstr[TCCLEARSCREEN] = ztrdup("\14"); tclen[TCCLEARSCREEN] = 1; } - rprompt_indent = 1; + rprompt_indent = 1; /* If you change this, update rprompt_indent_unsetfn() */ /* The following is an attempt at a heuristic, * but it fails in some cases */ /* rprompt_indent = ((hasam && !hasbw) || hasye || !tccan(TCLEFT)); */ diff --git a/Src/input.c b/Src/input.c index eb968ea72..9787dedf6 100644 --- a/Src/input.c +++ b/Src/input.c @@ -144,9 +144,10 @@ shingetline(void) int q = queue_signal_level(); p = buf; + winch_unblock(); + dont_queue_signals(); for (;;) { - winch_unblock(); - dont_queue_signals(); + /* Can't fgets() here because we need to accept '\0' bytes */ do { errno = 0; c = fgetc(bshin); @@ -176,7 +177,8 @@ shingetline(void) ll += p - buf; line[ll] = '\0'; p = buf; - unqueue_signals(); + winch_unblock(); + dont_queue_signals(); } } } @@ -670,3 +672,30 @@ ingetptr(void) { return inbufptr; } + +/* + * Check if the current input line, including continuations, is + * expanding an alias. This does not detect alias expansions that + * have been fully processed and popped from the input stack. + * If there is an alias, the most recently expanded is returned, + * else NULL. + */ + +/**/ +char *input_hasalias(void) +{ + int flags = inbufflags; + struct instacks *instackptr = instacktop; + + for (;;) + { + if (!(flags & INP_CONT)) + break; + instackptr--; + if (instackptr->alias) + return instackptr->alias->node.nam; + flags = instackptr->flags; + } + + return NULL; +} diff --git a/Src/jobs.c b/Src/jobs.c index d1b98ac4d..66dfb5a7e 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -277,6 +277,10 @@ handle_sub(int job, int fg) (!jn->procs->next || cp || jn->procs->pid != jn->gleader)) attachtty(jn->gleader); kill(sj->other, SIGCONT); + if (jn->stat & STAT_DISOWN) + { + deletejob(jn, 1); + } } curjob = jn - jobtab; } else if (sj->stat & STAT_STOPPED) { @@ -2288,8 +2292,10 @@ bin_fg(char *name, char **argv, Options ops, int func) case BIN_FG: case BIN_BG: case BIN_WAIT: - if (func == BIN_BG) + if (func == BIN_BG) { jobtab[job].stat |= STAT_NOSTTY; + jobtab[job].stat &= ~STAT_CURSH; + } if ((stopped = (jobtab[job].stat & STAT_STOPPED))) { makerunning(jobtab + job); if (func == BIN_BG) { @@ -2373,6 +2379,10 @@ bin_fg(char *name, char **argv, Options ops, int func) printjob(job + (oldjobtab ? oldjobtab : jobtab), lng, 2); break; case BIN_DISOWN: + if (jobtab[job].stat & STAT_SUPERJOB) { + jobtab[job].stat |= STAT_DISOWN; + continue; + } if (jobtab[job].stat & STAT_STOPPED) { char buf[20], *pids = ""; @@ -1359,17 +1359,13 @@ gettokstr(int c, int sub) case LX2_DASH: /* * - shouldn't be treated as a special character unless - * we're in a pattern. Howeve,simply counting "[" doesn't - * work as []a-z] is a valid expression and we don't know - * down here what this "[" is for as $foo[stuff] is valid - * in zsh. So just detect an opening [, which is enough - * to turn this into a pattern; the Dash will be harmlessly - * untokenised if not wanted. + * we're in a pattern. Unfortunately, working out for + * sure in complicated expressions whether we're in a + * pattern is tricky. So we'll make it special and + * turn it back any time we don't need it special. + * This is not ideal as it's a lot of work. */ - if (seen_brct) - c = Dash; - else - c = '-'; + c = Dash; break; case LX2_BANG: /* @@ -2064,9 +2060,7 @@ skipcomm(void) int new_lexstop, new_lex_add_raw; int save_infor = infor; struct lexbufstate new_lexbuf; - int noalias = noaliases; - noaliases = 1; infor = 0; cmdpush(CS_CMDSUBST); SETPARBEGIN @@ -2193,7 +2187,6 @@ skipcomm(void) SETPAREND cmdpop(); infor = save_infor; - noaliases = noalias; return lexstop; #endif diff --git a/Src/linklist.c b/Src/linklist.c index 3aa8125d9..85d9bb367 100644 --- a/Src/linklist.c +++ b/Src/linklist.c @@ -348,6 +348,35 @@ newsizedlist(int size) } /* + * Join two linked lists. Neither may be null, though either + * may be empty. + * + * It is assumed the pieces come from the heap, but if not it is + * safe to free LinkList second. + */ + +/**/ +mod_export LinkList +joinlists(LinkList first, LinkList second) +{ + LinkNode moveme = firstnode(second); + if (moveme) { + if (firstnode(first)) { + LinkNode anchor = lastnode(first); + anchor->next = moveme; + moveme->prev = anchor; + } else { + first->list.first = moveme; + moveme->prev = &first->node; + } + first->list.last = second->list.last; + + second->list.first = second->list.last = NULL; + } + return first; +} + +/* * Return the node whose data is the pointer "dat", else NULL. * Can be used as a boolean test. */ diff --git a/Src/loop.c b/Src/loop.c index ae87b2f5f..f7eae307b 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -620,7 +620,9 @@ execcase(Estate state, int do_exec) spprog = state->prog->pats + npat; pprog = NULL; pat = NULL; - + + queue_signals(); + if (isset(XTRACE)) { int htok = 0; pat = dupstring(ecrawstr(state->prog, state->pc, &htok)); @@ -657,6 +659,8 @@ execcase(Estate state, int do_exec) patok = anypatok = 1; state->pc += 2; nalts--; + + unqueue_signals(); } state->pc += 2 * nalts; if (isset(XTRACE)) { diff --git a/Src/math.c b/Src/math.c index 37981cf22..f9613001a 100644 --- a/Src/math.c +++ b/Src/math.c @@ -463,7 +463,7 @@ lexconstant(void) char *nptr; nptr = ptr; - if (*nptr == '-') + if (IS_DASH(*nptr)) nptr++; if (*nptr == '0') { @@ -527,7 +527,7 @@ lexconstant(void) } if (*nptr == 'e' || *nptr == 'E') { nptr++; - if (*nptr == '+' || *nptr == '-') + if (*nptr == '+' || IS_DASH(*nptr)) nptr++; while (idigit(*nptr) || *nptr == '_') nptr++; @@ -599,7 +599,8 @@ zzlex(void) } return (unary) ? UPLUS : PLUS; case '-': - if (*ptr == '-') { + case Dash: + if (IS_DASH(*ptr)) { ptr++; return (unary) ? PREMINUS : POSTMINUS; } @@ -974,7 +975,7 @@ callmathfunc(char *o) a[strlen(a) - 1] = '\0'; if ((f = getmathfunc(n, 1))) { - if (f->flags & MFF_STR) { + if ((f->flags & (MFF_STR|MFF_USERFUNC)) == MFF_STR) { return f->sfunc(n, a, f->funcid); } else { int argc = 0; @@ -987,22 +988,34 @@ callmathfunc(char *o) addlinknode(l, n); } - while (iblank(*a)) - a++; + if (f->flags & MFF_STR) { + if (!*a) { + addlinknode(l, dupstring("")); + argc++; + } + } else { + while (iblank(*a)) + a++; + } while (*a) { if (*a) { argc++; if (f->flags & MFF_USERFUNC) { /* need to pass strings */ char *str; - marg = mathevall(a, MPREC_ARG, &a); - if (marg.type & MN_FLOAT) { - /* convfloat is off the heap */ - str = convfloat(marg.u.d, 0, 0, NULL); + if (f->flags & MFF_STR) { + str = dupstring(a); + a = ""; } else { - char buf[BDIGBUFSIZE]; - convbase(buf, marg.u.l, 10); - str = dupstring(buf); + marg = mathevall(a, MPREC_ARG, &a); + if (marg.type & MN_FLOAT) { + /* convfloat is off the heap */ + str = convfloat(marg.u.d, 0, 0, NULL); + } else { + char buf[BDIGBUFSIZE]; + convbase(buf, marg.u.l, 10); + str = dupstring(buf); + } } addlinknode(l, str); } else { diff --git a/Src/module.c b/Src/module.c index 41f142adb..21d68b1ac 100644 --- a/Src/module.c +++ b/Src/module.c @@ -2326,7 +2326,7 @@ load_module(char const *name, Feature_enables enablesarr, int silent) /**/ mod_export int -require_module(const char *module, Feature_enables features) +require_module(const char *module, Feature_enables features, int silent) { Module m = NULL; int ret = 0; @@ -2336,7 +2336,7 @@ require_module(const char *module, Feature_enables features) m = find_module(module, FINDMOD_ALIASP, &module); if (!m || !m->u.handle || (m->node.flags & MOD_UNLOAD)) - ret = load_module(module, features, 0); + ret = load_module(module, features, silent); else ret = do_module_features(m, features, 0); unqueue_signals(); @@ -2972,7 +2972,7 @@ bin_zmodload_load(char *nam, char **args, Options ops) } else { /* load modules */ for (; *args; args++) { - int tmpret = require_module(*args, NULL); + int tmpret = require_module(*args, NULL, OPT_ISSET(ops,'s')); if (tmpret && ret != 1) ret = tmpret; } @@ -3242,7 +3242,7 @@ bin_zmodload_features(const char *nam, char **args, Options ops) fep->str = NULL; fep->pat = NULL; - return require_module(modname, features); + return require_module(modname, features, OPT_ISSET(ops,'s')); } @@ -3403,14 +3403,14 @@ ensurefeature(const char *modname, const char *prefix, const char *feature) struct feature_enables features[2]; if (!feature) - return require_module(modname, NULL); + return require_module(modname, NULL, 0); f = dyncat(prefix, feature); features[0].str = f; features[0].pat = NULL; features[1].str = NULL; features[1].pat = NULL; - return require_module(modname, features); + return require_module(modname, features, 0); } /* diff --git a/Src/options.c b/Src/options.c index 18619c851..2b5795bab 100644 --- a/Src/options.c +++ b/Src/options.c @@ -78,6 +78,7 @@ mod_export HashTable optiontab; */ static struct optname optns[] = { {{NULL, "aliases", OPT_EMULATE|OPT_ALL}, ALIASESOPT}, +{{NULL, "aliasfuncdef", OPT_EMULATE|OPT_BOURNE}, ALIASFUNCDEF}, {{NULL, "allexport", OPT_EMULATE}, ALLEXPORT}, {{NULL, "alwayslastprompt", OPT_ALL}, ALWAYSLASTPROMPT}, {{NULL, "alwaystoend", 0}, ALWAYSTOEND}, @@ -257,6 +258,7 @@ static struct optname optns[] = { {{NULL, "verbose", 0}, VERBOSE}, {{NULL, "vi", 0}, VIMODE}, {{NULL, "warncreateglobal", OPT_EMULATE}, WARNCREATEGLOBAL}, +{{NULL, "warnnestedvar", OPT_EMULATE}, WARNNESTEDVAR}, {{NULL, "xtrace", 0}, XTRACE}, {{NULL, "zle", OPT_SPECIAL}, USEZLE}, {{NULL, "braceexpand", OPT_ALIAS}, /* ksh/bash */ -IGNOREBRACES}, @@ -645,7 +647,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) /* Expand the current arg. */ tokenize(s); - if (!(pprog = patcompile(s, PAT_STATIC, NULL))) { + if (!(pprog = patcompile(s, PAT_HEAPDUP, NULL))) { zwarnnam(nam, "bad pattern: %s", *args); continue; } diff --git a/Src/params.c b/Src/params.c index c64d7486b..6fbee880c 100644 --- a/Src/params.c +++ b/Src/params.c @@ -128,6 +128,11 @@ struct timeval shtimer; /**/ mod_export int termflags; +/* Forward declaration */ + +static void +rprompt_indent_unsetfn(Param pm, int exp); + /* Standard methods for get/set/unset pointers in parameters */ /**/ @@ -241,6 +246,9 @@ static const struct gsu_integer argc_gsu = static const struct gsu_array pipestatus_gsu = { pipestatgetfn, pipestatsetfn, stdunsetfn }; +static const struct gsu_integer rprompt_indent_gsu = +{ intvargetfn, zlevarsetfn, rprompt_indent_unsetfn }; + /* Nodes for special parameters for parameter hash table */ #ifdef HAVE_UNION_INIT @@ -327,7 +335,7 @@ IPDEF4("ZSH_SUBSHELL", &zsh_subshell), #define IPDEF5U(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0} IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu), IPDEF5("LINES", &zterm_lines, zlevar_gsu), -IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, zlevar_gsu), +IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, rprompt_indent_gsu), IPDEF5("SHLVL", &shlvl, varinteger_gsu), /* Don't import internal integer status variables. */ @@ -353,6 +361,17 @@ IPDEF7("PS3", &prompt3), IPDEF7R("PS4", &prompt4), IPDEF7("SPROMPT", &sprompt), +#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0} +#define IPDEF9(A,B,C) IPDEF9F(A,B,C,0) +IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), +IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), + +/* + * This empty row indicates the end of parameters available in + * all emulations. + */ +{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0}, + #define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0} IPDEF8("CDPATH", &cdpath, "cdpath", 0), IPDEF8("FIGNORE", &fignore, "fignore", 0), @@ -366,17 +385,6 @@ IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY), /* MODULE_PATH is not imported for security reasons */ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED), -#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0} -#define IPDEF9(A,B,C) IPDEF9F(A,B,C,0) -IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), -IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), - -/* - * This empty row indicates the end of parameters available in - * all emulations. - */ -{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0}, - #define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0} /* @@ -416,6 +424,26 @@ IPDEF10("pipestatus", pipestatus_gsu), }; /* + * Alternative versions of colon-separated path parameters for + * sh emulation. These don't link to the array versions. + */ +static initparam special_params_sh[] = { +IPDEF8("CDPATH", &cdpath, NULL, 0), +IPDEF8("FIGNORE", &fignore, NULL, 0), +IPDEF8("FPATH", &fpath, NULL, 0), +IPDEF8("MAILPATH", &mailpath, NULL, 0), +IPDEF8("WATCH", &watch, NULL, 0), +IPDEF8("PATH", &path, NULL, PM_RESTRICTED), +IPDEF8("PSVAR", &psvar, NULL, 0), +IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY), + +/* MODULE_PATH is not imported for security reasons */ +IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED), + +{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0}, +}; + +/* * Special way of referring to the positional parameters. Unlike $* * and $@, this is not readonly. This parameter is not directly * visible in user space. @@ -745,9 +773,13 @@ createparamtable(void) /* Add the special parameters to the hash table */ for (ip = special_params; ip->node.nam; ip++) paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip); - if (!EMULATION(EMULATE_SH|EMULATE_KSH)) + if (EMULATION(EMULATE_SH|EMULATE_KSH)) { + for (ip = special_params_sh; ip->node.nam; ip++) + paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip); + } else { while ((++ip)->node.nam) paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip); + } argvparam = (Param) &argvparam_pm; @@ -1175,7 +1207,7 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, int *prevcharlen, int *nextcharlen) { int hasbeg = 0, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash; - int keymatch = 0, needtok = 0, arglen, len; + int keymatch = 0, needtok = 0, arglen, len, inpar = 0; char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt, c; zlong num = 1, beg = 0, r = 0, quote_arg = 0; Patprog pprog = NULL; @@ -1314,8 +1346,9 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, } for (t = s, i = 0; - (c = *t) && ((c != Outbrack && - (ishash || c != ',')) || i); t++) { + (c = *t) && + ((c != Outbrack && (ishash || c != ',')) || i || inpar); + t++) { /* Untokenize inull() except before brackets and double-quotes */ if (inull(c)) { c = t[1]; @@ -1336,6 +1369,10 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, i++; else if (c == ']' || c == Outbrack) i--; + if (c == '(' || c == Inpar) + inpar++; + else if (c == ')' || c == Outpar) + inpar--; if (ispecial(c)) needtok = 1; } @@ -1979,7 +2016,9 @@ fetchvalue(Value v, char **pptr, int bracks, int flags) *s++ = '$'; else if (c == Star) *s++ = '*'; - else if (c == '#' || c == '-' || c == '?' || c == '$' || + else if (IS_DASH(c)) + *s++ = '-'; + else if (c == '#' || c == '?' || c == '$' || c == '!' || c == '@' || c == '*') s++; else @@ -2708,24 +2747,73 @@ setarrvalue(Value v, char **val) post_assignment_length += pre_assignment_length - v->end; } - p = new = (char **) zalloc(sizeof(char *) - * (post_assignment_length + 1)); + if (pre_assignment_length == post_assignment_length + && v->pm->gsu.a->setfn == arrsetfn + /* ... and isn't something that arrsetfn() treats specially */ + && 0 == (v->pm->node.flags & (PM_SPECIAL|PM_UNIQUE)) + && NULL == v->pm->ename) + { + /* v->start is 0-based */ + p = old + v->start; + for (r = val; *r;) { + /* Free previous string */ + zsfree(*p); + /* Give away ownership of the string */ + *p++ = *r++; + } + } else { + /* arr+=( ... ) + * arr[${#arr}+x,...]=( ... ) */ + if (post_assignment_length > pre_assignment_length && + pre_assignment_length <= v->start && + pre_assignment_length > 0 && + v->pm->gsu.a->setfn == arrsetfn) + { + p = new = (char **) zrealloc(old, sizeof(char *) + * (post_assignment_length + 1)); + + p += pre_assignment_length; /* after old elements */ + + /* Consider 1 < 0, case for a=( 1 ); a[1,..] = + * 1 < 1, case for a=( 1 ); a[2,..] = */ + if (pre_assignment_length < v->start) { + for (i = pre_assignment_length; i < v->start; i++) { + *p++ = ztrdup(""); + } + } + + for (r = val; *r;) { + /* Give away ownership of the string */ + *p++ = *r++; + } + + /* v->end doesn't matter: + * a=( 1 2 ); a[4,100]=( a b ); echo "${(q@)a}" + * 1 2 '' a b */ + *p = NULL; + + v->pm->u.arr = NULL; + v->pm->gsu.a->setfn(v->pm, new); + } else { + p = new = (char **) zalloc(sizeof(char *) + * (post_assignment_length + 1)); + for (i = 0; i < v->start; i++) + *p++ = i < pre_assignment_length ? ztrdup(*q++) : ztrdup(""); + for (r = val; *r;) { + /* Give away ownership of the string */ + *p++ = *r++; + } + if (v->end < pre_assignment_length) + for (q = old + v->end; *q;) + *p++ = ztrdup(*q++); + *p = NULL; + + v->pm->gsu.a->setfn(v->pm, new); + } - for (i = 0; i < v->start; i++) - *p++ = i < pre_assignment_length ? ztrdup(*q++) : ztrdup(""); - for (r = val; *r;) { - /* Give away ownership of the string */ - *p++ = *r++; + DPUTS2(p - new != post_assignment_length, "setarrvalue: wrong allocation: %d 1= %lu", + post_assignment_length, (unsigned long)(p - new)); } - if (v->end < pre_assignment_length) - for (q = old + v->end; *q;) - *p++ = ztrdup(*q++); - *p = NULL; - - DPUTS2(p - new != post_assignment_length, "setarrvalue: wrong allocation: %d 1= %lu", - post_assignment_length, (unsigned long)(p - new)); - - v->pm->gsu.a->setfn(v->pm, new); /* Ownership of all strings has been * given away, can plainly free */ @@ -2833,20 +2921,51 @@ gethkparam(char *s) return NULL; } +/* + * Function behind WARNCREATEGLOBAL and WARNNESTEDVAR option. + * + * For WARNNESTEDVAR: + * Called when the variable is created. + * Apply heuristics to see if this variable was just created + * globally but in a local context. + * + * For WARNNESTEDVAR: + * Called when the variable already exists and is set. + * Apply heuristics to see if this variable is setting + * a variable that was created in a less nested function + * or globally. + */ + /**/ static void -check_warn_create(Param pm, const char *pmtype) +check_warn_pm(Param pm, const char *pmtype, int created, + int may_warn_about_nested_vars) { Funcstack i; - if (pm->level != 0 || (pm->node.flags & PM_SPECIAL)) + if (!may_warn_about_nested_vars && !created) + return; + + if (created && isset(WARNCREATEGLOBAL)) { + if (locallevel <= forklevel || pm->level != 0) + return; + } else if (!created && isset(WARNNESTEDVAR)) { + if (pm->level >= locallevel) + return; + } else + return; + + if (pm->node.flags & PM_SPECIAL) return; for (i = funcstack; i; i = i->prev) { if (i->tp == FS_FUNC) { + char *msg; DPUTS(!i->name, "funcstack entry with no name"); - zwarn("%s parameter %s created globally in function %s", - pmtype, pm->node.nam, i->name); + msg = created ? + "%s parameter %s created globally in function %s" : + "%s parameter %s set in enclosing scope in function %s"; + zwarn(msg, pmtype, pm->node.nam, i->name); break; } } @@ -2862,7 +2981,7 @@ assignsparam(char *s, char *val, int flags) char *ss, *copy, *var; size_t lvar; mnumber lhs, rhs; - int sstart; + int sstart, created = 0; if (!isident(s)) { zerr("not an identifier: %s", s); @@ -2873,9 +2992,10 @@ assignsparam(char *s, char *val, int flags) queue_signals(); if ((ss = strchr(s, '['))) { *ss = '\0'; - if (!(v = getvalue(&vbuf, &s, 1))) + if (!(v = getvalue(&vbuf, &s, 1))) { createparam(t, PM_ARRAY); - else { + created = 1; + } else { if (v->pm->node.flags & PM_READONLY) { zerr("read-only variable: %s", v->pm->node.nam); *ss = '['; @@ -2883,23 +3003,27 @@ assignsparam(char *s, char *val, int flags) unqueue_signals(); return NULL; } - flags &= ~ASSPM_WARN_CREATE; + /* + * Parameter defined here is a temporary bogus one. + * Don't warn about anything. + */ + flags &= ~ASSPM_WARN; } *ss = '['; v = NULL; } else { - if (!(v = getvalue(&vbuf, &s, 1))) + if (!(v = getvalue(&vbuf, &s, 1))) { createparam(t, PM_SCALAR); - else if ((((v->pm->node.flags & PM_ARRAY) && !(flags & ASSPM_AUGMENT)) || + created = 1; + } else if ((((v->pm->node.flags & PM_ARRAY) && !(flags & ASSPM_AUGMENT)) || (v->pm->node.flags & PM_HASHED)) && !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) { unsetparam(t); createparam(t, PM_SCALAR); + /* not regarded as a new creation */ v = NULL; } - else - flags &= ~ASSPM_WARN_CREATE; } if (!v && !(v = getvalue(&vbuf, &t, 1))) { unqueue_signals(); @@ -2907,8 +3031,8 @@ assignsparam(char *s, char *val, int flags) /* errflag |= ERRFLAG_ERROR; */ return NULL; } - if (flags & ASSPM_WARN_CREATE) - check_warn_create(v->pm, "scalar"); + if (flags & ASSPM_WARN) + check_warn_pm(v->pm, "scalar", created, 1); if (flags & ASSPM_AUGMENT) { if (v->start == 0 && v->end == -1) { switch (PM_TYPE(v->pm->node.flags)) { @@ -2989,9 +3113,7 @@ assignsparam(char *s, char *val, int flags) mod_export Param setsparam(char *s, char *val) { - return assignsparam( - s, val, isset(WARNCREATEGLOBAL) && locallevel > forklevel ? - ASSPM_WARN_CREATE : 0); + return assignsparam(s, val, ASSPM_WARN); } /**/ @@ -3002,6 +3124,8 @@ assignaparam(char *s, char **val, int flags) Value v; char *t = s; char *ss; + int created = 0; + int may_warn_about_nested_vars = 1; if (!isident(s)) { zerr("not an identifier: %s", s); @@ -3012,10 +3136,12 @@ assignaparam(char *s, char **val, int flags) queue_signals(); if ((ss = strchr(s, '['))) { *ss = '\0'; - if (!(v = getvalue(&vbuf, &s, 1))) + if (!(v = getvalue(&vbuf, &s, 1))) { createparam(t, PM_ARRAY); - else - flags &= ~ASSPM_WARN_CREATE; + created = 1; + } else { + may_warn_about_nested_vars = 0; + } *ss = '['; if (v && PM_TYPE(v->pm->node.flags) == PM_HASHED) { unqueue_signals(); @@ -3027,9 +3153,10 @@ assignaparam(char *s, char **val, int flags) } v = NULL; } else { - if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) + if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) { createparam(t, PM_ARRAY); - else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) && + created = 1; + } else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) && !(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) { int uniq = v->pm->node.flags & PM_UNIQUE; if (flags & ASSPM_AUGMENT) { @@ -3047,8 +3174,6 @@ assignaparam(char *s, char **val, int flags) createparam(t, PM_ARRAY | uniq); v = NULL; } - else - flags &= ~ASSPM_WARN_CREATE; } if (!v) if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) { @@ -3058,8 +3183,8 @@ assignaparam(char *s, char **val, int flags) return NULL; } - if (flags & ASSPM_WARN_CREATE) - check_warn_create(v->pm, "array"); + if (flags & ASSPM_WARN) + check_warn_pm(v->pm, "array", created, may_warn_about_nested_vars); if (flags & ASSPM_AUGMENT) { if (v->start == 0 && v->end == -1) { if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) { @@ -3087,9 +3212,7 @@ assignaparam(char *s, char **val, int flags) mod_export Param setaparam(char *s, char **aval) { - return assignaparam( - s, aval, isset(WARNCREATEGLOBAL) && locallevel > forklevel ? - ASSPM_WARN_CREATE : 0); + return assignaparam(s, aval, ASSPM_WARN); } /**/ @@ -3118,13 +3241,18 @@ sethparam(char *s, char **val) queue_signals(); if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) { createparam(t, PM_HASHED); - checkcreate = isset(WARNCREATEGLOBAL) && locallevel > forklevel; - } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) && - !(v->pm->node.flags & PM_SPECIAL)) { - unsetparam(t); - /* no WARNCREATEGLOBAL check here as parameter already existed */ - createparam(t, PM_HASHED); - v = NULL; + checkcreate = 1; + } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED)) { + if (!(v->pm->node.flags & PM_SPECIAL)) { + unsetparam(t); + /* no WARNCREATEGLOBAL check here as parameter already existed */ + createparam(t, PM_HASHED); + v = NULL; + } else { + zerr("%s: can't change type of a special parameter", t); + unqueue_signals(); + return NULL; + } } if (!v) if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) { @@ -3132,8 +3260,7 @@ sethparam(char *s, char **val) /* errflag |= ERRFLAG_ERROR; */ return NULL; } - if (checkcreate) - check_warn_create(v->pm, "associative array"); + check_warn_pm(v->pm, "associative array", checkcreate, 1); setarrvalue(v, val); unqueue_signals(); return v->pm; @@ -3142,11 +3269,12 @@ sethparam(char *s, char **val) /* * Set a generic shell number, floating point or integer. + * Option to warn on setting. */ /**/ -Param -setnparam(char *s, mnumber val) +mod_export Param +assignnparam(char *s, mnumber val, int flags) { struct value vbuf; Value v; @@ -3198,14 +3326,41 @@ setnparam(char *s, mnumber val) unqueue_signals(); return NULL; } - if (!was_unset && isset(WARNCREATEGLOBAL) && locallevel > forklevel) - check_warn_create(v->pm, "numeric"); + if (flags & ASSPM_WARN) + check_warn_pm(v->pm, "numeric", !was_unset, 1); + } else { + if (flags & ASSPM_WARN) + check_warn_pm(v->pm, "numeric", 0, 1); } setnumvalue(v, val); unqueue_signals(); return v->pm; } +/* + * Set a generic shell number, floating point or integer. + * Warn on setting based on option. + */ + +/**/ +mod_export Param +setnparam(char *s, mnumber val) +{ + return assignnparam(s, val, ASSPM_WARN); +} + +/* Simplified interface to assignnparam */ + +/**/ +mod_export Param +assigniparam(char *s, zlong val, int flags) +{ + mnumber mnval; + mnval.type = MN_INTEGER; + mnval.u.l = val; + return assignnparam(s, mnval, flags); +} + /* Simplified interface to setnparam */ /**/ @@ -3215,7 +3370,7 @@ setiparam(char *s, zlong val) mnumber mnval; mnval.type = MN_INTEGER; mnval.u.l = val; - return setnparam(s, mnval); + return assignnparam(s, mnval, ASSPM_WARN); } /* @@ -3234,10 +3389,7 @@ setiparam_no_convert(char *s, zlong val) */ char buf[BDIGBUFSIZE]; convbase(buf, val, 10); - return assignsparam( - s, ztrdup(buf), - isset(WARNCREATEGLOBAL) && locallevel > forklevel ? - ASSPM_WARN_CREATE : 0); + return assignsparam(s, ztrdup(buf), ASSPM_WARN); } /* Unset a parameter */ @@ -3458,6 +3610,8 @@ strsetfn(Param pm, char *x) pm->node.flags |= PM_NAMEDDIR; adduserdir(pm->node.nam, x, 0, 0); } + /* If you update this function, you may need to update the + * `Implement remainder of strsetfn' block in assignstrvalue(). */ } /* Function to get value of an array parameter */ @@ -3485,6 +3639,8 @@ arrsetfn(Param pm, char **x) /* Arrays tied to colon-arrays may need to fix the environment */ if (pm->ename && x) arrfixenv(pm->ename, x); + /* If you extend this function, update the list of conditions in + * setarrvalue(). */ } /* Function to get value of an association parameter */ @@ -3621,6 +3777,16 @@ zlevarsetfn(Param pm, zlong x) adjustwinsize(2 + (p == &zterm_columns)); } + +/* Implements gsu_integer.unsetfn for ZLE_RPROMPT_INDENT; see stdunsetfn() */ + +static void +rprompt_indent_unsetfn(Param pm, int exp) +{ + stdunsetfn(pm, exp); + rprompt_indent = 1; /* Keep this in sync with init_term() */ +} + /* Function to set value of generic special scalar * * parameter. data is pointer to a character pointer * * representing the scalar (string). */ @@ -3720,8 +3886,7 @@ colonarrsetfn(Param pm, char *x) *dptr = colonsplit(x, pm->node.flags & PM_UNIQUE); else *dptr = mkarray(NULL); - if (pm->ename) - arrfixenv(pm->node.nam, *dptr); + arrfixenv(pm->node.nam, *dptr); zsfree(x); } diff --git a/Src/parse.c b/Src/parse.c index 50a0d5f9f..ba9cd61eb 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -394,9 +394,12 @@ ecdel(int p) static wordcode ecstrcode(char *s) { - int l, t = has_token(s); + int l, t; + + unsigned val = hasher(s); if ((l = strlen(s) + 1) && l <= 4) { + t = has_token(s); wordcode c = (t ? 3 : 2); switch (l) { case 4: c |= ((wordcode) STOUC(s[2])) << 19; @@ -410,16 +413,21 @@ ecstrcode(char *s) int cmp; for (pp = &ecstrs; (p = *pp); ) { - if (!(cmp = p->nfunc - ecnfunc) && !(cmp = strcmp(p->str, s))) + if (!(cmp = p->nfunc - ecnfunc) && !(cmp = (((signed)p->hashval) - ((signed)val))) && !(cmp = strcmp(p->str, s))) { return p->offs; + } pp = (cmp < 0 ? &(p->left) : &(p->right)); } + + t = has_token(s); + p = *pp = (Eccstr) zhalloc(sizeof(*p)); p->left = p->right = 0; p->offs = ((ecsoffs - ecssub) << 2) | (t ? 1 : 0); p->aoffs = ecsoffs; p->str = s; p->nfunc = ecnfunc; + p->hashval = val; ecsoffs += l; return p->offs; @@ -1738,6 +1746,7 @@ par_simple(int *cmplx, int nr) { int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0; int c = *cmplx, nrediradd, assignments = 0, ppost = 0, is_typeset = 0; + char *hasalias = input_hasalias(); wordcode postassigns = 0; r = ecused; @@ -1809,6 +1818,8 @@ par_simple(int *cmplx, int nr) } else break; zshlex(); + if (!hasalias) + hasalias = input_hasalias(); } if (tok == AMPER || tok == AMPERBANG) YYERROR(oecused); @@ -1833,12 +1844,14 @@ par_simple(int *cmplx, int nr) if (*ptr == Outbrace && ptr > tokstr + 1) { - if (itype_end(tokstr+1, IIDENT, 0) >= ptr - 1) + if (itype_end(tokstr+1, IIDENT, 0) >= ptr) { char *toksave = tokstr; char *idstring = dupstrpfx(tokstr+1, eptr-tokstr-1); redir_var = 1; zshlex(); + if (!hasalias) + hasalias = input_hasalias(); if (IS_REDIROP(tok) && tokfd == -1) { @@ -1874,6 +1887,8 @@ par_simple(int *cmplx, int nr) argc++; } zshlex(); + if (!hasalias) + hasalias = input_hasalias(); } } else if (IS_REDIROP(tok)) { *cmplx = c = 1; @@ -1902,6 +1917,8 @@ par_simple(int *cmplx, int nr) ecstr(name); ecstr(str); zshlex(); + if (!hasalias) + hasalias = input_hasalias(); } else if (tok == ENVARRAY) { int n, parr; @@ -1936,6 +1953,11 @@ par_simple(int *cmplx, int nr) /* Error if preceding assignments */ if (assignments || postassigns) YYERROR(oecused); + if (hasalias && !isset(ALIASFUNCDEF) && argc && + hasalias != input_hasalias()) { + zwarn("defining function based on alias `%s'", hasalias); + YYERROR(oecused); + } *cmplx = c; lineno = 0; @@ -2016,10 +2038,21 @@ par_simple(int *cmplx, int nr) /* Unnamed function */ int parg = ecadd(0); ecadd(0); - while (tok == STRING) { - ecstr(tokstr); - argc++; - zshlex(); + while (tok == STRING || IS_REDIROP(tok)) { + if (tok == STRING) + { + ecstr(tokstr); + argc++; + zshlex(); + } else { + *cmplx = c = 1; + nrediradd = par_redir(&r, NULL); + p += nrediradd; + if (ppost) + ppost += nrediradd; + sr += nrediradd; + parg += nrediradd; + } } if (argc > 0) *cmplx = 1; @@ -2129,7 +2162,7 @@ par_redir(int *rp, char *idstring) * the definition of WC_REDIR_WORDS. */ ecispace(r, ncodes); *rp = r + ncodes; - ecbuf[r] = WCB_REDIR(type); + ecbuf[r] = WCB_REDIR(type | REDIR_FROM_HEREDOC_MASK); ecbuf[r + 1] = fd1; /* @@ -2303,6 +2336,19 @@ par_cond_1(void) } /* + * Return 1 if condition matches. This also works for non-elided options. + * + * input is test string, may begin - or Dash. + * cond is condition following the -. + */ +static int check_cond(const char *input, const char *cond) +{ + if (!IS_DASH(input[0])) + return 0; + return !strcmp(input + 1, cond); +} + +/* * cond_2 : BANG cond_2 | INPAR { SEPER } cond_2 { SEPER } OUTPAR | STRING STRING STRING @@ -2328,7 +2374,7 @@ par_cond_2(void) s1 = tokstr; condlex(); /* ksh behavior: [ -t ] means [ -t 1 ]; bash disagrees */ - if (unset(POSIXBUILTINS) && !strcmp(s1, "-t")) + if (unset(POSIXBUILTINS) && check_cond(s1, "t")) return par_cond_double(s1, dupstring("1")); return par_cond_double(dupstring("-n"), s1); } @@ -2338,7 +2384,7 @@ par_cond_2(void) if (!strcmp(*testargs, "=") || !strcmp(*testargs, "==") || !strcmp(*testargs, "!=") || - (**testargs == '-' && get_cond_num(*testargs + 1) >= 0)) { + (IS_DASH(**testargs) && get_cond_num(*testargs + 1) >= 0)) { s1 = tokstr; condlex(); s2 = tokstr; @@ -2360,8 +2406,8 @@ par_cond_2(void) * In "test" compatibility mode, "! -a ..." and "! -o ..." * are treated as "[string] [and] ..." and "[string] [or] ...". */ - if (!(n_testargs > 1 && - (!strcmp(*testargs, "-a") || !strcmp(*testargs, "-o")))) + if (!(n_testargs > 1 && (check_cond(*testargs, "a") || + check_cond(*testargs, "o")))) { condlex(); ecadd(WCB_COND(COND_NOT, 0)); @@ -2383,7 +2429,7 @@ par_cond_2(void) return r; } s1 = tokstr; - dble = (s1 && *s1 == '-' + dble = (s1 && IS_DASH(*s1) && (!n_testargs || strspn(s1+1, "abcdefghknoprstuvwxzLONGS") == 1) && !s1[2]); @@ -2397,7 +2443,7 @@ par_cond_2(void) YYERROR(ecused); } condlex(); - if (n_testargs == 2 && tok != STRING && tokstr && s1[0] == '-') { + if (n_testargs == 2 && tok != STRING && tokstr && IS_DASH(s1[0])) { /* * Something like "test -z" followed by a token. * We'll turn the token into a string (we've also @@ -2432,9 +2478,9 @@ par_cond_2(void) } else YYERROR(ecused); } - s2 = tokstr; + s2 = tokstr; if (!n_testargs) - dble = (s2 && *s2 == '-' && !s2[2]); + dble = (s2 && IS_DASH(*s2) && !s2[2]); incond++; /* parentheses do globbing */ do condlex(); while (COND_SEP()); incond--; /* parentheses do grouping */ @@ -2462,7 +2508,7 @@ par_cond_2(void) static int par_cond_double(char *a, char *b) { - if (a[0] != '-' || !a[1]) + if (!IS_DASH(a[0]) || !a[1]) COND_ERROR("parse error: condition expected: %s", a); else if (!a[2] && strspn(a+1, "abcdefgknoprstuvwxzhLONGS") == 1) { ecadd(WCB_COND(a[1], 0)); @@ -2520,7 +2566,7 @@ par_cond_triple(char *a, char *b, char *c) ecadd(WCB_COND(COND_REGEX, 0)); ecstr(a); ecstr(c); - } else if (b[0] == '-') { + } else if (IS_DASH(b[0])) { if ((t0 = get_cond_num(b + 1)) > -1) { ecadd(WCB_COND(t0 + COND_NT, 0)); ecstr(a); @@ -2531,7 +2577,7 @@ par_cond_triple(char *a, char *b, char *c) ecstr(a); ecstr(c); } - } else if (a[0] == '-' && a[1]) { + } else if (IS_DASH(a[0]) && a[1]) { ecadd(WCB_COND(COND_MOD, 2)); ecstr(a); ecstr(b); @@ -2546,7 +2592,7 @@ par_cond_triple(char *a, char *b, char *c) static int par_cond_multi(char *a, LinkList l) { - if (a[0] != '-' || !a[1]) + if (!IS_DASH(a[0]) || !a[1]) COND_ERROR("condition expected: %s", a); else { LinkNode n; @@ -3242,10 +3288,10 @@ build_dump(char *nam, char *dump, char **files, int ali, int map, int flags) for (hlen = FD_PRELEN, tlen = 0; *files; files++) { struct stat st; - if (!strcmp(*files, "-k")) { + if (check_cond(*files, "k")) { flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD; continue; - } else if (!strcmp(*files, "-z")) { + } else if (check_cond(*files, "z")) { flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_ZSHLOAD; continue; } @@ -3324,7 +3370,7 @@ cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs, return 1; } noaliases = (shf->node.flags & PM_UNALIASED); - if (!(prog = getfpfunc(shf->node.nam, NULL, NULL)) || + if (!(prog = getfpfunc(shf->node.nam, NULL, NULL, NULL, 0)) || prog == &dummy_eprog) { noaliases = ona; zwarnnam(nam, "can't load function: %s", shf->node.nam); @@ -3399,6 +3445,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, for (; *names; names++) { tokenize(pat = dupstring(*names)); + /* Signal-safe here, caller queues signals */ if (!(pprog = patcompile(pat, PAT_STATIC, NULL))) { zwarnnam(nam, "bad pattern: %s", *names); close(dfd); @@ -3566,7 +3613,7 @@ load_dump_file(char *dump, struct stat *sbuf, int other, int len) /**/ Eprog -try_dump_file(char *path, char *name, char *file, int *ksh) +try_dump_file(char *path, char *name, char *file, int *ksh, int test_only) { Eprog prog; struct stat std, stc, stn; @@ -3575,7 +3622,7 @@ try_dump_file(char *path, char *name, char *file, int *ksh) if (strsfx(FD_EXT, path)) { queue_signals(); - prog = check_dump_file(path, NULL, name, ksh); + prog = check_dump_file(path, NULL, name, ksh, test_only); unqueue_signals(); return prog; } @@ -3594,14 +3641,14 @@ try_dump_file(char *path, char *name, char *file, int *ksh) if (!rd && (rc || std.st_mtime > stc.st_mtime) && (rn || std.st_mtime > stn.st_mtime) && - (prog = check_dump_file(dig, &std, name, ksh))) { + (prog = check_dump_file(dig, &std, name, ksh, test_only))) { unqueue_signals(); return prog; } /* No digest file. Now look for the per-function compiled file. */ if (!rc && (rn || stc.st_mtime > stn.st_mtime) && - (prog = check_dump_file(wc, &stc, name, ksh))) { + (prog = check_dump_file(wc, &stc, name, ksh, test_only))) { unqueue_signals(); return prog; } @@ -3629,7 +3676,7 @@ try_source_file(char *file) if (strsfx(FD_EXT, file)) { queue_signals(); - prog = check_dump_file(file, NULL, tail, NULL); + prog = check_dump_file(file, NULL, tail, NULL, 0); unqueue_signals(); return prog; } @@ -3640,7 +3687,7 @@ try_source_file(char *file) queue_signals(); if (!rc && (rn || stc.st_mtime > stn.st_mtime) && - (prog = check_dump_file(wc, &stc, tail, NULL))) { + (prog = check_dump_file(wc, &stc, tail, NULL, 0))) { unqueue_signals(); return prog; } @@ -3653,7 +3700,8 @@ try_source_file(char *file) /**/ static Eprog -check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh) +check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh, + int test_only) { int isrec = 0; Wordcode d; @@ -3695,6 +3743,11 @@ check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh) if ((h = dump_find_func(d, name))) { /* Found the name. If the file is already mapped, return the eprog, * otherwise map it and just go up. */ + if (test_only) + { + /* This is all we need. Just return dummy. */ + return &dummy_eprog; + } #ifdef USE_MMAP @@ -3731,7 +3784,7 @@ check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh) #endif - { + { Eprog prog; Patprog *pp; int np, fd, po = h->npats * sizeof(Patprog); diff --git a/Src/pattern.c b/Src/pattern.c index 1f2e94bd9..fc7c73739 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -668,15 +668,9 @@ patcompile(char *exp, int inflags, char **endexp) if (imeta(*mtest)) nmeta++; if (nmeta) { - char *oldpatout = patout; - ptrdiff_t pd; patadd(NULL, 0, nmeta, 0); - /* - * Yuk. - */ p = (Patprog)patout; - pd = patout - oldpatout; - opnd += pd; + opnd = dupstring_wlen(opnd, oplen); dst = patout + startoff; } @@ -1527,7 +1521,7 @@ patcomppiece(int *flagp, int paren) patparse = nptr; len |= 1; } - DPUTS(*patparse != '-', "BUG: - missing from numeric glob"); + DPUTS(!IS_DASH(*patparse), "BUG: - missing from numeric glob"); patparse++; if (idigit(*patparse)) { to = (zrange_t) zstrtol((char *)patparse, @@ -3631,7 +3625,7 @@ mb_patmatchrange(char *range, wchar_t ch, int zmb_ind, wint_t *indptr, int *mtp) return 1; break; case PP_PRINT: - if (iswprint(ch)) + if (WC_ISPRINT(ch)) return 1; break; case PP_PUNCT: diff --git a/Src/prompt.c b/Src/prompt.c index ee77c8bc8..c478e69fb 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -399,7 +399,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) test = 1; break; case 'V': - if (arrlen_ge(psvar, arg)) { + if (psvar && *psvar && arrlen_ge(psvar, arg)) { if (*psvar[(arg ? arg : 1) - 1]) test = 1; } @@ -920,6 +920,7 @@ addbufspc(int need) if(need & 255) need = (need | 255) + 1; bv->buf = realloc(bv->buf, bv->bufspc += need); + memset(bv->buf + bv->bufspc - need, 0, need); bv->bp = bv->buf + bo; if(bo1 != -1) bv->bp1 = bv->buf + bo1; diff --git a/Src/signals.c b/Src/signals.c index 9e05add09..cad40f4eb 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -55,6 +55,11 @@ mod_export Eprog siglists[VSIGCOUNT]; /**/ mod_export int nsigtrapped; +/* Running an exit trap? */ + +/**/ +int in_exit_trap; + /* * Flag that exit trap has been set in POSIX mode. * The setter's expectation is therefore that it is run @@ -522,6 +527,11 @@ wait_for_processes(void) #if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE) struct timezone dummy_tz; gettimeofday(&pn->endtime, &dummy_tz); +#ifdef WIFCONTINUED + if (WIFCONTINUED(status)) + pn->status = SP_RUNNING; + else +#endif pn->status = status; pn->ti = ru; #else @@ -811,7 +821,11 @@ dosavetrap(int sig, int level) newshf->node.nam = ztrdup(shf->node.nam); newshf->node.flags = shf->node.flags; newshf->funcdef = dupeprog(shf->funcdef, 0); - newshf->filename = ztrdup(shf->filename); + if (shf->node.flags & PM_LOADDIR) { + dircache_set(&newshf->filename, shf->filename); + } else { + newshf->filename = ztrdup(shf->filename); + } if (shf->sticky) { newshf->sticky = sticky_emulation_dup(shf->sticky, 0); } else @@ -1426,7 +1440,13 @@ dotrap(int sig) dont_queue_signals(); + if (sig == SIGEXIT) + ++in_exit_trap; + dotrapargs(sig, sigtrapped+sig, funcprog); + if (sig == SIGEXIT) + --in_exit_trap; + restore_queue_signals(q); } diff --git a/Src/string.c b/Src/string.c index a8da14fe0..9e14ef949 100644 --- a/Src/string.c +++ b/Src/string.c @@ -52,7 +52,8 @@ dupstring_wlen(const char *s, unsigned len) if (!s) return NULL; t = (char *) zhalloc(len + 1); - strcpy(t, s); + memcpy(t, s, len); + t[len] = '\0'; return t; } diff --git a/Src/subst.c b/Src/subst.c index 64b440027..5b1bf8988 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -446,7 +446,7 @@ singsub(char **s) * NULL to use IFS). The return value is true iff the expansion resulted * in an empty list. * - * *ms_flags is set to bits in the enum above as neeed. + * *ms_flags is set to bits in the enum above as needed. */ /**/ @@ -481,6 +481,8 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, for ( ; *x; x += l) { int rawc = -1; convchar_t c; + if (*x == Dash) + *x = '-'; if (itok(STOUC(*x))) { /* token, can't be separator, must be single byte */ rawc = *x; @@ -622,7 +624,7 @@ filesub(char **namptr, int assign) char * equalsubstr(char *str, int assign, int nomatch) { - char *pp, *cnam, *cmdstr, *ret; + char *pp, *cnam, *cmdstr; for (pp = str; !isend2(*pp); pp++) ; @@ -634,10 +636,10 @@ equalsubstr(char *str, int assign, int nomatch) zerr("%s not found", cmdstr); return NULL; } - ret = dupstring(cnam); if (*pp) - ret = dyncat(ret, pp); - return ret; + return dyncat(cnam, pp); + else + return cnam; /* already duplicated */ } /**/ @@ -1766,7 +1768,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, */ c = *s; if (itype_end(s, IIDENT, 1) == s && *s != '#' && c != Pound && - c != '-' && c != '!' && c != '$' && c != String && c != Qstring && + !IS_DASH(c) && + c != '!' && c != '$' && c != String && c != Qstring && c != '?' && c != Quest && c != '*' && c != Star && c != '@' && c != '{' && c != Inbrace && c != '=' && c != Equals && c != Hat && @@ -1895,13 +1898,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, if (quotetype == QT_DOLLARS || quotetype == QT_BACKSLASH_PATTERN) goto flagerr; - if (s[1] == '-' || s[1] == '+') { + if (IS_DASH(s[1]) || s[1] == '+') { if (quotemod) goto flagerr; s++; quotemod = 1; - quotetype = (*s == '-') ? QT_SINGLE_OPTIONAL : - QT_QUOTEDZPUTS; + quotetype = (*s == '+') ? QT_QUOTEDZPUTS : + QT_SINGLE_OPTIONAL; } else { if (quotetype == QT_SINGLE_OPTIONAL) { /* extra q's after '-' not allowed */ @@ -2208,9 +2211,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * properly in the first place we wouldn't * have this nonsense. */ - || ((cc == '#' || cc == Pound) && - s[2] == Outbrace) - || cc == '-' || (cc == ':' && s[2] == '-') + || ((cc == '#' || cc == Pound) && s[2] == Outbrace) + || IS_DASH(cc) + || (cc == ':' && IS_DASH(s[2])) || (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) { getlen = 1 + whichlen, s++; /* @@ -2605,14 +2608,17 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * Again, this duplicates tests for characters we're about to * examine properly later on. */ - if (inbrace && - (c = *s) != '-' && c != '+' && c != ':' && c != '%' && c != '/' && - c != '=' && c != Equals && - c != '#' && c != Pound && - c != '?' && c != Quest && - c != '}' && c != Outbrace) { - zerr("bad substitution"); - return NULL; + if (inbrace) { + c = *s; + if (!IS_DASH(c) && + c != '+' && c != ':' && c != '%' && c != '/' && + c != '=' && c != Equals && + c != '#' && c != Pound && + c != '?' && c != Quest && + c != '}' && c != Outbrace) { + zerr("bad substitution"); + return NULL; + } } /* * Join arrays up if we're in quotes and there isn't some @@ -2690,8 +2696,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, /* Check for ${..?..} or ${..=..} or one of those. * * Only works if the name is in braces. */ - if (inbrace && ((c = *s) == '-' || - c == '+' || + if (inbrace && ((c = *s) == '+' || + IS_DASH(c) || c == ':' || /* i.e. a doubled colon */ c == '=' || c == Equals || c == '%' || @@ -2802,6 +2808,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, vunset = 1; /* Fall Through! */ case '-': + case Dash: if (vunset) { int split_flags; val = dupstring(s); @@ -2902,6 +2909,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, } else setaparam(idbeg, a); isarr = 1; + arrasg = 0; } else { untokenize(val); setsparam(idbeg, ztrdup(val)); @@ -3066,7 +3074,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, if (sval) zip = hmkarray(sval); } - if (!isarr) aval = mkarray(val); + if (!isarr) { + aval = mkarray(val); + isarr = 1; + } if (zip) { char **out; int alen, ziplen, outlen, i = 0; @@ -3089,7 +3100,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, out[i*2] = NULL; aval = out; copied = 1; - isarr = 1; } } else { if (unset(UNSET)) { @@ -3473,8 +3483,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, if (nojoin == 0 || sep) { val = sepjoin(aval, sep, 1); isarr = 0; - ms_flags = 0; - } else if (force_split && (spsep || nojoin == 2)) { + } else if (force_split && + (spsep || nojoin == 2 || (!ifs && isarr < 0))) { /* Hack to simulate splitting individual elements: * forced joining as previously determined, or * join on what we later use to forcibly split @@ -3482,6 +3492,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, val = sepjoin(aval, (nojoin == 1 ? NULL : spsep), 1); isarr = 0; } + if (!isarr) + ms_flags = 0; } if (force_split && !isarr) { aval = sepsplit(val, spsep, 0, 1); @@ -3767,6 +3779,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * as a scalar.) */ + if (isarr && ssub) { + /* prefork() wants a scalar, so join no matter what else */ + val = sepjoin(aval, NULL, 1); + isarr = 0; + l->list.flags &= ~LF_ARRAY; + } + /* * If a multsub result had whitespace at the start and we're * splitting and there's a previous string, now's the time to do so. @@ -3780,6 +3799,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, insertlinknode(l, n, dupstring(fstr)); /* appended, no incnode */ *fstr = '\0'; } + if (arrasg && !isarr) { + /* + * Caller requested this be forced to an array even if scalar. + * Any point in distinguishing arrasg == 2 (assoc array) here? + */ + l->list.flags |= LF_ARRAY; + aval = hmkarray(val); + isarr = 1; + DPUTS(!val, "value is NULL in paramsubst, empty array"); + } if (isarr) { char *x; char *y; @@ -4302,7 +4331,11 @@ modify(char **str, char **ptr) break; case 'P': if (*copy != '/') { - copy = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", copy); + char *here = zgetcwd(); + if (here[strlen(here)-1] != '/') + copy = zhtricat(metafy(here, -1, META_HEAPDUP), "/", copy); + else + copy = dyncat(here, copy); } copy = xsymlink(copy, 1); break; @@ -4384,7 +4417,11 @@ modify(char **str, char **ptr) break; case 'P': if (**str != '/') { - *str = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *str); + char *here = zgetcwd(); + if (here[strlen(here)-1] != '/') + *str = zhtricat(metafy(here, -1, META_HEAPDUP), "/", *str); + else + *str = dyncat(here, *str); } *str = xsymlink(*str, 1); break; diff --git a/Src/utils.c b/Src/utils.c index 7f3ddad40..5055d69fe 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -629,7 +629,7 @@ wcs_nicechar_sel(wchar_t c, size_t *widthp, char **swidep, int quotable) } s = buf; - if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { + if (!WC_ISPRINT(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { if (c == 0x7f) { if (quotable) { *s++ = '\\'; @@ -734,7 +734,7 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep) /**/ mod_export int is_wcs_nicechar(wchar_t c) { - if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { + if (!WC_ISPRINT(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { if (c == 0x7f || c == L'\n' || c == L'\t' || c < 0x20) return 1; if (c >= 0x80) { @@ -886,7 +886,7 @@ xsymlinks(char *s, int full) char **pp, **opp; char xbuf2[PATH_MAX*3+1], xbuf3[PATH_MAX*2+1]; int t0, ret = 0; - zulong xbuflen = strlen(xbuf); + zulong xbuflen = strlen(xbuf), pplen; opp = pp = slashsplit(s); for (; xbuflen < sizeof(xbuf) && *pp && ret >= 0; pp++) { @@ -907,10 +907,18 @@ xsymlinks(char *s, int full) xbuflen--; continue; } - sprintf(xbuf2, "%s/%s", xbuf, *pp); + /* Includes null byte. */ + pplen = strlen(*pp) + 1; + if (xbuflen + pplen + 1 > sizeof(xbuf2)) { + *xbuf = 0; + ret = -1; + break; + } + memcpy(xbuf2, xbuf, xbuflen); + xbuf2[xbuflen] = '/'; + memcpy(xbuf2 + xbuflen + 1, *pp, pplen); t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); if (t0 == -1) { - zulong pplen = strlen(*pp) + 1; if ((xbuflen += pplen) < sizeof(xbuf)) { strcat(xbuf, "/"); strcat(xbuf, *pp); @@ -1230,13 +1238,13 @@ adduserdir(char *s, char *t, int flags, int always) * named directory, since these are sometimes used for * special purposes. */ - nd->dir = ztrdup(t); + nd->dir = metafy(t, -1, META_DUP); } else - nd->dir = ztrduppfx(t, eptr - t); + nd->dir = metafy(t, eptr - t, META_DUP); /* The variables PWD and OLDPWD are not to be displayed as ~PWD etc. */ if (!strcmp(s, "PWD") || !strcmp(s, "OLDPWD")) nd->node.flags |= ND_NOABBREV; - nameddirtab->addnode(nameddirtab, ztrdup(s), nd); + nameddirtab->addnode(nameddirtab, metafy(s, -1, META_DUP), nd); } /* Get a named directory: this function can cause a directory name * @@ -2376,7 +2384,7 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore) while (inblank(*s)) s++; - if ((neg = (*s == '-'))) + if ((neg = IS_DASH(*s))) s++; else if (*s == '+') s++; @@ -4788,6 +4796,41 @@ unmeta(const char *file_name) } /* + * Unmetafy just one character and store the number of bytes it occupied. + */ +/**/ +mod_export convchar_t +unmeta_one(const char *in, int *sz) +{ + convchar_t wc; + int newsz; +#ifdef MULTIBYTE_SUPPORT + mbstate_t wstate; +#endif + + if (!sz) + sz = &newsz; + *sz = 0; + + if (!in || !*in) + return 0; + +#ifdef MULTIBYTE_SUPPORT + memset(&wstate, 0, sizeof(wstate)); + *sz = mb_metacharlenconv_r(in, &wc, &wstate); +#else + if (in[0] == Meta) { + *sz = 2; + wc = STOUC(in[1] ^ 32); + } else { + *sz = 1; + wc = STOUC(in[0]); + } +#endif + return wc; +} + +/* * Unmetafy and compare two strings, comparing unsigned character values. * "a\0" sorts after "a". * @@ -5076,7 +5119,7 @@ niceztrlen(char const *s) * If flags contains NICEFLAG_HEAP, use the heap for *outstrp, else * zalloc. * If flags contsins NICEFLAG_QUOTE, the output is going to be within - * $'...', so quote "'" with a backslash. + * $'...', so quote "'" and "\" with a backslash. */ /**/ @@ -5132,6 +5175,10 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags) fmt = "\\'"; newl = 2; } + else if (c == L'\\' && (flags & NICEFLAG_QUOTE)) { + fmt = "\\\\"; + newl = 2; + } else fmt = wcs_nicechar_sel(c, &newl, NULL, flags & NICEFLAG_QUOTE); break; @@ -5374,7 +5421,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr) int num, num_in_char, complete; if (!isset(MULTIBYTE)) - return ztrlen(ptr); + return eptr ? (int)(eptr - ptr) : ztrlen(ptr); laststart = ptr; ret = MB_INVALID; @@ -6118,7 +6165,9 @@ quotedzputs(char const *s, FILE *stream) } else *ptr++ = '\''; while(*s) { - if (*s == Meta) + if (*s == Dash) + c = '-'; + else if (*s == Meta) c = *++s ^ 32; else c = *s; @@ -6155,7 +6204,9 @@ quotedzputs(char const *s, FILE *stream) } else { /* use Bourne-style quoting, avoiding empty quoted strings */ while (*s) { - if (*s == Meta) + if (*s == Dash) + c = '-'; + else if (*s == Meta) c = *++s ^ 32; else c = *s; diff --git a/Src/watch.c b/Src/watch.c index c804913ad..cd7dc643d 100644 --- a/Src/watch.c +++ b/Src/watch.c @@ -87,6 +87,15 @@ #if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMPX) && defined(REAL_UTMPX_FILE) # define WATCH_STRUCT_UTMP struct utmpx +# if defined(HAVE_SETUTXENT) && defined(HAVE_GETUTXENT) && defined(HAVE_ENDUTXENT) +# define setutent setutxent +# define getutent getutxent +# define endutent endutxent +# ifndef HAVE_GETUTENT +# define HAVE_GETUTENT 1 +# endif +# endif + /* * In utmpx, the ut_name field is replaced by ut_user. * Howver, on some systems ut_name may already be defined this @@ -141,9 +150,9 @@ char const * const default_watchfmt = DEFAULT_WATCHFMT; # define WATCH_WTMP_FILE "/dev/null" # endif -static int wtabsz; -static WATCH_STRUCT_UTMP *wtab; -static time_t lastutmpcheck; +static int wtabsz = 0; +static WATCH_STRUCT_UTMP *wtab = NULL; +static time_t lastutmpcheck = 0; /* get the time of login/logout for WATCH */ @@ -473,34 +482,60 @@ ucmp(WATCH_STRUCT_UTMP *u, WATCH_STRUCT_UTMP *v) /* initialize the user List */ /**/ -static void -readwtab(void) +static int +readwtab(WATCH_STRUCT_UTMP **head, int initial_sz) { WATCH_STRUCT_UTMP *uptr; - int wtabmax = 32; + int wtabmax = initial_sz < 2 ? 32 : initial_sz; + int sz = 0; +# ifdef HAVE_GETUTENT + WATCH_STRUCT_UTMP *tmp; +# else FILE *in; +# endif - wtabsz = 0; + uptr = *head = (WATCH_STRUCT_UTMP *) + zalloc(wtabmax * sizeof(WATCH_STRUCT_UTMP)); +# ifdef HAVE_GETUTENT + setutent(); + while ((tmp = getutent()) != NULL) { + memcpy(uptr, tmp, sizeof (WATCH_STRUCT_UTMP)); +# else if (!(in = fopen(WATCH_UTMP_FILE, "r"))) - return; - uptr = wtab = (WATCH_STRUCT_UTMP *)zalloc(wtabmax * sizeof(WATCH_STRUCT_UTMP)); - while (fread(uptr, sizeof(WATCH_STRUCT_UTMP), 1, in)) + return 0; + while (fread(uptr, sizeof(WATCH_STRUCT_UTMP), 1, in)) { +# endif # ifdef USER_PROCESS - if (uptr->ut_type == USER_PROCESS) + if (uptr->ut_type == USER_PROCESS) # else /* !USER_PROCESS */ - if (uptr->ut_name[0]) + if (uptr->ut_name[0]) # endif /* !USER_PROCESS */ { uptr++; - if (++wtabsz == wtabmax) - uptr = (wtab = (WATCH_STRUCT_UTMP *)realloc((void *) wtab, (wtabmax *= 2) * - sizeof(WATCH_STRUCT_UTMP))) + wtabsz; + if (++sz == wtabmax) { + uptr = (WATCH_STRUCT_UTMP *) + realloc(*head, (wtabmax *= 2) * sizeof(WATCH_STRUCT_UTMP)); + if (uptr == NULL) { + /* memory pressure - so stop consuming and use, what we have + * Other option is to exit() here, as zmalloc does on error */ + sz--; + break; + } + *head = uptr; + uptr += sz; + } } + } +# ifdef HAVE_GETUTENT + endutent(); +# else fclose(in); +# endif - if (wtabsz) - qsort((void *) wtab, wtabsz, sizeof(WATCH_STRUCT_UTMP), + if (sz) + qsort((void *) *head, sz, sizeof(WATCH_STRUCT_UTMP), (int (*) _((const void *, const void *)))ucmp); + return sz; } /* Check for login/logout events; executed before * @@ -510,55 +545,28 @@ readwtab(void) void dowatch(void) { - FILE *in; WATCH_STRUCT_UTMP *utab, *uptr, *wptr; struct stat st; char **s; char *fmt; - int utabsz = 0, utabmax = wtabsz + 4; - int uct, wct; + int utabsz, uct, wct; s = watch; holdintr(); - if (!wtab) { - readwtab(); - noholdintr(); - return; - } + if (!wtab) + wtabsz = readwtab(&wtab, 32); if ((stat(WATCH_UTMP_FILE, &st) == -1) || (st.st_mtime <= lastutmpcheck)) { noholdintr(); return; } lastutmpcheck = st.st_mtime; - uptr = utab = (WATCH_STRUCT_UTMP *) zalloc(utabmax * sizeof(WATCH_STRUCT_UTMP)); - - if (!(in = fopen(WATCH_UTMP_FILE, "r"))) { - free(utab); - noholdintr(); - return; - } - while (fread(uptr, sizeof *uptr, 1, in)) -# ifdef USER_PROCESS - if (uptr->ut_type == USER_PROCESS) -# else /* !USER_PROCESS */ - if (uptr->ut_name[0]) -# endif /* !USER_PROCESS */ - { - uptr++; - if (++utabsz == utabmax) - uptr = (utab = (WATCH_STRUCT_UTMP *)realloc((void *) utab, (utabmax *= 2) * - sizeof(WATCH_STRUCT_UTMP))) + utabsz; - } - fclose(in); + utabsz = readwtab(&utab, wtabsz + 4); noholdintr(); if (errflag) { free(utab); return; } - if (utabsz) - qsort((void *) utab, utabsz, sizeof(WATCH_STRUCT_UTMP), - (int (*) _((const void *, const void *)))ucmp); wct = wtabsz; uct = utabsz; @@ -571,13 +579,14 @@ dowatch(void) queue_signals(); if (!(fmt = getsparam_u("WATCHFMT"))) fmt = DEFAULT_WATCHFMT; - while ((uct || wct) && !errflag) + while ((uct || wct) && !errflag) { if (!uct || (wct && ucmp(uptr, wptr) > 0)) wct--, watchlog(0, wptr++, s, fmt); else if (!wct || (uct && ucmp(uptr, wptr) < 0)) uct--, watchlog(1, uptr++, s, fmt); else uptr++, wptr++, wct--, uct--; + } unqueue_signals(); free(wtab); wtab = utab; diff --git a/Src/wcwidth9.h b/Src/wcwidth9.h index 07e6bae1c..448f548e9 100644 --- a/Src/wcwidth9.h +++ b/Src/wcwidth9.h @@ -22,6 +22,7 @@ static const struct wcwidth9_interval wcwidth9_nonprint[] = { {0x070f, 0x070f}, {0x180b, 0x180e}, {0x200b, 0x200f}, + {0x2028, 0x2029}, {0x202a, 0x202e}, {0x206a, 0x206f}, {0xd800, 0xdfff}, @@ -1283,6 +1284,9 @@ static inline bool wcwidth9_intable(const struct wcwidth9_interval *table, size_ } static inline int wcwidth9(int c) { + if (c == 0) { + return 0; + } if (c < 0|| c > 0x10ffff) { return -1; } @@ -1292,7 +1296,7 @@ static inline int wcwidth9(int c) { } if (wcwidth9_intable(wcwidth9_combining, WCWIDTH9_ARRAY_SIZE(wcwidth9_combining), c)) { - return -1; + return 0; } if (wcwidth9_intable(wcwidth9_not_assigned, WCWIDTH9_ARRAY_SIZE(wcwidth9_not_assigned), c)) { @@ -238,6 +238,16 @@ struct mathfunc { #define PATCHARS "#^*()|[]<>?~\\" /* + * Check for a possibly tokenized dash. + * + * A dash only needs to be a token in a character range, [a-z], but + * it's difficult in general to ensure that. So it's turned into + * a token at the usual point in the lexer. However, we need + * to check for a literal dash at many points. + */ +#define IS_DASH(x) ((x) == '-' || (x) == Dash) + +/* * Types of quote. This is used in various places, so care needs * to be taken when changing them. (Oooh, don't you look surprised.) * - Passed to quotestring() to indicate style. This is the ultimate @@ -803,6 +813,7 @@ struct eccstr { char *str; wordcode offs, aoffs; int nfunc; + int hashval; }; #define EC_NODUP 0 @@ -1019,6 +1030,7 @@ struct job { #define STAT_BUILTIN (0x4000) /* job at tail of pipeline is a builtin */ #define STAT_SUBJOB_ORPHANED (0x8000) /* STAT_SUBJOB with STAT_SUPERJOB exited */ +#define STAT_DISOWN (0x10000) /* STAT_SUPERJOB with disown pending */ #define SP_RUNNING -1 /* fake status for jobs currently running */ @@ -1233,7 +1245,9 @@ struct cmdnam { struct shfunc { struct hashnode node; - char *filename; /* Name of file located in */ + char *filename; /* Name of file located in. + For not yet autoloaded file, name + of explicit directory, if not NULL. */ zlong lineno; /* line number in above file */ Eprog funcdef; /* function definition */ Eprog redir; /* redirections to apply */ @@ -1529,6 +1543,7 @@ struct patstralloc { /* Flags used in pattern matchers (Patprog) and passed down to patcompile */ +#define PAT_HEAPDUP 0x0000 /* Dummy flag for default behavior */ #define PAT_FILE 0x0001 /* Pattern is a file name */ #define PAT_FILET 0x0002 /* Pattern is top level file, affects ~ */ #define PAT_ANY 0x0004 /* Match anything (cheap "*") */ @@ -1804,6 +1819,7 @@ struct tieddata { #define PM_READONLY (1<<10) /* readonly */ #define PM_TAGGED (1<<11) /* tagged */ #define PM_EXPORTED (1<<12) /* exported */ +#define PM_ABSPATH_USED (1<<12) /* (function): loaded using absolute path */ /* The following are the same since they * * both represent -U option to typeset */ @@ -1811,7 +1827,9 @@ struct tieddata { #define PM_UNALIASED (1<<13) /* do not expand aliases when autoloading */ #define PM_HIDE (1<<14) /* Special behaviour hidden by local */ +#define PM_CUR_FPATH (1<<14) /* (function): can use $fpath with filename */ #define PM_HIDEVAL (1<<15) /* Value not shown in `typeset' commands */ +#define PM_WARNNESTED (1<<15) /* (function): non-recursive WARNNESTEDVAR */ #define PM_TIED (1<<16) /* array tied to colon-path or v.v. */ #define PM_TAGGED_LOCAL (1<<16) /* (function): non-recursive PM_TAGGED */ @@ -1820,6 +1838,7 @@ struct tieddata { /* Remaining flags do not correspond directly to command line arguments */ #define PM_DONTIMPORT_SUID (1<<19) /* do not import if running setuid */ +#define PM_LOADDIR (1<<19) /* (function) filename gives load directory */ #define PM_SINGLE (1<<20) /* special can only have a single instance */ #define PM_LOCAL (1<<21) /* this parameter will be made local */ #define PM_SPECIAL (1<<22) /* special builtin parameter */ @@ -2012,9 +2031,15 @@ struct paramdef { * Flags for assignsparam and assignaparam. */ enum { + /* Add to rather than override value */ ASSPM_AUGMENT = 1 << 0, + /* Test for warning if creating global variable in function */ ASSPM_WARN_CREATE = 1 << 1, - ASSPM_ENV_IMPORT = 1 << 2 + /* Test for warning if using nested variable in function */ + ASSPM_WARN_NESTED = 1 << 2, + ASSPM_WARN = (ASSPM_WARN_CREATE|ASSPM_WARN_NESTED), + /* Import from environment, so exercise care evaluating value */ + ASSPM_ENV_IMPORT = 1 << 3, }; /* node for named directory hash table (nameddirtab) */ @@ -2222,6 +2247,7 @@ struct histent { enum { OPT_INVALID, ALIASESOPT, + ALIASFUNCDEF, ALLEXPORT, ALWAYSLASTPROMPT, ALWAYSTOEND, @@ -2395,6 +2421,7 @@ enum { VERBOSE, VIMODE, WARNCREATEGLOBAL, + WARNNESTEDVAR, XTRACE, USEZLE, DVORAK, @@ -2893,6 +2920,7 @@ struct hist_stack { int histdone; int stophist; int hlinesz; + zlong defev; char *hline; char *hptr; short *chwords; @@ -3133,9 +3161,7 @@ typedef wint_t convchar_t; * works on MacOS which doesn't define that. */ #ifdef ENABLE_UNICODE9 -#define WCWIDTH(wc) mk_wcwidth(wc) -#elif defined(BROKEN_WCWIDTH) && (defined(__STDC_ISO_10646__) || defined(__APPLE__)) -#define WCWIDTH(wc) mk_wcwidth(wc) +#define WCWIDTH(wc) u9_wcwidth(wc) #else #define WCWIDTH(wc) wcwidth(wc) #endif @@ -3180,15 +3206,7 @@ typedef wint_t convchar_t; * sense throughout the shell. I am not aware of a way of * detecting the Unicode trait in standard libraries. */ -#ifdef BROKEN_WCWIDTH -/* - * We can't be quite sure the wcwidth we've provided is entirely - * in agreement with the system's, so be extra safe. - */ -#define IS_COMBINING(wc) (wc != 0 && WCWIDTH(wc) == 0 && !iswcntrl(wc)) -#else #define IS_COMBINING(wc) (wc != 0 && WCWIDTH(wc) == 0) -#endif /* * Test for the base of a combining character. * diff --git a/Src/ztype.h b/Src/ztype.h index 76589b152..ae7236774 100644 --- a/Src/ztype.h +++ b/Src/ztype.h @@ -72,7 +72,11 @@ #ifdef MULTIBYTE_SUPPORT #define WC_ZISTYPE(X,Y) wcsitype((X),(Y)) -#define WC_ISPRINT(X) iswprint(X) +# ifdef ENABLE_UNICODE9 +# define WC_ISPRINT(X) u9_iswprint(X) +# else +# define WC_ISPRINT(X) iswprint(X) +# endif #else #define WC_ZISTYPE(X,Y) zistype((X),(Y)) #define WC_ISPRINT(X) isprint(X) diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst index e4b6870d7..9625a15bc 100644 --- a/Test/A01grammar.ztst +++ b/Test/A01grammar.ztst @@ -103,16 +103,39 @@ 0:`exec' with -a option, no space >/bin/SPLOOSH + ( + opts=(-a /bin/WHOOOSH) + exec $opts /bin/sh -c 'echo $0' + ) +0:`exec' with -a option from expansion +>/bin/WHOOOSH + (export FOO=bar; exec -c /bin/sh -c 'echo x${FOO}x') 0:`exec' with -c option >xx + (\exec /bin/sh -c 'echo Test one'; print Not reached) + ('exec' /bin/sh -c 'echo Test two'; print Not reached) + (\exec -c /bin/sh -c 'echo Test three'; print Not reached) +0:precommand modifiers with quotes +>Test one +>Test two +>Test three + cat() { echo Function cat executed; } command cat && unfunction cat 0:`command' precommand modifier <External command cat executed >External command cat executed + (command -p echo this is output) + (\command -p echo this is more output) + ('command' -p echo this is yet more output) +0: command -p without -v or -V +>this is output +>this is more output +>this is yet more output + command -pv cat command -pv echo command -p -V cat @@ -123,6 +146,21 @@ >cat is /*/cat >echo is a shell builtin + args=( + 'command -pv cat' + 'command -pv echo' + 'command -p -V cat' + 'command -p -V -- echo' + ) + for arg in $args; do + ${=arg} + done +0:command -p in combination, using expansion +*>*/cat +>echo +>cat is /*/cat +>echo is a shell builtin + cd() { echo Not cd at all; } builtin cd . && unfunction cd 0:`builtin' precommand modifier diff --git a/Test/A02alias.ztst b/Test/A02alias.ztst index e52578ec3..e68e93e0d 100644 --- a/Test/A02alias.ztst +++ b/Test/A02alias.ztst @@ -82,6 +82,7 @@ 0:Global aliasing quotes > a string S *>*5*echo S a string S " +# " # Note there is a trailing space on the "> a string S " line ( @@ -115,3 +116,24 @@ 1:error message has the correct sign ?(eval):alias:1: bad option: +x ?(eval):alias:1: bad option: -z + + # Usual issue that aliases aren't expanded until we + # trigger a new parse... + (alias badalias=notacommand + eval 'badalias() { print does not work; }') +1:ALIAS_FUNC_DEF off by default. +?(eval):1: defining function based on alias `badalias' +?(eval):1: parse error near `()' + + (alias goodalias=isafunc + setopt ALIAS_FUNC_DEF + eval 'goodalias() { print does now work; }' + isafunc) +0:ALIAS_FUNC_DEF causes the icky behaviour to be avaliable +>does now work + + (alias thisisokthough='thisworks() { print That worked; }' + eval thisisokthough + thisworks) +0:NO_ALIAS_FUNC_DEF works if the alias is a complete definition +>That worked diff --git a/Test/A03quoting.ztst b/Test/A03quoting.ztst index da3ce359a..be9ca66de 100644 --- a/Test/A03quoting.ztst +++ b/Test/A03quoting.ztst @@ -78,3 +78,8 @@ () { print $# } '' "" $'' 0:$'' should not be elided, in common with other empty quotes >3 + + foo=$'one\\two\n\'buckle\'\tmy\\shoe\n' + print -r ${(q+)foo} +0:Extended minimal quoting of quotes and backslashes +>$'one\\two\n\'buckle\'\tmy\\shoe\n' diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst index d7fe22fb0..cb82751ce 100644 --- a/Test/A04redirect.ztst +++ b/Test/A04redirect.ztst @@ -165,6 +165,15 @@ ?About to close a second time *?\(eval\):*: failed to close file descriptor * + eval $'fn-varid() { print {\x18}<<0 }' + { which -x2 fn-varid; fn-varid } | tr $'\x18' '?' +0:Regression test for off-by-one in varid check +>fn-varid () { +> print {?} <<0 +>0 +>} +>{?} + print foo >&- 0:'>&-' redirection @@ -475,6 +484,18 @@ >Nothing output yet >I just read any old rubbish + print you cannot be serious >input1 + () { + local var + read var + print $1 $var $2 + } <input1 Shirley >output1 dude + print Nothing output yet + cat output1 +0:anonymous function redirections mixed with argument +>Nothing output yet +>Shirley you cannot be serious dude + redirfn() { local var read var @@ -586,3 +607,18 @@ >x >bar >y + + fn-here-pipe() { + cat <<-HERE |& cat + FOO + HERE + } + fn-here-pipe + which fn-here-pipe +0:Combination of HERE-document and |& +>FOO +>fn-here-pipe () { +> cat <<HERE 2>&1 | cat +>FOO +>HERE +>} diff --git a/Test/A06assign.ztst b/Test/A06assign.ztst index bf39aee7f..fd2b4177c 100644 --- a/Test/A06assign.ztst +++ b/Test/A06assign.ztst @@ -133,6 +133,72 @@ >1 2 42 43 44 5 >1 2 42 100 99 5 +# (subsection: append to array) + + array=( ) + array[5,6]=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append to empty array by range +>1 2 3 +>'' '' '' '' 1 2 3 + + array=( a ) + array[5,6]=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append to 1-element array by range +>a 1 2 3 +>a '' '' '' 1 2 3 + + array=( a b ) + array[5,6]=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append to 2-element array by range +>a b 1 2 3 +>a b '' '' 1 2 3 + + array=( a b ) + array[5,5]=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append to 2-element array by [a,a] range +>a b 1 2 3 +>a b '' '' 1 2 3 + + array=( a b c d ) + array[5,6]=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append array by range, continuously +>a b c d 1 2 3 +>a b c d 1 2 3 + + array=( a b c d ) + array[5,5]=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append array by [a,a] range, continuously +>a b c d 1 2 3 +>a b c d 1 2 3 + + array=( ) + array+=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append empty array via += +>1 2 3 +>1 2 3 + + array=( a ) + array+=( 1 2 3 ) + print $array + print "${(q@)array}" +0:Append 1-element array via += +>a 1 2 3 +>a 1 2 3 + # tests of var+=scalar s+=foo diff --git a/Test/B01cd.ztst b/Test/B01cd.ztst index 94447e717..8d4f0955c 100644 --- a/Test/B01cd.ztst +++ b/Test/B01cd.ztst @@ -137,6 +137,10 @@ F:something is broken. But you already knew that. 0: ?(eval):cd:3: not a directory: link_to_nonexistent + (unset HOME; ARGV0=sh $ZTST_testdir/../Src/zsh -c cd) +1:Implicit cd with unset HOME. +?zsh:cd:1: HOME not set + %clean # This optional section cleans up after the test, if necessary, # e.g. killing processes etc. This is in addition to the removal of *.tmp diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 7bc0b486d..759401225 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -756,6 +756,27 @@ F:Must be tested with a top-level script rather than source or function >'' >hello + $ZTST_testdir/../Src/zsh -f =(<<<" + trap handler EXIT + handler() { + echoa + echo b + } + echoa() { + echo a + } + exit0() { + exit + } + main() { + exit0 + } + main + ") +0:No early exit from nested function in EXIT trap. +>a +>b + %clean rm -f TRAPEXIT diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst index ab7b42928..6a675e0b4 100644 --- a/Test/C04funcdef.ztst +++ b/Test/C04funcdef.ztst @@ -2,6 +2,10 @@ mkdir funcdef.tmp cd funcdef.tmp + setopt chaselinks + cd . + unsetopt chaselinks + mydir=$PWD %test @@ -98,6 +102,24 @@ >4 >5 + strmathfunc() { + if [[ $0 = stralpha ]]; then + set -- ${1//[^[:alpha:]]} + fi + (( $#1 )) + } + functions -Ms strlen 1 1 strmathfunc + functions -Ms stralpha 1 1 strmathfunc + print $(( strlen(this, is, a, raw, string) )) + print $(( strlen() )) + print $(( stralpha(this, is, a, raw, string) )) + print $(( stralpha() )) +0:User-defined math functions, string arguments +>24 +>0 +>16 +>0 + command_not_found_handler() { print "Great News! I've handled the command:" print "$1" @@ -327,8 +349,171 @@ oops whence -v oops ) -0:whence -v of zsh-style autoload ->oops is a shell function from ./oops +0q:whence -v of zsh-style autoload +>oops is a shell function from $mydir/oops + + ( + fpath=(.) + mkdir extra + print 'print "I have been loaded by explicit path."' >extra/spec + autoload -Uz $PWD/extra/spec + spec + ) +0:autoload with explicit path +>I have been loaded by explicit path. + + ( + fpath=(.) + print 'print "I have been loaded by default path."' >def + autoload -Uz $PWD/extra/def + def + ) +1:autoload with explicit path with function in normal path, no -d +?(eval):5: def: function definition file not found + + ( + fpath=(.) + autoload -dUz $PWD/extra/def + def + ) +0:autoload with explicit path with function in normal path, with -d +>I have been loaded by default path. + + ( + cd extra + fpath=(.) + autoload -r spec + cd .. + spec + ) +0:autoload -r +>I have been loaded by explicit path. + + ( + cd extra + fpath=(.) + autoload -r def + cd .. + def + ) +0:autoload -r is permissive +>I have been loaded by default path. + + ( + cd extra + fpath=(.) + autoload -R def + ) +1:autoload -R is not permissive +?(eval):4: def: function definition file not found + + ( + spec() { autoload -XUz $PWD/extra; } + spec + ) +0:autoload -X with path +>I have been loaded by explicit path. + +# The line number 1 here and in the next test seems suspect, +# but this example proves it's not down to the new features +# being tested here. + ( + fpath=(.) + cod() { autoload -XUz; } + cod + ) +1:autoload -X with no path, failure +?(eval):1: cod: function definition file not found + + ( + fpath=(.) + def() { autoload -XUz $PWD/extra; } + def + ) +1:autoload -X with wrong path and no -d +?(eval):1: def: function definition file not found + + ( + fpath=(.) + def() { autoload -dXUz $PWD/extra; } + def + ) +0:autoload -dX with path +>I have been loaded by default path. + + ( + fpath=(.) + print 'loadthisfunc() { autoload -X }' >loadthisfunc_sourceme + print 'print Function was loaded correctly.' >loadthisfunc + source $PWD/loadthisfunc_sourceme + loadthisfunc + ) +0: autoload -X interaction with absolute filename used for source location +>Function was loaded correctly. + + ( + fpath=() + mkdir extra2 + for f in fun2a fun2b; do + print "print $f" >extra2/$f + done + repeat 3; do + autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec + fun2a + fun2b + spec + unfunction fun2a fun2b spec + autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec + spec + fun2b + fun2a + unfunction fun2a fun2b spec + done + ) +0: Exercise the directory name cache for autoloads +>fun2a +>fun2b +>I have been loaded by explicit path. +>I have been loaded by explicit path. +>fun2b +>fun2a +>fun2a +>fun2b +>I have been loaded by explicit path. +>I have been loaded by explicit path. +>fun2b +>fun2a +>fun2a +>fun2b +>I have been loaded by explicit path. +>I have been loaded by explicit path. +>fun2b +>fun2a + + not_trashed() { print This function was not trashed; } + autoload -Uz /foo/bar/not_trashed + not_trashed +0:autoload with absolute path doesn't trash loaded function +>This function was not trashed + + # keep spec from getting loaded in parent shell for simplicity + ( + if whence spec; then print spec already loaded >&2; exit 1; fi + autoload -Uz $PWD/spec + autoload -Uz $PWD/extra/spec + spec + ) +0:autoload with absolute path can be overridden if not yet loaded +>I have been loaded by explicit path. + + ( + if whence spec; then print spec already loaded >&2; exit 1; fi + autoload -Uz $PWD/extra/spec + autoload spec + spec + ) +0:autoload with absolute path not cancelled by bare autoload +>I have been loaded by explicit path. %clean diff --git a/Test/D01prompt.ztst b/Test/D01prompt.ztst index 607ffb698..11f18dc71 100644 --- a/Test/D01prompt.ztst +++ b/Test/D01prompt.ztst @@ -82,9 +82,12 @@ # We could test for that, but we can't be bothered. # I hope LC_ALL is enough to make the format what's expected. +# The $date2 assignment tests that %s is interpreted as a printf format +# string, rather than as a prompt escape (end standout). + LC_ALL=C date1=$(print -P %w) - date2=$(print -P %W) + date2=$(print -P -f %s %W) date3=$(print -P %D) if [[ $date1 != [A-Z][a-z][a-z][[:blank:]]##[0-9]## ]]; then print "Date \`$date1' is not in the form \`Day DD' (e.g. \`Mon 1'" @@ -201,3 +204,12 @@ ?+zsh_directory_name:14> return 0 ?+fn:7> local d='~[<parent>:l]' ?+fn:8> print '~[<parent>:l]' + +# Test that format strings are not subject to prompt expansion + print -P -f '%%Sfoo%%s\n' bar +0:print -P -f +>%Sfoo%s + + print ${(%U)Y-%(v} +0:Regression test for test on empty psvar +> diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst index 1385d57d9..08b71dc8e 100644 --- a/Test/D02glob.ztst +++ b/Test/D02glob.ztst @@ -686,3 +686,17 @@ rm glob.tmp/link 0:modifier ':P' resolves symlinks before '..' components *>*glob.tmp/hello/world + + # This is a bit brittle as it depends on PATH_MAX. + # We could use sysconf.. + bad_pwd="/${(l:16000:: :):-}" + print ${bad_pwd:P} +0:modifier ':P' with path too long +?(eval):4: path expansion failed, using root directory +>/ + + foo=a + value="ac" + print ${value//[${foo}b-z]/x} +0:handling of - range in complicated pattern context +>xx diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 9128c3c38..3c93990f1 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -640,6 +640,11 @@ >echo >$(|||) bar + foo=$'\x06ZUI\x1f text-field example: \x1azuitfieldtfield1_1\x1a\'\'\x1a\'\'\x1a1\x1aZUI\\[my_tfield1_width\\]\x1aZUI\\[my_tfield1_start\\]\x1aZUI\\[my_tfield1_data\\]\x1c' + print "${#${(z@)foo}}" +0:Test real-world data that once seemed to fail +>4 + psvar=(dog) setopt promptsubst foo='It shouldn'\''t $(happen) to a %1v.' @@ -778,16 +783,36 @@ 0:${(R)...} >is the , + # Although there's no reliance on multibyte here, the + # code exercised is different, so test both paths in the following group. + # If the shell isn't multibyte capable the tests are the same; + # that's not a problem. # This (1) doesn't work with // or / # (2) perhaps ought to be 18, to be consistent with normal zsh # substring indexing and with backreferences. print ${(BES)string##white} + (unsetopt multibyte; print ${(BES)string##white}) 0:${(BE...)...} >14 19 +>14 19 print ${(NS)string##white} + (unsetopt multibyte; print ${(NS)string##white}) 0:${(N)...} >5 +>5 + + fn() { + emulate -L zsh + local a=abcdef + print ${(SNBE)a#abcd} + unsetopt multibyte + print ${(SNBE)a#abcd} + } + fn +0:${(BEN)...} again, with match +>1 5 4 +>1 5 4 string='abcdefghijklmnopqrstuvwxyz' print ${${string%[aeiou]*}/(#m)?(#e)/${(U)MATCH}} @@ -2055,4 +2080,123 @@ a='~-/'; echo $~a 0:Regression: "-" became Dash in workers/37689, breaking ~- expansion *>* -F:We do not care what $OLDPWD is, as long as it doesn't cause an error +F:We do not care what $OLDPWD is, as long as it does not cause an error + + ( + set -- one 'two three' four + for ifs in default null unset; do + for wordsplit in native sh; do + print -r -- "--- $ifs IFS, $wordsplit splitting ---" + case $ifs in + default) IFS=$' \t\n\00' ;; + null) IFS= ;; + unset) unset -v IFS ;; + esac + case $wordsplit in + native) unsetopt shwordsplit ;; + sh) setopt shwordsplit ;; + esac + for testcmd in 'var=$@' 'var=$*' 'var="$@"' 'var="$*"'; do + print -r -- "> $testcmd" + eval "$testcmd" + printf '[%s]\n' "${var[@]}" + done + done + done + ) +0:Assigning $@, $*, "$@", "$*" to var with various shwordsplit/IFS settings +>--- default IFS, native splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] +>--- default IFS, sh splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] +>--- null IFS, native splitting --- +>> var=$@ +>[onetwo threefour] +>> var=$* +>[onetwo threefour] +>> var="$@" +>[onetwo threefour] +>> var="$*" +>[onetwo threefour] +>--- null IFS, sh splitting --- +>> var=$@ +>[onetwo threefour] +>> var=$* +>[onetwo threefour] +>> var="$@" +>[onetwo threefour] +>> var="$*" +>[onetwo threefour] +>--- unset IFS, native splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] +>--- unset IFS, sh splitting --- +>> var=$@ +>[one two three four] +>> var=$* +>[one two three four] +>> var="$@" +>[one two three four] +>> var="$*" +>[one two three four] +F:As of this writing, var=$@ and var="$@" with null IFS have unspecified +F:behavior, see http://austingroupbugs.net/view.php?id=888 + + () { + setopt localoptions extendedglob + [[ $- = [[:alnum:]]## ]] || print Failed 1 + [[ ${-} = [[:alnum:]]## ]] || print Failed 2 + } +0:$- expansion correctly handles Dash token + + a=(1 "" 3) + print -rl -- "${(@)a//*/x}" + a="" + print -rl -- "${(@)a//*/y}" +0:Zero-length string match in parameter substitution +>x +>x +>x +>y + + a=(1 "" 3) + print -rl -- "${(@)a//#%*/x}" + a="" + print -rl -- "${(@)a//#%*/y}" +0:Zero-length string match at end +>x +>x +>x +>y + + my_width=6 + my_index=1 + my_options=Option1 + hyperlink=$'\034'"MYID"$'\034'"DATA1"$'\034'"DATA2"$'\034'"DATA3"$'\034'"my_width"$'\034'"my_index"$'\034'"my_options"$'\02' + array=( $hyperlink "Regular text" $hyperlink ) + array=( "${array[@]//(#b)$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'([^$'\034']#)$'\034'([^$'\034']#)$'\034'([^$'\02']#)$'\02'/${(mr:${(P)${(Q)match[1]}}:: :)${(As:;:)${(P)${(Q)match[3]}}}[${(P)${(Q)match[2]}}]}}" ) + print -rl -- "${array[@]}" +0:Test substitution that uses P,Q,A,s,r,m flags +>Option +>Regular text +>Option diff --git a/Test/D06subscript.ztst b/Test/D06subscript.ztst index 144923667..f0a858b1c 100644 --- a/Test/D06subscript.ztst +++ b/Test/D06subscript.ztst @@ -266,3 +266,10 @@ >of the gang >of the gang >of the gang + + string='abcde' + twoarg() { return $(( $2 - $1 )) } + functions -M twoarg + print ${string[1,twoarg(1,4)]} +0:Commas inside parentheses do not confuse subscripts +>abc diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst index d5a15ef04..e20315340 100644 --- a/Test/D07multibyte.ztst +++ b/Test/D07multibyte.ztst @@ -549,24 +549,22 @@ "↓" } : $functions) -0:Multibtye handling of functions parameter - - if [[ -n ${$(locale -a 2>/dev/null)[(R)pl_PL.utf8]} ]]; then - ( - export LC_ALL=pl_PL.UTF-8 - local -a names=(a b c d e f $'\u0105' $'\u0107' $'\u0119') - print -o $names - mkdir -p plchars - cd plchars - touch $names - print ? - ) - else - ZTST_skip="No Polish UTF-8 locale found, skipping sort test" - fi -0:Sorting of metafied Polish characters ->a ą b c ć d e ę f ->a ą b c ć d e ę f +0:Multibyte handling of functions parameter + +# c1=U+0104 (Ą) and c2=U+0120 (Ġ) are chosen so that +# u1 = utf8(c1) = c4 84 < u2 = utf8(c2) = c4 a0 +# metafy(u1) = c4 83 a4 > metafy(u2) = c4 83 80 +# in both UTF-8 and ASCII collations (the latter is used in macOS +# and some versions of BSDs). + local -a names=( $'\u0104' $'\u0120' ) + print -o $names + mkdir -p colltest + cd colltest + touch $names + print ? +0:Sorting of metafied characters +>Ą Ġ +>Ą Ġ printf '%q%q\n' 你你 0:printf %q and quotestring and general metafy / token madness diff --git a/Test/D08cmdsubst.ztst b/Test/D08cmdsubst.ztst index 362537349..4e0759e35 100644 --- a/Test/D08cmdsubst.ztst +++ b/Test/D08cmdsubst.ztst @@ -167,3 +167,13 @@ empty=$() && print "'$empty'" 0:Empty $() is a valid assignment >'' + + ( + setopt ignoreclosebraces + alias OPEN='{' CLOSE='};' + eval '{ OPEN print hi; CLOSE } + var=$({ OPEN print bye; CLOSE}) && print $var' + ) +0:Alias expansion needed in parsing substituions +>hi +>bye diff --git a/Test/D09brace.ztst b/Test/D09brace.ztst index 3e667a8d1..580ed430f 100644 --- a/Test/D09brace.ztst +++ b/Test/D09brace.ztst @@ -112,3 +112,7 @@ print -r left{[..]}right 0:{char..char} ranges with tokenized characters >left[right left\right left]right + + print -r {1..10}{.. +0:Unmatched braces after matched braces are left alone. +>1{.. 2{.. 3{.. 4{.. 5{.. 6{.. 7{.. 8{.. 9{.. 10{.. diff --git a/Test/E01options.ztst b/Test/E01options.ztst index 45df9f572..f01d83567 100644 --- a/Test/E01options.ztst +++ b/Test/E01options.ztst @@ -804,6 +804,20 @@ >print is a shell builtin ?(eval):8: command not found: print + ( + setopt posixbuiltins + opts=() + command $opts print foo + opts=(-v) + command $opts print + opts=(-V) + command $opts print + ) +0:command with options from expansion +>foo +>print +>print is a shell builtin + # With non-special command: original value restored # With special builtin: new value kept # With special builtin preceeded by "command": original value restored. @@ -817,6 +831,20 @@ >val2 >val2 + print "Contents of file" >cat_arg + ( + cat() { print Function with argument $1 } + print Without + (exec cat cat_arg; print Not reached) + print With + (setopt posixbuiltins; exec cat cat_arg; print Not reached) + ) +0:POSIX_BUILTINS and exec +>Without +>Function with argument cat_arg +>With +>Contents of file + # PRINTEXITVALUE only works if shell input is coming from standard input. # Goodness only knows why. $ZTST_testdir/../Src/zsh -f <<<' @@ -1118,7 +1146,8 @@ integer foo6=9 (( foo6=10 )) } - fn + # don't pollute the test environment with the variables... + (fn) 0:WARN_CREATE_GLOBAL option ?fn:3: scalar parameter foo1 created globally in function fn ?fn:5: scalar parameter foo1 created globally in function fn @@ -1133,6 +1162,103 @@ fn 0:WARN_CREATE_GLOBAL negative cases + ( + foo1=global1 foo2=global2 foo3=global3 foo4=global4 + integer foo5=5 + # skip foo6, defined in fn_wnv + foo7=(one two) + fn_wnv() { + # warns + foo1=bar1 + # doesn't warn + local foo2=bar3 + unset foo2 + # still doesn't warn + foo2=bar4 + # doesn't warn + typeset -g foo3=bar5 + # warns + foo3=bar6 + fn2() { + # warns if global option, not attribute + foo3=bar6 + } + fn2 + # doesn't warn + foo4=bar7 =true + # warns + (( foo5=8 )) + integer foo6=9 + # doesn't warn + (( foo6=10 )) + foo7[3]=three + foo7[4]=(four) + } + print option off >&2 + fn_wnv + print option on >&2 + setopt warnnestedvar + fn_wnv + unsetopt warnnestedvar + print function attribute on >&2 + functions -W fn_wnv + fn_wnv + print all off again >&2 + functions +W fn_wnv + fn_wnv + ) +0:WARN_NESTED_VAR option +?option off +?option on +?fn_wnv:2: scalar parameter foo1 set in enclosing scope in function fn_wnv +?fn_wnv:11: scalar parameter foo3 set in enclosing scope in function fn_wnv +?fn2:2: scalar parameter foo3 set in enclosing scope in function fn2 +?fn_wnv:20: numeric parameter foo5 set in enclosing scope in function fn_wnv +?function attribute on +?fn_wnv:2: scalar parameter foo1 set in enclosing scope in function fn_wnv +?fn_wnv:11: scalar parameter foo3 set in enclosing scope in function fn_wnv +?fn_wnv:20: numeric parameter foo5 set in enclosing scope in function fn_wnv +?all off again + + + ( + setopt warnnestedvar + () { + typeset -A a + : ${a[hello world]::=foo} + print ${(t)a} + key="hello world" + print $a[$key] + } + ) +0:No false positive on parameter used with subscripted assignment +>association-local +>foo + + ( + setopt warnnestedvar + () { + local var=(one two) + () { var=three; } + print $var + } + ) +0:Warn when changing type of nested variable: array to scalar. +?(anon): scalar parameter var set in enclosing scope in function (anon) +>three + + ( + setopt warnnestedvar + () { + local var=three + () { var=(one two); } + print $var + } + ) +0:Warn when changing type of nested variable: scalar to array. +?(anon): array parameter var set in enclosing scope in function (anon) +>one two + # This really just tests if XTRACE is egregiously broken. # To test it properly would need a full set of its own. fn() { print message; } diff --git a/Test/V06parameter.ztst b/Test/V06parameter.ztst index c7df35dce..27d587852 100644 --- a/Test/V06parameter.ztst +++ b/Test/V06parameter.ztst @@ -1,15 +1,22 @@ +%prep + + setopt chaselinks + cd . + unsetopt chaselinks + mydir=$PWD + %test print 'print In sourced file - print $LINENO + $functrace + $funcsourcetrace + print $LINENO + $functrace + ${funcsourcetrace} ' >sourcedfile print -r -- 'print Started functrace.zsh module_path=(./Modules) - print $LINENO + $functrace + $funcsourcetrace + print $LINENO + $functrace + ${funcsourcetrace} : fn() { print Inside function $0 - print $LINENO + $functrace + $funcsourcetrace + print $LINENO + $functrace + ${funcsourcetrace} } : fn @@ -17,7 +24,7 @@ fpath=(. $fpath) : echo '\''print Inside $0 - print $LINENO + $functrace + $funcsourcetrace + print $LINENO + $functrace + ${funcsourcetrace} '\'' >autofn : autoload autofn @@ -26,15 +33,15 @@ autofn . ./sourcedfile' >functrace.zsh $ZTST_testdir/../Src/zsh +Z -f ./functrace.zsh -0:Function tracing +0q:Function tracing >Started functrace.zsh >3 + + >Inside function fn >2 + ./functrace.zsh:10 + ./functrace.zsh:5 >Inside autofn ->2 + ./functrace.zsh:20 + ./autofn:0 +>2 + ./functrace.zsh:20 + $mydir/autofn:0 >Inside autofn ->2 + ./functrace.zsh:21 + ./autofn:0 +>2 + ./functrace.zsh:21 + $mydir/autofn:0 >In sourced file >2 + ./functrace.zsh:22 + ./sourcedfile:0 @@ -66,6 +73,25 @@ >./rocky3.zsh:13 (eval):2 >./rocky3.zsh:14 ./rocky3.zsh:14 + ( + fpath=($PWD) + print "print I have been autoloaded" >myfunc + autoload $PWD/myfunc + print ${functions_source[myfunc]} + myfunc + print ${functions_source[myfunc]} + ) +0q: $functions_source +>$mydir/myfunc +>I have been autoloaded +>$mydir/myfunc + + functions+=(a 'echo foo'); a + functions+=(a 'echo bar'); a +0:$functions can be appended to twice +>foo +>bar + %clean - rm -f autofn functrace.zsh rocky3.zsh sourcedfile + rm -f autofn functrace.zsh rocky3.zsh sourcedfile myfunc diff --git a/Test/V07pcre.ztst b/Test/V07pcre.ztst index ad1770712..7426e7bf8 100644 --- a/Test/V07pcre.ztst +++ b/Test/V07pcre.ztst @@ -131,6 +131,12 @@ >78884; ZPCRE_OP: 25 30 >90210; ZPCRE_OP: 31 36 +# Embedded NULs allowed in plaintext, but not in RE (although \0 as two-chars allowed) + [[ $'a\0bc\0d' =~ '^(a\0.)(.+)$' ]] + print "${#MATCH}; ${#match[1]}; ${#match[2]}" +0:ensure ASCII NUL passes in and out of matched plaintext +>6; 3; 3 + # Subshell because crash on failure ( setopt re_match_pcre [[ test.txt =~ '^(.*_)?(test)' ]] diff --git a/Test/V09datetime.ztst b/Test/V09datetime.ztst index 7905155d8..ffad96c04 100644 --- a/Test/V09datetime.ztst +++ b/Test/V09datetime.ztst @@ -8,19 +8,21 @@ # It's not clear this skip_extensions is correct, but the # format in question is causing problems on Solaris. # We'll revist this after the release. - [[ "$(strftime %^_10B 0)" = " JANUARY" ]] || skip_extensions=1 - [[ "$(LC_TIME=ja_JP.UTF-8 strftime %OS 1)" = 一 ]] || skip_japanese=1 + [[ "$(strftime %^_10B 0 2>/dev/null)" = " JANUARY" ]] || skip_extensions=1 + [[ "$(LC_TIME=ja_JP.UTF-8 strftime %OS 1 2>/dev/null)" = 一 ]] || skip_japanese=1 else ZTST_unimplemented="can't load the zsh/datetime module for testing" fi %test + strftime '' 0 strftime %y 0 strftime %Y 1000000000 strftime %x 1200000000 strftime %X 1200000001 0:basic format specifiers +> >70 >2001 >01/10/08 @@ -61,6 +63,8 @@ strftime '%^_10B' 0 strftime %03Ey 650000000 strftime %-Oe 0 + # width=400 is too wide and should cause an error + strftime %400d 0 2> /dev/null || echo OK ) fi 0:various extensions @@ -68,7 +72,13 @@ > JANUARY >090 >1 +>OK print -r -- ${(V)"$(strftime $'%Y\0%m\0%d' 100000000)"} 0:Embedded nulls >1973^@03^@03 + +# We assume '%@' is not a valid format on any OSs. +# The result can be '%@' (Linux), '@' (BSDs) or an error (Cygwin). + [[ $(strftime '%@' 0 2> /dev/null) == (%|)@ || $? != 0 ]] +0:bad format specifier diff --git a/Test/V11db_gdbm.ztst b/Test/V11db_gdbm.ztst new file mode 100644 index 000000000..6d74cef2c --- /dev/null +++ b/Test/V11db_gdbm.ztst @@ -0,0 +1,327 @@ +# Tests for the zsh/db/gdbm module. +# This contains literal UTF-8 characters; if editing, use +# UTF-8 mode. + +%prep + + modname="zsh/db/gdbm" + dbfile=db.gdbm + if ! zmodload $modname 2>/dev/null; then + ZTST_unimplemented="can't load $modname module for testing" + fi + rm -f db.gdbm + +%test + + (zmodload -u $modname && zmodload $modname) +0:unload and reload the module without crashing + + ztie -d db/gdbm -f $dbfile dbase + zuntie dbase +0:create the database + + ztie -r -d db/gdbm -f $dbfile dbase + zuntie -u dbase +0:open the database read-only + + ztie -d db/gdbm -f $dbfile dbase + dbase[testkey]=testdata + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + echo $dbase[testkey] + zuntie -u dbase +0:store key in database +>testdata + + ztie -d db/gdbm -f $dbfile dbase2 + unset 'dbase2[testkey]' + zuntie dbase2 + ztie -d db/gdbm -f $dbfile dbase + echo $dbase[testkey] + zuntie dbase +0:remove key from database (different variables) +> + + ztie -d db/gdbm -f $dbfile dbase + dbase[testkey]=testdata + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + echo $dbase[testkey] + zuntie -u dbase + ztie -d db/gdbm -f $dbfile dbase + unset 'dbase[testkey]' + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + echo $dbase[testkey] + zuntie -u dbase +0:store & remove key from database (the same variables) +>testdata +> + + ztie -d db/gdbm -f $dbfile dbase + dbase[testkey]=testdata + dbase[testkey2]=$dbase[testkey] + dbase[testkey3]=$dbase[testkey]x$dbase[testkey2] + zuntie dbase + ztie -d db/gdbm -f $dbfile dbase + echo $dbase[testkey] + echo $dbase[testkey2] + echo $dbase[testkey3] + zuntie dbase +0:store 2 keys fetching 1st +>testdata +>testdata +>testdataxtestdata + + ztie -d db/gdbm -f $dbfile dbase + val=$dbase[testkey2] + unset 'dbase[testkey2]' + echo $val + zuntie dbase +0:unset key that was fetched +>testdata + + ztie -r -d db/gdbm -f $dbfile dbase + local -a result=( "${(kv)dbase[@]}" ) + print -rl -- "${(o)result[@]}" + zuntie -u dbase +0:scan read-only tied hash, directly assign local -a +>testdata +>testdataxtestdata +>testkey +>testkey3 + + ztie -d db/gdbm -f $dbfile dbase + dbase=( a a ) + print -rl -- "${(kv)dbase[@]}" + zuntie dbase +0:Use scan directly, read-write mode +>a +>a + + ztie -d db/gdbm -f $dbfile dbase + dbase=( a b c d ) + zuntie dbase + ztie -d db/gdbm -f $dbfile dbase + result=( "${(kv)dbase[@]}" ) + print -rl -- "${(o)result[@]}" + zuntie dbase +0:replace hash / database, scan +>a +>b +>c +>d + + ztie -d db/gdbm -f $dbfile dbase + local -a arr + arr=( "${dbase[@]}" ) + print -rl -- "${(o)arr[@]}" + zuntie dbase +0:scan with no (kv) +>b +>d + + ztie -d db/gdbm -f $dbfile dbase + result=( "${(k)dbase[@]}" ) + print -rl -- "${(o)result[@]}" + zuntie dbase +0:scan with keys only (k) +>a +>c + + ztie -d db/gdbm -f $dbfile dbase + result=( "${(v)dbase[@]}" ) + print -rl -- "${(o)result[@]}" + zuntie dbase +0:scan with keys only explicit (v) +>b +>d + + rm -f $dbfile + ztie -r -d db/gdbm -f $dbfile dbase 2>/dev/null +1:read-only open non-existent database + + ztie -d db/gdbm -f $dbfile dbase + dbase+=( a b ) + echo $dbase[a] + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + echo $dbase[a] + result=( "${(kv)dbase[@]}" ) + print -rl -- "${(o)result[@]}" + zuntie -u dbase + ztie -d db/gdbm -f $dbfile dbase + dbase+=( c d ) + echo $dbase[a] + echo $dbase[c] + result=( "${(kv)dbase[@]}" ) + print -rl -- "${(o)result[@]}" + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + echo $dbase[a] + echo $dbase[c] + result=( "${(kv)dbase[@]}" ) + print -rl -- "${(o)result[@]}" + zuntie -u dbase +0:Append with +=( ), also with existing data, also (kv) scan +>b +>b +>a +>b +>b +>d +>a +>b +>c +>d +>b +>d +>a +>b +>c +>d + + ztie -d db/gdbm -f $dbfile dbase + echo ${(t)dbase} + zuntie dbase +0:Type of tied parameter +>association-special + + typeset -ga dbase + ztie -d db/gdbm -f $dbfile dbase + echo ${(t)dbase} + zuntie dbase +0:Type of tied parameter, with preceding unset +>association-special + + local -a dbase + ztie -d db/gdbm -f $dbfile dbase + echo ${(t)dbase} + zuntie dbase +0:Type of tied parameter, with local parameter already existing +>association-local-special + + local -a dbase + dbase=( fromarray ) + () { + local -a dbase + ztie -d db/gdbm -f $dbfile dbase + echo ${(t)dbase} + zuntie dbase + } + echo $dbase[1] + ztie -d db/gdbm -f $dbfile dbase2 + echo "Can connect, so untie happened:" $dbase2[a] + zuntie dbase2 +0:Test of automatic untie (use of local scope) and of scoping +>association-local-special +>fromarray +>Can connect, so untie happened: b + + echo $zgdbm_tied ${#zgdbm_tied} + ztie -r -d db/gdbm -f $dbfile dbase + echo $zgdbm_tied ${#zgdbm_tied} + ztie -d db/gdbm -f ${dbfile}2 dbase2 + echo $zgdbm_tied ${#zgdbm_tied} + zuntie -u dbase + echo $zgdbm_tied ${#zgdbm_tied} + zuntie dbase2 + echo $zgdbm_tied ${#zgdbm_tied} +0:zgdbm_tied parameter +>0 +>dbase 1 +>dbase dbase2 2 +>dbase2 1 +>0 + + unset zgdbm_tied 2>/dev/null +1:unset of read-only zgdbm_tied parameter + + ztie -d db/gdbm -f $dbfile dbase + dbase[漢字]=漢字 + echo $dbase[漢字] + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + echo $dbase[漢字] + zuntie -u dbase +0:Unicode test +>漢字 +>漢字 + + key="ab"$'\0'"ef" + ztie -d db/gdbm -f $dbfile dbase + dbase[$key]=value + echo $dbase[$key] + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + echo $dbase[$key] + zuntie -u dbase + ztie -d db/gdbm -f $dbfile dbase + dbase[$key]=$key + zuntie dbase + ztie -d db/gdbm -f $dbfile dbase + [[ "$dbase[$key]" = "$key" ]] && echo correct + zuntie dbase +0:Metafication of $'\0' +>value +>value +>correct + + ztie -d db/gdbm -f $dbfile dbase + dbase=( 漢字 漢字 ) + echo $dbase[漢字] + zuntie dbase + ztie -d db/gdbm -f $dbfile dbase + echo $dbase[漢字] + zuntie dbase + key="ab"$'\0'"ef" + ztie -d db/gdbm -f $dbfile dbase + dbase+=( $key $key ) + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + [[ "$dbase[$key]" = "$key" ]] && echo correct + zuntie -u dbase +0:Unicode & metafication test, different hash access +>漢字 +>漢字 +>correct + + ztie -d db/gdbm -f $dbfile dbase + dbase=( 漢字 漢字 ) + zuntie dbase + ztie -d db/gdbm -f $dbfile dbase + noglob print -rl ${(kv)dbase[@]} + zuntie dbase +0:Hash scanning and metafication +>漢字 +>漢字 + + ztie -d db/gdbm -f $dbfile dbase + noglob print -rl ${(okv)dbase[@]} + zuntie dbase +0:Sorted hash scanning and metafication +>漢字 +>漢字 + + ztie -d db/gdbm -f $dbfile dbase + zgdbmpath dbase + [[ $REPLY = */Test/db.gdbm ]] && echo correct + zuntie dbase + ztie -r -d db/gdbm -f $dbfile dbase + zgdbmpath dbase + [[ $REPLY = */Test/db.gdbm ]] && echo correct + zuntie -u dbase +0:zgdbmpath builtin +>correct +>correct + + ztie -d db/gdbm -f $dbfile dbase + fun() { while read line; do echo $line; done } + eval "dbase[testkey]=value1" | fun + echo $dbase[testkey] +0:Test store in forked Zsh +>value1 + +%clean + + rm -f ${dbfile}* diff --git a/Test/Y03arguments.ztst b/Test/Y03arguments.ztst index 6f0cac034..25bb96b84 100644 --- a/Test/Y03arguments.ztst +++ b/Test/Y03arguments.ztst @@ -64,6 +64,20 @@ >line: {tst arg1 }{} >MESSAGE:{no more arguments} + tst_arguments -a '2:desc2:(arg2)' + comptest $'tst a1\t \t' +0:second argument but no first argument +>line: {tst a1}{} +>MESSAGE:{no more arguments} +>line: {tst a1 arg2 }{} + + tst_arguments '2:desc2:(arg2)' '*:rest:(rest)' + comptest $'tst \t\t\t' +0:second and rest arguments but no first argument +>line: {tst rest }{} +>line: {tst rest arg2 }{} +>line: {tst rest arg2 rest }{} + tst_arguments '-\+[opt]' comptest $'tst -\C-d' 0:-+ @@ -82,6 +96,14 @@ >line: {tst +o -o }{} >MESSAGE:{no arguments} + tst_arguments +-o + comptest $'tst \t' +0:option beginning with + and -, specified the other way around +>line: {tst }{} +>DESCRIPTION:{option} +>NO:{+o} +>NO:{-o} + tst_arguments '-o:1:(a):2:(b)' comptest $'tst \t\t\t' 0:two option arguments @@ -206,6 +228,15 @@ 0:opt_args with multiple arguments and quoting of colons and backslashes >line: {tst -a 1:x \2 1\:x:\\2 }{} + tst_arguments -a -b + comptest $'tst rest -\t\C-w\eb\C-b-\t' +0:option completion with rest arguments on the line but not in the specs +>line: {tst rest -}{} +>line: {tst -}{ rest } +>DESCRIPTION:{option} +>NO:{-a} +>NO:{-b} + tst_arguments '-a' '*::rest:{compadd - -b}' comptest $'tst arg -\t' 0:rest arguments @@ -277,6 +308,11 @@ >line: {tst j}{} >line: {tst -y }{} + tst_arguments -M 'm:{j}={y}' -y -n - set1 -i - set2 -k + comptest $'tst -k -j\t' +0:matcher in combination with sets (implies separate cadef structure) +>line: {tst -k -y }{} + tst_arguments -x :word comptest $'tst -- -\t' 0:option after -- @@ -322,26 +358,24 @@ 0:repeatable options >line: {tst -v -v }{} -# necessary to exclude the rest arguments for the other set because -# it is currently any unknown option rather than options from another -# set that causes a set to be excluded tst_arguments -A '-*' - help -h -V - other -a '*: :(-x more)' comptest $'tst -a -x m\t' 0:continue completion after rest argument that looks like an option (with sets) ->line: {tst -a -x m}{} -#>line: {tst -a -x more }{} +>line: {tst -a -x more }{} tst_arguments - '(help)' -h -V - other -a '*:rest:(1 2 3)' - comptest $'tst -h \t' -0:unknown option disables whole set (without -A) + comptest $'tst -h \t-a \t' +0:foreign option disables whole set (without -A) >line: {tst -h }{} >MESSAGE:{no arguments} +>line: {tst -h -a }{} tst_arguments -A "-*" - '(help)' -h -V - other -a '*:rest:(1 2 3)' - comptest $'tst -h \t' -0:unknown option disables whole set (with -A) + comptest $'tst -h \t-a \t' +0:foreign option disables whole set (with -A) >line: {tst -h }{} >MESSAGE:{no arguments} +>line: {tst -h -a }{} tst_arguments '(-C)-a' - set1 -C -v - set2 '(-a)-C' -w comptest $'tst -a -\t' $'\C-w\C-w-C -\t' @@ -404,7 +438,6 @@ 0:exclude own set from an option >line: {tst -m -a }{} -# the following two tests only verify the current questionable behaviour tst_arguments - set1 '(set2)-a' -m -n - set2 -a -t -u comptest $'tst -a -\t' 0:exclude later set from an option common to both @@ -412,10 +445,12 @@ >DESCRIPTION:{option} >NO:{-m} >NO:{-n} +>NO:{-t} +>NO:{-u} tst_arguments - set2 -a -t -u - set1 '(set2)-a' -m -n comptest $'tst -a -\t' -0:exclude later set from an option common to both +0:exclude earlier set from an option common to both >line: {tst -a -}{} >DESCRIPTION:{option} >NO:{-m} @@ -423,6 +458,19 @@ >NO:{-t} >NO:{-u} + tst_arguments -x - '(set1)' -a -b - '(set2)' -m -n + comptest $'tst -m -\t' +0:single option sets are still mutually exclusive +>line: {tst -m -x }{} + + tst_arguments '(set-c set-g)-a' '(set)-b' -c + grp -g - set -s + comptest $'tst -a -b -\t' +0:excluding a set doesn't exclude common options as part of the set +>line: {tst -a -b -}{} +>DESCRIPTION:{option} +>NO:{-c} +>NO:{-g} + tst_arguments '(-)-h' -a -b -c comptest $'tst -h -\t' 0:exclude all other options @@ -439,12 +487,9 @@ F:shouldn't offer -b as it is already on the command-line tst_arguments -s : '(-d)-a' -b -c -d - comptest $'tst -ab\t -\t\eb\eb \C-b-\t' + comptest $'tst -ab\t\C-h -\t\eb\eb \C-b-\t' 0:exclusion with clumped options, in, after and before ->line: {tst -ab}{} ->DESCRIPTION:{option} ->NO:{-c} ->NO:{-d} +>line: {tst -abc}{} >line: {tst -ab -c }{} >line: {tst -}{ -ab -c} >DESCRIPTION:{option} @@ -452,7 +497,41 @@ F:shouldn't offer -b as it is already on the command-line >NO:{-b} >NO:{-c} >NO:{-d} -F:the first tab press shouldn't offer -d since -a is on the command line + + tst_arguments -s '(-conf)-c' '-conf' '-f' '(-)--long' --longer + comptest $'tst -c\t\C-h-long\t' +0:don't prematurely exclude option that current word is a prefix of +>line: {tst -c}{} +>DESCRIPTION:{option} +>NO:{-conf} +>NO:{-f} +>line: {tst --long}{} +>DESCRIPTION:{option} +>NO:{--long} +>NO:{--longer} + + tst_arguments -s '(set)-c' - set '-conf' '-f' + comptest $'tst -c\t' +0:don't prematurely exclude option that current word is a prefix of (with sets) +>line: {tst -conf }{} + + tst_arguments -s : -ad '(-d)-a' -b -ca -d + comptest $'tst -ad\t-b\t' +0:option clumping mixed with real option that looks like clump +>line: {tst -ad }{} +>line: {tst -ad -b}{} +>DESCRIPTION:{option} +>NO:{-a} +>NO:{-d} + + tst_arguments -s : '(-d)-a+:arg:(b)' '(-c)-b' -c -d + comptest $'tst -ab\t-\t' +0:option clumping mixed with direct argument +>line: {tst -ab }{} +>line: {tst -ab -}{} +>DESCRIPTION:{option} +>NO:{-b} +>NO:{-c} tst_arguments '-a:arg' -b '(-b)-c' comptest $'tst -a -c -\t' @@ -465,6 +544,75 @@ F:>DESCRIPTION:{option} F:>NO:{-b} F:>NO:{-c} + tst_arguments + grp1 -a -b - onlyset '(-a grp3--y grp2 grp4--)-m' -n + grp2 -u -v + grp3 -x -y + grp4 -0 ':rest' + comptest $'tst -m -\t' +0:exclude group options +>line: {tst -m -}{} +>DESCRIPTION:{rest} +>DESCRIPTION:{option} +>NO:{-b} +>NO:{-n} +>NO:{-x} + + tst_arguments -x + '(grp1)' -a -b + '(grp2)' -m -n + comptest $'tst -m -\t' +0:single option groups are not mutually exclusive +>line: {tst -m -}{} +>DESCRIPTION:{option} +>NO:{-a} +>NO:{-b} +>NO:{-x} + + tst_arguments '(grp1 grp2-2)-a' '(grp1-*)-b' + grp1 ':first' '*:rest' + grp2 ':second' + comptest $'tst -a \t\eb\C-w\C-e x y \t' +0:exclude rest args listed within a group +>line: {tst -a -b }{} +>line: {tst -b x y -a }{} + + tst_arguments '(grp--m)-a' + grp '-m:value:(a b c)' + agrp '-m:other:(1 2 3)' + comptest $'tst -m \t\C-w-a -m \t' +0:two forms of same option in different groups +>line: {tst -m }{} +>DESCRIPTION:{value} +>NO:{a} +>NO:{b} +>NO:{c} +>line: {tst -a -m }{} +>DESCRIPTION:{other} +>NO:{1} +>NO:{2} +>NO:{3} +F:should offer both sets of arguments in first case + + tst_arguments '(grp--m)-x' + '(grp)' -a -b -c ':val:(1 2 3)' + comptest $'tst 1 -\t' +0:normal argument excludes options in internally mutually exclusive group +>line: {tst 1 -x }{} + + tst_arguments -s -a - set1 -c -s - set2 -c -t + grp -d + comptest $'tst -s\t -\t' +0:mix sets, groups and option stacking +>line: {tst -s}{} +>DESCRIPTION:{option} +>NO:{-a} +>NO:{-c} +>NO:{-d} +>NO:{-t} +>line: {tst -s -}{} +>DESCRIPTION:{option} +>NO:{-a} +>NO:{-c} +>NO:{-d} +F:shouldn't offer -t in the first case (with stacked options) + + tst_arguments -s '(set-a set--b grp-a grp--b grp-)-a' - set-a -s - set--b -t + grp-a -g + grp--b -h + grp- -i + comptest $'tst -a\t' +0:sets and groups with - in their name +>line: {tst -a}{} +>DESCRIPTION:{option} +>NO:{-h} +>NO:{-t} + tst_arguments --abc --aah :arg: comptesteval 'setopt bashautolist automenu' comptest $'tst --a\t\t\t' diff --git a/Test/ztst.zsh b/Test/ztst.zsh index f172ae143..0b2679927 100755 --- a/Test/ztst.zsh +++ b/Test/ztst.zsh @@ -334,7 +334,7 @@ ZTST_diff() { diff_ret=1 fi else - diff_out=$(diff "$@") + diff_out=$(diff -a "$@") diff_ret="$?" if [[ "$diff_ret" != "0" ]]; then print -r -- "$diff_out" diff --git a/configure.ac b/configure.ac index 920c2fc17..ec0bdae6e 100644 --- a/configure.ac +++ b/configure.ac @@ -628,6 +628,7 @@ if test "x$ac_cv_prog_YODL" = xyodl; then case `yodl --version` in *"version 2."*) YODL_OPTIONS='-k' ;; *"version 3."*) YODL_OPTIONS='-k -L' ;; + *"version 4."*) YODL_OPTIONS='-k -L' ;; esac fi AC_SUBST(YODL_OPTIONS) @@ -1309,7 +1310,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \ putenv getenv setenv unsetenv xw\ brk sbrk \ pathconf sysconf \ - tgetent tigetflag tigetnum tigetstr setupterm initscr \ + tgetent tigetflag tigetnum tigetstr setupterm initscr resize_term \ getcchar setcchar waddwstr wget_wch win_wch use_default_colors \ pcre_compile pcre_study pcre_exec \ nl_langinfo \ @@ -1324,7 +1325,8 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \ symlink getcwd \ cygwin_conv_path \ nanosleep \ - srand_deterministic) + srand_deterministic \ + setutxent getutxent endutxent getutent) AC_FUNC_STRCOLL AH_TEMPLATE([REALPATH_ACCEPTS_NULL], @@ -2309,21 +2311,6 @@ AH_TEMPLATE([HAVE_FIFOS], if test x$zsh_cv_sys_fifo = xyes; then AC_DEFINE(HAVE_FIFOS) fi -dnl --------------------- -dnl echo style of /bin/sh -dnl --------------------- -AC_CACHE_CHECK(if echo in /bin/sh interprets escape sequences, -zsh_cv_prog_sh_echo_escape, -[if test "`/bin/sh -c \"echo '\\n'\"`" = "\\n"; then - zsh_cv_prog_sh_echo_escape=no -else - zsh_cv_prog_sh_echo_escape=yes -fi]) -AH_TEMPLATE([SH_USE_BSD_ECHO], -[Define to 1 if /bin/sh does not interpret \ escape sequences.]) -if test x$zsh_cv_prog_sh_echo_escape = xno; then - AC_DEFINE(SH_USE_BSD_ECHO) -fi dnl ----------- dnl test for whether link() works @@ -2603,16 +2590,21 @@ AC_HELP_STRING([--enable-unicode9], [compile with unicode9 character widths]), AC_DEFINE(ENABLE_UNICODE9) fi]) -AH_TEMPLATE([BROKEN_WCWIDTH], -[Define to 1 if the wcwidth() function is present but broken.]) AH_TEMPLATE([BROKEN_ISPRINT], [Define to 1 if the isprint() function is broken under UTF-8 locale.]) + if test x$zsh_cv_c_unicode_support = xyes; then AC_DEFINE(MULTIBYTE_SUPPORT) - dnl Test for a wcwidth() implementation that gives the wrong width for - dnl zero-width combining characters. - dnl For the test we use a combining acute accent (\u0301). + dnl Test if wcwidth() and/or iswprint() is broken for + dnl zero-width combining characters, or + dnl some characters in the Latin Extended-B. + dnl If either of the functions is broken, both functions will be replaced + dnl by the ones from wcwidth9.h by defining ENABLE_UNICODE9. We will do + dnl this only if __STDC_ISO_10646__ is defined (or if building on macOS, + dnl where __STDC_ISO_10646__ is not defined but wchar_t is UCS). + dnl For the test we use a combining acute accent (\u0301) or + dnl a LATIN SMALL LETTER L WITH CURL (\u0234). dnl We input it as UTF-8 since that is the standard we can rely dnl upon most: we can't rely on a wchar_t being stored as a dnl Unicode code point on all systems. @@ -2621,9 +2613,8 @@ if test x$zsh_cv_c_unicode_support = xyes; then dnl - the programme compiled, linked and ran dnl - we successfully set a UTF-8 locale dnl - the locale we set plausibly converted the UTF-8 string - dnl for a zero-width combining character (the only way to be - dnl 100% sure would be to output it and ask if it looked right) - dnl - the converted wide character gave a non-zero width. + dnl into the correct wide character + dnl - but wcwidth() or iswprint() is broken for the converted wide character. dnl locale -a is a fallback; on most systems we should find en_US.UTF-8. [locale_prog='char *my_locales[] = { "en_US.UTF-8", "en_GB.UTF-8", "en.UTF-8", ' @@ -2635,32 +2626,38 @@ if test x$zsh_cv_c_unicode_support = xyes; then #include <stdlib.h> #include <locale.h> #include <wchar.h> + #include <wctype.h> int main() { char **localep; char comb_acute_mb[] = { (char)0xcc, (char)0x81 }; + char u_0234[] = { (char)0xc8, (char)0xb4 }; wchar_t wc; + #if !defined(__STDC_ISO_10646__) && !defined(__APPLE__) + return 1; + #endif for (localep = my_locales; *localep; localep++) - if (setlocale(LC_ALL, *localep) && - mbtowc(&wc, comb_acute_mb, 2) == 2) + if (setlocale(LC_ALL, *localep)) break; if (!*localep) return 1; - if (wcwidth(wc) == 0) - return 1; - return 0; + if (mbtowc(&wc, comb_acute_mb, 2) == 2 && (wcwidth(wc) != 0 || !iswprint(wc))) + return 0; + if (mbtowc(&wc, u_0234, 2) == 2 && (wcwidth(wc) != 1 || !iswprint(wc))) + return 0; + return 1; } "] - AC_CACHE_CHECK(if the wcwidth() function is broken, + AC_CACHE_CHECK(if the wcwidth() and/or iswprint() functions are broken, zsh_cv_c_broken_wcwidth, [AC_TRY_RUN([$locale_prog], zsh_cv_c_broken_wcwidth=yes, zsh_cv_c_broken_wcwidth=no, zsh_cv_c_broken_wcwidth=no)]) if test x$zsh_cv_c_broken_wcwidth = xyes; then - AC_DEFINE(BROKEN_WCWIDTH) + AC_DEFINE(ENABLE_UNICODE9) fi dnl Check if isprint() behaves correctly under UTF-8 locale. |