summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--ChangeLog713
-rw-r--r--Completion/BSD/Command/_sockstat61
-rw-r--r--Completion/Base/Utility/_arguments45
-rw-r--r--Completion/Base/Widget/_complete_help9
-rw-r--r--Completion/Linux/Command/_losetup36
-rw-r--r--Completion/Redhat/Command/_scl38
-rw-r--r--Completion/Unix/Command/_beep2
-rw-r--r--Completion/Unix/Command/_date17
-rw-r--r--Completion/Unix/Command/_git132
-rw-r--r--Completion/Unix/Command/_gphoto22
-rw-r--r--Completion/Unix/Command/_head45
-rw-r--r--Completion/Unix/Command/_hg275
-rw-r--r--Completion/Unix/Command/_lldb55
-rw-r--r--Completion/Unix/Command/_nm2
-rw-r--r--Completion/Unix/Command/_objdump8
-rw-r--r--Completion/Unix/Command/_qemu4
-rw-r--r--Completion/Unix/Command/_sed8
-rw-r--r--Completion/Unix/Command/_sh17
-rw-r--r--Completion/Unix/Command/_ssh2
-rw-r--r--Completion/Unix/Command/_systemd470
-rw-r--r--Completion/Unix/Command/_tail69
-rw-r--r--Completion/Unix/Command/_tmux16
-rw-r--r--Completion/Unix/Command/_tr53
-rw-r--r--Completion/Unix/Command/_user_admin2
-rw-r--r--Completion/Unix/Command/_zfs12
-rw-r--r--Completion/Unix/Command/_zpool4
-rw-r--r--Completion/Unix/Command/_zsh23
-rw-r--r--Completion/Unix/Type/_zfs_dataset6
-rw-r--r--Completion/Zsh/Command/_zsocket14
-rw-r--r--Completion/Zsh/Context/_brace_parameter6
-rw-r--r--Completion/Zsh/Type/_delimiters2
-rw-r--r--Completion/Zsh/Type/_globquals2
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Makefile.in4
-rw-r--r--Doc/Zsh/arith.yo10
-rw-r--r--Doc/Zsh/builtins.yo30
-rw-r--r--Doc/Zsh/compsys.yo5
-rw-r--r--Doc/Zsh/compwid.yo6
-rw-r--r--Doc/Zsh/contrib.yo383
-rw-r--r--Doc/Zsh/expn.yo100
-rw-r--r--Doc/Zsh/func.yo3
-rw-r--r--Doc/Zsh/grammar.yo3
-rw-r--r--Doc/Zsh/manual.yo1
-rw-r--r--Doc/Zsh/mod_parameter.yo6
-rw-r--r--Doc/Zsh/mod_pcre.yo8
-rw-r--r--Doc/Zsh/mod_private.yo89
-rw-r--r--Doc/Zsh/mod_socket.yo5
-rw-r--r--Doc/Zsh/options.yo28
-rw-r--r--Doc/Zsh/params.yo17
-rw-r--r--Doc/Zsh/zle.yo34
-rw-r--r--Doc/zman.yo2
-rw-r--r--Doc/ztexi.yo2
-rw-r--r--Etc/FAQ.yo2
-rw-r--r--Etc/zsh-development-guide6
-rw-r--r--Functions/Calendar/age2
-rw-r--r--Functions/Chpwd/cdr37
-rw-r--r--Functions/Chpwd/zsh_directory_name_generic151
-rw-r--r--Functions/MIME/zsh-mime-setup2
-rw-r--r--Functions/Misc/add-zsh-hook2
-rw-r--r--Functions/Misc/zcalc4
-rw-r--r--Functions/Misc/zed35
-rw-r--r--Functions/Misc/zrecompile2
-rw-r--r--Functions/TCP/tcp_open2
-rw-r--r--Functions/TCP/tcp_read2
-rw-r--r--Functions/TCP/tcp_send2
-rw-r--r--Functions/TCP/tcp_shoot4
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_git65
-rw-r--r--Functions/VCS_Info/VCS_INFO_quilt31
-rw-r--r--Functions/VCS_Info/vcs_info2
-rw-r--r--Functions/Zle/bracketed-paste-magic29
-rw-r--r--Functions/Zle/bracketed-paste-url-magic44
-rw-r--r--Functions/Zle/edit-command-line9
-rw-r--r--Functions/Zle/match-word-context9
-rw-r--r--Functions/Zle/smart-insert-last-word10
-rw-r--r--MACHINES4
-rw-r--r--NEWS36
-rw-r--r--README27
-rw-r--r--Src/Modules/curses.c4
-rw-r--r--Src/Modules/curses.mdd2
-rw-r--r--Src/Modules/db_gdbm.c9
-rw-r--r--Src/Modules/param_private.c587
-rw-r--r--Src/Modules/param_private.mdd7
-rw-r--r--Src/Modules/socket.c23
-rw-r--r--Src/Modules/tcp.c13
-rw-r--r--Src/Modules/zftp.c8
-rw-r--r--Src/Modules/zpty.c2
-rw-r--r--Src/Zle/compctl.c4
-rw-r--r--Src/Zle/complist.c13
-rw-r--r--Src/Zle/compmatch.c17
-rw-r--r--Src/Zle/computil.c11
-rw-r--r--Src/Zle/zle_hist.c8
-rw-r--r--Src/Zle/zle_keymap.c37
-rw-r--r--Src/Zle/zle_main.c15
-rw-r--r--Src/Zle/zle_misc.c11
-rw-r--r--Src/Zle/zle_params.c24
-rw-r--r--Src/Zle/zle_refresh.c3
-rw-r--r--Src/Zle/zle_thingy.c47
-rw-r--r--Src/Zle/zle_tricky.c7
-rw-r--r--Src/Zle/zle_utils.c23
-rw-r--r--Src/Zle/zle_vi.c2
-rw-r--r--Src/builtin.c100
-rw-r--r--Src/cond.c2
-rw-r--r--Src/exec.c424
-rw-r--r--Src/glob.c458
-rw-r--r--Src/hist.c18
-rw-r--r--Src/init.c6
-rw-r--r--Src/lex.c40
-rw-r--r--Src/math.c3
-rw-r--r--Src/mem.c89
-rw-r--r--Src/mkmakemod.sh10
-rw-r--r--Src/options.c31
-rw-r--r--Src/params.c110
-rw-r--r--Src/parse.c5
-rw-r--r--Src/pattern.c388
-rw-r--r--Src/subst.c131
-rw-r--r--Src/text.c4
-rw-r--r--Src/utils.c106
-rw-r--r--Src/zsh.h117
-rw-r--r--Src/zsh.mdd2
-rw-r--r--Test/C03traps.ztst14
-rw-r--r--Test/D02glob.ztst8
-rw-r--r--Test/D04parameter.ztst141
-rw-r--r--Test/D06subscript.ztst17
-rw-r--r--Test/D07multibyte.ztst17
-rw-r--r--Test/E01options.ztst8
-rw-r--r--Test/V10private.ztst268
-rw-r--r--configure.ac6
128 files changed, 5158 insertions, 1652 deletions
diff --git a/.gitignore b/.gitignore
index 08f90a29e..c0b7964ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ tags
TAGS
*.o
*.o.c
+*.orig
*.a
*.so
*.dll
diff --git a/ChangeLog b/ChangeLog
index 83db49234..8dbd45686 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,717 @@
+2015-11-21 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * unposted: Config/version.mk, Etc/FAQ.yo, README: make
+ 5.1.1-test-1 in preparation for 5.2.
+
+2015-11-20 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted: Doc/Zsh/mod_paramter.yo: document order of entries
+ for $history and $historywords
+
+2015-11-20 Mikael Magnusson <mikachu@gmail.com>
+
+ * 37161: Src/init.c: Disable the heuristic setting RPROMPT_INDENT
+ to 0
+
+2015-11-20 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37170: Functions/Zle/smart-insert-last-word: suppress
+ WARN_CREATE_GLOBAL for intentional creation of global variables.
+
+ * 37168: Src/params.c: no WARN_CREATE_GLOBAL on special parameters.
+
+ * 20974: Src/builtin.c, Test/D04parameter.ztst: fix bug
+ when scalar value assigned to special array in typeset.
+
+2015-11-20 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37164: Completion/Unix/Command/_tmux: _tmux: Complete external
+ commands
+
+ * 37149: Completion/Unix/Command/_git: _git: Complete
+ 'bisect/bad' ref
+
+2015-11-19 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37159: NEWS, README: update for next version.
+
+ * unposted: Doc/Zsh/params.yo: describe separators between
+ values in array assignment.
+
+2015-11-18 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37145: Src/lex.c: suppress alias expansion in skipcomm() to
+ defer parsing aliases in $(...) et al. into the subshell
+
+2015-11-18 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37140: Doc/Zsh/expn.yo: note that <<(...) is < <(...).
+
+2015-11-17 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37129: Completion/Unix/Command/_git: _git: Complete 'commit -p'
+
+2015-11-17 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37128: Src/lex.c, Test/D06subscript.ztst: work around alias
+ expansion trashing subcript being parsed.
+
+ * 37127 (minor tweak): Doc/Zsh/params.yo: document indexing of
+ $signals.
+
+2015-11-16 Mikael Magnusson <mikachu@gmail.com>
+
+ * Eric Cook: 36986: Functions/Misc/zed: Add -- to the `functions'
+ builtin calls
+
+ * Eric Cook: 37050: Completion/BSD/Command/_sockstat: minor improvements
+
+2015-11-15 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37119: Doc/Zsh/expn.yo: further "Rules" clarifications
+
+2015-11-14 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37115: Completion/Unix/Commmand/_git, Doc/Zsh/expn.yo: update
+ for changes in ${(P)...} evaluation.
+
+2015-11-13 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Src/Zle/zle_tricky.c: Make $EDITOR's
+ jump-to-matching-brace happy.
+
+ * 37031: Completion/Unix/Command/_git: _git-merge: Exclude
+ ancestors of HEAD from recent commit completion
+
+ * 37025: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info git: Add a cherry-pick patch-format
+
+2015-11-13 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 37090: Doc/zman.yo, Doc/ztexi.yo: handle blank lines correctly
+ in yodl macro example()
+
+ * unposted: Doc/Zsh/builtins.yo, Doc/Zsh/contrib.yo,
+ Doc/Zsh/func.yo, Doc/Zsh/grammar.yo, Doc/Zsh/mod_pcre.yo,
+ Doc/Zsh/params.yo, Doc/Zsh/zle.yo: cosmetic format fix
+
+2015-11-12 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37096: Src/subst.c, Test/D04parameter.ztst: make top-level
+ ${(P)...} with nested ${(P)...} do the right thing.
+
+ * 37094: Src/subst.c, Test/D04parameter.ztst: Further tweaks to
+ parameter name references: array safety; nested parameters; tests.
+
+2015-11-11 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37092: Doc/Zsh/expn.yo, Src/Zle/compctl.c,
+ Src/Zle/zle_tricky.c, Src/cond.c, Src/exec.c, Src/glob.c,
+ Src/subst.c, Src/zsh.h: make a ${(P)name} subexpression properly
+ refer to a parameter name.
+
+ * 37091: Src/Zle/zle_utils.c: clear lastline and lastlinesz when
+ freeing.
+
+2015-11-10 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37084: Test/V10private.ztst: add check for zsh/param/private
+ implementation to test.
+
+2015-11-09 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 37085: Doc/Zsh/options.yo: DEBUG_BEFORE_CMD is set by default.
+ Also fix entries in the option index.
+
+2015-11-09 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted (cf. Jun T.: 37083): Doc/Zsh/mod_private.yo: proofreading
+
+2015-11-08 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37081: Doc/Makefile.in, Doc/Zsh/mod_private.yo,
+ Src/Modules/param_private.c, Src/Modules/param_private.mdd,
+ Test/V10private.ztst: new module zsh/param/private for
+ private-scoped parameters in functions
+
+ * 37080: Src/builtin.c, Src/params.c: use paramtab abstraction more
+ consistently, add explanatory comments
+
+ * 37079: Etc/zsh-development-guide: better description of "optstr"
+ field in struct builtin as used in BUILTIN() macro
+
+2015-11-07 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 37074: Src/subst.c, Test/D04parameter.ztst: extend previous
+ fix to cover whitespace at end of substitution.
+
+2015-11-06 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37073: Src/subst.c, Test/D04parameter.ztst: fix case of
+ SH_WORD_SPLIT with string before parameter substitution and
+ nested string that starts with a space e.g. x${:- y}.
+
+2015-11-04 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37062: Completion/Unix/Command/_git: allow verbose
+ descriptions of commits and branches using git log. Mechanism
+ for turning this on subject to change.
+
+2015-11-02 Daniel Hahler <zsh@thequod.de>
+
+ * 35303: Completion/Unix/Command/_systemd: remove it in favour of the
+ one from upstream.
+
+2015-11-01 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 37038: Doc/Zsh/builtins.yo, Src/builtin.c, Src/options.c: add
+ -l option to emulate.
+
+2015-10-31 Oliver Kiddle <opk@zsh.org>
+
+ * 37029: Completion/Unix/Command/_date,
+ Completion/Unix/Command/_sed, Completion/Unix/Command/_tail,
+ Completion/Unix/Command/_tr: update options and new tr completion
+
+ * 37028: Completion/Redhat/Command/_scl: new completion
+
+ * 36993: Eric Cook: Functions/Misc/zed: fix argument parsing
+
+2015-10-31 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted (cf. 36998,36999): Src/mem.c: undo 36956 / restore 34451
+ with expanded comment about the flip-flopping
+
+2015-10-31 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37032: Completion/Unix/Command/_git: Temporarily revert 36959.
+
+2015-10-30 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted (after 37018): Src/params.c, Test/E01options.ztst: Fix
+ typo in error message.
+
+2015-10-30 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37027: Doc/Zsh/contrib.yo, Functions/Zle/match-word-context:
+ add editing word context to allow detecting being between words.
+
+ * 37022: Doc/Zsh/expn.yo, Doc/Zsh/options.yo, Src/glob.c,
+ Src/options.c, Src/zsh.h: add GLOB_STAR_SHORT option to
+ allow shorthand ** for **/* and *** for ***/*.
+
+2015-10-29 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37018: Src/math.c, Src/params.c, Test/E01options.ztst: make
+ WARNCREATEGLOBAL consistent in all cases, outputting file name.
+
+ * unposted: .gitignore: ignore .orig files.
+
+ * 37014: Functions/MIME/zsh-mime-setup,
+ Functions/Misc/add-zsh-hook, Src/Modules/socket.c,
+ Src/Modules/tcp.c, Src/Modules/zpty.c, Src/builtin.c,
+ Src/params.c,Src/zsh.h: improved internal parameter setting.
+ Enhance WARNCREATEGLOBAL to work in many more cases. Don't
+ create REPLY as an integer if it didn't previously exist as one,
+ even if the value to be set is integral, as this is likely to
+ mess up later uses of REPLY.
+
+2015-10-29 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36983 (with fix from 36990): Completion/Unix/Command/_head,
+ Completion/Unix/Command/_tail: new completions for head and tail
+
+2015-10-27 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36994: Functions/Zle/bracketed-paste-magic: declare local REPLY
+ for use with "zle .read-command"; use .self-insert instead of
+ .self-insert-unmeta
+
+2015-10-27 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 36982: Doc/Zsh/expn.yo, Src/pattern.c, Test/D02glob.ztst,
+ Test/D04parameter.ztst: fix actual bug with (#cN) and back off
+ previous change.
+
+ * 36977: Doc/Zsh/expn.yo: note about complications of pattern
+ repetitions (#cN).
+
+ * 36974: Src/Modules/zftp.c, Src/Zle/complist.c,
+ Src/Zle/computil.c, Src/Zle/zle_thingy.c, Src/parse.c: fix empty
+ argument lists.
+
+2015-10-26 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36906: Kamil Dudka <kdudka@redhat.com>: Src/mem.c:
+ queue_signals() in ZSH_MEM realloc()
+
+ * 36968: Src/Modules/db_gdbm.c: use addmodulefd() to tell the
+ shell about the descriptor of the dbm file
+
+ * 36956: Src/mem.c: revert 34451, mmap() is too slow on MacOS
+
+2015-10-26 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * users/20825: Src/Zle/zle_utils.c: get_undo_current_change()
+ needs same protection as mkundoent() for execution within
+ completion.
+
+2015-10-25 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 36962: Completion/Unix/Command/_git: _git: Fix completion of
+ RHS of refspecs.
+
+ * 36964: Completion/Unix/Command/_git: _git: Complete remotes
+ branch names with slashes correctly.
+
+ * 36960: Completion/Unix/Command/_git: _git: Enable slash matcher
+ for more branch and tag completions, include 'git branch <TAB>'
+ and 'git tag <TAB>'.
+
+ * 36959: Completion/Unix/Command/_git: _git: Offer @~$n as
+ completion of recent commits.
+
+ * 36958: Completion/Unix/Command/_git: _git: Fix recent commit
+ completion descriptions.
+
+ * unposted: Completion/Unix/Command/_git: _git: Fix 'commit
+ object name' completion messages.
+
+2015-10-25 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36911: Src/Zle/computil.c: '-optarg' should not match
+ optspec '-opt='
+
+2015-10-24 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36943 (with updated comment): Src/mem.c: restore scan for
+ reclaimable blocks in freeheap() [had been removed by 36834]
+
+2015-10-24 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Completion/Unix/Command/_beep: _beep completion:
+ Actually hook it for the 'beep' command.
+
+ * 36913 + 36945: Functions/VCS_Info/VCS_INFO_quilt: vcs_info quilt:
+ Pass patch subject lines to gen-applied-string
+
+ * 36912: Functions/VCS_Info/VCS_INFO_quilt: vcs_info quilt:
+ Tolerate being in child of .pc's parent
+
+2015-10-24 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * unposted: Src/utils.c: small typo.
+
+ * 36944: Src/utils.c, Src/Modules/tcp.c, Src/Modules/socket.c:
+ extend the previous to zsocket, although this needs to allow the
+ fd to be closed explicitly.
+
+ * 36941: Src/utils.c, Src/zsh.h, Src/Modules/tcp.c: ensure shell
+ knows about file descriptiors used by ztcp and allow such file
+ descriptors to be marked as internal if needed (not yet used).
+
+2015-10-22 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Doc/Zsh/contrib.yo: vcs_info docs: Typo fix.
+
+2015-10-21 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted: Src/math.c: strdup should be ztrdup
+
+ * 36909: Src/hist.c: in getargs(), sanity-check the offsets for
+ start and end of the requested words, in case of overflow
+
+ * 36871: Functions/Zle/bracketed-paste-magic: move initial call
+ to "zle .bracketed-paste-magic" to occur earlier in the function
+
+2015-10-20 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 36900: Completion/Unix/Command/_git: _git: stash names
+ completion: Display log messages
+
+2015-10-19 Oliver Kiddle <opk@zsh.org>
+
+ * 36642: Eric Cook: Completion/Unix/Command/_zfs:
+ complete jail/unjail subcommands on freebsd
+
+ * 36646: Eric Cook: Completion/Unix/Type/_zfs_dataset,
+ Completion/Unix/Command/_zpool, Completion/Unix/Command/_zfs:
+ solaris/openzfs differences; only use -t share solaris
+
+ * 36889: Eric Cook: Completion/BSD/Command/_sockstat:
+ completion of system specific sockstat options
+
+ * 36869: Matthew Martin: Completion/Unix/Command/_ssh: use
+ permissions to limit files completed for ssh identity files
+
+2015-10-18 Frank Terbeck <ft@bewatermyfriend.org>
+
+ * 36888: Functions/VCS_Info/vcs_info: vcs_info: Prevent
+ warn_create_global warning with '-preinit-' state
+
+2015-10-15 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 36864: Completion/Unix/Command/_nm,
+ Completion/Unix/Command/_objdump: new objdump completion plus
+ tweak to _nm.
+
+2015-10-14 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36853: Src/exec.c: replace pushheap/popheap by NEWHEAPS/OLDHEAPS
+ in doshfunc() to optimize memory management
+
+2015-10-14 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 36856: Doc/Zsh/contrib.yo, Functions/Chpwd/cdr: add -p and -P
+ options to cdr for pruning the directory list.
+
+2015-10-11 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36841: Completion/Base/Widget/_complete_help: factor out and
+ update the patterns that filter "uninteresting" functions out
+ of the $funcstack list when generating the call trace to show
+ where a tag is active.
+
+ * 36836: Src/mem.c: zhalloc() avoids re-scanning all heaps when
+ the last known heap with free space does not have enough space
+
+ * 36834: Src/mem.c: freeheap() preserves last allocated heap
+
+2015-10-11 Frank Terbeck <ft@bewatermyfriend.org>
+
+ * 36830: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info: Silence an error message with new git versions
+
+ * 36832: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info: Remove dependency on "seq"
+
+2015-10-06 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 36780: Src/params.c: ensure HOME parameter is unset if
+ corresponding internal variable is null.
+
+2015-10-04 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36773: Src/utils.c: limit CORRECT / CORRECT_ALL to directory
+ names in cases where it is obvious that a directory is expected
+
+2015-10-03 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted (cf. 36696): Test/C03traps.ztst: test case for 36766
+
+ * unposted: Src/exec.c, Src/loop.c: back out 36707, fixed by 36766
+
+ * 36766: Src/exec.c: fix incorrect reset of noerrexit during
+ "if" conditions
+
+2015-10-03 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 36760: Src/pattern.c: ensure we don't do anything untoward
+ with an already metafied pattern trial match.
+
+2015-10-03 Mikael Magnusson <mikachu@gmail.com>
+
+ * 36754: Functions/TCP/tcp_open, Functions/TCP/tcp_read,
+ Functions/TCP/tcp_send, Functions/TCP/tcp_shoot: Tweak some
+ usage output in the tcp_* functions
+
+2015-10-02 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36732: Completion/Unix/Command/_zsh: support -s and -b,
+ and complete script arguments
+
+2015-10-01 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 36737: Src/pattern.c: Ensure we are not dereferencing
+ zero-length unterminated string.
+
+ * 36735: Doc/Zsh/contrib.yo, Functions/Misc/zcalc: ~/.zcalcrc.
+
+ * Andrew Janke: 36729: MACHINES, NEWS, README: fix some typos.
+
+ * 36722: Completion/Unix/Command/_git: allow range to complete
+ after ^, taking acoount of backslash quoting.
+
+2015-10-01 Mikael Magnusson <mikachu@gmail.com>
+
+ * 36709: Doc/Zsh/zle.yo, Functions/Zle/bracketed-paste-url-magic,
+ Src/Zle/zle_main.c, Src/Zle/zle_params.c, Src/Zle/zle_thingy.c:
+ zle -f from inside widget to set flags and make yank start/end
+ zle params writable.
+
+ * 36692: Functions/Zle/bracketed-paste-url-magic: simpler
+ alternative for handling pasted urls
+
+2015-09-30 Barton E. Schaefer <schaefer@zsh.org>
+
+ * users/20672: Src/text.c: missing "do" in gettext2() for "select"
+
+ * 36707: Src/exec.c, Src/loop.c: distinguish ERR_RETURN value
+ of retflag so that execif() can ignore it in the test sublist
+
+ * cf. 36690: Doc/Zsh/builtins.yo: remove sentence fragment
+
+2015-09-30 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 36725: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info git: Compute %b correctly when "git am"-ing onto
+ detached heads.
+
+ * 36725: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info git: Compute %b correctly when rebasing detached heads.
+
+ * 36725: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info git: Compute %b correctly when merging to detached
+ heads.
+
+2015-09-30 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36697: Completion/Base/Utility/_arguments: handle options
+ of _arguments correctly
+
+2015-09-30 Peter Stephenson <p.stephenson@samsung.com>
+
+ * Matthew Martin: 36693: Doc/Zsh/arith.yo: arithmetic rounds
+ towards zero.
+
+ * 36711: Src/glob.c, Src/pattern.c: Memory for early unmetafied
+ pattern trial string is on the heap.
+
+2015-09-28 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 36682: Src/glob.c, Src/pattern.c, Src/zsh.h,
+ Src/Zle/complist,c, Src/Zle/zle_hist.c: expand pattern interface
+ to allow unmetafying trial string once for reuse.
+
+2015-09-28 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Test/D04parameter.ztst: Test for 36669
+
+2015-09-28 Daniel Hahler <git@thequod.de>
+
+ * 36601: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info: handle missing .git/rebase-apply/{next,msg-clean}
+
+2015-09-28 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36669: Src/lex.c: fix ${(z)...} of an an incomplete math
+ expression by restoring "((" at the front of the token
+
+2015-09-28 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Etc/zsh-development-guide: Update link to my
+ ChangeLog generator script, on account of patching it to handle
+ commas properly (thanks Mikael).
+
+2015-09-28 Mikael Magnusson <mikachu@gmail.com>
+
+ * unposted: Completion/Zsh/Context/_brace_parameter,
+ Completion/Zsh/Type/_delimiters, Completion/Zsh/Type/_globquals,
+ Functions/Calendar/age: Fix broken case condition and "qualifer"
+ typo
+
+2015-09-27 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 36651: Doc/Zsh/options.yo, Src/exec.c, Src/math.c,
+ Test/E01options.ztst: WARN_CREATE_GLOBAL += math expressions
+
+ * Matthew Martin: 36653: Completion/Unix/Command/_user_admin:
+ OpenBSD's usermod has no -a flag
+
+2015-09-27 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36663: Src/mkmakemod.sh, Src/zsh.mdd: replace obsolete
+ "autobins" commentary with "autofeatures"
+
+ * 36661: Src/Modules/curses.mdd: replace obsolete "autobins"
+ setting with "autofeatures"
+
+2015-09-28 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36631: Completion/Unix/Command/_sh,
+ Completion/Unix/Command/_zsh: separate _zsh from _sh
+
+2015-09-26 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36641: Src/Modules/complist.c: fix multibyte handling in
+ incremental search during menu selection
+
+2015-09-26 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted (see 36633): Completion/Unix/Command/_hg: _hg:
+ Enable --option=value syntax and disable '-xy Xarg Yarg' syntax
+
+2015-09-25 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Src/Zle/zle_tricky.c Src/Zle/zle_utils.c: zle:
+ Document the C helper function processcmd().
+
+2015-09-25 Christoph Mathys <eraserix@gmail.com>
+
+ * 36626: Completion/Unix/Command/_hg: _hg: completion for
+ 'hg bookmarks'
+
+2015-09-25 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 36630: Doc/Zsh/contrib.yo, Doc/Zsh/manual.yo,
+ Functions/Chpwd/zsh_directory_name_generic: new helper function.
+
+2015-09-24 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36623: Doc/Zsh/contrib.yo: document bracketed-paste-magic and
+ url-quote-magic; add cross-reference to vim text object widgets
+
+2015-09-24 Mikael Magnusson <mikachu@gmail.com>
+
+ * 36603: Src/glob.c: fix dirfd leak during Y shortcut qualifier
+
+2015-09-24 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Completion/Unix/Command/_hg: Declare $expl as an array
+
+2015-09-24 Christoph Mathys <eraserix@gmail.com>
+
+ * 36613: Completion/Unix/Command/_hg: extend completion for hg
+ push to support branch and bookmark
+
+2015-09-23 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36604: Functions/Misc/zrecompile: fix getopts+shift calculation
+
+2015-09-23 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Src/Zle/compmatch.c: Followup to 36586: Change C99
+ comment syntax to the C89 syntax.
+
+2015-09-23 Mikael Magnusson <mikachu@gmail.com>
+
+ * Eric Cook: 36571: Completion/Linux/Command/_losetup,
+ Completion/Zsh/Command/_zsocket: Completion for zsocket and
+ updated losetup's completion
+
+2015-09-22 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36587: Functions/Zle/edit-command-line: use +LINE:COLUMN to
+ place the cursor when invoking emacs variants, for emacsclient
+
+2015-09-22 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 36586: Han Pingtian: Src/Zle/compmatch.c: tweak to completion
+ matching with right anchor.
+
+ * 36545: Han Pingtian: Doc/Zsh/compwid.yo: tweak doc for match
+ anchors e and E.
+
+ * 36538: Han Pingtian: Doc/Zsh/compwid.yo: tweak doc for match
+ anchors to get correct difference between b and B.
+
+2015-09-22 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36578: Doc/Zsh/compsys.yo: option in a mutually exclusive set
+ has key "set-opt" in $opt_args
+
+2015-09-21 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 36580: Src/Zle/compmatch.c: don't copy empty buffer and check
+ size is consistent.
+
+2015-09-21 Frank Terbeck <ft@bewatermyfriend.org>
+
+ * 36575: Completion/Unix/Command/_tmux: _tmux: 'lock-server'
+ option is gone in tmux.git
+
+ * 36576: Completion/Unix/Command/_tmux: _tmux: Fix tmux homepage
+ URI
+
+2015-09-21 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36574: Completion/Unix/Command/_lldb: new completion for
+ the lldb debugger
+
+ * 36556: Completion/Unix/Command/_sh: remove unnecessary
+ helpspec to '_argument --'
+
+2015-09-21 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 36577: configure.ac, Src/zsh.h: supplement 36559 to
+ use LONG_MAX for 64-bit long.
+
+ * unposted: Src/zsh.h: typo in 36559.
+
+2015-09-19 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted: Doc/Zsh/builtins.yo: zcompile prepares scripts for
+ sourcing, not for execution
+
+ * 36566: Src/parse.c: check for regular file before lseek()
+
+ * 36562: Src/utils.c: sanitize $PWD on import, per POSIX
+
+2015-09-19 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 36559: Src/pattern.c: test earlier for overflow in pattern
+ range.
+
+ * unposted: Test/D07multibyte.ztst: fix typo.
+
+2015-09-18 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted (cf. users/20586): Doc/Zsh/builtins.yo: clean up
+ cross-references to the "Autoloading Functions" section.
+
+2015-09-17 Barton E. Schaefer <schaefer@zsh.org>
+
+ * unposted: Test/D04parameter.ztst: test for 36552
+
+ * 36552: Src/utils.c: fix Nularg string in quotestring(QT_DOLLARS)
+
+2015-09-14 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Doc/Zsh/zle.yo README: docs: Typo fixes
+
+2015-09-13 Axel Beckert <abe@deuxchevaux.org>
+
+ * 36523: Thue Janus Kristensen: Completion/Unix/Command/_gphoto2:
+ Replace --delete-files with --delete-file.
+
+2015-09-12 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 36525: Src/Zle/zle_misc.c: revert only the selfinsert() bit of
+ 36496 because selfinsert() may be called with incomplete wide
+ character processing from places other than getkeymapcmd()
+
+ * unposted: Functions/Zle/bracketed-paste-magic: revert 36483 as
+ multibyte is now handled by "zle .read-command"; adapt to new
+ default behavior of zle_highlight for paste
+
+ * 36522: Src/Zle/zle_thingy.c: unmetafy the argument of "zle -U"
+
+ * 36509: Src/Modules/curses.c: allocate hash table nodes with
+ zshcalloc() to avoid garbage flag values
+
+2015-09-12 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
+
+ * 36491: Src/glob.c, Test/D07multibyte.ztst: Multibyte
+ support for the parameter expansion flags B, E and N.
+
+2015-09-11 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 36443: Doc/Zsh/zle.yo Src/Zle/zle_refresh.c:
+ Highlight pasted/yanked text as standout by default (i.e., when
+ $zle_highlight doesn't specify otherwise).
+
+ * 36443: Revert 35834.
+
2015-09-11 Peter Stephenson <p.w.stephenson@ntlworld.com>
+ * 36496 (plus tweak for key buffer length): Src/Zle/zle_hist.c,
+ Src/Zle/zle_keymap.c, Src/Zle/zle_main.c, Src/Zle/zle_misc.c,
+ Src/Zle/zle_vi.c: Read full multibyte string early for
+ self-insert.
+
+ * unposted: Config/version.mk: Update internal build to
+ 5.1.1-dev-0
+
* unposted: Config/version.mk: 5.1.1
* Sebastian Gniazdowski: 36489: Src/Modules/curses.c: fix bug
@@ -430,6 +1142,7 @@
* 35834 (tweaked): Src/Zle/zle_misc.c: strip a final newline from
pasted text: inserting is hard to tell apart from accepting it
+ [reverted in 36443]
2015-08-12 Mikael Magnusson <mikachu@gmail.com>
diff --git a/Completion/BSD/Command/_sockstat b/Completion/BSD/Command/_sockstat
index e61854622..daad946fc 100644
--- a/Completion/BSD/Command/_sockstat
+++ b/Completion/BSD/Command/_sockstat
@@ -1,23 +1,46 @@
#compdef sockstat
+local -a args protocols
+local proto
-local tmp_proto protocols proto
+case $OSTYPE in
+ *bsd*)
+ args=(
+ '-4[show AF_INET (IPv4) sockets]'
+ '-6[show AF_INET6 (IPv6) sockets]'
+ '-c[show connected sockets]'
+ '-l[show listening sockets]'
+ '*-p+[specify port number]:port numbers (comma delimited)'
+ '-u[show AF_LOCAL (UNIX) sockets]'
+ )
+ ;|
+ freebsd*)
+ for proto in ${${(M)${(f)"$(</etc/protocols)"}##[a-z0-9]*}}; do
+ case $proto in
+ *\#*)
+ protocols+=(${${${(j: :)${(q)=proto}}// *\# /\[}/%/\]})
+ ;;
+ *)
+ protocols+=(${${(j: :)${=proto}}// */})
+ esac
+ done
-tmp_proto=(${${(M)${(f)"$(</etc/protocols)"}##[a-z0-9]*}})
-for proto ($tmp_proto) {
- case $proto in
- *\#*)
- protocols=($protocols ${${(j: :)${=proto}}// *\# /:})
- ;;
- *)
- protocols=($protocols ${${(j: :)${=proto}}// */})
- esac
-}
+ args+=(
+ '*-j[show sockets belonging to JID]: : _jails -0 -o jid'
+ '-L[exclude loopback]'
+ '*-P+[specify protocol]: : _values -s , protocols $protocols'
+ )
+ ;;
+ netbsd*)
+ args+=(
+ '*-f+[only show specified address family]:address family:(inet inet6 local unix)'
+ '-n[no symbolic names for addresses/ports]'
+ )
+ ;;
+esac
-_arguments -s \
- '-4[show AF_INET (IPv4) sockets]' \
- '-6[show AF_INET6 (IPv6) sockets]' \
- '-c[show connected sockets]' \
- '-l[show listening sockets]' \
- '-u[show AF_LOCAL (UNIX) sockets]' \
- '-p[only show Internet sockets if the port number is on the specified list]' \
- '-P[only show sockets of the specified protocols]:protocols:(($protocols))'
+if (( $#args )); then
+ _arguments -s -w : $args
+ return
+fi
+
+_default
diff --git a/Completion/Base/Utility/_arguments b/Completion/Base/Utility/_arguments
index 1f35e8d43..87fb20e6b 100644
--- a/Completion/Base/Utility/_arguments
+++ b/Completion/Base/Utility/_arguments
@@ -8,15 +8,33 @@ local oldcontext="$curcontext" hasopts rawret optarg singopt alwopt
local setnormarg start rest
local -a match mbegin mend
+subopts=()
+singopt=()
+while [[ "$1" = -([AMO]*|[CRSWnsw]) ]]; do
+ case "$1" in
+ -C) usecc=yes; shift ;;
+ -O) subopts=( "${(@P)2}" ); shift 2 ;;
+ -O*) subopts=( "${(@P)${1[3,-1]}}" ); shift ;;
+ -R) rawret=yes; shift;;
+ -n) setnormarg=yes; NORMARG=-1; shift;;
+ -w) optarg=yes; shift;;
+ -W) alwopt=arg; shift;;
+ -[Ss]) singopt+=( $1 ); shift;;
+ -[AM]) singopt+=( $1 $2 ); shift 2 ;;
+ -[AM]*) singopt+=( $1 ); shift ;;
+ esac
+done
+
+[[ $1 = ':' ]] && shift
+singopt+=( ':' ) # always end with ':' to indicate the end of options
+
+[[ "$PREFIX" = [-+] ]] && alwopt=arg
+
long=$argv[(I)--]
if (( long )); then
local name tmp tmpargv
- if [[ long -eq 1 ]]; then
- tmpargv=()
- else
- tmpargv=( "${(@)argv[1,long-1]}" )
- fi
+ tmpargv=( "${(@)argv[1,long-1]}" ) # optspec's before --, if any
name=${~words[1]}
[[ "$name" = [^/]*/* ]] && name="$PWD/$name"
@@ -290,23 +308,6 @@ if (( long )); then
set -- "$tmpargv[@]" "${(@P)name}"
fi
-subopts=()
-singopt=()
-while [[ "$1" = -(O*|[CRWnsw]) ]]; do
- case "$1" in
- -C) usecc=yes; shift ;;
- -O) subopts=( "${(@P)2}" ); shift 2 ;;
- -O*) subopts=( "${(@P)${1[3,-1]}}" ); shift ;;
- -R) rawret=yes; shift;;
- -n) setnormarg=yes; NORMARG=-1; shift;;
- -w) optarg=yes; shift;;
- -s) singopt=(-s); shift;;
- -W) alwopt=arg; shift;;
- esac
-done
-
-[[ "$PREFIX" = [-+] ]] && alwopt=arg
-
zstyle -s ":completion:${curcontext}:options" auto-description autod
if (( $# )) && comparguments -i "$autod" "$singopt[@]" "$@"; then
diff --git a/Completion/Base/Widget/_complete_help b/Completion/Base/Widget/_complete_help
index 0563c618f..09637ecb9 100644
--- a/Completion/Base/Widget/_complete_help
+++ b/Completion/Base/Widget/_complete_help
@@ -6,12 +6,15 @@ _complete_help() {
local _sort_tags=_help_sort_tags text i j k tmp
typeset -A help_funcs help_tags help_sfuncs help_styles
+ local -H _help_scan_funcstack="main_complete|complete|approximate|normal"
+ local -H _help_filter_funcstack="alternative|call_function|describe|dispatch|wanted|requested|all_labels|next_label"
+
{
compadd() { return 1 }
zstyle() {
- local _f="${${(@)${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(dispatch|wanted|requested|all_labels|next_label)}% *}"
+ local _f="${${(@)${(@)funcstack[2,(i)_($~_help_scan_funcstack)]}:#(_($~_help_filter_funcstack)|\((eval|anon)\))}% *}"
- [[ -z "$_f" ]] && _f="${${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(dispatch|wanted|requested|all_labels|next_label)}"
+ [[ -z "$_f" ]] && _f="${${(@)funcstack[2,(i)_($~_help_scan_funcstack)]}:#(_($~_help_filter_funcstack)|\((eval|anon)\))}"
if [[ "$help_sfuncs[$2]" != *${_f}* ||
"$help_styles[${2}${_f}]" != *${3}* ]]; then
@@ -73,7 +76,7 @@ _complete_help() {
}
_help_sort_tags() {
- local f="${${(@)${(@)funcstack[3,(i)_(main_complete|complete|approximate|normal)]}:#(_(dispatch|wanted|requested|all_labels|next_label)|\(eval\))}% *}"
+ local f="${${(@)${(@)funcstack[3,(i)_($~_help_scan_funcstack)]}:#(_($~_help_filter_funcstack)|\((eval|anon)\))}% *}"
if [[ "$help_funcs[$curcontext]" != *${f}* ||
"$help_tags[${curcontext}${f}]" != *(${(j:|:)~argv})* ]]; then
diff --git a/Completion/Linux/Command/_losetup b/Completion/Linux/Command/_losetup
index ff18681f1..359a9e0ea 100644
--- a/Completion/Linux/Command/_losetup
+++ b/Completion/Linux/Command/_losetup
@@ -1,14 +1,28 @@
#compdef losetup
+# based on util-linux 2.26.2
-local cyphers
-cyphers=( /proc/crypto/cipher/*(N:t) )
-cyphers="${cyphers[@]%-*}"
-
-_arguments -S \
+_arguments -S -A '-*' \
+ '(-l --list)'{-l,--list}'[list currently used loop devices]' \
+ '(-n --noheadings)'{-n,--noheadings}'[do not print heading for --list output]' \
+ '(-d --delete --detach -o --offset -a --all)'{-o,--offset}'+[specify data start is offset]:offset (bytes)' \
+ '(-O --output)'{-O,--output}'[specify columns to be printed with --list]:column: _values -s , column name sizelimit offset autoclear ro back-file' \
+ '(-P --partscan)'{-P,--partscan}'[scan the partition table of newly created loop devices]' \
+ '--raw[raw output format]' \
+ '(-r --read-only)'{-r,--read-only}'[set up a read-only loop device]' \
+ '(-v --verbose)'{-v,--verbose}'[verbose mode]' \
+ '(-V --version)'{-V,--version}'[display version information]' \
+ '(-h --help)'{-h,--help}'[display help]' \
+ '1:device:_files -g "/dev/loop<->"' \
+ '(-d --delete --detach)2:file:_files' \
+ - '(set1)' \
+ '(-o --offset)'{-a,--all}'[show the status of all loop devices]' \
+ - '(set2)' \
+ {-c,--set-capacity}'[reread the size of the file associated with the loop device]' \
+ - '(set3)' \
'(- 2)'{--delete,--detach,-d}'[detach from specified loop device]' \
- '(-d --delete --detach -e --encryption)'{-e,--encryption}"+[enable encryption]:cypher:( $cyphers )" \
- '(-d --delete --detach -o --offset)'{-o,--offset}'+[specify data start is offset]:offset (bytes)' \
- '(-d --delete --detach -p --pass-fd)'{-p,--pass-fd}'+[read passphrase from specified file descriptor]:file descriptor:_file_descriptors' \
- '(-d --delete --detach -k --keybits)'{-k,--keybits}'+[set the number of bits to use in key]:key size:(64 128 160 192 256)' \
- '1:device:_files -g "loop*(-.)"' \
- '(-d --delete --detach)2:file:_files'
+ - '(set4)' \
+ '(-D --detach-all)'{-D,--detach-all}'[detach all associated loop devices]' \
+ - '(set5)' \
+ {-f,--find}'[find the first unused loop device]' \
+ - '(set6)' \
+ {-j,--associated}'[show the status of all loop devices associated with an file]: : _files'
diff --git a/Completion/Redhat/Command/_scl b/Completion/Redhat/Command/_scl
new file mode 100644
index 000000000..e1a4b69db
--- /dev/null
+++ b/Completion/Redhat/Command/_scl
@@ -0,0 +1,38 @@
+#compdef scl
+
+local curcontext="$curcontext" dashes ret=1
+local -a state line force alts cmd
+
+[[ $words[2] = deregister ]] &&
+ force=( '--force[deregister even SCL installed as packages]' )
+
+_arguments -C $force \
+ '(- 1)'{-l,--list}'[list installed software collections or packages within a collection]' \
+ '(-l --list)1:action:(enable register deregister)' \
+ '(-)*:collections:->collections' && ret=0
+
+if [[ -n $state ]]; then
+ (( $#line > 1 )) && curcontext="${curcontext%:*}-$line[1]:"
+ if [[ $line[1] = register ]]; then
+ _directories -P / -W /
+ return
+ fi
+ if (( ${dashes:=$words[(I)--]} )); then
+ shift dashes words
+ (( CURRENT -= dashes ))
+ _normal
+ return
+ fi
+ if [[ $CURRENT -gt 3 && $words[CURRENT] = - ]]; then
+ compadd - --
+ return
+ fi
+ [[ $line[1] = enable && $CURRENT -gt 3 ]] &&
+ cmd='command:command:_cmdstring'
+
+ _alternative 'collections:collection:compadd
+ $(_call_program collections ${words[1]} -l)' \
+ $cmd && ret=0
+fi
+
+return ret
diff --git a/Completion/Unix/Command/_beep b/Completion/Unix/Command/_beep
index c49c09726..d393bc91e 100644
--- a/Completion/Unix/Command/_beep
+++ b/Completion/Unix/Command/_beep
@@ -1,4 +1,4 @@
-#compdef _beep
+#compdef beep
# beep [--verbose | --debug] [-e device | --device device] [-f N] [-l N]
# [-r N] [-d N] [-D N] [-s] [-c]
diff --git a/Completion/Unix/Command/_date b/Completion/Unix/Command/_date
index e596ac038..ff3bac398 100644
--- a/Completion/Unix/Command/_date
+++ b/Completion/Unix/Command/_date
@@ -1,6 +1,6 @@
#compdef date gdate
-local -a args
+local -a args alts
if _pick_variant gnu="Free Software Foundation" unix --version; then
args=(
@@ -20,16 +20,27 @@ else
solaris*)
args=( '-a:adjustment' )
;;
+ darwin*|dragonfly*|netbsd*|openbsd*)
+ args+=( '-r[specify reference time]:seconds since epoch' )
+ ;|
freebsd*|darwin*|dragonfly*|netbsd*|openbsd*)
args=(
'-n[only set time on current machine]'
'-d:daylight saving time value'
'-j[do not try to set date]'
- '-r:seconds since epoch'
'-t:minutes west of GMT'
)
;|
- freebsd*) args+=( '-R[RFC2822 format]' ) ;|
+ freebsd*)
+ alts=(
+ 'seconds:sec:_guard "(0x[0-9a-fA-F]#|[0-9]#)" "seconds since epoch"'
+ 'files:file:_files'
+ )
+ args+=(
+ '-r[reference time: file modification or literal time]:reference: _alternative $alts'
+ '-R[RFC2822 format]'
+ )
+ ;|
freebsd*|dragonfly*|darwin*)
args+=( '-f:parsing format' '-v:adjustment value' )
;;
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 40a9fb63b..6e8e9c665 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -656,7 +656,7 @@ _git-commit () {
'( --porcelain --dry-run)--short[output dry run in short format]' \
'(--short --dry-run)--porcelain[output dry run in porcelain-ready format]' \
'(--short --porcelain --dry-run -z --null)'{-z,--null}'[separate dry run entry output with NUL]' \
- '--patch[use the interactive patch selection interface to chose which changes to commit]' \
+ {-p,--patch}'[use the interactive patch selection interface to chose which changes to 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]' \
@@ -1131,6 +1131,7 @@ _git-log () {
_git-merge () {
local -a merge_options
__git_setup_merge_options
+ local -a git_commit_opts=(--all --not HEAD --not)
_arguments -w -S -s \
$merge_options \
@@ -1138,7 +1139,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]' \
- '*: :__git_commits'
+ '*: : __git_commits -O expl:git_commit_opts'
}
(( $+functions[_git-mv] )) ||
@@ -5004,6 +5005,33 @@ __git_is_in_middle_of_merge () {
[[ -f $gitdir/MERGE_HEAD ]]
}
+(( $+functions[__git_describe_branch] )) ||
+__git_describe_branch () {
+ local __commits_in=$1
+ local __tag=$2
+ local __desc=$3
+ shift 3
+
+ integer maxverbose
+ if zstyle -s :completion:$curcontext max-verbose maxverbose &&
+ (( ${compstate[nmatches]} <= maxverbose )); then
+ local __c
+ local -a __commits
+ for __c in ${(P)__commits_in}; do
+ __commits+=("${__c}:${$(_call_program describe git log -1 --oneline $__c)//:/\\:}")
+ done
+ _describe -t $__tag $__desc __commits "$@"
+ else
+ local expl
+ _wanted $__tag expl $__desc compadd "$@" -a - $__commits_in
+ fi
+}
+
+(( $+functions[__git_describe_commit] )) ||
+__git_describe_commit () {
+ __git_describe_branch $1 $2 $3 -M 'r:|/=**' "${(@)argv[4,-1]}"
+}
+
# Completion Wrappers
(( $+functions[__git_ignore_line] )) ||
@@ -5216,7 +5244,7 @@ _git_commands () {
for cmdtype in aliases $cmdtypes; do
local -a ${cmdtype}_d
(( $#disp )) && set -A ${cmdtype}_d \
- ${${(Pr.COLUMNS-4.)cmdtype/(#s)(#m)[^:]##:/${(r.len.)MATCH[1,-2]} $sep }%% #}
+ ${${(r.COLUMNS-4.)${(P)cmdtype}/(#s)(#m)[^:]##:/${(r.len.)MATCH[1,-2]} $sep }%% #}
alts+=( "${cmdtype//_/-}:${${cmdtype//_/ }%%(e|)s}:compadd ${(e)disp} -a ${cmdtype}_m" )
done
@@ -5313,7 +5341,8 @@ __git_remotes () {
__git_ref_specs () {
# TODO: This needs to deal with a lot more types of things.
if compset -P '*:'; then
- __git_heads
+ # TODO: have the caller supply the correct remote name, restrict to refs/remotes/${that_remote}/* only
+ __git_remote_branch_names_noprefix
else
compset -P '+'
if compset -S ':*'; then
@@ -5487,12 +5516,21 @@ __git_signoff_file () {
(( $+functions[__git_stashes] )) ||
__git_stashes () {
local expl
+ declare -a interleaved
declare -a stashes
+ declare -a descriptions
- stashes=(${(f)"$(_call_program stashes git stash list --pretty=format:%gd 2>/dev/null)"})
+ interleaved=(${(ps:\0:)"$(_call_program stashes git stash list -z --pretty='format:%gd%x00%s%x00\(%cr\)' 2>/dev/null)"})
__git_command_successful $pipestatus || return 1
+ () {
+ local i j k
+ for i j k in $interleaved; do
+ stashes+=($i)
+ descriptions+=("$i: $j $k")
+ done
+ }
- _wanted stashes expl stash compadd "$@" -a - stashes
+ _wanted stashes expl 'stash' compadd -Vx -d descriptions -a - stashes
}
(( $+functions[__git_svn_revisions] )) ||
@@ -5531,29 +5569,27 @@ __git_branch_names () {
branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads 2>/dev/null)"}#refs/heads/})
__git_command_successful $pipestatus || return 1
- _wanted branch-names expl branch-name compadd "$@" -a - branch_names
+ __git_describe_commit branch_names branch-names 'branch name' "$@"
}
(( $+functions[__git_remote_branch_names] )) ||
__git_remote_branch_names () {
- local expl
declare -a branch_names
branch_names=(${${(f)"$(_call_program remote-branch-refs git for-each-ref --format='"%(refname)"' refs/remotes 2>/dev/null)"}#refs/remotes/})
__git_command_successful $pipestatus || return 1
- _wanted remote-branch-names expl 'remote branch name' compadd -M 'r:|/=**' "$@" -a - branch_names
+ __git_describe_commit branch_names remote-branch-names 'remote branch name' "$@"
}
(( $+functions[__git_remote_branch_names_noprefix] )) ||
__git_remote_branch_names_noprefix () {
- local expl
declare -a heads
- branch_names=(${${${(f)"$(_call_program remote-branch-refs-noprefix git for-each-ref --format='"%(refname)"' refs/remotes 2>/dev/null)"}##*/}:#HEAD})
+ branch_names=(${${${${(f)"$(_call_program remote-branch-refs-noprefix git for-each-ref --format='"%(refname)"' refs/remotes 2>/dev/null)"}#refs/remotes/}#*/}:#HEAD})
__git_command_successful $pipestatus || return 1
- _wanted remote-branch-names-noprefix expl 'remote branch name' compadd -M 'r:|/=**' "$@" -a - branch_names
+ __git_describe_commit branch_names remote-branch-names-noprefix 'remote branch name' "$@"
}
(( $+functions[__git_commit_objects_prefer_recent] )) ||
@@ -5593,7 +5629,7 @@ __git_heads () {
(( $+functions[__git_heads_local] )) ||
__git_heads_local () {
- local gitdir expl start
+ local gitdir
declare -a heads
heads=(${(f)"$(_call_program headrefs git for-each-ref --format='"%(refname:short)" refs/heads' 2>/dev/null)"})
@@ -5603,19 +5639,19 @@ __git_heads_local () {
[[ -f $gitdir/$f ]] && heads+=$f
done
[[ -f $gitdir/refs/stash ]] && heads+=stash
+ [[ -f $gitdir/refs/bisect/bad ]] && heads+=bisect/bad
fi
- _wanted heads-local expl "local head" compadd -M 'r:|/=**' "$@" -a - heads
+ __git_describe_commit heads heads-local "local head" "$@"
}
(( $+functions[__git_heads_remote] )) ||
__git_heads_remote () {
- local gitdir expl start
declare -a heads
heads=(${(f)"$(_call_program headrefs git for-each-ref --format='"%(refname:short)" refs/remotes' 2>/dev/null)"})
- _wanted heads-remote expl "remote head" compadd -M 'r:|/=**' "$@" -a - heads
+ __git_describe_commit heads heads-remote "remote head" "$@"
}
(( $+functions[__git_commit_objects] )) ||
@@ -5631,7 +5667,7 @@ __git_commit_objects () {
commits=(${(f)"$(_call_program commits git --no-pager log -1000 --all --reflog --format='%h:\[%h\]\ %s\ \(%cr\)')"})
__git_command_successful $pipestatus || return 1
- _describe -V -t commits 'commit object name' commits
+ _describe -Vx -t commits 'commit object name' commits
}
(( $+functions[__git_recent_commits] )) ||
@@ -5641,6 +5677,8 @@ __git_recent_commits () {
local i j k ret
integer distance_from_head
local label
+ local parents
+ local next_first_parent_ancestral_line_commit
zparseopts -D -E O:=argument_array_names
# Turn (-O foo:bar) to (foo bar)
@@ -5650,10 +5688,10 @@ __git_recent_commits () {
# Careful: most %d will expand to the empty string. Quote properly!
# NOTE: we could use %D directly, but it's not available in git 1.9.1 at least.
- commits=("${(f)"$(_call_program commits git --no-pager log $commit_opts -20 --format='%h%n%d%n%s\ \(%cr\)')"}")
+ commits=("${(f)"$(_call_program commits git --no-pager log $commit_opts -20 --format='%h%n%d%n%s\ \(%cr\)%n%p')"}")
__git_command_successful $pipestatus || return 1
- for i j k in "$commits[@]" ; do
+ for i j k parents in "$commits[@]" ; do
# Note: the after-the-colon part must be unique across the entire array;
# see workers/34768
if (( $#commit_opts )); then
@@ -5662,20 +5700,39 @@ __git_recent_commits () {
# description unique (due to workers/34768), which we do by including the
# hash. Git always prints enough hash digits to make the output unique.)
label="[$i]"
- elif (( distance_from_head == 0 )); then
- label="[HEAD] "
- elif (( distance_from_head == 1 )); then
- label="[HEAD^] "
- elif (( distance_from_head == 2 )); then
- label="[HEAD^^] "
- elif (( distance_from_head < 10 )); then
- label="[HEAD~$distance_from_head] "
+ elif (( distance_from_head )) && [[ $i != $next_first_parent_ancestral_line_commit ]]; then
+ # The first commit (HEAD), and its ancestors along the first-parent line,
+ # get HEAD~$n labels.
+ #
+ # For other commits, we just print the hash. (${parents} does provide enough
+ # information to compute HEAD~3^2~4 -style labels, though, if somebody cared
+ # enough to implement that.)
+ label="[$i]"
else
- label="[HEAD~$distance_from_head]"
+ # Compute a first-parent-ancestry commit's label.
+ if false ; then
+ elif (( distance_from_head == 0 )); then
+ label="[HEAD] "
+ elif (( distance_from_head == 1 )); then
+ label="[HEAD^] "
+ elif (( distance_from_head == 2 )); then
+ label="[HEAD^^] "
+ elif (( distance_from_head < 10 )); then
+ label="[HEAD~$distance_from_head] "
+ else
+ label="[HEAD~$distance_from_head]"
+ fi
+ ## Disabled because _describe renders the output unhelpfuly when this function
+ ## is called twice during a single completion operation, and list-grouped is
+ ## in its default setting (enabled).
+ #descr+=("@~${distance_from_head}":"${label} $k") # CROSSREF: use the same label as below
+
+ # Prepare for the next first-parent-ancestry commit.
+ (( ++distance_from_head ))
+ next_first_parent_ancestral_line_commit=${parents%% *}
fi
# label is now 9 bytes, so the descriptions ($k) will be aligned.
- descr+=($i:"${label} $k")
- (( ++distance_from_head ))
+ descr+=($i:"${label} $k") # CROSSREF: use the same label as above
j=${${j# \(}%\)} # strip leading ' (' and trailing ')'
j=${j/ ->/,} # Convert " -> master, origin/master".
@@ -5695,7 +5752,7 @@ __git_recent_commits () {
expl=()
_wanted heads expl 'head' compadd "$@" -a - heads && ret=0
expl=()
- _describe -Vx -t commits 'recent commit object name' descr && ret=0
+ _describe -V -t commits 'recent commit object name' descr && ret=0
return $ret
}
@@ -5753,7 +5810,14 @@ __git_commit_ranges () {
if compset -P '*..(.|)'; then
expl=( $* )
else
- compset -S '..*' || suf=( -S .. -r '.@~ ^:\t\n\-' )
+ if ! compset -S '..*'; then
+ local match mbegin mend
+ if [[ ${PREFIX} = (#b)((\\|)\^)* ]]; then
+ compset -p ${#match[1]}
+ else
+ suf=( -S .. -r '.@~ ^:\t\n\-' )
+ fi
+ fi
expl=( $* $suf )
fi
@@ -5814,7 +5878,7 @@ __git_tags () {
tags=(${${(f)"$(_call_program tagrefs git for-each-ref --format='"%(refname)"' refs/tags 2>/dev/null)"}#refs/tags/})
__git_command_successful $pipestatus || return 1
- _wanted tags expl tag compadd "$@" -a - tags
+ _wanted tags expl tag compadd -M 'r:|/=**' "$@" -a - tags
}
(( $+functions[__git_commit_tags] )) ||
@@ -5837,7 +5901,7 @@ __git_tags_of_type () {
tags=(${${(M)${(f)"$(_call_program $type-tag-refs "git for-each-ref --format='%(*objecttype)%(objecttype) %(refname)' refs/tags 2>/dev/null")"}:#$type(tag|) *}#$type(tag|) refs/tags/})
__git_command_successful $pipestatus || return 1
- _wanted $type-tags expl "$type tag" compadd "$@" -a - tags
+ _wanted $type-tags expl "$type tag" compadd -M 'r:|/=**' "$@" -a - tags
}
# Reference Argument Types
diff --git a/Completion/Unix/Command/_gphoto2 b/Completion/Unix/Command/_gphoto2
index 95d8a49b7..314d83e3a 100644
--- a/Completion/Unix/Command/_gphoto2
+++ b/Completion/Unix/Command/_gphoto2
@@ -32,7 +32,7 @@ _arguments -s \
'--get-all-raw-data[get all raw data from folder]' \
'--get-audio-data[get audio data given in range]:range' \
'--get-all-audio-data[get all audio data from folder]' \
- '--delete-files[delete files given in range]:range' \
+ '--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]' \
diff --git a/Completion/Unix/Command/_head b/Completion/Unix/Command/_head
new file mode 100644
index 000000000..4f956acdc
--- /dev/null
+++ b/Completion/Unix/Command/_head
@@ -0,0 +1,45 @@
+#compdef head
+
+local curcontext=$curcontext state state_descr line expl opts args ret=1
+typeset -A opt_args
+
+if _pick_variant gnu=GNU unix --version; then
+ args=(
+ '(-n --lines -c --bytes)'{-c+,--bytes=}'[print the first (or with -, all but the last) specified bytes]:number of bytes:->number'
+ '(-n --lines -c --bytes)'{-n+,--lines=}'[print the first (or with -, all but the last) specified lines]:number of lines:->number'
+ '(-q --quiet --silent -v --verbose)'{-q,--quiet,--silent}'[never print headers giving file names]'
+ '(-q --quiet --silent -v --verbose)'{-v,--verbose}'[always print headers giving file names]'
+ '(- *)--help[display help and exit]'
+ '(- *)--version[output version information and exit]'
+ )
+else
+ opts=(-A '-*')
+ args=( '(-c)-n+[display the first specified lines]:number of lines' )
+ case $OSTYPE in
+ (freebsd*|darwin*|dragonfly*|netbsd*)
+ args+=( '(-n)-c+[display the first specified bytes]:number of bytes' )
+ ;;
+ esac
+fi
+
+_arguments -C -s -S $opts : $args '*:file:_files' && return 0
+
+case $state in
+ (number)
+ local mlt sign digit
+ mlt='multiplier:multiplier:((b\:512 K\:1024 KB\:1000 M\:1024\^2'
+ mlt+=' MB\:1000\^2 G\:1024\^3 GB\:1000\^3 T\:1024\^4 TB\:1000\^4))'
+ sign='sign:sign:((-\:"print all but the last specified bytes/lines"'
+ sign+=' +\:"print the first specified bytes/lines (default)"))'
+ digit='digits:digit:(0 1 2 3 4 5 6 7 8 9)'
+ if compset -P '*[0-9]'; then
+ _alternative $mlt $digit && ret=0
+ elif [[ -z $PREFIX ]]; then
+ _alternative $sign $digit && ret=0
+ elif compset -P '(+|-)'; then
+ _alternative $digit && ret=0
+ fi
+ ;;
+esac
+
+return ret
diff --git a/Completion/Unix/Command/_hg b/Completion/Unix/Command/_hg
index e7c21b9d1..8d31cd377 100644
--- a/Completion/Unix/Command/_hg
+++ b/Completion/Unix/Command/_hg
@@ -163,19 +163,26 @@ _hg_revrange() {
}
_hg_tags_internal() {
- local expl
+ local -a expl
typeset -a hgtags
hgtags=( ${(f)"$(_hg_cmd tags -q 2>/dev/null)"} )
_wanted tags expl 'tags' compadd -a - hgtags
}
_hg_bookmarks_internal() {
- local expl
+ local -a expl
typeset -a hgbookmarks
hgbookmarks=( ${(f)"$(_hg_cmd bookmarks -q 2>/dev/null)"} )
_wanted bookmarks expl 'bookmarks' compadd -a - hgbookmarks
}
+_hg_branches_internal() {
+ local -a expl
+ typeset -a hgbranches
+ hgbranches=( ${(f)"$(_hg_cmd branches -q 2>/dev/null)"} )
+ _wanted branches expl 'branches' compadd -a - hgbranches
+}
+
_hg_tags() {
_alternative \
'bookmarks:bookmark:_hg_bookmarks_internal' \
@@ -352,7 +359,7 @@ _hg_clone_dest() {
# Common options
_hg_global_opts=(
- '(--repository -R)'{-R+,--repository}'[repository root directory]:repository:_files -/'
+ '(--repository -R)'{-R+,--repository=}'[repository root directory]:repository:_files -/'
'--cwd[change working directory]:new working directory:_files -/'
'(--noninteractive -y)'{-y,--noninteractive}'[do not prompt, assume yes for any required answers]'
'(--verbose -v)'{-v,--verbose}'[enable additional output]'
@@ -371,8 +378,8 @@ _hg_global_opts=(
)
_hg_pat_opts=(
- '*'{-I+,--include}'[include names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/'
- '*'{-X+,--exclude}'[exclude names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/')
+ '*'{-I+,--include=}'[include names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/'
+ '*'{-X+,--exclude=}'[exclude names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/')
_hg_diff_opts=(
'(--text -a)'{-a,--text}'[treat all files as text]'
@@ -388,11 +395,11 @@ _hg_style_opts=(
_hg_commit_opts=(
'(-m --message -l --logfile --edit -e)'{-e,--edit}'[edit commit message]'
- '(-e --edit -l --logfile --message -m)'{-m+,--message}'[use <text> as commit message]:message:'
- '(-e --edit -m --message --logfile -l)'{-l+,--logfile}'[read the commit message from <file>]:log file:_files')
+ '(-e --edit -l --logfile --message -m)'{-m+,--message=}'[use <text> as commit message]:message:'
+ '(-e --edit -m --message --logfile -l)'{-l+,--logfile=}'[read the commit message from <file>]:log file:_files')
_hg_remote_opts=(
- '(--ssh -e)'{-e+,--ssh}'[specify ssh command to use]:'
+ '(--ssh -e)'{-e+,--ssh=}'[specify ssh command to use]:'
'--remotecmd[specify hg command to run on the remote side]:')
_hg_cmd() {
@@ -401,19 +408,19 @@ _hg_cmd() {
}
_hg_cmd_add() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
'*:unknown files:_hg_unknown'
}
_hg_cmd_addremove() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
- '(--similarity -s)'{-s+,--similarity}'[guess renamed files by similarity (0<=s<=100)]:' \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
+ '(--similarity -s)'{-s+,--similarity=}'[guess renamed files by similarity (0<=s<=100)]:' \
'*:unknown or missing files:_hg_addremove'
}
_hg_cmd_annotate() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
- '(--rev -r)'{-r+,--rev}'[annotate the specified revision]:revision:_hg_tags' \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
+ '(--rev -r)'{-r+,--rev=}'[annotate the specified revision]:revision:_hg_tags' \
'(--follow -f)'{-f,--follow}'[follow file copies and renames]' \
'(--text -a)'{-a,--text}'[treat all files as text]' \
'(--user -u)'{-u,--user}'[list the author]' \
@@ -424,48 +431,58 @@ _hg_cmd_annotate() {
}
_hg_cmd_archive() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
'--no-decode[do not pass files through decoders]' \
- '(--prefix -p)'{-p+,--prefix}'[directory prefix for files in archive]:' \
- '(--rev -r)'{-r+,--rev}'[revision to distribute]:revision:_hg_tags' \
- '(--type -t)'{-t+,--type}'[type of distribution to create]:archive type:(files tar tbz2 tgz uzip zip)' \
+ '(--prefix -p)'{-p+,--prefix=}'[directory prefix for files in archive]:' \
+ '(--rev -r)'{-r+,--rev=}'[revision to distribute]:revision:_hg_tags' \
+ '(--type -t)'{-t+,--type=}'[type of distribution to create]:archive type:(files tar tbz2 tgz uzip zip)' \
'*:destination:_files'
}
_hg_cmd_backout() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
'--merge[merge with old dirstate parent after backout]' \
- '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
+ '(--date -d)'{-d+,--date=}'[record datecode as commit date]:date code:' \
'--parent[parent to choose when backing out merge]' \
- '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
- '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_tags' \
- '(--message -m)'{-m+,--message}'[specify commit message]:text' \
- '(--logfile -l)'{-l+,--logfile}'[read commit message from specified file]:log file:_files'
+ '(--user -u)'{-u+,--user=}'[record user as commiter]:user:' \
+ '(--rev -r)'{-r+,--rev=}'[revision]:revision:_hg_tags' \
+ '(--message -m)'{-m+,--message=}'[specify commit message]:text' \
+ '(--logfile -l)'{-l+,--logfile=}'[read commit message from specified file]:log file:_files'
}
_hg_cmd_bisect() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(-)'{-r,--reset}'[reset bisect state]' \
'(--good -g --bad -b --skip -s --reset -r)'{-g,--good}'[mark changeset good]'::revision:_hg_tags \
'(--good -g --bad -b --skip -s --reset -r)'{-b,--bad}'[mark changeset bad]'::revision:_hg_tags \
'(--good -g --bad -b --skip -s --reset -r)'{-s,--skip}'[skip testing changeset]' \
- '(--command -c --noupdate -U)'{-c+,--command}'[use command to check changeset state]':commands:_command_names \
+ '(--command -c --noupdate -U)'{-c+,--command=}'[use command to check changeset state]':commands:_command_names \
'(--command -c --noupdate -U)'{-U,--noupdate}'[do not update to target]'
}
+_hg_cmd_bookmarks() {
+ _arguments -s : $_hg_global_opts \
+ '(--force -f)'{-f,--force}'[force]' \
+ '(--rev -r)'{-r+,--rev=}'[set bookmark at revision]:revision:_hg_tags' \
+ '(--delete -d)'{-d,--delete}'[delete a given bookmark]' \
+ '(--rename -m)'{-m+,--rename=}'[rename given bookmark]:bookmark:_hg_bookmarks_internal' \
+ '(--inactive -i)'{-i,--inactive}'[mark a bookmark inactive]' \
+ ':bookmark:_hg_bookmarks_internal'
+}
+
_hg_cmd_branch() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--force -f)'{-f,--force}'[set branch name even if it shadows an existing branch]' \
'(--clean -C)'{-C,--clean}'[reset branch name to parent branch name]'
}
_hg_cmd_branches() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--active -a)'{-a,--active}'[show only branches that have unmerge heads]'
}
_hg_cmd_bundle() {
- _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
+ _arguments -s : $_hg_global_opts $_hg_remote_opts \
'(--force -f)'{-f,--force}'[run even when remote repository is unrelated]' \
'(2)*--base[a base changeset to specify instead of a destination]:revision:_hg_tags' \
':output file:_files' \
@@ -473,33 +490,33 @@ _hg_cmd_bundle() {
}
_hg_cmd_cat() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
- '(--output -o)'{-o+,--output}'[print output to file with formatted name]:filespec:' \
- '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_tags' \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
+ '(--output -o)'{-o+,--output=}'[print output to file with formatted name]:filespec:' \
+ '(--rev -r)'{-r+,--rev=}'[revision]:revision:_hg_tags' \
'*:file:_hg_files'
}
_hg_cmd_clone() {
- _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
+ _arguments -s : $_hg_global_opts $_hg_remote_opts \
'(--noupdate -U)'{-U,--noupdate}'[do not update the new working directory]' \
- '(--rev -r)'{-r+,--rev}'[a changeset you would like to have after cloning]:' \
+ '(--rev -r)'{-r+,--rev=}'[a changeset you would like to have after cloning]:' \
'--uncompressed[use uncompressed transfer (fast over LAN)]' \
':source repository:_hg_remote' \
':destination:_hg_clone_dest'
}
_hg_cmd_commit() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
'(--addremove -A)'{-A,--addremove}'[mark new/missing files as added/removed before committing]' \
- '(--message -m)'{-m+,--message}'[specify commit message]:text' \
- '(--logfile -l)'{-l+,--logfile}'[read commit message from specified file]:log file:_files' \
- '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
- '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
+ '(--message -m)'{-m+,--message=}'[specify commit message]:text' \
+ '(--logfile -l)'{-l+,--logfile=}'[read commit message from specified file]:log file:_files' \
+ '(--date -d)'{-d+,--date=}'[record datecode as commit date]:date code:' \
+ '(--user -u)'{-u+,--user=}'[record user as commiter]:user:' \
'*:file:_hg_committable'
}
_hg_cmd_copy() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
'(--after -A)'{-A,--after}'[record a copy that has already occurred]' \
'(--force -f)'{-f,--force}'[forcibly copy over an existing managed file]' \
'*:file:_hg_files'
@@ -507,8 +524,8 @@ _hg_cmd_copy() {
_hg_cmd_diff() {
typeset -A opt_args
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_diff_opts \
- '*'{-r,--rev}'+[revision]:revision:_hg_revrange' \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_diff_opts \
+ '*'{-r+,--rev=}'[revision]:revision:_hg_revrange' \
'(--show-function -p)'{-p,--show-function}'[show which function each change is in]' \
'(--ignore-all-space -w)'{-w,--ignore-all-space}'[ignore white space when comparing lines]' \
'(--ignore-space-change -b)'{-b,--ignore-space-change}'[ignore changes in the amount of white space]' \
@@ -527,99 +544,99 @@ _hg_cmd_diff() {
}
_hg_cmd_export() {
- _arguments -s -w : $_hg_global_opts $_hg_diff_opts \
+ _arguments -s : $_hg_global_opts $_hg_diff_opts \
'(--outout -o)'{-o+,--output}'[print output to file with formatted name]:filespec:' \
'--switch-parent[diff against the second parent]' \
'*:revision:_hg_tags'
}
_hg_cmd_grep() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
'(--print0 -0)'{-0,--print0}'[end filenames with NUL]' \
'--all[print all revisions with matches]' \
'(--follow -f)'{-f,--follow}'[follow changeset or file history]' \
'(--ignore-case -i)'{-i,--ignore-case}'[ignore case when matching]' \
'(--files-with-matches -l)'{-l,--files-with-matches}'[print only filenames and revs that match]' \
'(--line-number -n)'{-n,--line-number}'[print matching line numbers]' \
- '*'{-r+,--rev}'[search in given revision range]:revision:_hg_revrange' \
+ '*'{-r+,--rev=}'[search in given revision range]:revision:_hg_revrange' \
'(--user -u)'{-u,--user}'[print user who committed change]' \
'1:search pattern:' \
'*:files:_hg_files'
}
_hg_cmd_heads() {
- _arguments -s -w : $_hg_global_opts $_hg_style_opts \
- '(--rev -r)'{-r+,--rev}'[show only heads which are descendants of rev]:revision:_hg_tags'
+ _arguments -s : $_hg_global_opts $_hg_style_opts \
+ '(--rev -r)'{-r+,--rev=}'[show only heads which are descendants of rev]:revision:_hg_tags'
}
_hg_cmd_help() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'*:mercurial command:_hg_commands'
}
_hg_cmd_identify() {
- _arguments -s -w : $_hg_global_opts \
- '(--rev -r)'{-r+,--rev}'[identify the specified rev]:revision:_hg_tags' \
- '(--num -n)'{-n+,--num}'[show local revision number]' \
- '(--id -i)'{-i+,--id}'[show global revision id]' \
- '(--branch -b)'{-b+,--branch}'[show branch]' \
- '(--tags -t)'{-t+,--tags}'[show tags]'
+ _arguments -s : $_hg_global_opts \
+ '(--rev -r)'{-r+,--rev=}'[identify the specified rev]:revision:_hg_tags' \
+ '(--num -n)'{-n+,--num=}'[show local revision number]' \
+ '(--id -i)'{-i+,--id=}'[show global revision id]' \
+ '(--branch -b)'{-b+,--branch=}'[show branch]' \
+ '(--tags -t)'{-t+,--tags=}'[show tags]'
}
_hg_cmd_import() {
- _arguments -s -w : $_hg_global_opts \
- '(--strip -p)'{-p+,--strip}'[directory strip option for patch (default: 1)]:count:' \
- '(--message -m)'{-m+,--message}'[use <text> as commit message]:text:' \
+ _arguments -s : $_hg_global_opts \
+ '(--strip -p)'{-p+,--strip=}'[directory strip option for patch (default: 1)]:count:' \
+ '(--message -m)'{-m+,--message=}'[use <text> as commit message]:text:' \
'(--force -f)'{-f,--force}'[skip check for outstanding uncommitted changes]' \
'*:patch:_files'
}
_hg_cmd_incoming() {
- _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \
+ _arguments -s : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \
'(--no-merges -M)'{-M,--no-merges}'[do not show merge revisions]' \
'(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \
'(--patch -p)'{-p,--patch}'[show patch]' \
- '(--rev -r)'{-r+,--rev}'[a specific revision up to which you would like to pull]:revision:_hg_tags' \
+ '(--rev -r)'{-r+,--rev=}'[a specific revision up to which you would like to pull]:revision:_hg_tags' \
'(--newest-first -n)'{-n,--newest-first}'[show newest record first]' \
'--bundle[file to store the bundles into]:bundle file:_files' \
':source:_hg_remote'
}
_hg_cmd_init() {
- _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
+ _arguments -s : $_hg_global_opts $_hg_remote_opts \
':dir:_files -/'
}
_hg_cmd_locate() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
- '(--rev -r)'{-r+,--rev}'[search repository as it stood at revision]:revision:_hg_tags' \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
+ '(--rev -r)'{-r+,--rev=}'[search repository as it stood at revision]:revision:_hg_tags' \
'(--print0 -0)'{-0,--print0}'[end filenames with NUL, for use with xargs]' \
'(--fullpath -f)'{-f,--fullpath}'[print complete paths]' \
'*:search pattern:_hg_files'
}
_hg_cmd_log() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_style_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_style_opts \
'(--follow --follow-first -f)'{-f,--follow}'[follow changeset or history]' \
'(-f --follow)--follow-first[only follow the first parent of merge changesets]' \
'(--copies -C)'{-C,--copies}'[show copied files]' \
- '(--keyword -k)'{-k+,--keyword}'[search for a keyword]:' \
- '(--limit -l)'{-l+,--limit}'[limit number of changes displayed]:' \
+ '(--keyword -k)'{-k+,--keyword=}'[search for a keyword]:' \
+ '(--limit -l)'{-l+,--limit=}'[limit number of changes displayed]:' \
'*'{-r,--rev}'[show the specified revision or range]:revision:_hg_revrange' \
'(--no-merges -M)'{-M,--no-merges}'[do not show merges]' \
'(--only-merges -m)'{-m,--only-merges}'[show only merges]' \
'(--patch -p)'{-p,--patch}'[show patch]' \
- '(--prune -P)'{-P+,--prune}'[do not display revision or any of its ancestors]:revision:_hg_tags' \
+ '(--prune -P)'{-P+,--prune=}'[do not display revision or any of its ancestors]:revision:_hg_tags' \
'*:files:_hg_files'
}
_hg_cmd_manifest() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
':revision:_hg_tags'
}
_hg_cmd_merge() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--force -f)'{-f,--force}'[force a merge with outstanding changes]' \
'(--rev -r 1)'{-r,--rev}'[revision to merge]:revision:_hg_mergerevs' \
'(--preview -P)'{-P,--preview}'[review revisions to merge (no merge is performed)]' \
@@ -627,50 +644,54 @@ _hg_cmd_merge() {
}
_hg_cmd_outgoing() {
- _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \
+ _arguments -s : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \
'(--no-merges -M)'{-M,--no-merges}'[do not show merge revisions]' \
'(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \
'(--patch -p)'{-p,--patch}'[show patch]' \
- '(--rev -r)'{-r+,--rev}'[a specific revision you would like to push]' \
+ '(--rev -r)'{-r+,--rev=}'[a specific revision you would like to push]' \
'(--newest-first -n)'{-n,--newest-first}'[show newest record first]' \
':destination:_hg_remote'
}
_hg_cmd_parents() {
- _arguments -s -w : $_hg_global_opts $_hg_style_opts \
- '(--rev -r)'{-r+,--rev}'[show parents of the specified rev]:revision:_hg_tags' \
+ _arguments -s : $_hg_global_opts $_hg_style_opts \
+ '(--rev -r)'{-r+,--rev=}'[show parents of the specified rev]:revision:_hg_tags' \
':last modified file:_hg_files'
}
_hg_cmd_paths() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
':path:_hg_paths'
}
_hg_cmd_pull() {
- _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
+ _arguments -s : $_hg_global_opts $_hg_remote_opts \
'(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \
'(--update -u)'{-u,--update}'[update to new tip if changesets were pulled]' \
- '(--rev -r)'{-r+,--rev}'[a specific revision up to which you would like to pull]:revision:' \
+ '(--rev -r)'{-r+,--rev=}'[a specific revision up to which you would like to pull]:revision:' \
':source:_hg_remote'
}
_hg_cmd_push() {
- _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
+ _arguments -s : $_hg_global_opts $_hg_remote_opts \
'(--force -f)'{-f,--force}'[force push]' \
- '(--rev -r)'{-r+,--rev}'[a specific revision you would like to push]:revision:_hg_tags' \
+ '(--rev -r)'{-r+,--rev=}'[a specific revision you would like to push]:revision:_hg_tags' \
+ '*'{-B,--bookmark=}'[bookmark to push]:bookmark:_hg_bookmarks_internal' \
+ '*'{-b,--branch=}'[branch to push]:branch:_hg_branches_internal' \
+ '--insecure[do not verify server certificate]' \
+ '--new-branch[allow pushing a new branch]' \
':destination:_hg_remote'
}
_hg_cmd_remove() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
'(--after -A)'{-A,--after}'[record remove that has already occurred]' \
'(--force -f)'{-f,--force}'[remove file even if modified]' \
'*:file:_hg_files'
}
_hg_cmd_rename() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
'(--after -A)'{-A,--after}'[record a rename that has already occurred]' \
'(--force -f)'{-f,--force}'[forcibly copy over an existing managed file]' \
'*:file:_hg_files'
@@ -680,7 +701,7 @@ _hg_cmd_resolve() {
local context state line
typeset -A opt_args
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--list -l --mark -m --unmark -u)'{-l,--list}'[list state of files needing merge]:*:merged files:->resolve_files' \
'(--mark -m --list -l --unmark -u)'{-m,--mark}'[mark files as resolved]:*:unresolved files:_hg_unresolved' \
'(--unmark -u --list -l --mark -m)'{-u,--unmark}'[unmark files as resolved]:*:resolved files:_hg_resolved' \
@@ -697,9 +718,9 @@ _hg_cmd_revert() {
local context state line
typeset -A opt_args
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
'(--all -a :)'{-a,--all}'[revert all changes when no arguments given]' \
- '(--rev -r)'{-r+,--rev}'[revision to revert to]:revision:_hg_tags' \
+ '(--rev -r)'{-r+,--rev=}'[revision to revert to]:revision:_hg_tags' \
'--no-backup[do not save backup copies of files]' \
'*:file:->diff_files'
@@ -717,13 +738,13 @@ _hg_cmd_revert() {
}
_hg_cmd_serve() {
- _arguments -s -w : $_hg_global_opts \
- '(--accesslog -A)'{-A+,--accesslog}'[name of access log file]:log file:_files' \
- '(--errorlog -E)'{-E+,--errorlog}'[name of error log file]:log file:_files' \
+ _arguments -s : $_hg_global_opts \
+ '(--accesslog -A)'{-A+,--accesslog=}'[name of access log file]:log file:_files' \
+ '(--errorlog -E)'{-E+,--errorlog=}'[name of error log file]:log file:_files' \
'(--daemon -d)'{-d,--daemon}'[run server in background]' \
- '(--port -p)'{-p+,--port}'[listen port]:listen port:' \
- '(--address -a)'{-a+,--address}'[interface address]:interface address:' \
- '(--name -n)'{-n+,--name}'[name to show in web pages]:repository name:' \
+ '(--port -p)'{-p+,--port=}'[listen port]:listen port:' \
+ '(--address -a)'{-a+,--address=}'[interface address]:interface address:' \
+ '(--name -n)'{-n+,--name=}'[name to show in web pages]:repository name:' \
'(--templates -t)'{-t,--templates}'[web template directory]:template dir:_files -/' \
'--style[web template style]:style' \
'--stdio[for remote clients]' \
@@ -731,13 +752,13 @@ _hg_cmd_serve() {
}
_hg_cmd_showconfig() {
- _arguments -s -w : $_hg_global_opts \
- '(--untrusted -u)'{-u+,--untrusted}'[show untrusted configuration options]' \
+ _arguments -s : $_hg_global_opts \
+ '(--untrusted -u)'{-u+,--untrusted=}'[show untrusted configuration options]' \
':config item:_hg_config'
}
_hg_cmd_status() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
'(--all -A)'{-A,--all}'[show status of all files]' \
'(--modified -m)'{-m,--modified}'[show only modified files]' \
'(--added -a)'{-a,--added}'[show only added files]' \
@@ -754,37 +775,37 @@ _hg_cmd_status() {
}
_hg_cmd_tag() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--local -l)'{-l,--local}'[make the tag local]' \
- '(--message -m)'{-m+,--message}'[message for tag commit log entry]:message:' \
- '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
- '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
- '(--rev -r)'{-r+,--rev}'[revision to tag]:revision:_hg_tags' \
+ '(--message -m)'{-m+,--message=}'[message for tag commit log entry]:message:' \
+ '(--date -d)'{-d+,--date=}'[record datecode as commit date]:date code:' \
+ '(--user -u)'{-u+,--user=}'[record user as commiter]:user:' \
+ '(--rev -r)'{-r+,--rev=}'[revision to tag]:revision:_hg_tags' \
':tag name:'
}
_hg_cmd_tip() {
- _arguments -s -w : $_hg_global_opts $_hg_style_opts \
+ _arguments -s : $_hg_global_opts $_hg_style_opts \
'(--patch -p)'{-p,--patch}'[show patch]'
}
_hg_cmd_unbundle() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--update -u)'{-u,--update}'[update to new tip if changesets were unbundled]' \
':files:_files'
}
_hg_cmd_update() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--clean -C)'{-C,--clean}'[overwrite locally modified files]' \
- '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_tags' \
+ '(--rev -r)'{-r+,--rev=}'[revision]:revision:_hg_tags' \
':revision:_hg_tags'
}
# HGK
_hg_cmd_view() {
- _arguments -s -w : $_hg_global_opts \
- '(--limit -l)'{-l+,--limit}'[limit number of changes displayed]:' \
+ _arguments -s : $_hg_global_opts \
+ '(--limit -l)'{-l+,--limit=}'[limit number of changes displayed]:' \
':revision range:_hg_tags'
}
@@ -838,35 +859,35 @@ _hg_qseries_opts=(
'(--summary -s)'{-s,--summary}'[print first line of patch header]')
_hg_cmd_qapplied() {
- _arguments -s -w : $_hg_global_opts $_hg_qseries_opts
+ _arguments -s : $_hg_global_opts $_hg_qseries_opts
}
_hg_cmd_qdelete() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--keep -k)'{-k,--keep}'[keep patch file]' \
- '*'{-r+,--rev}'[stop managing a revision]:applied patch:_hg_revrange' \
+ '*'{-r+,--rev=}'[stop managing a revision]:applied patch:_hg_revrange' \
'*:unapplied patch:_hg_qdeletable'
}
_hg_cmd_qdiff() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts \
'*:pattern:_hg_files'
}
_hg_cmd_qfold() {
- _arguments -s -w : $_hg_global_opts $_h_commit_opts \
+ _arguments -s : $_hg_global_opts $_h_commit_opts \
'(--keep,-k)'{-k,--keep}'[keep folded patch files]' \
'*:unapplied patch:_hg_qunapplied'
}
_hg_cmd_qgoto() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--force -f)'{-f,--force}'[overwrite any local changes]' \
':patch:_hg_qseries'
}
_hg_cmd_qguard() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--list -l)'{-l,--list}'[list all patches and guards]' \
'(--none -n)'{-n,--none}'[drop all guards]' \
':patch:_hg_qseries' \
@@ -874,66 +895,66 @@ _hg_cmd_qguard() {
}
_hg_cmd_qheader() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
':patch:_hg_qseries'
}
_hg_cmd_qimport() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--existing -e)'{-e,--existing}'[import file in patch dir]' \
- '(--name -n 2)'{-n+,--name}'[patch file name]:name:' \
+ '(--name -n 2)'{-n+,--name=}'[patch file name]:name:' \
'(--force -f)'{-f,--force}'[overwrite existing files]' \
- '*'{-r+,--rev}'[place existing revisions under mq control]:revision:_hg_revrange' \
+ '*'{-r+,--rev=}'[place existing revisions under mq control]:revision:_hg_revrange' \
'*:patch:_files'
}
_hg_cmd_qnew() {
- _arguments -s -w : $_hg_global_opts $_hg_commit_opts \
+ _arguments -s : $_hg_global_opts $_hg_commit_opts \
'(--force -f)'{-f,--force}'[import uncommitted changes into patch]' \
':patch:'
}
_hg_cmd_qnext() {
- _arguments -s -w : $_hg_global_opts $_hg_qseries_opts
+ _arguments -s : $_hg_global_opts $_hg_qseries_opts
}
_hg_cmd_qpop() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--all -a :)'{-a,--all}'[pop all patches]' \
- '(--name -n)'{-n+,--name}'[queue name to pop]:' \
+ '(--name -n)'{-n+,--name=}'[queue name to pop]:' \
'(--force -f)'{-f,--force}'[forget any local changes]' \
':patch:_hg_qapplied'
}
_hg_cmd_qprev() {
- _arguments -s -w : $_hg_global_opts $_hg_qseries_opts
+ _arguments -s : $_hg_global_opts $_hg_qseries_opts
}
_hg_cmd_qpush() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--all -a :)'{-a,--all}'[apply all patches]' \
'(--list -l)'{-l,--list}'[list patch name in commit text]' \
- '(--merge -m)'{-m+,--merge}'[merge from another queue]:' \
- '(--name -n)'{-n+,--name}'[merge queue name]:' \
+ '(--merge -m)'{-m+,--merge=}'[merge from another queue]:' \
+ '(--name -n)'{-n+,--name=}'[merge queue name]:' \
'(--force -f)'{-f,--force}'[apply if the patch has rejects]' \
':patch:_hg_qunapplied'
}
_hg_cmd_qrefresh() {
- _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_commit_opts \
+ _arguments -s : $_hg_global_opts $_hg_pat_opts $_hg_commit_opts \
'(--git -g)'{-g,--git}'[use git extended diff format]' \
'(--short -s)'{-s,--short}'[short refresh]' \
'*:files:_hg_files'
}
_hg_cmd_qrename() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
':patch:_hg_qseries' \
':destination:'
}
_hg_cmd_qselect() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--none -n :)'{-n,--none}'[disable all guards]' \
'(--series -s :)'{-s,--series}'[list all guards in series file]' \
'--pop[pop to before first guarded applied patch]' \
@@ -942,20 +963,20 @@ _hg_cmd_qselect() {
}
_hg_cmd_qseries() {
- _arguments -s -w : $_hg_global_opts $_hg_qseries_opts \
+ _arguments -s : $_hg_global_opts $_hg_qseries_opts \
'(--missing -m)'{-m,--missing}'[print patches not in series]'
}
_hg_cmd_qunapplied() {
- _arguments -s -w : $_hg_global_opts $_hg_qseries_opts
+ _arguments -s : $_hg_global_opts $_hg_qseries_opts
}
_hg_cmd_qtop() {
- _arguments -s -w : $_hg_global_opts $_hg_qseries_opts
+ _arguments -s : $_hg_global_opts $_hg_qseries_opts
}
_hg_cmd_strip() {
- _arguments -s -w : $_hg_global_opts \
+ _arguments -s : $_hg_global_opts \
'(--force -f)'{-f,--force}'[force multi-head removal]' \
'(--backup -b)'{-b,--backup}'[bundle unrelated changesets]' \
'(--nobackup -n)'{-n,--nobackup}'[no backups]' \
diff --git a/Completion/Unix/Command/_lldb b/Completion/Unix/Command/_lldb
new file mode 100644
index 000000000..16e346cfb
--- /dev/null
+++ b/Completion/Unix/Command/_lldb
@@ -0,0 +1,55 @@
+#compdef lldb
+
+local curcontext=$curcontext state state_descr line expl ret=1
+typeset -A opt_args
+local -a args
+
+args=(
+ '*'{-o+,--one-line=}'[run one-line lldb command after loading executable]:lldb command: '
+ '*'{-s+,--source=}'[run lldb commands from a file after loading executable]:file:_files'
+ '*'{-O+,--one-line-before-file=}'[run one-line lldb command before loading executable]:lldb command'
+ '*'{-S+,--source-before-file=}'[run lldb commands from a file before loading executable]:file:_files'
+ '(-k --one-line-on-crash)'{-k+,--one-line-on-crash=}'[run one-line lldb command if target crashes in batch mode]:lldb command'
+ '(-K --source-on-crash)'{-K+,--source-on-crash=}'[run lldb commands from a file if target crashes in batch mode]:file:_files'
+ '(-b --batch)'{-b,--batch}'[run commands from -s -S -o -O and quit]'
+ '(-Q --source-quietly)'{-Q,--source-quietly}'[suppress output from -s, -S, -o or -O]'
+ '(-e --editor)'{-e,--editor}'[open source files using "external editor" mechanism]'
+ '(-x --no-lldbinit)'{-x,--no-lldbinit}'[do not automatically parse .lldbinit files]'
+ '(-X --no-use-colors)'{-X,--no-use-colors}'[do not use colors]'
+ '(-d --debug)'{-d,--debug}'[print extra information for debugging itself]'
+ '(-r --repl)'{-r,--repl}'[run lldb in REPL mode]'
+ '(-l --script-language)'{-l+,--script-language=}'[use the specified scripting language]:language:(Python Perl Ruby Tcl)'
+ - info
+ '(-)'{-h,--help}'[print the usage information]'
+ '(-)'{-v,--version}'[print the current version number]'
+ '(-)'{-P,--python-path}'[print path to the lldb.py file]'
+ - file
+ '(-f --file)'{-f+,--file=}'[specify executable file to debug]:executable:_files -g "*(-*)"'
+ '(-a --arch)'{-a+,--arch=}'[use the specified architecture]:arch'
+ '(-c --core)'{-c+,--core=}'[specify core file to open]:core file:_files -g "*core*(-.)"'
+ '*::executable and arguments:->exe_args'
+ - name
+ '(-n --attach-name)'{-n+,--attach-name=}'[attach to the named process]:process name'
+ '(-w --wait-for)'{-w,--wait-for}'[wait for the specified process to launch]'
+ - pid
+ '(-p --attach-pid)'{-p+,--attach-pid=}'[attach to the specified process]:pid:_pids'
+)
+
+_arguments -C -s -S : $args && return 0
+
+case $state in
+ (exe_args)
+ if [[ -z $opt_args[(I)file-(-f|--file)] ]]; then
+ if [[ $CURRENT -eq 1 ]]; then
+ _wanted executables expl 'executable' _files -g '*(-*)' && ret=0
+ else
+ _normal && ret=0
+ fi
+ else
+ words=( ${(v)opt_args[(i)file-(-f|--file)]} "$words[@]" )
+ (( CURRENT++ ))
+ _normal && ret=0
+ fi
+esac
+
+return ret
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 80136329d..d171ef5a3 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -6,7 +6,7 @@ _nm_object_file() {
[[ -x $REPLY || $REPLY = *.([ao]|so|elf) ]]
}
-files="*:object file:_files -g '*(-.e:_nm_object_file:)'"
+files="*:object file:_files -g '*(-.e,_nm_object_file,)'"
args=(
'(-A -o --print-file-name)'{-A,-o,--print-file-name}'[print name of input file on each line]'
'(--demangle)-C[decode symbol names]'
diff --git a/Completion/Unix/Command/_objdump b/Completion/Unix/Command/_objdump
new file mode 100644
index 000000000..607719a19
--- /dev/null
+++ b/Completion/Unix/Command/_objdump
@@ -0,0 +1,8 @@
+#compdef objdump
+
+# borrowed from _nm_object_file
+_objdump_object_file() {
+ [[ -x $REPLY || $REPLY = *.([ao]|so|elf) ]]
+}
+
+_arguments -- '*:object file:_files -g "*(-.e,_objdump_object_file,)"'
diff --git a/Completion/Unix/Command/_qemu b/Completion/Unix/Command/_qemu
index db07eba33..3c21c3e74 100644
--- a/Completion/Unix/Command/_qemu
+++ b/Completion/Unix/Command/_qemu
@@ -2,7 +2,7 @@
_qemu_log_items () {
local -a opts hline
- $service -d \? | while read -A hline; do
+ $service -d \? 2>/dev/null | while read -A hline; do
[[ $hline[1] = Log ]] && continue
opts=($opts "${hline[1]}[${hline[2,-1]}]")
done
@@ -11,7 +11,7 @@ _qemu_log_items () {
local _qemu_machines
-_qemu_machines=(${${${(f)"$($service -M \?)"}[2,-1]}%% *})
+_qemu_machines=(${${${(f)"$($service -M \? 2>/dev/null)"}[2,-1]}%% *})
_arguments \
'-'{fda,fdb,hda,hdb,hdc,hdd,cdrom}':disk image:_files' \
diff --git a/Completion/Unix/Command/_sed b/Completion/Unix/Command/_sed
index 8e2385cc8..cc7a9631d 100644
--- a/Completion/Unix/Command/_sed
+++ b/Completion/Unix/Command/_sed
@@ -38,12 +38,8 @@ else
'-a[delay opening files listed with w function]'
)
;|
- darwin*|freebsd*|netbsd*)
- args+=(
- '-i'$inplace
- '-l[make output line buffered]'
- )
- ;|
+ darwin*|freebsd*|netbsd*|openbsd*) args+=( '-i'$inplace ) ;|
+ darwin*|freebsd*|netbsd*) args+=( '-l[make output line buffered]' ) ;|
freebsd*) args+=( '-u[disable data buffering]' ) ;|
freebsd*|netbsd*)
args+=(
diff --git a/Completion/Unix/Command/_sh b/Completion/Unix/Command/_sh
index 21ebfc3b2..2afb46621 100644
--- a/Completion/Unix/Command/_sh
+++ b/Completion/Unix/Command/_sh
@@ -1,13 +1,4 @@
-#compdef sh ksh bash zsh csh tcsh rc
-
-if [[ $service == zsh ]]; then
- # try a bit harder
- if [[ ${words[CURRENT-1]} == -o ]]; then
- _options
- # no other possibilities
- return
- fi
-fi
+#compdef sh ksh bash csh tcsh rc
if (( CURRENT == ${words[(i)-c]} + 1 )); then
_cmdstring
@@ -21,9 +12,3 @@ else
fi
_default
fi
-
-local ret=$?
-
-[[ $service == zsh ]] && _arguments -S -s -- '*:' && ret=0
-
-return ret
diff --git a/Completion/Unix/Command/_ssh b/Completion/Unix/Command/_ssh
index a66702a65..c6ede9efe 100644
--- a/Completion/Unix/Command/_ssh
+++ b/Completion/Unix/Command/_ssh
@@ -18,7 +18,7 @@ _ssh () {
# for protocol version 2, this can be a comma-separated list
'-c+[select encryption cipher]:encryption cipher:(idea des 3des blowfish arcfour tss none)'
'-F+[specify alternate config file]:config file:_files'
- '*-i+[select identity file]:SSH identity file:_files'
+ '*-i+[select identity file]:SSH identity file:_files -g "*(-.^AR)"'
'*-o+[specify extra options]:option string:->option'
)
common_transfer=(
diff --git a/Completion/Unix/Command/_systemd b/Completion/Unix/Command/_systemd
deleted file mode 100644
index 028ecddd9..000000000
--- a/Completion/Unix/Command/_systemd
+++ /dev/null
@@ -1,470 +0,0 @@
-#compdef systemctl systemd-loginctl
-
-# Copyright (c) 2011 Foudil Bre'tel <foudil.newbie+zshsystemctl@gmail.com>
-#
-# This file is released under the GPLv3.
-#
-# inspired from _yum and systemctl-bash-completion.sh (shipped with systemctl)
-#
-# TODO: enable options after commands. Ex: systemctl list-units --all --full
-
-# Main dispatcher
-_systemd()
-{
- local curcontext="$curcontext" state lstate line
-
- case "$service" in
- systemctl)
- # -s for aggregated options like -aP
- _arguments -s \
- {-h,--help}'[Show help]' \
- '--version[Show package version]' \
- {-t,--type=}'[List only units of a particular type]:unit type:(automount device mount path service snapshot socket swap target timer)' \
- \*{-p,--property=}'[Show only properties by specific name]:unit property:()' \
- {-a,--all}'[Show all units/properties, including dead/empty ones]' \
- '--failed[Show only failed units]' \
- "--full[Don't ellipsize unit names on output]" \
- '--fail[When queueing a new job, fail if conflicting jobs are pending]' \
- '--ignore-dependencies[When queueing a new job, ignore all its dependencies]' \
- '--kill-mode=[How to send signal]:killmode:(control-group process)' \
- '--kill-who=[Who to send signal to]:killwho:(main control all)' \
- {-s,--signal=}'[Which signal to send]:signal:_signals' \
- {-H,--host=}'[Show information for remote host]:userathost:_hosts_or_user_at_host' \
- {-P,--privileged}'[Acquire privileges before execution]' \
- {-q,--quiet}'[Suppress output]' \
- '--no-block[Do not wait until operation finished]' \
- "--no-wall[Don't send wall message before halt/power-off/reboot]" \
- "--no-reload[When enabling/disabling unit files, don't reload daemon configuration]" \
- '--no-legend[Do not print a legend, i.e. the column headers and the footer with hints]' \
- '--no-pager[Do not pipe output into a pager]' \
- '--no-ask-password[Do not ask for system passwords]' \
- '--order[When generating graph for dot, show only order]' \
- '--require[When generating graph for dot, show only requirement]' \
- '--system[Connect to system manager]' \
- '--user[Connect to user service manager]' \
- '--global[Enable/disable unit files globally]' \
- {-f,--force}'[When enabling unit files, override existing symlinks. When shutting down, execute action immediately]' \
- '--root=[Enable unit files in the specified root directory]:directory:_directories' \
- '--runtime[Enable unit files only temporarily until next reboot]' \
- '*::systemctl command:_systemctl_command'
- ;;
-
- systemd-loginctl)
- _arguments -s \
- {-h,--help}'[Show help]' \
- '--version[Show package version]' \
- \*{-p,--property=}'[Show only properties by this name]:unit property:' \
- {-a,--all}'[Show all properties, including empty ones]' \
- '--failed[Show only failed units]' \
- '--kill-who=[Who to send signal to]:killwho:(main control all)' \
- {-s,--signal=}'[Which signal to send]:signal:_signals' \
- {-H,--host=}'[Show information for remote host]:userathost:_hosts_or_user_at_host' \
- {-P,--privileged}'[Acquire privileges before execution]' \
- '--no-pager[Do not pipe output into a pager]' \
- '*::systemd-loginctl command:_systemd_loginctl_command'
- ;;
-
- *) _message 'eh?' ;;
- esac
-
-}
-
-_hosts_or_user_at_host()
-{
- _alternative \
- 'users-hosts:: _user_at_host' \
- 'hosts:: _hosts'
-}
-
-(( $+functions[_systemctl_command] )) || _systemctl_command()
-{
- local -a _systemctl_cmds
- _systemctl_cmds=(
- "list-units:List units"
- "start:Start (activate) one or more units"
- "stop:Stop (deactivate) one or more units"
- "reload:Reload one or more units"
- "restart:Start or restart one or more units"
- "condrestart:Restart one or more units if active"
- "try-restart:Restart one or more units if active"
- "reload-or-restart:Reload one or more units is possible, otherwise start or restart"
- "force-reload:Reload one or more units is possible, otherwise restart if active"
- "reload-or-try-restart:Reload one or more units is possible, otherwise restart if active"
- "isolate:Start one unit and stop all others"
- "kill:Send signal to processes of a unit"
- "is-active:Check whether units are active"
- "status:Show runtime status of one or more units"
- "show:Show properties of one or more units/jobs or the manager"
- "reset-failed:Reset failed state for all, one, or more units"
- "load:Load one or more units"
- "list-unit-files:List installed unit files"
- "enable:Enable one or more unit files"
- "disable:Disable one or more unit files"
- "reenable:Reenable one or more unit files"
- "preset:Enable/disable one or more unit files based on preset configuration"
- "mask:Mask one or more units"
- "unmask:Unmask one or more units"
- "link:Link one or more units files into the search path"
- "is-enabled:Check whether unit files are enabled"
- "list-jobs:List jobs"
- "cancel:Cancel all, one, or more jobs"
- "dump:Dump server status"
- "dot:Dump dependency graph for dot(1)"
- "snapshot:Create a snapshot"
- "delete:Remove one or more snapshots"
- "show-environment:Dump environment"
- "set-environment:Set one or more environment variables"
- "unset-environment:Unset one or more environment variables"
- "daemon-reload:Reload systemd manager configuration"
- "daemon-reexec:Reexecute systemd manager"
- "default:Enter system default mode"
- "rescue:Enter system rescue mode"
- "emergency:Enter system emergency mode"
- "halt:Shut down and halt the system"
- "poweroff:Shut down and power-off the system"
- "reboot:Shut down and reboot the system"
- "kexec:Shut down and reboot the system with kexec"
- "exit:Ask for user instance termination"
- "switch-root:Change to a different root file system"
- "suspend:Suspend the system"
- "hibernate:Hibernate the system"
- "hibernate-sleep:Hibernate and suspend the system"
- )
-
- if (( CURRENT == 1 )); then
- _describe -t commands 'systemctl command' _systemctl_cmds
- else
- local curcontext="$curcontext" ret
-
- cmd="${${_systemctl_cmds[(r)$words[1]:*]%%:*}}"
- # Deal with any aliases
- case $cmd in
- condrestart) cmd="try-restart";;
- force-reload) cmd="reload-or-try-restart";;
- esac
-
- if (( $#cmd )); then
- curcontext="${curcontext%:*:*}:systemctl-${cmd}:"
-
- local update_policy
- zstyle -s ":completion:${curcontext}:" cache-policy update_policy
- if [[ -z "$update_policy" ]]; then
- zstyle ":completion:${curcontext}:" cache-policy _systemctl_caching_policy
- fi
-
- _call_function ret _systemctl_$cmd || _message 'no more arguments'
- else
- _message "unknown systemctl command: $words[1]"
- fi
- return ret
- fi
-}
-
-__systemctl()
-{
- systemctl --full --no-legend --no-pager "$@"
-}
-
-
-# Fills the unit list
-_systemctl_all_units()
-{
- if ( [[ ${+_sys_all_units} -eq 0 ]] || _cache_invalid SYS_ALL_UNITS ) &&
- ! _retrieve_cache SYS_ALL_UNITS;
- then
- _sys_all_units=( $(__systemctl list-units --all | { while read a b; do echo "$a"; done; }) )
- _store_cache SYS_ALL_UNITS _sys_all_units
- fi
-}
-
-# Fills the unit list including all file units
-_systemctl_really_all_units()
-{
- local -a all_unit_files;
- local -a really_all_units;
- if ( [[ ${+_sys_really_all_units} -eq 0 ]] || _cache_invalid SYS_REALLY_ALL_UNITS ) &&
- ! _retrieve_cache SYS_REALLY_ALL_UNITS;
- then
- all_unit_files=( $(__systemctl list-unit-files | { while read a b; do echo "$a"; done; }) )
- _systemctl_all_units
- really_all_units=($_sys_all_units $all_unit_files)
- _sys_really_all_units=(${(u)really_all_units})
- _store_cache SYS_REALLY_ALL_UNITS _sys_really_all_units
- fi
-}
-
-_filter_units_by_property() {
- local property=$1 value=$2 ; shift ; shift
- local -a units ; units=($*)
- local prop unit
- for ((i=1; $i <= ${#units[*]}; i++)); do
- # FIXME: "Failed to issue method call: Unknown unit" errors are ignored for
- # now (related to DBUS_ERROR_UNKNOWN_OBJECT). in the future, we need to
- # revert to calling 'systemctl show' once for all units, which is way
- # faster
- unit=${units[i]}
- prop=$(systemctl show --no-pager --property="$property" ${unit} 2>/dev/null)
- if [[ "${prop}" = "$property=$value" ]]; then
- echo "${unit}"
- fi
- done
-}
-
-_systemctl_active_units() {_sys_active_units=( $(__systemctl list-units | { while read a b; do echo "$a"; done; }) )}
-_systemctl_inactive_units(){_sys_inactive_units=($(__systemctl list-units --all | { while read a b c d; do [[ $c == "inactive" ]] && echo "$a"; done; }) )}
-_systemctl_failed_units() {_sys_failed_units=( $(__systemctl list-units --failed | { while read a b; do echo "$a"; done; }) )}
-_systemctl_enabled_units() {_sys_enabled_units=( $(__systemctl list-unit-files | { while read a b; do [[ $b == "enabled" ]] && echo "$a"; done; }) )}
-_systemctl_disabled_units(){_sys_disabled_units=($(__systemctl list-unit-files | { while read a b; do [[ $b == "disabled" ]] && echo "$a"; done; }) )}
-_systemctl_masked_units() {_sys_masked_units=( $(__systemctl list-unit-files | { while read a b; do [[ $b == "masked" ]] && echo "$a"; done; }) )}
-
-# Completion functions for ALL_UNITS
-for fun in is-active is-enabled status show mask preset ; do
- (( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
- {
- _systemctl_really_all_units
- compadd "$@" -a - _sys_really_all_units
- }
-done
-
-# Completion functions for ENABLED_UNITS
-for fun in disable reenable ; do
- (( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
- {
- _systemctl_enabled_units
- compadd "$@" -a - _sys_enabled_units
- }
-done
-
-# Completion functions for DISABLED_UNITS
-(( $+functions[_systemctl_enable] )) || _systemctl_enable()
-{
- _systemctl_disabled_units
- compadd "$@" -a - _sys_disabled_units
-}
-
-# Completion functions for FAILED_UNITS
-(( $+functions[_systemctl_reset-failed] )) || _systemctl_reset-failed()
-{
- _systemctl_failed_units
- compadd "$@" -a - _sys_failed_units || _message "no failed unit found"
-}
-
-# Completion functions for STARTABLE_UNITS
-(( $+functions[_systemctl_start] )) || _systemctl_start()
-{
- _systemctl_inactive_units
- compadd "$@" -a - _sys_inactive_units
-}
-
-# Completion functions for STOPPABLE_UNITS
-for fun in stop kill try-restart condrestart ; do
- (( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
- {
- _systemctl_active_units
- compadd "$@" - $( _filter_units_by_property CanStop yes \
- ${_sys_active_units[*]} )
- }
-done
-
-# Completion functions for ISOLATABLE_UNITS
-(( $+functions[_systemctl_isolate] )) || _systemctl_isolate()
-{
- _systemctl_all_units
- compadd "$@" - $( _filter_units_by_property AllowIsolate yes \
- ${_sys_all_units[*]} )
-}
-
-# Completion functions for RELOADABLE_UNITS
-for fun in reload reload-or-try-restart force-reload ; do
- (( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
- {
- _systemctl_active_units
- compadd "$@" - $( _filter_units_by_property CanReload yes \
- ${_sys_active_units[*]} )
- }
-done
-
-# Completion functions for RESTARTABLE_UNITS
-for fun in restart reload-or-restart ; do
- (( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
- {
- _systemctl_all_units
- compadd "$@" - $( _filter_units_by_property CanStart yes \
- ${_sys_all_units[*]} | while read line; do \
- [[ "$line" =~ \.(device|snapshot|socket|timer)$ ]] || echo "$line"; \
- done )
- }
-done
-
-# Completion functions for MASKED_UNITS
-(( $+functions[_systemctl_unmask] )) || _systemctl_unmask()
-{
- _systemctl_masked_units
- compadd "$@" -a - _sys_masked_units || _message "no masked unit found"
-}
-
-# Completion functions for JOBS
-(( $+functions[_systemctl_cancel] )) || _systemctl_cancel()
-{
- compadd "$@" - $(__systemctl list-jobs \
- | cut -d' ' -f1 2>/dev/null ) || _message "no job found"
-}
-
-# Completion functions for SNAPSHOTS
-(( $+functions[_systemctl_delete] )) || _systemctl_delete()
-{
- compadd "$@" - $(__systemctl list-units --type snapshot --all \
- | cut -d' ' -f1 2>/dev/null ) || _message "no snampshot found"
-}
-
-# Completion functions for ENVS
-for fun in set-environment unset-environment ; do
- (( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
- {
- local fun=$0 ; fun=${fun##_systemctl_}
- local suf
- if [[ "${fun}" = "set-environment" ]]; then
- suf='-S='
- fi
-
- compadd "$@" ${suf} - $(systemctl show-environment \
- | while read line; do echo "${line%%\=}";done )
- }
-done
-
-(( $+functions[_systemctl_link] )) || _systemctl_link() { _files }
-
-(( $+functions[_systemctl_switch-root] )) || _systemctl_switch-root()
-{
- if (( CURRENT == 2 )); then
- _directories
- fi
-}
-
-# no systemctl completion for:
-# [STANDALONE]='daemon-reexec daemon-reload default dot dump
-# emergency exit halt kexec list-jobs list-units
-# list-unit-files poweroff reboot rescue show-environment'
-# [NAME]='snapshot load'
-
-_systemctl_caching_policy()
-{
- local _sysunits
- local -a oldcache
-
- # rebuild if cache is more than a day old
- oldcache=( "$1"(mh+1) )
- (( $#oldcache )) && return 0
-
- _sysunits=($(__systemctl --all | cut -d' ' -f1))
-
- if (( $#_sysunits )); then
- for unit in $_sysunits; do
- [[ "$unit" -nt "$1" ]] && return 0
- done
- fi
-
- return 1
-}
-
-
-
-_systemd_loginctl_all_sessions(){_sys_all_sessions=($(systemd-loginctl list-sessions | { while read a b; do echo "$a"; done; }) )}
-_systemd_loginctl_all_users() {_sys_all_users=( $(systemd-loginctl list-users | { while read a b; do echo "$a"; done; }) )}
-_systemd_loginctl_all_seats() {_sys_all_seats=( $(systemd-loginctl list-seats | { while read a b; do echo "$a"; done; }) )}
-
-# Completion functions for SESSIONS
-for fun in session-status show-session activate lock-session unlock-session terminate-session kill-session ; do
- (( $+functions[_systemd_loginctl_$fun] )) || _systemd_loginctl_$fun()
- {
- _systemd_loginctl_all_sessions
- compadd "$@" -a - _sys_all_sessions
- }
-done
-
-# Completion functions for USERS
-for fun in user-status show-user enable-linger disable-linger terminate-user kill-user ; do
- (( $+functions[_systemd_loginctl_$fun] )) || _systemd_loginctl_$fun()
- {
- _systemd_loginctl_all_users
- compadd "$@" -a - _sys_all_users
- }
-done
-
-# Completion functions for SEATS
-(( $+functions[_systemd_loginctl_seats] )) || _systemd_loginctl_seats()
-{
- _systemd_loginctl_all_seats
- compadd "$@" -a - _sys_all_seats
-}
-for fun in seat-status show-seat terminate-seat ; do
- (( $+functions[_systemd_loginctl_$fun] )) || _systemd_loginctl_$fun()
- { _systemd_loginctl_seats }
-done
-
-# Completion functions for ATTACH
-(( $+functions[_systemd_loginctl_attach] )) || _systemd_loginctl_attach()
-{
- _systemd_loginctl_all_seats
-
- _arguments -w -C -S -s \
- ':seat:_systemd_loginctl_seats' \
- '*:device:_files'
-}
-
-# no systemd-loginctl completion for:
-# [STANDALONE]='list-sessions list-users list-seats flush-devices'
-
-(( $+functions[_systemd_loginctl_command] )) || _systemd_loginctl_command()
-{
- local -a _systemd_loginctl_cmds
- _systemd_loginctl_cmds=(
- "list-sessions:List sessions"
- "session-status:Show session status"
- "show-session:Show properties of one or more sessions"
- "activate:Activate a session"
- "lock-session:Screen lock one or more sessions"
- "unlock-session:Screen unlock one or more sessions"
- "terminate-session:Terminate one or more sessions"
- "kill-session:Send signal to processes of a session"
- "list-users:List users"
- "user-status:Show user status"
- "show-user:Show properties of one or more users"
- "enable-linger:Enable linger state of one or more users"
- "disable-linger:Disable linger state of one or more users"
- "terminate-user:Terminate all sessions of one or more users"
- "kill-user:Send signal to processes of a user"
- "list-seats:List seats"
- "seat-status:Show seat status"
- "show-seat:Show properties of one or more seats"
- "attach:Attach one or more devices to a seat"
- "flush-devices:Flush all device associations"
- "terminate-seat:Terminate all sessions on one or more seats"
- )
-
- if (( CURRENT == 1 )); then
- _describe -t commands 'systemd-loginctl command' _systemd_loginctl_cmds || compadd "$@"
- else
- local curcontext="$curcontext"
-
- cmd="${${_systemd_loginctl_cmds[(r)$words[1]:*]%%:*}}"
-
- if (( $#cmd )); then
- curcontext="${curcontext%:*:*}:systemd_loginctl-${cmd}:"
-
- _call_function ret _systemd_loginctl_$cmd || _message 'no more arguments'
- else
- _message "unknown systemd-loginctl command: $words[1]"
- fi
- return ret
- fi
-}
-
-_systemd "$@"
-
-# Local Variables:
-# mode: sh
-# sh-indentation: 2
-# indent-tabs-mode: nil
-# sh-basic-offset: 2
-# End:
diff --git a/Completion/Unix/Command/_tail b/Completion/Unix/Command/_tail
new file mode 100644
index 000000000..fbe30f13a
--- /dev/null
+++ b/Completion/Unix/Command/_tail
@@ -0,0 +1,69 @@
+#compdef tail
+
+local curcontext=$curcontext state state_descr line opts args ret=1
+typeset -A opt_args
+
+if _pick_variant gnu=GNU unix --version; then
+ args=(
+ '(-n --lines -c --bytes)'{-c+,--bytes=}'[print the last specified bytes; with +, start at the specified byte]:number of bytes:->number'
+ '(-n --lines -c --bytes)'{-n+,--lines=}'[print the last specified lines; with +, start at the specified line]:number of lines:->number'
+ '(-F -f)--follow=-[output appended data as the file grows]::how:(name descriptor)'
+ '(-F --follow)-f[same as --follow=descriptor]'
+ '(-f --follow --retry)-F[same as --follow=name --retry]'
+ '--max-unchanged-stats=[with --follow=name, check file rename after the specified number of iterations]:number of iterations'
+ '(-s --sleep-interval)'{-s+,--sleep-interval=}'[with -f, sleep the specfied seconds between iterations]:seconds'
+ '--pid=[with -f, terminate after the specified process dies]:pid:_pids'
+ '(-q --quiet --silent -v --verbose)'{-q,--quiet,--silent}'[never output headers giving file names]'
+ '(-q --quiet --silent -v --verbose)'{-v,--verbose}'[always output headers giving file names]'
+ '--retry[keep trying to open a file even when it becomes inaccessible]'
+ '(- *)--help[display help and exit]'
+ '(- *)--version[output version information and exit]'
+ )
+else
+ opts=(-A '-*')
+ args=(
+ '(-b -n)-c+[start at the specified byte]:bytes relative to the end (with +, beginning) of file'
+ '(-b -c)-n+[start at the specified line]:lines relative to the end (with +, beginning) of file'
+ '(-F -r)-f[wait for new data to be appended to the file]'
+ )
+ case $OSTYPE in
+ (freebsd*|darwin*|dragonfly*|netbsd*|openbsd*|solaris*)
+ args+=(
+ '(-f -F)-r[display the file in reverse order]'
+ )
+ ;|
+ (freebsd*|darwin*|dragonfly*|netbsd*|openbsd*)
+ args+=(
+ '(-c -n)-b+[start at the specified block (512-byte)]:blocks relative to the end (with +, beginning) of file'
+ )
+ ;|
+ (freebsd*|darwin*|dragonfly*|netbsd*)
+ args+=( '(-f -r)-F[implies -f, but also detect file rename]' )
+ ;|
+ (freebsd*|darwin*|dragonfly*)
+ args+=( '-q[suppress the headers when displaying multiple files]' )
+ ;;
+ esac
+fi
+
+_arguments -C -s -S $opts : $args '*:file:_files' && return
+
+case $state in
+ (number)
+ local mlt sign digit
+ mlt='multipliers:multiplier:((b\:512 K\:1024 KB\:1000 M\:1024\^2'
+ mlt+=' MB\:1000\^2 G\:1024\^3 GB\:1000\^3 T\:1024\^4 TB\:1000\^4))'
+ sign='signs:sign:((+\:"start at the specified byte/line"'
+ sign+=' -\:"output the last specified bytes/lines (default)"))'
+ digit='digits:digit:(0 1 2 3 4 5 6 7 8 9)'
+ if compset -P '*[0-9]'; then
+ _alternative $mlt $digit && ret=0
+ elif [[ -z $PREFIX ]]; then
+ _alternative $sign $digit && ret=0
+ elif compset -P '(+|-)'; then
+ _alternative $digit && ret=0
+ fi
+ ;;
+esac
+
+return ret
diff --git a/Completion/Unix/Command/_tmux b/Completion/Unix/Command/_tmux
index 49c2b63ed..d218cc3f3 100644
--- a/Completion/Unix/Command/_tmux
+++ b/Completion/Unix/Command/_tmux
@@ -1,6 +1,6 @@
#compdef tmux
-# tmux <http://tmux.sf.net> completion for zsh <http://zsh.sf.net>.
+# tmux <http://tmux.github.io> completion for zsh <http://zsh.sf.net>.
#
# Configuration:
#
@@ -640,7 +640,7 @@ function _tmux-new-session() {
'-t[specify target session]:sessions:__tmux-sessions'
'-x[specify width]:width:_guard "[0-9]#" "numeric value"'
'-y[specify height]:height:_guard "[0-9]#" "numeric value"'
- '*:: :_command'
+ '*:: :_cmdstring'
)
_arguments -s ${args}
}
@@ -657,7 +657,7 @@ function _tmux-new-window() {
'-n[specify a window name]:window name:'
'-P[print information about new window after it is created]'
'-t[specify target window]:windows:__tmux-windows'
- '*:: :_command'
+ '*:: :_cmdstring'
)
_arguments ${args}
}
@@ -776,7 +776,7 @@ function _tmux-respawn-pane() {
args=(
'-k[kill window if it is in use]'
'-t[choose target pane]:window:__tmux-pane'
- '*::command:_command'
+ '*::command:_cmdstring'
)
_arguments ${args}
}
@@ -787,7 +787,7 @@ function _tmux-respawn-window() {
args=(
'-k[kill window if it is in use]'
'-t[choose target window]:window:__tmux-windows'
- '*::command:_command'
+ '*::command:_cmdstring'
)
_arguments ${args}
}
@@ -809,7 +809,7 @@ function _tmux-run-shell() {
args=(
'-b[run shell command in background]'
'-t[choose target pane]:pane:__tmux-panes'
- '*::command:_command'
+ '*::command:_cmdstring'
)
_arguments ${args}
}
@@ -1042,7 +1042,7 @@ function _tmux-split-window() {
# changing the command's name might annoy users. So it stays like
# this.
'-t[choose target pane]:window:__tmux-panes'
- '*:: :_command'
+ '*:: :_cmdstring'
)
_arguments ${args} && return
}
@@ -1270,7 +1270,6 @@ function __tmux-option-guard() {
'history-limit:'${int_guard}
'lock-after-time:'${int_guard}
'lock-command:MSG:command string'
- 'lock-server:DESC:on off'
'message-command-style:__tmux-style'
'message-style:__tmux-style'
'mouse:DESC:on off'
@@ -1394,7 +1393,6 @@ function __tmux-session-options() {
'history-limit:number of copy-mode lines per window'
'lock-after-time:lock sessions after N seconds'
'lock-command:command to run for locking a client'
- 'lock-server:make lock-after-time lock the server instead of sessions'
'message-command-style:status line message command style'
'message-style:status line message style'
'mouse:enable mouse support'
diff --git a/Completion/Unix/Command/_tr b/Completion/Unix/Command/_tr
new file mode 100644
index 000000000..d55fab5ff
--- /dev/null
+++ b/Completion/Unix/Command/_tr
@@ -0,0 +1,53 @@
+#compdef tr
+
+local curcontext="$curcontext" state line expl ret=1
+local args variant
+local -A descr
+descr=(
+ -c '[complement characters specified by first string]'
+ -d '[delete specified characters from input]'
+ -s '[squeeze repeated instances of character to a single instance]'
+)
+
+_pick_variant -r variant gnu=GNU $OSTYPE --version
+case $variant in
+ gnu)
+ args=(
+ '(-c -C --complement)'{-c,-C,--complement}"${descr[-c]}"
+ '(-d --delete 2)'{-d,--delete}"${descr[-d]}"
+ '(-s --squeeze-repeats)'{-s,--squeeze-repeats}"${descr[-s]}"
+ '(- 1 2)--help[display help information]'
+ '(- 1 2)--version[display version information]'
+ )
+ ;;
+ darwin*|dragonfly*|*bsd*)
+ args+=( "(-c)-C$descr[-c]" )
+ ;|
+ darwin*|dragonfly*|freebsd*)
+ args+=( '-u[guarantee that output is unbuffered]' )
+ ;|
+ *)
+ for k in c d s; do
+ args+=( -$k$descr[$k] )
+ done
+ ;;
+esac
+
+_arguments -C -s $args \
+ '1:character set:->chsets' \
+ '2:character set:->chsets' && ret=0
+
+if [[ -n $state ]]; then
+ if compset -P '*\[:'; then
+ _wanted characters expl 'character class' \
+ compadd -S ":${${QIPREFIX:+]}:-\]}$compstate[quote] " \
+ alnum alpha blank cntrl digit graph lower print punct space upper \
+ xdigit && return
+ elif compset -P '*\\'; then
+ _describe -t characters character \
+ '(\\\\:backslash a:alert b:backspace f:form\ feed n:new\ line r:return t:tab v:vertical\ tab)' -S '' && return
+ fi
+ _message -e characters 'character set'
+fi
+
+return ret
diff --git a/Completion/Unix/Command/_user_admin b/Completion/Unix/Command/_user_admin
index 31ccbf1c2..3653308a1 100644
--- a/Completion/Unix/Command/_user_admin
+++ b/Completion/Unix/Command/_user_admin
@@ -44,8 +44,8 @@ if [[ $service = user* ]]; then
"(-U -p)-L[lock user's password]"
"(-L -p)-U[unlock user's password]"
)
+ [[ $OSTYPE = openbsd* ]] || args+=('-a[append groups]')
args+=(
- '-a[append groups]'
'-l[specify new user name]:new username'
':username:_users'
)
diff --git a/Completion/Unix/Command/_zfs b/Completion/Unix/Command/_zfs
index cd5ad3edc..f3869da43 100644
--- a/Completion/Unix/Command/_zfs
+++ b/Completion/Unix/Command/_zfs
@@ -2,7 +2,7 @@
# Synced with the S11U1 man page
_zfs() {
- local context state line expl
+ local context state line expl implementation
typeset -A opt_args
local -a subcmds rw_properties rw_propnames ro_properties create_properties
local -a share_nfs_ro_properties share_nfs_rw_properties
@@ -10,6 +10,8 @@ _zfs() {
local -a share_ro_properties share_rw_properties
local -a difffields delegatable_perms
+ _pick_variant -r implementation -c 'zpool upgrade -v' openzfs='This system supports ZFS pool feature flags' solaris
+
subcmds=(
"create" "destroy" "clone" "promote" "rename" "snapshot"
"rollback" "list" "set" "get" "inherit" "mount" "unmount"
@@ -18,6 +20,8 @@ _zfs() {
"diff" "key" "help"
)
+ [[ $OSTYPE == freebsd<7->.* ]] && subcmds+=(jail unjail)
+
share_nfs_ro_properties=(
"share.nfs.all"
)
@@ -531,6 +535,12 @@ _zfs() {
':filesystem or volume:_zfs_dataset -t fs -t vol'
;;
+ ("jail"|"unjail")
+ _arguments \
+ '1: : _jails' \
+ '2:filesystem:_zfs_dataset -t fs'
+ ;;
+
("help")
_arguments -A "-*" \
- set1 \
diff --git a/Completion/Unix/Command/_zpool b/Completion/Unix/Command/_zpool
index f2116dc2e..53022db8a 100644
--- a/Completion/Unix/Command/_zpool
+++ b/Completion/Unix/Command/_zpool
@@ -2,9 +2,11 @@
# Synced with the S11U1 man page
_zpool() {
- local context state line expl
+ local context state line expl implementation
local -a subcmds fields ro_props rw_props versions create_properties_dataset
+ _pick_variant -r implementation -c 'zpool upgrade -v' openzfs='This system supports ZFS pool feature flags' solaris
+
subcmds=(
create destroy add remove list iostat status online
offline clear attach detach replace scrub import export
diff --git a/Completion/Unix/Command/_zsh b/Completion/Unix/Command/_zsh
new file mode 100644
index 000000000..a5414670b
--- /dev/null
+++ b/Completion/Unix/Command/_zsh
@@ -0,0 +1,23 @@
+#compdef zsh
+
+local curcontext=$curcontext state state_descr line expl
+typeset -A opt_args
+
+_arguments -S -s : \
+ '*-o+[set named option]:option:_options' \
+ '*+o+[unset named option]:option:_options' \
+ '(1 -s --shinstdin)'{-s,--shinstdin}'[read commands from standard input]' \
+ '(-)-b[end of option processing, like --]' \
+ '(1 -)-c[run a command]:command:_cmdstring' \
+ '(-)1:script file:_files' \
+ '*::script arguments:->args' -- && return 0
+
+case $state in
+ (args)
+ if [[ -n ${opt_args[(I)-c|-s|--shinstdin]} ]]; then
+ _files
+ else
+ _normal
+ fi
+ ;;
+esac
diff --git a/Completion/Unix/Type/_zfs_dataset b/Completion/Unix/Type/_zfs_dataset
index 64e343f3a..5fa3e9e50 100644
--- a/Completion/Unix/Type/_zfs_dataset
+++ b/Completion/Unix/Type/_zfs_dataset
@@ -34,6 +34,8 @@ if [[ ${#rsrc} -gt 0 ]]; then
typearg=( -t snapshot )
elif [[ -n $words[(r)-p] ]]; then
typearg=( -t filesystem,volume )
+ elif [[ $implementation == openzfs ]]; then
+ typearg=( -t filesystem,snapshot,volume )
else
typearg=( -t filesystem,share,snapshot,volume )
fi
@@ -50,13 +52,13 @@ if [[ ${#rdst} -gt 0 ]]; then
else
# The parent dataset must be a filesystem, and can't rename
# a dataset into another pool. Plus we hardcode the expl.
- typearg=( -t fs -r ${${words[CURRENT - 1]}%%/*} )
+ typearg=( -t filesystem -r ${${words[CURRENT - 1]}%%/*} )
expl_type_arr=( -e "parent dataset" )
fi
fi
if [[ -n $type[(r)clone] ]]; then
- datasetlist=( ${="$(zfs list -H -o name,origin -t fs | awk "\$2 != \"-\" {print \$1}")":#no cloned filesystems available} )
+ datasetlist=( ${="$(zfs list -H -o name,origin -t filesystem | awk "\$2 != \"-\" {print \$1}")":#no cloned filesystems available} )
else
datasetlist=( ${="$(zfs list -H -o name $typearg)":#no datasets available} )
fi
diff --git a/Completion/Zsh/Command/_zsocket b/Completion/Zsh/Command/_zsocket
new file mode 100644
index 000000000..eeed9f1d8
--- /dev/null
+++ b/Completion/Zsh/Command/_zsocket
@@ -0,0 +1,14 @@
+#compdef zsocket
+
+_arguments -s -w -A "-*" \
+ '-v[verbose output]' \
+ '-d[target file descriptor]:fd:_file_descriptors' \
+ - outbound \
+ '1: :_files' \
+ - listen \
+ '-l[open a socket listening]' \
+ '1: :_files' \
+ - accept \
+ '-a[accept an incoming connection]' \
+ '-t[return if no incoming connections are pending]' \
+ '1:fd:{ (( words[(I)-*a*] )) && _file_descriptors }'
diff --git a/Completion/Zsh/Context/_brace_parameter b/Completion/Zsh/Context/_brace_parameter
index 9eb3465ae..e77d4c58b 100644
--- a/Completion/Zsh/Context/_brace_parameter
+++ b/Completion/Zsh/Context/_brace_parameter
@@ -31,7 +31,7 @@ if [[ $PREFIX = *'${('[^\)]# ]]; then
([gIjsZ_])
# Single delimited argument.
if [[ -z $PREFIX ]]; then
- _delimiters qualifer-$char
+ _delimiters qualifier-$char
return
elif ! _globqual_delims; then
# still completing argument
@@ -46,7 +46,7 @@ if [[ $PREFIX = *'${('[^\)]# ]]; then
_message 'integer expression'
;;
- (js)
+ ([js])
_message "separator"
;;
@@ -71,7 +71,7 @@ if [[ $PREFIX = *'${('[^\)]# ]]; then
([lr])
# One compulsory argument, two optional.
if [[ -z $PREFIX ]]; then
- _delimiters qualifer-$char
+ _delimiters qualifier-$char
return
else
delim=$PREFIX[1]
diff --git a/Completion/Zsh/Type/_delimiters b/Completion/Zsh/Type/_delimiters
index bb5bba8d0..d98d5a766 100644
--- a/Completion/Zsh/Type/_delimiters
+++ b/Completion/Zsh/Type/_delimiters
@@ -1,6 +1,6 @@
#autoload
-# Simple function to offer delimiters for modifiers and qualifers.
+# Simple function to offer delimiters for modifiers and qualifiers.
# Single argument is tag to use.
local expl
diff --git a/Completion/Zsh/Type/_globquals b/Completion/Zsh/Type/_globquals
index 5cdb8f7c4..2523eb333 100644
--- a/Completion/Zsh/Type/_globquals
+++ b/Completion/Zsh/Type/_globquals
@@ -47,7 +47,7 @@ while [[ -n $PREFIX ]]; do
(e)
# complete/skip delimited command line
if [[ -z $PREFIX ]]; then
- _delimiters qualifer-e
+ _delimiters qualifier-e
return
elif ! _globqual_delims; then
# still completing command to eval
diff --git a/Config/version.mk b/Config/version.mk
index 21577997b..ff259cd5b 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.1.1
-VERSION_DATE='September 11, 2015'
+VERSION=5.1.1-test-1
+VERSION_DATE='November 21, 2015'
diff --git a/Doc/Makefile.in b/Doc/Makefile.in
index 7645f42f7..d5899917e 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -62,8 +62,8 @@ Zsh/mod_computil.yo Zsh/mod_curses.yo \
Zsh/mod_datetime.yo Zsh/mod_db_gdbm.yo Zsh/mod_deltochar.yo \
Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_langinfo.yo \
Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_newuser.yo \
-Zsh/mod_parameter.yo Zsh/mod_pcre.yo Zsh/mod_regex.yo \
-Zsh/mod_sched.yo Zsh/mod_socket.yo \
+Zsh/mod_parameter.yo Zsh/mod_pcre.yo Zsh/mod_private.yo \
+Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
Zsh/mod_stat.yo Zsh/mod_system.yo Zsh/mod_tcp.yo \
Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_zleparameter.yo \
diff --git a/Doc/Zsh/arith.yo b/Doc/Zsh/arith.yo
index 1dcd18cad..c152bf48d 100644
--- a/Doc/Zsh/arith.yo
+++ b/Doc/Zsh/arith.yo
@@ -215,7 +215,7 @@ findex(integer, use of)
Arithmetic evaluation is performed on the value of each
assignment to a named parameter declared integer
in this manner. Assigning a floating point number to an integer results in
-rounding down to the next integer.
+rounding towards zero.
cindex(parameters, floating point)
cindex(floating point parameters)
@@ -230,16 +230,16 @@ format.
Promotion of integer to floating point values is performed where
necessary. In addition, if any operator which requires an integer
-(`tt(~)', `tt(&)', `tt(|)', `tt(^)', `tt(%)', `tt(<<)', `tt(>>)' and their
-equivalents with assignment) is given a floating point argument, it will be
-silently rounded down to the next integer.
+(`tt(&)', `tt(|)', `tt(^)', `tt(<<)', `tt(>>)' and their equivalents with
+assignment) is given a floating point argument, it will be silently rounded
+towards zero except for `tt(~)' which rounds down.
Users should beware that, in common with many other programming
languages but not software designed for calculation, the evaluation of
an expression in zsh is taken a term at a time and promotion of integers
to floating point does not occur in terms only containing integers. A
typical result of this is that a division such as tt(6/8) is truncated,
-in this being rounded down to 0. The tt(FORCE_FLOAT) shell option can
+in this being rounded towards 0. The tt(FORCE_FLOAT) shell option can
be used in scripts or functions where floating point evaluation is
required throughout.
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 5bbe7e70b..49806e4d8 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -144,8 +144,12 @@ findex(autoload)
cindex(functions, autoloading)
cindex(autoloading functions)
item(tt(autoload) [ {tt(PLUS())|tt(-)}tt(TUXkmtz) ] [ tt(-w) ] [ var(name) ... ])(
+vindex(fpath, searching)
Equivalent to tt(functions -u), with the exception of tt(-X)/tt(+X) and
-tt(-w).
+tt(-w). 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
@@ -473,7 +477,7 @@ cindex(compatibility, csh)
cindex(sh, compatibility)
cindex(ksh, compatibility)
cindex(csh, compatibility)
-item(tt(emulate) [ tt(-LR) ] [ {tt(zsh)|tt(sh)|tt(ksh)|tt(csh)} [ var(flags) ... ] ])(
+item(tt(emulate) [ tt(-lLR) ] [ {tt(zsh)|tt(sh)|tt(ksh)|tt(csh)} [ var(flags) ... ] ])(
Without any argument print current emulation mode.
With single argument set up zsh options to emulate the specified shell
@@ -514,6 +518,14 @@ function, if any; normally these options are turned off in all emulation
modes except tt(ksh). The tt(-L) switch is mutually exclusive with the
use of tt(-c) in var(flags).
+If there is a single argument and the tt(-l) switch is given, the
+options that would be set or unset (the latter indicated with the prefix
+`tt(no)') are listed. tt(-l) can be combined with tt(-L) or tt(-R) and
+the list will be modified in the appropriate way. Note the list does
+not depend on the current setting of options, i.e. it includes all
+options that may in principle change, not just those that would actually
+change.
+
The var(flags) may be any of the invocation-time flags described in
ifnzman(noderef(Invocation))\
ifzman(the section INVOCATION in zmanref(zsh)),
@@ -546,8 +558,7 @@ For example:
example(emulate sh -c 'fni+LPAR()RPAR() { setopt cshnullglob; }
fno+LPAR()RPAR() { fni; }'
-fno
-)
+fno)
The two functions tt(fni) and tt(fno) are defined with sticky tt(sh)
emulation. tt(fno) is then executed, causing options associated
@@ -1981,12 +1992,8 @@ for this function; the flag tt(-T) does the same, but turns off tracing
on any function called from the present one, unless that function also
has the tt(-t) or tt(-T) flag. The tt(-u) and tt(-U) flags cause the
function to be marked for autoloading; tt(-U) also causes alias
-expansion to be suppressed when the function is loaded. The tt(fpath)
-parameter will be searched to find the function definition when the
-function is first referenced; see noderef(Functions). The tt(-k) and
-tt(-z) flags make the function be loaded using ksh-style or zsh-style
-autoloading respectively. If neither is given, the setting of the
-tt(KSH_AUTOLOAD) option determines how the function is loaded.
+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.
@@ -2320,7 +2327,7 @@ item(tt(zcompile -t) var(file) [ var(name) ... ])(
This builtin command can be used to compile functions or scripts,
storing the compiled form in a file, and to examine files containing
the compiled form. This allows faster autoloading of functions and
-execution of scripts by avoiding parsing of the text when the files
+sourcing of scripts by avoiding parsing of the text when the files
are read.
The first form (without the tt(-c), tt(-a) or tt(-t) options) creates a
@@ -2338,6 +2345,7 @@ noderef(Functions)
for a description of how autoloaded functions are searched. The
extension tt(.zwc) stands for `zsh word code'.
+vindex(fpath, with zcompile)
If there is at least one var(name) argument, all the named files
are compiled into the output var(file) given as the first argument. If
var(file) does not end in tt(.zwc), this extension is automatically
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index d067795dd..d6b180301 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -3982,6 +3982,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
diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo
index 40cabea88..c01763316 100644
--- a/Doc/Zsh/compwid.yo
+++ b/Doc/Zsh/compwid.yo
@@ -899,8 +899,8 @@ var(lanchor), the var(ranchor) only needs to match the trial
completion string.
The tt(b) and tt(B) forms are similar to tt(l) and tt(L) with an empty
-anchor, but need to match only the beginning of the trial completion
-or the word on the command line, respectively.
+anchor, but need to match only the beginning of the word on the command line
+or trial completion, respectively.
)
xitem(tt(r:)var(lpat)tt(|)var(ranchor)tt(=)var(tpat))
xitem(tt(R:)var(lpat)tt(|)var(ranchor)tt(=)var(tpat))
@@ -911,7 +911,7 @@ item(tt(E:)var(lpat)tt(=)var(tpat))(
As tt(l), tt(L), tt(b) and tt(B), with the difference that the command
line and trial completion patterns are anchored on the right side.
Here an empty var(ranchor) and the tt(e) and tt(E) forms force the
-match to the end of the trial completion or command line string.
+match to the end of the command line or trial completion string.
)
enditem()
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 741d4ad07..07a5eb08e 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -12,6 +12,7 @@ such as shell functions, look for comments in the function source files.
startmenu()
menu(Utilities)
menu(Recent Directories)
+menu(Other Directory Functions)
menu(Version Control Information)
menu(Prompt Themes)
menu(ZLE Functions)
@@ -324,7 +325,7 @@ options tt(-Uz) are appropriate.
)
enditem()
-texinode(Recent Directories)(Version Control Information)(Utilities)(User Contributions)
+texinode(Recent Directories)(Other Directory Functions)(Utilities)(User Contributions)
cindex(recent directories, maintaining list of)
cindex(directories, maintaining list of recent)
findex(cdr)
@@ -414,6 +415,18 @@ newlines, where I have in any case no sympathy); directories are in
unabbreviated from and contain an absolute path, i.e. they start with tt(/).
Usually the first entry should be left as the current directory.
)
+item(tt(-p ')var(pattern)tt('))(
+Prunes any items in the directory list that match the given extended glob
+pattern; the pattern needs to be quoted from immediate expansion on the
+command line. The pattern is matched against each completely expanded
+file name in the list; the full string must match, so wildcards at the
+end (e.g. tt('*removeme*')) are needed to remove entries with a given
+substring.
+
+If output is to a terminal, then the function will print the new list
+after pruning and prompt for confirmation by the user. This output and
+confirmation step can be skipped by using tt(-P) instead of tt(-p).
+)
enditem()
subsect(Configuration)
@@ -585,7 +598,189 @@ avoid side effects if the change to the directory is to be invisible at the
command line. See the contents of the function tt(chpwd_recent_dirs) for
more details.
-texinode(Version Control Information)(Prompt Themes)(Recent Directories)(User Contributions)
+texinode(Other Directory Functions)(Version Control Information)(Recent Directories)(User Contributions)
+cindex(directories, named, dynamic, helper function)
+cindex(dynamic directory naming, helper function)
+cindex(named directories, dynamic, helper function)
+findex(zsh_directory_name_generic)
+sect(Abbreviated dynamic references to directories)
+
+The dynamic directory naming system is described in the subsection
+em(Dynamic named directories) of
+ifzman(the section em(Filename Expansion) in zmanref(expn))\
+ifnzman(noderef(Filename Expansion)). In this, a reference to
+tt(~[)var(...)tt(]) is expanded by a function found by the hooks
+mechanism.
+
+The contributed function tt(zsh_directory_name_generic) provides a
+system allowing the user to refer to directories with only a limited
+amount of new code. It supports all three of the standard interfaces
+for directory naming: converting from a name to a directory, converting
+in the reverse direction to find a short name, and completion of names.
+
+The main feature of this function is a path-like syntax,
+combining abbreviations at multiple levels separated by ":".
+As an example, ~[g:p:s] might specify:
+startitem()
+item(tt(g))(
+The top level directory for your git area. This first component
+has to match, or the function will retrun indicating another
+directory name hook function should be tried.
+)
+item(tt(p))(
+The name of a project within your git area.
+)
+item(tt(s))(
+The source area within that project.
+)
+enditem()
+This allows you to collapse references to long hierarchies to a very
+compact form, particularly if the hierarchies are similar across different
+areas of the disk.
+
+Name components may be completed: if a description is shown at the top
+of the list of completions, it includes the path to which previous
+components expand, while the description for an individual completion
+shows the path segment it would add. No additional configuration is
+needed for this as the completion system is aware of the dynamic
+directory name mechanism.
+
+subsect(Usage)
+
+To use the function, first define a wrapper function for your specific
+case. We'll assume it's to be autoloaded. This can have any name but
+we'll refer to it as zdn_mywrapper. This wrapper function will define
+various variables and then call this function with the same arguments
+that the wrapper function gets. This configuration is described below.
+
+Then arrange for the wrapper to be run as a zsh_directory_name hook:
+
+example(autoload -Uz add-zsh-hook zsh_diretory_name_generic zdn_mywrapper
+add-zsh-hook -U zsh_directory_name zdn_mywrapper)
+
+subsect(Configuration)
+
+The wrapper function should define a local associative array zdn_top.
+Alternatively, this can be set with a style called tt(mapping). The
+context for the style is tt(:zdn:)var(wrapper-name) where
+var(wrapper-name) is the function calling zsh_directory_name_generic;
+for example:
+
+example(zstyle :zdn:zdn_mywrapper: mapping zdn_mywrapper_top)
+
+The keys in this associative array correspond to the first component of
+the name. The values are matching directories. They may have an
+optional suffix with a slash followed by a colon and the name of a
+variable in the same format to give the next component. (The slash
+before the colon is to disambiguate the case where a colon is needed in
+the path for a drive. There is otherwise no syntax for escaping this,
+so path components whose names start with a colon are not supported.) A
+special component tt(:default:) specifies a variable in the form
+tt(/:)var(var) (the path section is ignored and so is usually empty)
+that will be used for the next component if no variable is given for the
+path. Variables referred to within tt(zdn_top) have the same format as
+tt(zdn_top) itself, but contain relative paths.
+
+For example,
+
+example(local -A zdn_top=(
+ g ~/git
+ ga ~/alternate/git
+ gs /scratch/$USER/git/:second2
+ :default: /:second1
+))
+
+This specifies the behaviour of a directory referred to as tt(~[g:...])
+or tt(~[ga:...]) or tt(~[gs:...]). Later path components are optional;
+in that case tt(~[g]) expands to tt(~/git), and so on. tt(gs) expands
+to tt(/scratch/$USER/git) and uses the associative array tt(second2) to
+match the second component; tt(g) and tt(ga) use the associative array
+tt(second1) to match the second component.
+
+When expanding a name to a directory, if the first component is not tt(g) or
+tt(ga) or tt(gs), it is not an error; the function simply returns 1 so that a
+later hook function can be tried. However, matching the first component
+commits the function, so if a later component does not match, an error
+is printed (though this still does not stop later hooks from being
+executed).
+
+For components after the first, a relative path is expected, but note that
+multiple levels may still appear. Here is an example of tt(second1):
+
+example(local -A second1=(
+ p myproject
+ s somproject
+ os otherproject/subproject/:third
+))
+
+The path as found from tt(zdn_top) is extended with the matching
+directory, so tt(~[g:p]) becomes tt(~/git/myproject). The slash between
+is added automatically (it's not possible to have a later component
+modify the name of a directory already matched). Only tt(os) specifies
+a variable for a third component, and there's no tt(:default:), so it's
+an error to use a name like tt(~[g:p:x]) or tt(~[ga:s:y]) because
+there's nowhere to look up the tt(x) or tt(y).
+
+The associative arrays need to be visible within this function; the
+generic function therefore uses internal variable names beginning
+tt(_zdn_) in order to avoid clashes. Note that the variable tt(reply)
+needs to be passed back to the shell, so should not be local in the
+calling function.
+
+The function does not test whether directories assembled by component
+actually exist; this allows the system to work across automounted
+file systems. The error from the command trying to use a non-existent
+directory should be sufficient to indicate the problem.
+
+subsect(Complete example)
+
+Here is a full fictitious but usable autoloadable definition of the
+example function defined by the code above. So tt(~[gs:p:s]) expands
+to tt(/scratch/$USER/git/myscratchproject/top/srcdir) (with tt($USER)
+also expanded).
+
+example(local -A zdn_top=(
+ g ~/git
+ ga ~/alternate/git
+ gs /scratch/$USER/git/:second2
+ :default: /:second1
+)
+
+local -A second1=(
+ p myproject
+ s somproject
+ os otherproject/subproject/:third
+)
+
+local -A second2=(
+ p myscratchproject
+ s somescratchproject
+)
+
+local -A third=(
+ s top/srcdir
+ d top/documentation
+)
+
+# autoload not needed if you did this at initialisation...
+autoload -Uz zsh_directory_name_generic
+zsh_directory_name_generic "$@)
+
+It is also possible to use global associative arrays, suitably named,
+and set the style for the context of your wrapper function to
+refer to this. Then your set up code would contain the following:
+
+example(typeset -A zdn_mywrapper_top=(...)
+# ... and so on for other associative arrays ...
+zstyle ':zdn:zdn_mywrapper:' mapping zdn_mywrapper_top
+autoload -Uz add-zsh-hook zsh_directory_name_generic zdn_mywrapper
+add-zsh-hook -U zsh_directory_name zdn_mywrapper)
+
+and the function tt(zdn_mywrapper) would contain only the following:
+
+example(zsh_directory_name_generic "$@")
+
+texinode(Version Control Information)(Prompt Themes)(Other Directory Functions)(User Contributions)
sect(Gathering information from version control systems)
cindex(version control utility)
@@ -1137,7 +1332,7 @@ otherwise would be something like `svn' or `cvs') will be set to
identifier is the second element. tt(vcs_info) will have filled in a proper
value for the "repository's" root directory and the string containing the
information about quilt's state will be available as the `misc' replacement
-(and tt(%Q) for compatibility with `addon' mode.
+(and tt(%Q) for compatibility with `addon' mode).
What is left to discuss is how `standalone' mode is detected. The detection
itself is a series of searches for directories. You can have this detection
@@ -1560,7 +1755,7 @@ a customised bookmark string for the tt(hg) backend.
Again, we start off by registering a function:
example(zstyle ':vcs_info:hg+gen-hg-bookmark-string:*' hooks hgbookmarks)
-And then we define the `tt(+vi-hgbookmarks) function:
+And then we define the `tt(+vi-hgbookmarks)' function:
example(
function +vi-hgbookmarks+LPAR()RPAR() {
# The default is to connect all bookmark names by
@@ -1585,8 +1780,7 @@ function +vi-hgbookmarks+LPAR()RPAR() {
# something other than the default zero:
ret=1
return 0
-}
-)
+})
Some longer examples and code snippets which might be useful are available in
the examples file located at Misc/vcs_info-examples in the Zsh source
@@ -1705,7 +1899,10 @@ item(tt(select-word-style), tt(match-word-context), tt(match-words-by-style))(
The eight `tt(-match)' functions are drop-in replacements for the
builtin widgets without the suffix. By default they behave in a similar
way. However, by the use of styles and the function tt(select-word-style),
-the way words are matched can be altered.
+the way words are matched can be altered. For comparison, the widgets
+described in ifzman(zmanref(zshzle) under Text Objects)\
+ifnzman(noderef(Text Objects)) use fixed definitions of words, compatible
+with the tt(vim) editor.
The simplest way of configuring the functions is to use
tt(select-word-style), which can either be called as a normal function with
@@ -1818,9 +2015,10 @@ matched against each var(pattern) in turn until one matches; if it does,
the context is extended by a colon and the corresponding var(subcontext).
Note that the test is made against the original word on the line, with no
stripping of quotes. Special handling is done between words: the current
-context is examined and if it contains the string tt(back), the word before
-the cursor is considered, else the word after cursor is considered. Some
-examples are given below.
+context is examined and if it contains the string tt(between) the word
+is set to a single space; else if it is contains the string tt(back),
+the word before the cursor is considered, else the word after cursor is
+considered. Some examples are given below.
The style tt(skip-whitespace-first) is only used with the
tt(forward-word) widget. If it is set to true, then tt(forward-word)
@@ -1895,6 +2093,100 @@ The tt(word-context) style is implemented by the function
tt(match-word-context). This should not usually need to be called
directly.
)
+tindex(bracketed-paste-magic)
+item(bracketed-paste-magic)(
+The tt(bracketed-paste) widget (see ifzman(subsection Miscellaneous in
+zmanref(zshzle))ifnzman(noderef(Miscellaneous) in noderef(Zle Widgets)))
+inserts pasted text literally into the editor buffer rather than interpret
+it as keystrokes. This disables some common usages where the self-insert
+widget is replaced in order to accomplish some extra processing. An
+example is the contributed tt(url-quote-magic) widget described below.
+
+The tt(bracketed-paste-magic) widget is meant to replace tt(bracketed-paste)
+with a wrapper that re-enables these self-insert actions, and other
+actions as selected by zstyles. Therefore this widget is installed with
+ifzman()
+example(autoload -Uz bracketed-paste-magic
+zle -N bracketed-paste bracketed-paste-magic)
+
+Other than enabling some widget processing, tt(bracketed-paste-magic)
+attempts to replicate tt(bracketed-paste) as faithfully as possible.
+
+The following zstyles may be set to control processing of pasted text.
+All are looked up in the context `tt(:bracketed-paste-magic)'.
+
+startitem()
+item(tt(active-widgets))(
+A list of patterns matching widget names that should be activated during
+the paste. All other key sequences are processed as self-insert-unmeta.
+The default is `tt(self-*)' so any user-defined widgets named with that
+prefix are active along with the builtin self-insert.
+
+If this style is not set (explicitly deleted) or set to an empty value,
+no widgets are active and the pasted text is inserted literally. If the
+value includes `tt(undefined-key)', any unknown sequences are discarded
+from the pasted text.
+)
+item(tt(inactive-keys))(
+The inverse of tt(active-widgets), a list of key sequences that always use
+tt(self-insert-unmeta) even when bound to an active widget. Note that
+this is a list of literal key sequences, not patterns.
+)
+item(tt(paste-init))(
+A list of function names, called in widget context (but not as widgets).
+The functions are called in order until one of them returns a non-zero
+status. The parameter `tt(PASTED)' contains the initial state of the
+pasted text. All other ZLE parameters such as `tt(BUFFER)' have their
+normal values and side-effects, and full history is available, so for
+example tt(paste-init) functions may move words from tt(BUFFER) into
+tt(PASTED) to make those words visible to the tt(active-widgets).
+
+A non-zero return from a tt(paste-init) function does em(not) prevent the
+paste itself from proceeding.
+
+Loading tt(bracketed-paste-magic) defines tt(backward-extend-paste), a
+helper function for use in tt(paste-init).
+
+example(zstyle :bracketed-paste-magic paste-init \
+ backward-extend-paste)
+
+When a paste would insert into the middle of a word or append text to a
+word already on the line, tt(backward-extend-paste) moves the prefix
+from tt(LBUFFER) into tt(PASTED) so that the tt(active-widgets) see the
+full word so far. This may be useful with tt(url-quote-magic).
+)
+item(tt(paste-finish))(
+Another list of function names called in order until one returns non-zero.
+These functions are called em(after) the pasted text has been processed
+by the tt(active-widgets), but em(before) it is inserted into `tt(BUFFER)'.
+ZLE parameters have their normal values and side-effects.
+
+A non-zero return from a tt(paste-finish) function does em(not) prevent
+the paste itself from proceeding.
+
+Loading tt(bracketed-paste-magic) also defines tt(quote-paste), a helper
+function for use in tt(paste-finish).
+
+example(zstyle :bracketed-paste-magic paste-finish \
+ quote-paste
+zstyle :bracketed-paste-magic:finish quote-style \
+ qqq)
+
+When the pasted text is inserted into tt(BUFFER), it is quoted per the
+tt(quote-style) value. To forcibly turn off the built-in numeric prefix
+quoting of tt(bracketed-paste), use:
+
+example(zstyle :bracketed-paste-magic:finish quote-style \
+ none)
+)
+enditem()
+
+em(Important:) During tt(active-widgets) processing of the paste (after
+tt(paste-init) and before tt(paste-finish)), tt(BUFFER) starts empty and
+history is restricted, so cursor motions, etc., may not pass outside of
+the pasted content. Text assigned to tt(BUFFER) by the active widgets
+is copied back into tt(PASTED) before tt(paste-finish).
+)
tindex(copy-earlier-word)
item(tt(copy-earlier-word))(
This widget works like a combination of tt(insert-last-word) and
@@ -2557,6 +2849,69 @@ start of the previous line. Using a numeric argument less than -1
has the effect of moving the line above the cursor up by minus that
number of lines.
)
+tindex(url-quote-magic)
+item(tt(url-quote-magic))(
+This widget replaces the built-in tt(self-insert) to make it easier to
+type URLs as command line arguments. As you type, the input character is
+analyzed and, if it may need quoting, the current word is checked for a
+URI scheme. If one is found and the current word is not already in
+quotes, a backslash is inserted before the input character.
+
+Styles to control quoting behavior:
+
+startitem()
+item(tt(url-metas))(
+This style is looked up in the context `tt(:url-quote-magic:)var(scheme)'
+(where var(scheme) is that of the current URL, e.g. "tt(ftp)"). The value
+is a string listing the characters to be treated as globbing
+metacharacters when appearing in a URL using that scheme. The default is
+to quote all zsh extended globbing characters, excluding 'tt(<)' and
+'tt(>)' but including braces (as in brace expansion). See also
+tt(url-seps).
+)
+item(tt(url-seps))(
+Like tt(url-metas), but lists characters that should be considered command
+separators, redirections, history references, etc. The default is to
+quote the standard set of shell separators, excluding those that overlap
+with the extended globbing characters, but including 'tt(<)' and
+'tt(>)' and the first character of tt($histchars).
+)
+item(tt(url-globbers))(
+This style is looked up in the context `tt(:url-quote-magic)'. The values
+form a list of command names that are expected to do their own globbing
+on the URL string. This implies that they are aliased to use the
+`tt(noglob)' modifier. When the first word on the line matches one of the
+values em(and) the URL refers to a local file (see tt(url-local-schema)),
+only the tt(url-seps) characters are quoted; the tt(url-metas) are left
+alone, allowing them to affect command-line parsing, completion, etc. The
+default values are a literal `tt(noglob)' plus (when the tt(zsh/parameter)
+module is available) any commands aliased to the helper function
+`tt(urlglobber)' or its alias `tt(globurl)'.
+)
+item(tt(url-local-schema))(
+This style is always looked up in the context `tt(:urlglobber)', even
+though it is used by both url-quote-magic and urlglobber. The values form
+a list of URI schema that should be treated as referring to local files by
+their real local path names, as opposed to files which are specified
+relative to a web-server-defined document root. The defaults are
+"tt(ftp)" and "tt(file)".
+)
+item(tt(url-other-schema))(
+Like tt(url-local-schema), but lists all other URI schema upon which
+tt(urlglobber) and tt(url-quote-magic) should act. If the URI on the
+command line does not have a scheme appearing either in this list or in
+tt(url-local-schema), it is not magically quoted. The default values are
+"tt(http)", "tt(https)", and "tt(ftp)". When a scheme appears both here
+and in tt(url-local-schema), it is quoted differently depending on whether
+the command name appears in tt(url-globbers).
+)
+enditem()
+
+Loading tt(url-quote-magic) also defines a helper function `tt(urlglobber)'
+and aliases `tt(globurl)' to `tt(noglob urlglobber)'. This function takes
+a local URL apart, attempts to pattern-match the local file portion of the
+URL path, and then puts the results back into URL format again.
+)
tindex(which-command)
item(tt(which-command))(
This function is a drop-in replacement for the builtin widget
@@ -3314,6 +3669,14 @@ integer arithmetic, which is not how an ordinary desk calculator
operates. To force floating point operation, pass the option tt(-f);
see further notes below.
+If the file tt(~/.zcalcrc) exists it will be sourced inside the function
+once it is set up and about to process the command line. This
+can be used, for example, to set shell options; tt(emulate -L zsh)
+and tt(setopt extendedglob) are in effect at this point. Any
+failure to source the file if it exists is treated as fatal.
+As with other initialisation files, the directory tt($ZDOTDIR) is used
+instead of tt($HOME) if it is set.
+
The mathematical library tt(zsh/mathfunc) will be loaded if it is
available; see
ifzman(the section `The zsh/mathfunc Module' in zmanref(zshmodules))\
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 5ea8610f2..564c70dd1 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -410,6 +410,12 @@ are only expanded when first parsing command or assignment arguments.
Process substitutions may be used following redirection operators; in this
case, the substitution must appear with no trailing string.
+Note that `tt(<<LPAR())var(list)tt(RPAR())' is not a special syntax; it
+is equivalent to `tt(< <LPAR())var(list)tt(RPAR())', redirecting
+standard input from the result of process substitution. Hence all
+the following documentation applies. The second form (with the space)
+is recommended for clarity.
+
In the case of the tt(<) or tt(>) forms, the shell runs the commands in
var(list) as a subprocess of the job executing the shell command line.
If the system supports the tt(/dev/fd)
@@ -1033,7 +1039,16 @@ var(name) used in this fashion.
If used with a nested parameter or command substitution, the result of that
will be taken as a parameter name in the same way. For example, if you
have `tt(foo=bar)' and `tt(bar=baz)', the strings tt(${(P)foo}),
-tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to `tt(baz)'.
+tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to
+`tt(baz)'.
+
+Likewise, if the reference is itself nested, the expression with the
+flag is treated as if it were directly replaced by the parameter name.
+It is an error if this nested substitution produces an array with more
+than one word. For example, if `tt(name=assoc)' where the parameter
+tt(assoc) is an associative array, then
+`tt(${${(P)name}[elt]})' refers to the element of the associative
+subscripted `tt(elt)'.
)
item(tt(q))(
Quote characters that are special to the shell in the resulting words with
@@ -1371,9 +1386,13 @@ outermost. The flags are not propagated up to enclosing
substitutions; the nested substitution will return either a scalar or an
array as determined by the flags, possibly adjusted for quoting. All the
following steps take place where applicable at all levels of substitution.
-Note that, unless the `tt((P))' flag is present, the flags and any subscripts
-apply directly to the value of the nested substitution; for example, the
-expansion tt(${${foo}}) behaves exactly the same as tt(${foo}).
+
+Note that, unless the `tt((P))' flag is present, the flags and any
+subscripts apply directly to the value of the nested substitution; for
+example, the expansion tt(${${foo}}) behaves exactly the same as
+tt(${foo}). When the `tt((P))' flag is present in a nested substitution,
+the other substitution rules are applied to the value em(before) it is
+interpreted as a name, so tt(${${(P)foo}}) may differ from tt(${(P)foo}).
At each nested level of substitution, the substituted words undergo all
forms of single-word substitution (i.e. not filename generation), including
@@ -1386,11 +1405,18 @@ substitution then applies the modifier tt(:h) and takes the directory part
of the path.)
)
item(tt(2.) em(Internal parameter flags))(
-Any parameter flags set by one of the tt(typeset) family of commands,
-in particular the tt(L), tt(R), tt(Z), tt(u) and tt(l) flags for padding
-and capitalization, are applied directly to the parameter value.
-Note these flags are options to the command, e.g. `tt(typeset -Z)';
-they are not the same as the flags used within parameter substitutions.
+Any parameter flags set by one of the tt(typeset) family of commands, in
+particular the tt(-L), tt(-R), tt(-Z), tt(-u) and tt(-l) options for
+padding and capitalization, are applied directly to the parameter value.
+Note these flags are options to the command, e.g. `tt(typeset -Z)'; they
+are not the same as the flags used within parameter substitutions.
+
+At the outermost level of substitution, the `tt((P))' flag (rule tt(4.))
+ignores these transformations and uses the unmodified value of the
+parameter as the name to be replaced. This is usually the desired
+behavior because padding may make the value syntactically illegal as a
+parameter name, but if capitalization changes are desired, use the
+tt(${${(P)foo}}) form (rule tt(25.)).
)
item(tt(3.) em(Parameter subscripting))(
If the value is a raw parameter reference with a subscript, such as
@@ -1401,19 +1427,25 @@ subscript. Thus if tt(var) is an array, tt(${var[1][2]}) is the second
character of the first word, but tt(${var[2,4][2]}) is the entire third
word (the second word of the range of words two through four of the
original array). Any number of subscripts may appear. Flags such as
-tt((k)) and tt((v)) which alter the result of subscripting are applied.
+`tt((k))' and `tt((v))' which alter the result of subscripting are applied.
)
item(tt(4.) em(Parameter name replacement))(
-The effect of any tt((P)) flag, which treats the value so far as a
-parameter name and replaces it with the corresponding value, is applied.
+At the outermost level of nesting only, the `tt((P))' flag is applied. This
+treats the value so far as a parameter name (which may include a subscript
+expression) and replaces that with the corresponding value. This
+replacement occurs later if the `tt((P))' flag appears in a nested
+substitution.
+
+If the value so far names a parameter that has internal flags (rule tt(2.)),
+those internal flags are applied to the new value after replacement.
)
item(tt(5.) em(Double-quoted joining))(
If the value after this process is an array, and the substitution
-appears in double quotes, and neither an tt((@)) flag nor a tt(#)
+appears in double quotes, and neither an `tt((@))' flag nor a `tt(#)'
length operator is present at the current level, then words of the
value are joined with the first character of the parameter tt($IFS),
by default a space, between each word (single word arrays are not
-modified). If the tt((j)) flag is present, that is used for joining
+modified). If the `tt((j))' flag is present, that is used for joining
instead of tt($IFS).
)
item(tt(6.) em(Nested subscripting))(
@@ -1427,22 +1459,22 @@ returns a scalar because of the quotes).
)
item(tt(7.) em(Modifiers))(
Any modifiers, as specified by a trailing `tt(#)', `tt(%)', `tt(/)'
-(possibly doubled) or by a set of modifiers of the form tt(:...) (see
+(possibly doubled) or by a set of modifiers of the form `tt(:...)' (see
noderef(Modifiers) in noderef(History Expansion)), are applied to the words
of the value at this level.
)
item(tt(8.) em(Character evaluation))(
-Any tt((#)) flag is applied, evaluating the result so far numerically
+Any `tt((#))' flag is applied, evaluating the result so far numerically
as a character.
)
item(tt(9.) em(Length))(
-Any initial tt(#) modifier, i.e. in the form tt(${#)var(var)tt(}), is
+Any initial `tt(#)' modifier, i.e. in the form tt(${#)var(var)tt(}), is
used to evaluate the length of the expression so far.
)
item(tt(10.) em(Forced joining))(
If the `tt((j))' flag is present, or no `tt((j))' flag is present but
the string is to be split as given by rule tt(11.), and joining
-did not take place at step tt(5.), any words in the value are joined
+did not take place at rule tt(5.), any words in the value are joined
together using the given string or the first character of tt($IFS) if none.
Note that the `tt((F))' flag implicitly supplies a string for joining in this
manner.
@@ -1459,22 +1491,22 @@ occurrences of any of the characters in tt($IFS). Note this step, too,
takes place at all levels of a nested substitution.
)
item(tt(12.) em(Case modification))(
-Any case modification from one of the flags tt((L)), tt((U)) or tt((C))
+Any case modification from one of the flags `tt((L))', `tt((U))' or `tt((C))'
is applied.
)
item(tt(13.) em(Escape sequence replacement))(
-First any replacements from the tt((g)) flag are performed, then any
-prompt-style formatting from the tt((%)) family of flags is applied.
+First any replacements from the `tt((g))' flag are performed, then any
+prompt-style formatting from the `tt((%))' family of flags is applied.
)
item(tt(14.) em(Quote application))(
-Any quoting or unquoting using tt((q)) and tt((Q)) and related flags
+Any quoting or unquoting using `tt((q))' and `tt((Q))' and related flags
is applied.
)
item(tt(15.) em(Directory naming))(
-Any directory name substitution using tt((D)) flag is applied.
+Any directory name substitution using `tt((D))' flag is applied.
)
item(tt(16.) em(Visibility enhancement))(
-Any modifications to make characters visible using the tt((V)) flag
+Any modifications to make characters visible using the `tt((V))' flag
are applied.
)
item(tt(17.) em(Lexical word splitting))(
@@ -1512,7 +1544,7 @@ In contexts where expansion semantics requires a single word to
result, all words are rejoined with the first character of tt(IFS)
between. So in `tt(${LPAR()P)tt(RPAR()${LPAR()f)tt(RPAR()lines}})'
the value of tt(${lines}) is split at newlines, but then must be
-joined again before the tt(P) flag can be applied.
+joined again before the `tt((P))' flag can be applied.
If a single word is not required, this rule is skipped.
)
@@ -1525,6 +1557,12 @@ Strictly speaking, the removal happens later as the same happens with
other forms of substitution; the point to note here is simply that
it occurs after any of the above parameter operations.
)
+item(tt(25.) em(Nested parameter name replacement))(
+If the `tt((P))' flag is present and rule tt(4.) has not applied, the
+value so far is treated as a parameter name (which may include a subscript
+expression) and replaced with the corresponding value, with internal flags
+(rule tt(2.)) applied to the new value.
+)
enditem()
subsect(Examples)
@@ -2381,6 +2419,18 @@ follow symbolic links; the alternative form `tt(***/)' does, but is
otherwise identical. Neither of these can be combined with other forms of
globbing within the same path segment; in that case, the `tt(*)'
operators revert to their usual effect.
+
+Even shorter forms are available when the option tt(GLOB_STAR_SHORT) is
+set. In that case if no tt(/) immediately follows a tt(**) or tt(***)
+they are treated as if both a tt(/) plus a further tt(*) are present.
+Hence:
+
+example(setopt GLOBSTARSHORT
+ls **.c)
+
+is equivalent to
+
+example(ls **/*.c)
subsect(Glob Qualifiers)
cindex(globbing, qualifiers)
cindex(qualifiers, globbing)
diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo
index ace0a4051..d500a78ae 100644
--- a/Doc/Zsh/func.yo
+++ b/Doc/Zsh/func.yo
@@ -111,8 +111,7 @@ arguments, at the end.
For example, suppose the autoload file tt(func) contains
example(func+LPAR()RPAR() { print This is func; }
-print func is initialized
-)
+print func is initialized)
then `tt(func; func)' with tt(KSH_AUTOLOAD) set will produce both messages
on the first call, but only the message `tt(This is func)' on the second
diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo
index 83968fedf..2a76964f3 100644
--- a/Doc/Zsh/grammar.yo
+++ b/Doc/Zsh/grammar.yo
@@ -421,8 +421,7 @@ works, but
example(if true { # Does not work!
print yes
-}
-)
+})
does em(not), since the test is not suitably delimited.
)
diff --git a/Doc/Zsh/manual.yo b/Doc/Zsh/manual.yo
index 86c72c0ff..119849e4c 100644
--- a/Doc/Zsh/manual.yo
+++ b/Doc/Zsh/manual.yo
@@ -164,6 +164,7 @@ User Contributions
menu(Utilities)
menu(Recent Directories)
+menu(Other Directory Functions)
menu(Version Control Information)
menu(Prompt Themes)
menu(ZLE Functions)
diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo
index 9d1dc8b7d..3d260f8e9 100644
--- a/Doc/Zsh/mod_parameter.yo
+++ b/Doc/Zsh/mod_parameter.yo
@@ -123,10 +123,14 @@ directory, the current working directory.
vindex(history)
item(tt(history))(
This associative array maps history event numbers to the full history lines.
+Although it is presented as an associative array, the array of all values
+(tt(${history[@]})) is guaranteed to be returned in order from most recent
+to oldest history event, that is, by decreasing history event number.
)
vindex(historywords)
item(tt(historywords))(
-A special array containing the words stored in the history.
+A special array containing the words stored in the history. These also
+appear in most to least recent order.
)
vindex(jobdirs)
item(tt(jobdirs))(
diff --git a/Doc/Zsh/mod_pcre.yo b/Doc/Zsh/mod_pcre.yo
index d6b4bd15d..c2817f519 100644
--- a/Doc/Zsh/mod_pcre.yo
+++ b/Doc/Zsh/mod_pcre.yo
@@ -54,8 +54,7 @@ used to implement the "find all non-overlapping matches" functionality.
A simple example of "find all non-overlapping matches":
-example(
-string="The following zip codes: 78884 90210 99513"
+example(string="The following zip codes: 78884 90210 99513"
pcre_compile -m "\d{5}"
accum=()
pcre_match -b -- $string
@@ -64,10 +63,7 @@ while [[ $? -eq 0 ]] do
accum+=$MATCH
pcre_match -b -n $b[2] -- $string
done
-print -l $accum
-
-
-)
+print -l $accum)
)
enditem()
diff --git a/Doc/Zsh/mod_private.yo b/Doc/Zsh/mod_private.yo
new file mode 100644
index 000000000..78aee0acf
--- /dev/null
+++ b/Doc/Zsh/mod_private.yo
@@ -0,0 +1,89 @@
+COMMENT(!MOD!zsh/param/private
+Builtins for managing private-scoped parameters in function context.
+!MOD!)
+The tt(zsh/param/private) module is used to create parameters whose scope
+is limited to the current function body, and em(not) to other functions
+called by the current function.
+
+This module provides a single autoloaded builtin:
+ifnzman()
+startitem()
+findex(private)
+cindex(private parameter, creating)
+item(tt(private) [ {tt(PLUS())|tt(-)}tt(AHUahlprtux) ] \
+[ {tt(PLUS())|tt(-)}tt(EFLRZi) [ var(n) ] ] [ var(name)[tt(=)var(value)] ... ])(
+The tt(private) builtin accepts all the same options and arguments as tt(local)
+(ifzman(zmanref(zshbuiltins))ifnzman(noderef(Shell Builtin Commands))) except
+for the `tt(-)tt(T)' option. Tied parameters may not be made private.
+
+If used at the top level (outside a function scope), tt(private) creates a
+normal parameter in the same manner as tt(declare) or tt(typeset). A
+warning about this is printed if tt(WARN_CREATE_GLOBAL) is set
+(ifzman(zmanref(zshoptions))ifnzman(noderef(Options))). Used inside a
+function scope, tt(private) creates a local parameter similar to one
+declared with tt(local), except having special properties noted below.
+
+Special parameters which expose or manipulate internal shell state, such
+as tt(ARGC), tt(argv), tt(COLUMNS), tt(LINES), tt(UID), tt(EUID), tt(IFS),
+tt(PROMPT), tt(RANDOM), tt(SECONDS), etc., cannot be made private unless
+the `tt(-)tt(h)' option is used to hide the special meaning of the
+parameter. This may change in the future.
+)
+enditem()
+
+As with other tt(typeset) equivalents, tt(private) is both a builtin and a
+reserved word, so arrays may be assigned with parenthesized word list
+var(name)tt(=LPAR())var(value)...tt(RPAR()) syntax. However, the reserved
+word `tt(private)' is not available until tt(zsh/param/private) is loaded,
+so care must be taken with order of execution and parsing for function
+definitions which use tt(private). To compensate for this, the module
+also adds the option `tt(-P)' to the `tt(local)' builtin to declare private
+parameters.
+
+For example, this construction fails if tt(zsh/param/private) has not yet
+been loaded when `tt(bad_declaration)' is defined:
+example(bad_declaration+LPAR()RPAR() {
+ zmodload zsh/param/private
+ private array=LPAR() one two three RPAR()
+})
+
+This construction works because tt(local) is already a keyword, and the
+module is loaded before the statement is executed:
+example(good_declaration+LPAR()RPAR() {
+ zmodload zsh/param/private
+ local -P array=LPAR() one two three RPAR()
+})
+
+The following is usable in scripts but may have trouble with tt(autoload):
+example(zmodload zsh/param/private
+iffy_declaration+LPAR()RPAR() {
+ private array=LPAR() one two three RPAR()
+})
+
+The tt(private) builtin may always be used with scalar assignments and
+for declarations without assignments.
+
+Parameters declared with tt(private) have the following properties:
+ifnzman()
+startitemize()
+itemiz(Within the function body where it is declared, the parameter
+behaves as a local, except as noted above for tied or special parameters.)
+itemiz(The type of a parameter declared private cannot be changed in the
+scope where it was declared, even if the parameter is unset. Thus an
+array cannot be assigned to a private scalar, etc.)
+itemiz(Within any other function called by the declaring function, the
+private parameter does em(NOT) hide other parameters of the same name, so
+for example a global parameter of the same name is visible and may be
+assigned or unset. This includes calls to anonymous functions, although
+that may also change in the future.)
+itemiz(An exported private remains in the environment of inner scopes but
+appears unset for the current shell in those scopes. Generally, exporting
+private parameters should be avoided.)
+enditemize()
+
+Note that this differs from the static scope defined by compiled languages
+derived from C, in that the a new call to the same function creates a new
+scope, i.e., the parameter is still associated with the call stack rather
+than with the function definition. It differs from ksh `tt(typeset -S)'
+because the syntax used to define the function has no bearing on whether
+the parameter scope is respected.
diff --git a/Doc/Zsh/mod_socket.yo b/Doc/Zsh/mod_socket.yo
index 332c551fe..867f6081f 100644
--- a/Doc/Zsh/mod_socket.yo
+++ b/Doc/Zsh/mod_socket.yo
@@ -28,6 +28,11 @@ will be taken as the target file descriptor for the
connection.
In order to elicit more verbose output, use tt(-v).
+
+File descriptors can be closed with normal shell syntax when no longer
+needed, for example:
+
+example(exec {REPLY}>&-)
)
enditem()
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index abd0f8715..f37753991 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -534,6 +534,21 @@ cindex(globbing, of . files)
item(tt(GLOB_DOTS) (tt(-4)))(
Do not require a leading `tt(.)' in a filename to be matched explicitly.
)
+pindex(GLOB_STAR_SHORT)
+pindex(NO_GLOB_STAR_SHORT)
+pindex(GLOBSTARSHORT)
+pindex(NOGLOBSTARSHORT)
+cindex(globbing, short forms)
+cindex(globbing, ** special)
+item(tt(GLOB_STAR_SHORT))(
+When this option is set and the default zsh-style globbing is in
+effect, the pattern `tt(**/*)' can be abbreviated to `tt(**)' and the
+pattern `tt(***/*)' can be abbreviated to tt(***). Hence `tt(**.c)'
+finds a file ending in tt(.c) in any subdirectory, and `tt(***.c)' does
+the same while also following symbolic links. A tt(/) immediately
+after the `tt(**)' or `tt(***)' forces the pattern to be treated as the
+unabbreviated form.
+)
pindex(GLOB_SUBST)
pindex(NO_GLOB_SUBST)
pindex(GLOBSUBST)
@@ -746,7 +761,8 @@ pindex(NOWARNCREATEGLOBAL)
cindex(parameters, warning when created globally)
item(tt(WARN_CREATE_GLOBAL))(
Print a warning message when a global parameter is created in a function
-by an assignment. This often indicates that a parameter has not been
+by an assignment or in math context.
+This often indicates that a parameter has not been
declared local when it should have been. Parameters explicitly declared
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
@@ -1552,13 +1568,13 @@ ifnzman(noderef(Arithmetic Evaluation))\
ifzman(the section ARITHMETIC EVALUATION in zmanref(zshmisc))
has an explicit list.
)
-pindex(DEBUG_BEFORE_CMD <D>)
-pindex(NO_DEBUG_BEFORE_CMD <D>)
-pindex(DEBUGBEFORECMD <D>)
-pindex(NODEBUGBEFORECMD <D>)
+pindex(DEBUG_BEFORE_CMD)
+pindex(NO_DEBUG_BEFORE_CMD)
+pindex(DEBUGBEFORECMD)
+pindex(NODEBUGBEFORECMD)
cindex(traps, DEBUG, before or after command)
cindex(DEBUG trap, before or after command)
-item(tt(DEBUG_BEFORE_CMD))(
+item(tt(DEBUG_BEFORE_CMD) <D>)(
Run the tt(DEBUG) trap before each command; otherwise it is run after
each command. Setting this option mimics the behaviour of ksh 93; with
the option unset the behaviour is that of ksh 88.
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index ba2856b34..21bb87442 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -99,6 +99,11 @@ the syntax:
ifzman()
indent(var(name)tt(+=LPAR())var(value) ...tt(RPAR()))
+Within the parentheses on the right hand side of either form of the
+assignment, newlines and semicolons are treated the same as white space,
+separating individual var(value)s. Any consecutive sequence of such
+characters has the same effect.
+
Ordinary array parameters may also be explicitly declared with:
findex(typeset, use of)
ifzman()
@@ -383,9 +388,7 @@ as part of an arithmetic expression in an ordinary subscript.
To avoid subscript parsing limitations in assignments to associative array
elements, use the append syntax:
-example(
- aa+=('key with "*strange*" characters' 'value string')
-)
+example(aa+=('key with "*strange*" characters' 'value string'))
The basic rule to remember when writing a subscript expression is that all
text between the opening `tt([)' and the closing `tt(])' is interpreted
@@ -773,7 +776,13 @@ Incremented by one each time a new shell is started.
)
vindex(signals)
item(tt(signals))(
-An array containing the names of the signals.
+An array containing the names of the signals. Note that with
+the standard zsh numbering of array indices, where the first element
+has index 1, the signals are offset by 1 from the signal number
+used by the operating system. For example, on typical Unix-like systems
+tt(HUP) is signal number 1, but is referred to as tt($signals[2]). This
+is because of tt(EXIT) at position 1 in the array, which is used
+internally by zsh but is not known to the operating system.
)
vindex(TRY_BLOCK_ERROR)
item(tt(TRY_BLOCK_ERROR) <S>)(
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 2c539c460..7047b43d9 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -404,6 +404,7 @@ xitem(tt(zle) tt(-l) [ tt(-L) | tt(-a) ] [ var(string) ... ])
xitem(tt(zle) tt(-D) var(widget) ...)
xitem(tt(zle) tt(-A) var(old-widget) var(new-widget))
xitem(tt(zle) tt(-N) var(widget) [ var(function) ])
+xitem(tt(zle) tt(-f) var(flag) [ var(flag)... ])
xitem(tt(zle) tt(-C) var(widget) var(completion-widget) var(function))
xitem(tt(zle) tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ])
xitem(tt(zle) tt(-M) var(string))
@@ -464,6 +465,21 @@ ifzman(the section `Widgets' below)\
ifnzman(noderef(Zle Widgets))\
.
)
+item(tt(-f) var(flag) [ var(flag)... ])(
+Set various flags on the running widget. Possible values for var(flag) are:
+
+tt(yank) for indicating that the widget has yanked text into the buffer.
+If the widget is wrapping an existing internal widget, no further
+action is necessary, but if it has inserted the text manually, then it
+should also take care to set tt(YANK_START) and tt(YANK_END) correctly.
+tt(yankbefore) does the same but is used when the yanked text appears
+after the cursor.
+
+tt(kill) for indicating that text has been killed into the cutbuffer.
+When repeatedly invoking a kill widget, text is appended to the cutbuffer
+instead of replacing it, but when wrapping such widgets, it is necessary
+to call `tt(zle -f kill)' to retain this effect.
+)
cindex(completion widgets, creating)
item(tt(-C) var(widget) var(completion-widget) var(function))(
Create a user-defined completion widget named var(widget). The
@@ -1011,11 +1027,14 @@ vindex(YANK_END)
xitem(tt(YANK_ACTIVE) (integer))
xitem(tt(YANK_START) (integer))
item(tt(YANK_END) (integer))(
-These three parameters indicate whether text has just been yanked (pasted)
-into the buffer. tt(YANK_START) and tt(YANK_END) are in the same unit sas
-tt(CURSOR), and are only valid when tt(YANK_ACTIVE) is non-zero.
+tt(YANK_ACTIVE) indicates whether text has just been yanked (pasted)
+into the buffer. tt(YANK_START) and tt(YANK_END) give the location of
+the pasted text and are in the same units as tt(CURSOR). They are only
+valid for reading when tt(YANK_ACTIVE) is non-zero. They can also be
+assigned by widgets that insert text in a yank-like fashion, for example
+wrappers of tt(bracketed-paste). See also tt(zle -f).
-All three are read-only.
+tt(YANK_ACTIVE) is read-only.
)
vindex(ZLE_STATE)
item(tt(ZLE_STATE) (scalar))(
@@ -2255,6 +2274,7 @@ the command line or key bindings temporarily.
The following widget, tt(caps-lock), serves as an example.
+
example(self-insert-ucase+LPAR()RPAR() {
LBUFFER+=${(U)KEYS[-1]}
}
@@ -2274,8 +2294,8 @@ zle -D save-caps-lock
(( stat )) && zle send-break
-return $stat
-)
+return $stat)
+
This causes typed letters to be inserted capitalised until either
tt(accept-line) (i.e. typically the return key) is typed or the
tt(caps-lock) widget is invoked again; the later is handled by saving
@@ -2679,7 +2699,7 @@ If tt(zle_highlight) is not set or no value applies to a particular
context, the defaults applied are equivalent to
example(zle_highlight=LPAR()region:standout special:standout
-suffix:bold isearch:underline+RPAR())
+suffix:bold isearch:underline paste:standout+RPAR())
i.e. both the region and special characters are shown in standout mode.
diff --git a/Doc/zman.yo b/Doc/zman.yo
index 73cc186e0..5050edb8b 100644
--- a/Doc/zman.yo
+++ b/Doc/zman.yo
@@ -174,9 +174,11 @@ def(itemiz)(1)(\
COMMENT(--- special effects ---)
def(example)(1)(\
+ undef(PARAGRAPH)\
NOTRANS(.RS)+NL()NOTRANS(.nf)+NL()\
NOTRANS(\fB)ARG1+NOTRANS(\fP)\
+NL()NOTRANS(.fi)+NL()NOTRANS(.RE)\
+ STDPAR()\
)
def(nofill)(1)(\
diff --git a/Doc/ztexi.yo b/Doc/ztexi.yo
index 699567724..e8783459e 100644
--- a/Doc/ztexi.yo
+++ b/Doc/ztexi.yo
@@ -225,9 +225,11 @@ def(nofill)(1)(\
)
def(example)(1)(\
+ undef(PARAGRAPH)\
NOTRANS(@example)+NL()\
ARG1\
+NL()NOTRANS(@end example)\
+ STDPAR()\
)
def(indent)(1)(\
diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo
index 0cd1e81ca..e71dd5310 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.1/1 is the latest production version. For details of all the
+ Zsh 5.2 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/zsh-development-guide b/Etc/zsh-development-guide
index cbbc798d3..c4aa1b243 100644
--- a/Etc/zsh-development-guide
+++ b/Etc/zsh-development-guide
@@ -77,7 +77,9 @@ avoided further changes to our workflow.
X-Seq: 33835, 33872, 34912
http://www.zsh.org/mla/workers/2014/msg01622.html
http://www.zsh.org/mla/workers/2014/msg01659.html
+ -> https://github.com/ft/zsh-am
http://www.zsh.org/mla/workers/2015/msg00836.html
+ -> https://github.com/danielshahaf/zsh-dev
Subject: Re: _git commit object name completion
X-Seq: 35414
@@ -501,7 +503,9 @@ arguments are:
- the options the builtin accepts, given as a string containing the
option characters (the above example makes the builtin accept the
options `f', `l', `a', `g', and `s'). Passing NULL here disables
- all flag handling, i.e. even "--".
+ all flag handling, i.e. even "--". Each option letter may be
+ followed by one of ":" (argument must follow), "::" (optional
+ argument may follow), or ":%" (optional numeric argument).
- and finally a optional string containing option characters that
will always be reported as set when calling the C-function (this,
too, can be used when using one C-function to implement multiple
diff --git a/Functions/Calendar/age b/Functions/Calendar/age
index 17cf4d13e..50755d610 100644
--- a/Functions/Calendar/age
+++ b/Functions/Calendar/age
@@ -1,4 +1,4 @@
-# Match the age of a file, for use as a glob qualifer. Can
+# Match the age of a file, for use as a glob qualifier. Can
# take one or two arguments, which can be supplied by one of two
# ways (always the same for both arguments):
#
diff --git a/Functions/Chpwd/cdr b/Functions/Chpwd/cdr
index 4f399106b..4bed88b13 100644
--- a/Functions/Chpwd/cdr
+++ b/Functions/Chpwd/cdr
@@ -51,6 +51,13 @@
# (and only /). Usually the first entry should be left as the current
# directory.
#
+# "cdr -p 'pattern'" prunes anything matching the given extended glob
+# pattern from the directory list. The match is against the fully
+# expanded directory path and the full string must match (use wildcards
+# at the ends if needed). If output is going to a terminal, the
+# function will print the new list for the user to confrim; this can be
+# skipped by giving -P instead of -p.
+#
# Details of directory handling
# =============================
#
@@ -217,11 +224,11 @@ setopt extendedglob
autoload -Uz chpwd_recent_filehandler chpwd_recent_add
-integer list set_reply i bad edit
-local opt dir
+integer list set_reply i bad edit force_prune
+local opt dir prune
local -aU dirs
-while getopts "elr" opt; do
+while getopts "elp:P:r" opt; do
case $opt in
(e)
edit=1
@@ -231,6 +238,12 @@ while getopts "elr" opt; do
list=1
;;
+ ([pP])
+ prune=$OPTARG
+ edit=1
+ [[ $opt = P ]] && force_prune=1
+ ;;
+
(r)
set_reply=1
;;
@@ -278,10 +291,22 @@ if [[ $PWD != $reply[1] ]]; then
fi
if (( edit )); then
- local compcontext='directories:directory:_path_files -/'
-IFS='
+ if [[ -n $prune ]]; then
+ reply=(${reply:#$~prune})
+ if [[ force_prune -eq 0 && -t 1 ]]; then
+ print -nrl "New list:" $reply 'Accept? '
+ if ! read -q; then
+ print
+ return 1
+ fi
+ print
+ fi
+ else
+ local compcontext='directories:directory:_path_files -/'
+ IFS='
' vared reply || return 1
-chpwd_recent_filehandler $reply
+ fi
+ chpwd_recent_filehandler $reply
fi
# Skip current directory if present (may have been pruned).
diff --git a/Functions/Chpwd/zsh_directory_name_generic b/Functions/Chpwd/zsh_directory_name_generic
new file mode 100644
index 000000000..9430c95e4
--- /dev/null
+++ b/Functions/Chpwd/zsh_directory_name_generic
@@ -0,0 +1,151 @@
+## zsh_directory_name_generic
+#
+# This function is useful as a hook function for the zsh_directory_name
+# facility.
+#
+# See the zsh-contrib manual page for more.
+
+emulate -L zsh
+setopt extendedglob
+local -a match mbegin mend
+
+# The variable containing the top level mapping.
+local _zdn_topvar
+
+zmodload -i zsh/parameter
+zstyle -s ":zdn:${funcstack[2]}:" mapping _zdn_topvar || _zdn_topvar=zdn_top
+
+if (( ! ${(P)#_zdn_topvar} )); then
+ print -r -- "$0: $_zdn_topver is not set" >&2
+ return 1
+fi
+
+local _zdn_var=$_zdn_topvar
+local -A _zdn_assoc
+
+if [[ $1 = n ]]; then
+ # Turning a name into a directory.
+ local _zdn_name=$2
+ local -a _zdn_words
+ local _zdn_dir _zdn_cpt
+
+ _zdn_words=(${(s.:.)_zdn_name})
+ while (( ${#_zdn_words} )); do
+ if [[ -z ${_zdn_var} ]]; then
+ print -r -- "$0: too many components in directory name \`$_zdn_name'" >&2
+ return 1
+ fi
+
+ # Subscripting (P)_zdn_var directly seems not to work.
+ _zdn_assoc=(${(Pkv)_zdn_var})
+ _zdn_cpt=${_zdn_assoc[${_zdn_words[1]}]}
+ shift _zdn_words
+
+ if [[ -z $_zdn_cpt ]]; then
+ # If top level component, just try another expansion
+ if [[ $_zdn_var != $_zdn_top ]]; then
+ # Committed to this expansion, so report failure.
+ print -r -- "$0: no expansion for directory name \`$_zdn_name'" >&2
+ fi
+ return 1
+ fi
+ if [[ $_zdn_cpt = (#b)(*)/:([[:IDENT:]]##) ]]; then
+ _zdn_cpt=$match[1]
+ _zdn_var=$match[2]
+ else
+ # may be empty
+ _zdn_var=${${_zdn_assoc[:default:]}##*/:}
+ fi
+ _zdn_dir=${_zdn_dir:+$_zdn_dir/}$_zdn_cpt
+ done
+ if (( ${#_zdn_dir} )); then
+ typeset -ag reply
+ reply=($_zdn_dir)
+ return 0
+ fi
+elif [[ $1 = d ]]; then
+ # Turning a directory into a name.
+ local _zdn_dir=$2
+ local _zdn_rest=$_zdn_dir
+ local -a _zdn_cpts
+ local _zdn_pref _zdn_pref_raw _zdn_matched _zdn_cpt _zdn_name
+
+ while [[ -n $_zdn_var && -n $_zdn_rest ]]; do
+ _zdn_assoc=(${(Pkv)_zdn_var})
+ # Sorting in descending order will ensure prefixes
+ # come after longer strings with that perfix, so
+ # we match more specific directory names preferentially.
+ _zdn_cpts=(${(Ov)_zdn_assoc})
+ _zdn_cpt=''
+ for _zdn_pref_raw in $_zdn_cpts; do
+ _zdn_pref=${_zdn_pref_raw%/:*}
+ [[ -z $_zdn_pref ]] && continue
+ if [[ $_zdn_rest = $_zdn_pref(#b)(/|)(*) ]]; then
+ _zdn_cpt=${(k)_zdn_assoc[(r)$_zdn_pref_raw]}
+ # if we matched a /, too, add it...
+ _zdn_matched+=$_zdn_pref$match[1]
+ _zdn_rest=$match[2]
+ break
+ fi
+ done
+ if [[ -n $_zdn_cpt ]]; then
+ _zdn_name+=${_zdn_name:+${_zdh_name}:}$_zdn_cpt
+ if [[ ${_zdn_assoc[$_zdn_cpt]} = (#b)*/:([[:IDENT:]]##) ]]; then
+ _zdn_var=$match[1]
+ else
+ _zdn_var=${${_zdn_assoc[:default:]}##*/:}
+ fi
+ else
+ break
+ fi
+ done
+ if [[ -n $_zdn_name ]]; then
+ # matched something, so report that.
+ integer _zdn_len=${#_zdn_matched}
+ [[ $_zdn_matched[-1] = / ]] && (( _zdn_len-- ))
+ typeset -ag reply
+ reply=($_zdn_name $_zdn_len)
+ return 0
+ fi
+ # else let someone else have a go.
+elif [[ $1 = c ]]; then
+ # Completion
+
+ if [[ -n $SUFFIX ]]; then
+ _message "Can't complete in the middle of a dynamic directory name"
+ else
+ local -a _zdn_cpts
+ local _zdn_word _zdn_cpt _zdn_desc _zdn_sofar expl
+
+ while [[ -n ${_zdn_var} && ${PREFIX} = (#b)([^:]##):* ]]; do
+ _zdn_word=$match[1]
+ compset -P '[^:]##:'
+ _zdn_assoc=(${(Pkv)_zdn_var})
+ _zdn_cpt=${_zdn_assoc[$_zdn_word]}
+ # We only complete at the end so must match here
+ [[ -z $_zdn_cpt ]] && return 1
+ if [[ $_zdn_cpt = (#b)(*)/:([[:IDENT:]]##) ]]; then
+ _zdn_cpt=$match[1]
+ _zdn_var=$match[2]
+ else
+ _zdn_var=${${_zdn_assoc[:default:]}##*/:}
+ fi
+ _zdn_sofar+=${_zdn_sofar:+${_zdn_sofar}/}$_zdn_cpt
+ done
+ if [[ -n $_zdn_var ]]; then
+ _zdn_assoc=(${(Pkv)_zdn_var})
+ local -a _zdn_cpts
+ for _zdn_cpt _zdn_desc in ${(kv)_zdn_assoc}; do
+ [[ $_zdn_cpt = :* ]] && continue
+ _zdn_cpts+=(${_zdn_cpt}:${_zdn_desc%/:[[:IDENT:]]##})
+ done
+ _describe -t dirnames "directory name under ${_zdn_sofar%%/}" \
+ _zdn_cpts -S: -r ':]'
+ return
+ fi
+ fi
+fi
+
+# Failed
+return 1
+## end
diff --git a/Functions/MIME/zsh-mime-setup b/Functions/MIME/zsh-mime-setup
index 23e44fdc0..35f6e6b6b 100644
--- a/Functions/MIME/zsh-mime-setup
+++ b/Functions/MIME/zsh-mime-setup
@@ -1,7 +1,7 @@
emulate -L zsh
setopt extendedglob cbases
-local opt o_verbose o_list
+local opt o_verbose o_list i
autoload -Uz zsh-mime-handler
diff --git a/Functions/Misc/add-zsh-hook b/Functions/Misc/add-zsh-hook
index ee37d674d..fc39659ae 100644
--- a/Functions/Misc/add-zsh-hook
+++ b/Functions/Misc/add-zsh-hook
@@ -82,9 +82,11 @@ if (( del )); then
else
if (( ${(P)+hook} )); then
if (( ${${(P)hook}[(I)$fn]} == 0 )); then
+ typeset -ga $hook
set -A $hook ${(P)hook} $fn
fi
else
+ typeset -ga $hook
set -A $hook $fn
fi
autoload $autoopts -- $fn
diff --git a/Functions/Misc/zcalc b/Functions/Misc/zcalc
index 63f67adb0..17700e48b 100644
--- a/Functions/Misc/zcalc
+++ b/Functions/Misc/zcalc
@@ -120,6 +120,10 @@ autoload -Uz zmathfuncdef
float PI E
(( PI = 4 * atan(1), E = exp(1) ))
+if [[ -f "${ZDOTDIR:-$HOME}/.zcalcrc" ]]; then
+ . "${ZDOTDIR:-$HOME}/.zcalcrc" || return 1
+fi
+
# Process command line
while [[ -n $1 && $1 = -(|[#-]*|f|e) ]]; do
optlist=${1[2,-1]}
diff --git a/Functions/Misc/zed b/Functions/Misc/zed
index 010b69bee..eb8f557ea 100644
--- a/Functions/Misc/zed
+++ b/Functions/Misc/zed
@@ -6,31 +6,20 @@
# Use ^X^W to save, ^C to abort.
# Option -f: edit shell functions. (Also if called as fned.)
-local var opt zed_file_name
+local var opts zed_file_name
# We do not want timeout while we are editing a file
integer TMOUT=0 okargs=1 fun bind
local -a expand
-while getopts "fbx:" opt; do
- case $opt in
- (f)
- fun=1
- ;;
-
- (b)
- bind=1
- ;;
-
- (x)
- if [[ $OPTARG != <-> ]]; then
- print -r "Integer expected after -x: $OPTARG" >&2
- return 1
- fi
- expand=(-x $OPTARG)
- ;;
- esac
-done
-shift $(( OPTIND - 1 ))
+zparseopts -D -A opts f b x:
+fun=$+opts[-f]
+bind=$+opts[-b]
+if [[ $opts[-x] == <-> ]]; then
+ expand=(-x $opts[-x])
+elif (( $+opts[-x] )); then
+ print -r "Integer expected after -x: $opts[-x]" >&2
+ return 1
+fi
[[ $0 = fned ]] && fun=1
(( bind )) && okargs=0
@@ -80,10 +69,10 @@ fi
setopt localoptions nobanghist
if ((fun)) then
- var="$(functions $expand $1)"
+ var="$(functions $expand -- $1)"
# If function is undefined but autoloadable, load it
if [[ $var = *\#\ undefined* ]] then
- var="$(autoload +X $1; functions $1)"
+ var="$(autoload +X $1; functions -- $1)"
elif [[ -z $var ]] then
var="$1() {
}"
diff --git a/Functions/Misc/zrecompile b/Functions/Misc/zrecompile
index 8fe990086..d9fc55020 100644
--- a/Functions/Misc/zrecompile
+++ b/Functions/Misc/zrecompile
@@ -52,7 +52,7 @@ while getopts ":tqp" opt; do
fi
esac
done
-shift OPTIND-${#tmp:-1}
+shift OPTIND-${#tmp}-1
if [[ -n $check ]]; then
ret=1
diff --git a/Functions/TCP/tcp_open b/Functions/TCP/tcp_open
index 091217788..a04403c76 100644
--- a/Functions/TCP/tcp_open
+++ b/Functions/TCP/tcp_open
@@ -152,7 +152,7 @@ fi
if (( $# )); then
print "Usage: $0 [-z] [-a fd | -f fd | host port [ session ] ]
- $0 [-z] [ -s session | -l sesslist ] ..." >&2
+ $0 [-z] [ -s session | -l sesslist ] ..." >&2
return 1
fi
diff --git a/Functions/TCP/tcp_read b/Functions/TCP/tcp_read
index f880395dd..ba9185ed5 100644
--- a/Functions/TCP/tcp_read
+++ b/Functions/TCP/tcp_read
@@ -116,7 +116,7 @@ while getopts "abdl:qs:t:T:u:" opt; do
read_fds[$((read_fd))]=1
done
;;
- (*) [[ $opt != \? ]] && print Unhandled option, complain: $opt >&2
+ (*) [[ $opt != \? ]] && print "Unhandled option, complain: $opt" >&2
return 1
;;
esac
diff --git a/Functions/TCP/tcp_send b/Functions/TCP/tcp_send
index c976a2fb7..86dda6403 100644
--- a/Functions/TCP/tcp_send
+++ b/Functions/TCP/tcp_send
@@ -29,7 +29,7 @@ while getopts "acl:nqs:" opt; do
fi
sessions+=($OPTARG)
;;
- (*) [[ $opt != '?' ]] && print Unhandled option, complain: $opt >&2
+ (*) [[ $opt != '?' ]] && print "Unhandled option, complain: $opt" >&2
return 1
;;
esac
diff --git a/Functions/TCP/tcp_shoot b/Functions/TCP/tcp_shoot
index 8ff9866ba..c485c140a 100644
--- a/Functions/TCP/tcp_shoot
+++ b/Functions/TCP/tcp_shoot
@@ -4,8 +4,8 @@ setopt extendedglob
local REPLY tfd
if [[ $# -ne 2 ]]; then
- print "Usage: tcp_dump host port
-Connect to the given host and port; send standard input.">&2
+ print "Usage: $0 host port
+Connect to the given host and port; send standard input." >&2
return 1
fi
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
index 638ea4572..704c1890e 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
@@ -87,13 +87,18 @@ VCS_INFO_git_getbranch () {
gitbranch="$(${(z)gitsymref} 2> /dev/null)"
[[ -z ${gitbranch} ]] && [[ -r ${actiondir}/head-name ]] \
&& gitbranch="$(< ${actiondir}/head-name)"
+ [[ -z ${gitbranch} ]] && gitbranch="$(< ${gitdir}/ORIG_HEAD)"
elif [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
gitbranch="$(${(z)gitsymref} 2> /dev/null)"
- [[ -z ${gitbranch} ]] && gitbranch="$(< ${gitdir}/MERGE_HEAD)"
+ [[ -z ${gitbranch} ]] && gitbranch="$(< ${gitdir}/ORIG_HEAD)"
elif [[ -d "${gitdir}/rebase-merge" ]] ; then
gitbranch="$(< ${gitdir}/rebase-merge/head-name)"
+ if [[ $gitbranch == 'detached HEAD' ]]; then
+ # get a sha1
+ gitbranch="$(< ${gitdir}/rebase-merge/orig-head)"
+ fi
elif [[ -d "${gitdir}/.dotest-merge" ]] ; then
gitbranch="$(< ${gitdir}/.dotest-merge/head-name)"
@@ -217,18 +222,32 @@ elif [[ -d "${gitdir}/rebase-merge" ]]; then
elif [[ -d "${gitdir}/rebase-apply" ]]; then
# Fake patch names for all but current patch
patchdir="${gitdir}/rebase-apply"
- local cur=$(< "${patchdir}/next")
- local p subject
- for p in $(seq $(($cur - 1))); do
- git_patches_applied+=("$(printf "%04d" $p) ?")
- done
- subject="${$(< "${patchdir}/msg-clean")[(f)1]}"
- if [[ -f "${patchdir}/original-commit" ]]; then
- git_patches_applied+=("$(< ${patchdir}/original-commit) $subject")
- else
- git_patches_applied+=("? $subject")
+ local next="${patchdir}/next"
+ if [[ -f $next ]]; then
+ local cur=$(< $next)
+ local p subject
+ for ((p = 1; p < cur; p++)); do
+ git_patches_applied+=("$(printf "%04d" $p) ?")
+ done
+ if [[ -f "${patchdir}/msg-clean" ]]; then
+ subject="${$(< "${patchdir}/msg-clean")[(f)1]}"
+ fi
+ if [[ -f "${patchdir}/original-commit" ]]; then
+ if [[ -n $subject ]]; then
+ git_patches_applied+=("$(< ${patchdir}/original-commit) $subject")
+ else
+ git_patches_applied+=("$(< ${patchdir}/original-commit)")
+ fi
+ else
+ if [[ -n $subject ]]; then
+ git_patches_applied+=("? $subject")
+ else
+ git_patches_applied+=("?")
+ fi
+ fi
+ local last="$(< "${patchdir}/last")"
+ git_patches_unapplied=( {$cur..$last} )
fi
- git_patches_unapplied=($(seq $cur $(< "${patchdir}/last")))
VCS_INFO_git_handle_patches
elif [[ -f "${gitdir}/MERGE_HEAD" ]]; then
@@ -248,6 +267,28 @@ elif [[ -f "${gitdir}/MERGE_HEAD" ]]; then
# Not touching git_patches_unapplied
VCS_INFO_git_handle_patches
+elif [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]]; then
+ # 'git cherry-pick' without -n, that conflicted. (With -n, git doesn't
+ # record the CHERRY_PICK_HEAD information anywhere, as of git 2.6.2.)
+ #
+ # ### 'git cherry-pick foo bar baz' only records the "remaining" part of
+ # ### the queue in the .git dir: if 'bar' has a conflict, the .git dir
+ # ### has a record of 'baz' being queued, but no record of 'foo' having been
+ # ### part of the queue as well. Therefore, the %n/%c applied/unapplied
+ # ### expandos will be memoryless: the "applied" counter will always
+ # ### be "1". The %u/%c tuple will assume the values [(1,2), (1,1), (1,0)],
+ # ### whereas the correct sequence would be [(1,2), (2,1), (3,0)].
+ local subject
+ IFS='' read -r subject < "${gitdir}/MERGE_MSG"
+ git_patches_applied=( "$(<${gitdir}/CHERRY_PICK_HEAD) ${subject}" )
+ if [[ -f "${gitdir}/sequencer/todo" ]]; then
+ # Get the next patches, and remove the one that's in CHERRY_PICK_HEAD.
+ git_patches_unapplied=( ${${(M)${(f)"$(<"${gitdir}/sequencer/todo")"}:#pick *}#pick } )
+ git_patches_unapplied[1]=()
+ else
+ git_patches_unapplied=()
+ fi
+ VCS_INFO_git_handle_patches
else
gitmisc=''
fi
diff --git a/Functions/VCS_Info/VCS_INFO_quilt b/Functions/VCS_Info/VCS_INFO_quilt
index bc71cfb7d..c3c3d864d 100644
--- a/Functions/VCS_Info/VCS_INFO_quilt
+++ b/Functions/VCS_Info/VCS_INFO_quilt
@@ -119,6 +119,7 @@ function VCS_INFO_quilt() {
applied=()
fi
patches=$(<$pc/.quilt_patches)
+ patches=`builtin cd -q "${pc:h}" && print -r - ${patches:A}`
fi
if zstyle -t "${context}" get-unapplied; then
# This zstyle call needs to be moved further up if `quilt' needs
@@ -144,6 +145,36 @@ function VCS_INFO_quilt() {
unapplied=()
fi
+ if [[ -n $patches ]]; then
+ () {
+ local i line
+ for ((i=1; i<=$#applied; i++)); do
+ if [[ -f "$patches/$applied[$i]" ]] &&
+ read -r line < "$patches/$applied[$i]" &&
+ [[ $line != (#b)(---|Index:)* ]] &&
+ true
+ ;
+ then
+ applied[$i]+=" $line"
+ else
+ applied[$i]+=" ?"
+ fi
+ done
+ for ((i=1; i<=$#unapplied; i++)); do
+ if [[ -f "$patches/$unapplied[$i]" ]] &&
+ read -r line < "$patches/$unapplied[$i]" &&
+ [[ $line != (#b)(---|Index:)* ]] &&
+ true
+ ;
+ then
+ unapplied[$i]+=" $line"
+ else
+ unapplied[$i]+=" ?"
+ fi
+ done
+ }
+ fi
+
all=( ${(Oa)applied} ${unapplied} )
if VCS_INFO_hook 'gen-applied-string' "${applied[@]}"; then
diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info
index 350b189e9..628dde9b1 100644
--- a/Functions/VCS_Info/vcs_info
+++ b/Functions/VCS_Info/vcs_info
@@ -11,6 +11,7 @@
setopt localoptions noksharrays extendedglob NO_shwordsplit
local file func sys
local -a static_functions
+local -i maxexports
static_functions=(
VCS_INFO_adjust
@@ -38,6 +39,7 @@ for func in ${static_functions} ; do
done
[[ -n ${(Mk)parameters:#vcs_info_msg_<->_} ]] && unset ${parameters[(I)vcs_info_msg_<->_]}
+VCS_INFO_maxexports
VCS_INFO_set --nvcs '-preinit-'
vcs_info_setsys
diff --git a/Functions/Zle/bracketed-paste-magic b/Functions/Zle/bracketed-paste-magic
index 464c6b339..2b2bc630d 100644
--- a/Functions/Zle/bracketed-paste-magic
+++ b/Functions/Zle/bracketed-paste-magic
@@ -116,10 +116,14 @@ quote-paste() {
# Now the actual function
bracketed-paste-magic() {
- # Fast exit in the vi-mode cut-buffer context
if [[ "$LASTWIDGET" = *vi-set-buffer ]]; then
+ # Fast exit in the vi-mode cut-buffer context
zle .bracketed-paste
return
+ else
+ # Capture the pasted text in $PASTED
+ local PASTED REPLY
+ zle .bracketed-paste PASTED
fi
# Really necessary to go to this much effort?
@@ -127,10 +131,9 @@ bracketed-paste-magic() {
emulate -L zsh
local -a bpm_hooks bpm_inactive
- local PASTED bpm_func bpm_active bpm_keymap=$KEYMAP
+ local bpm_func bpm_active bpm_keymap=$KEYMAP
- # Set PASTED and run the paste-init functions
- zle .bracketed-paste PASTED
+ # Run the paste-init functions
if zstyle -a :bracketed-paste-magic paste-init bpm_hooks; then
for bpm_func in $bpm_hooks; do
if (( $+functions[$bpm_func] )); then
@@ -164,25 +167,17 @@ bracketed-paste-magic() {
integer bpm_limit=$UNDO_LIMIT_NO bpm_undo=$UNDO_CHANGE_NO
UNDO_LIMIT_NO=$UNDO_CHANGE_NO
- local mbchar
- integer ismb
while [[ -n $PASTED ]] && zle .read-command; do
- mbchar=$KEYS
- ismb=0
- while [[ $mbchar = [[:INCOMPLETE:]]* ]] && zle .read-command; do
- mbchar+=$KEYS
- ismb=1
- done
- PASTED=${PASTED#$mbchar}
- if [[ ismb -ne 0 || $mbchar = ${(~j:|:)${(b)bpm_inactive}} ]]; then
- LBUFFER+=$mbchar
+ PASTED=${PASTED#$KEYS}
+ if [[ $KEYS = ${(~j:|:)${(b)bpm_inactive}} ]]; then
+ zle .self-insert
else
case $REPLY in
(${~bpm_active}) function () {
emulate -L $bpm_emulate; set -$bpm_opts
zle $REPLY
};;
- (*) LBUFFER+=$mbchar;
+ (*) zle .self-insert;;
esac
fi
done
@@ -221,7 +216,7 @@ bracketed-paste-magic() {
zle .split-undo
# Arrange to display highlighting if necessary
- if [[ -n ${(M)zle_highlight:#paste:*} ]]; then
+ if [[ -z $zle_highlight || -n ${(M)zle_highlight:#paste:*} ]]; then
zle -R
zle .read-command && zle -U - $KEYS
fi
diff --git a/Functions/Zle/bracketed-paste-url-magic b/Functions/Zle/bracketed-paste-url-magic
new file mode 100644
index 000000000..06dee2657
--- /dev/null
+++ b/Functions/Zle/bracketed-paste-url-magic
@@ -0,0 +1,44 @@
+# bracketed-paste-url-magic quotes pasted urls automatically, if the
+# paste exactly starts with a url, eg no spaces or other characters precede it
+#
+# If the numeric argument is provided (eg, pressing alt-0 or alt-1 in emacs mode,
+# or just the number by itself in vi command mode), then
+# 0 is the default and means auto detect urls
+# 1 means always quote
+# any other value means never quote
+#
+# To use this widget, put this in your startup files (eg, .zshrc)
+#
+# autoload -Uz bracketed-paste-url-magic
+# zle -N bracketed-paste bracketed-paste-url-magic
+#
+# You can customize which schemas are to be quoted by using
+#
+# zstyle :bracketed-paste-url-magic schema http https ftp
+#
+# The default can be seen just below.
+
+local -a schema
+zstyle -a :bracketed-paste-url-magic schema schema || schema=(http https ftp ftps file ssh sftp)
+
+local wantquote=${NUMERIC:-0}
+local content
+local start=$#LBUFFER
+
+zle .$WIDGET -N content
+
+if (( $wantquote == 0 )); then
+ if [[ $content = (${(~j:|:)schema})://* ]]; then
+ wantquote=1
+ fi
+fi
+
+if (( $wantquote == 1 )); then
+ content=${(q-)content}
+fi
+
+LBUFFER+=$content
+
+YANK_START=$start
+YANK_END=$#LBUFFER
+zle -f yank
diff --git a/Functions/Zle/edit-command-line b/Functions/Zle/edit-command-line
index 2c7f34b8b..103a1c1a5 100644
--- a/Functions/Zle/edit-command-line
+++ b/Functions/Zle/edit-command-line
@@ -11,13 +11,16 @@
# Compute the cursor's position in bytes, not characters.
setopt localoptions nomultibyte
- integer byteoffset=$(( $#PREBUFFER + $#LBUFFER + 1 ))
# Open the editor, placing the cursor at the right place if we know how.
local editor=${${VISUAL:-${EDITOR:-vi}}}
case $editor in
- (*vim*) ${=editor} -c "normal! ${byteoffset}go" -- $1;;
- (*emacs*) ${=editor} $1 -eval "(goto-char ${byteoffset})";;
+ (*vim*)
+ integer byteoffset=$(( $#PREBUFFER + $#LBUFFER + 1 ))
+ ${=editor} -c "normal! ${byteoffset}go" -- $1;;
+ (*emacs*)
+ local lines=( ${(f):-"$PREBUFFER$LBUFFER"} )
+ ${=editor} +${#lines}:$((${#lines[-1]} + 1)) $1;;
(*) ${=editor} $1;;
esac
diff --git a/Functions/Zle/match-word-context b/Functions/Zle/match-word-context
index 7f1154498..8793483f4 100644
--- a/Functions/Zle/match-word-context
+++ b/Functions/Zle/match-word-context
@@ -7,7 +7,7 @@ setopt extendedglob
local -a worcon bufwords
local pat tag lastword word backword forword
-integer iword
+integer iword between
zstyle -a $curcontext word-context worcon || return 0
@@ -25,13 +25,18 @@ if [[ $lastword = ${bufwords[iword]} ]]; then
# If the word immediately left of the cursor is complete,
# we're not on it for forward operations.
forword=${bufwords[iword+1]}
+ # If, furthermore, we're on whitespace, then we're between words.
+ # It can't be significant whitespace because the previous word is complete.
+ [[ $RBUFFER[1] = [[:space:]] ]] && between=1
else
# We're on a word.
forword=${bufwords[iword]}
fi
backword=${bufwords[iword]}
-if [[ $curcontext = *back* ]]; then
+if [[ between -ne 0 && $curcontext = *between* ]]; then
+ word=' '
+elif [[ $curcontext = *back* ]]; then
word=$backword
else
word=$forword
diff --git a/Functions/Zle/smart-insert-last-word b/Functions/Zle/smart-insert-last-word
index 67adea760..cf8715dfe 100644
--- a/Functions/Zle/smart-insert-last-word
+++ b/Functions/Zle/smart-insert-last-word
@@ -60,7 +60,7 @@ then
lcursor=$_ilw_lcursor
else
NUMERIC=1
- _ilw_lcursor=$lcursor
+ typeset -g _ilw_lcursor=$lcursor
fi
# Handle the up to three arguments of .insert-last-word
if (( $+1 ))
@@ -73,8 +73,8 @@ then
(( NUMERIC )) || LBUFFER[lcursor+1,cursor+1]=''
numeric=$((-(${2:--numeric})))
fi
-_ilw_hist=$HISTNO
-_ilw_count=$NUMERIC
+typeset -g _ilw_hist=$HISTNO
+typeset -g _ilw_count=$NUMERIC
if [[ -z "$numeric" ]]
then
@@ -119,7 +119,7 @@ fi
(( NUMERIC > $#lastcmd )) && return 1
LBUFFER[lcursor+1,cursor+1]=$lastcmd[-NUMERIC]
-_ilw_cursor=$CURSOR
+typeset -g _ilw_cursor=$CURSOR
# This is necessary to update UNDO_CHANGE_NO immediately
-zle split-undo && _ilw_changeno=$UNDO_CHANGE_NO
+zle split-undo && typeset -g _ilw_changeno=$UNDO_CHANGE_NO
diff --git a/MACHINES b/MACHINES
index ddbf69ac6..73f80c7d1 100644
--- a/MACHINES
+++ b/MACHINES
@@ -162,8 +162,8 @@ Other machines
Zsh has previously been compiled on the following machines, but the
developers do not have direct access to them and the reports may be out
-of date. Some of these OS's are now very long in the tooth. We would
-be glad to receive any reports of success or failure on these OS's ---
+of date. Some of these OSes are now very long in the tooth. We would
+be glad to receive any reports of success or failure on these OSes ---
and, of course, any others not mentioned in this file.
Apple/NeXT OpenStep 4.2 for i386.
diff --git a/NEWS b/NEWS
index 7b2994b6b..3964da732 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,36 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
Note also the list of incompatibilities in the README file.
+Changes from 5.1.1 to 5.2
+-------------------------
+
+The new module zsh/param/private can be loaded to allow the shell
+to define parameters that are private to a function scope (i.e. are
+not propagated to nested functions called within this function).
+
+The parameter flag ${(P)...} is now more useful when it appears in
+a nested expansion. For example,
+
+ typeset -A assoc=(one un two deux three trois)
+ name=assoc
+ print ${${(P)name}[one]}
+
+now prints "un". In previous versions of the shell the value of the
+substitution was fully expanded on return from ${(P)name}, making
+associative array subscripting difficult. As a side effect, flags
+for formatting appearing in the inner substitution now affect the
+substitution of the name (into "assoc" in this case), which is not
+normally useful: flags that should apply to the value must be in the
+outer substitution.
+
+The GLOB_STAR_SHORT option allows the pattern **/* to be shortened to
+just ** if no / follows. so **.c searches recursively for a file whose
+name has the suffix ".c".
+
+The effect of the WARN_CREATE_GLOBAL option has been significantly
+extended, so expect it to cause additional warning messages about
+parameters created globally within function scope.
+
Changes from 5.1 to 5.1.1
-------------------------
@@ -47,7 +77,7 @@ and an array "array" containing the words "several"
- Improved (though still not perfect) POSIX compatibility for getopts
builtin when POSIX_BUILTINS is set.
-- New setopt APPEND_CREATE for POSIX-compatible NO_CLOBBER behavior.
+- New setopt APPEND_CREATE for POSIX-compatible NO_CLOBBER behaviour.
- Completion of date values now displays in a calendar format when
the complist module is available. Controllable by zstyle.
@@ -929,7 +959,7 @@ Parameter and expansion changes:
- expansion of ~ and other globbing flags via ${~param} do not depend
upon EXTENDED_GLOB (bug fix).
- nested parameter substitutions require braces (this was always the
- documented behavior, but previous parsers didn't enforce it).
+ documented behaviour, but previous parsers didn't enforce it).
- quote only nested expansion, e.g. ${(f)"$(<file)"} reads complete
`file', then splits lines into array.
@@ -954,7 +984,7 @@ Other changes:
Debugging enhancements:
- LINENO is now very much more useful in scripts and functions and is
reported correctly in most error messages.
- - ERREXIT behavior is now consistent with newer Bourne-like shells,
+ - ERREXIT behaviour is now consistent with newer Bourne-like shells,
e.g. with respect to `if' tests that fail.
Configuration changes:
diff --git a/README b/README
index 1ebc8cd95..2e2ebce2b 100644
--- a/README
+++ b/README
@@ -5,13 +5,10 @@ THE Z SHELL (ZSH)
Version
-------
-This is version 5.1.1 of the shell. This is a stable release. There are
-a few visible improvements since 5.0.8 as well as many bugfixes. Note
-in particular the two changes highlighted under "Incompatibilites
-between 5.0.8 and 5.1" below. See NEWS for more information.
-
-There are mostly bug fixes between 5.1 and 5.1.1; however, a fewer minor
-features useful in resolving problems with shell functions were added.
+This is version 5.2 of the shell. This is a stable release. There are
+a few visible improvements since 5.1.1 as well as many bugfixes. Note
+in particular the changs highlighted under "Incompatibilites
+between 5.1 and 5.2" below. See NEWS for more information.
Installing Zsh
--------------
@@ -32,8 +29,16 @@ 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.
-Incompatibilites between 5.0.8 and 5.1
---------------------------------------
+Incompatibilities between 5.1 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
+before. See NEWS for more.
+
+Incompatibilities between 5.0.8 and 5.1
+---------------------------------------
The default behaviour when text is pasted into an X Windows terminal has
changed significantly (unless you are using a very old terminal emulator
@@ -48,7 +53,7 @@ As noted in NEWS, the builtins declare, export, float, integer, local,
readonly and typeset now have corresponding reserved words that provide
true assignment semantics instead of an approximation by means of normal
command line arguments. It is hoped that this additional consistency
-provides a more natural interface. However, compatbility with older
+provides a more natural interface. However, compatibility with older
versions of zsh can be obtained by turning off the reserved word
interface, exposing the builtin interface:
@@ -392,7 +397,7 @@ Doc/Zsh/*.yo The master source for the zsh documentation is written in
It is not required by zsh but it is a nice program so you
might want to get it anyway, especially if you are a zsh
developer. It can be downloaded from
- ftp://yodl.sourceforge.net/
+ https://fbb-git.github.io/yodl/
Doc/zsh*.1 Man pages in nroff format. These will be installed
by "make install.man" or "make install". By default,
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index 0054aef52..64329f643 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -370,7 +370,7 @@ zcurses_colorget(const char *nam, char *colorpair)
return NULL;
}
- cpn = (Colorpairnode)zalloc(sizeof(struct colorpairnode));
+ cpn = (Colorpairnode)zshcalloc(sizeof(struct colorpairnode));
if (!cpn) {
zsfree(cp);
@@ -462,7 +462,7 @@ zccmd_init(const char *nam, char **args)
use_default_colors();
#endif
/* Initialise the default color pair, always 0 */
- cpn = (Colorpairnode)zalloc(sizeof(struct colorpairnode));
+ cpn = (Colorpairnode)zshcalloc(sizeof(struct colorpairnode));
if (cpn) {
cpn->colorpair = 0;
addhashnode(zcurses_colorpairs,
diff --git a/Src/Modules/curses.mdd b/Src/Modules/curses.mdd
index 669c4f5c7..80c8f867b 100644
--- a/Src/Modules/curses.mdd
+++ b/Src/Modules/curses.mdd
@@ -2,7 +2,7 @@ name=zsh/curses
link='if test "x$ac_cv_func_initscr" = xyes && test "x$zsh_cv_path_curses_header" != x; then echo dynamic; else echo no; fi'
load=no
-autobins="zcurses"
+autofeatures="b:zcurses"
objects="curses.o"
diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c
index 76d4751bf..032963262 100644
--- a/Src/Modules/db_gdbm.c
+++ b/Src/Modules/db_gdbm.c
@@ -106,7 +106,9 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func))
}
dbf = gdbm_open(resource_name, 0, read_write, 0666, 0);
- if(!dbf) {
+ if(dbf)
+ addmodulefd(gdbm_fdesc(dbf), FDT_INTERNAL);
+ else {
zwarnnam(nam, "error opening database file %s", resource_name);
return 1;
}
@@ -114,6 +116,7 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func))
if (!(tied_param = createspecialhash(pmname, &getgdbmnode, &scangdbmkeys,
pmflags))) {
zwarnnam(nam, "cannot create the requested parameter %s", pmname);
+ fdtable[gdbm_fdesc(dbf)] = FDT_UNUSED;
gdbm_close(dbf);
return 1;
}
@@ -319,8 +322,10 @@ gdbmuntie(Param pm)
GDBM_FILE dbf = (GDBM_FILE)(pm->u.hash->tmpdata);
HashTable ht = pm->u.hash;
- if (dbf) /* paranoia */
+ if (dbf) { /* paranoia */
+ fdtable[gdbm_fdesc(dbf)] = FDT_UNUSED;
gdbm_close(dbf);
+ }
ht->tmpdata = NULL;
diff --git a/Src/Modules/param_private.c b/Src/Modules/param_private.c
new file mode 100644
index 000000000..7f9aa7921
--- /dev/null
+++ b/Src/Modules/param_private.c
@@ -0,0 +1,587 @@
+/*
+ * param_private.c - bindings for private parameter scopes
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2015 Barton E. Schaefer
+ * 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
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Barton E. Schaefer or the Zsh Development
+ * Group be liable to any party for direct, indirect, special, incidental, or
+ * consequential damages arising out of the use of this software and its
+ * documentation, even if Barton E. Schaefer and the Zsh
+ * Development Group have been advised of the possibility of such damage.
+ *
+ * Barton E. Schaefer and the Zsh Development Group
+ * specifically disclaim any warranties, including, but not limited to, the
+ * implied warranties of merchantability and fitness for a particular purpose.
+ * The software provided hereunder is on an "as is" basis, and
+ * Barton E. Schaefer and the Zsh Development Group have no
+ * obligation to provide maintenance, support, updates, enhancements, or
+ * modifications.
+ *
+ */
+
+#include "param_private.mdh"
+#include "param_private.pro"
+
+struct gsu_closure {
+ union {
+ struct gsu_scalar s;
+ struct gsu_integer i;
+ struct gsu_float f;
+ struct gsu_array a;
+ struct gsu_hash h;
+ } u;
+ void *g;
+};
+
+const struct gsu_scalar scalar_private_gsu =
+{ pps_getfn, pps_setfn, pps_unsetfn };
+
+const struct gsu_integer integer_private_gsu =
+{ ppi_getfn, ppi_setfn, ppi_unsetfn };
+
+const struct gsu_float float_private_gsu =
+{ ppf_getfn, ppf_setfn, ppf_unsetfn };
+
+const struct gsu_array array_private_gsu =
+{ ppa_getfn, ppa_setfn, ppa_unsetfn };
+
+const struct gsu_hash hash_private_gsu =
+{ pph_getfn, pph_setfn, pph_unsetfn };
+
+/*
+ * The trick here is:
+ *
+ * bin_private() opens a new parameter scope, then calls bin_typeset().
+ *
+ * bin_typeset() handles the usual parameter creation and error checks.
+ *
+ * makeprivate() then finds all parameters created in the new scope and
+ * rejects them if they can't be "promoted" to the surrounding scope.
+ * Otherwise it swaps out their GSU structure and promotes them so they
+ * will be removed when the surrounding scope ends.
+ *
+ * bin_private() then ends the current scope, which discards any of the
+ * parameters rejected by makeprivate().
+ *
+ */
+
+static int makeprivate_error = 0;
+
+static void
+makeprivate(HashNode hn, UNUSED(int flags))
+{
+ Param pm = (Param)hn;
+ if (pm->level == locallevel) {
+ if (pm->ename || (pm->node.flags & PM_NORESTORE) ||
+ (pm->old &&
+ (pm->old->level == locallevel - 1 ||
+ ((pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL &&
+ /* typeset_single() line 2300 discards PM_REMOVABLE -- why? */
+ !is_private(pm->old))))) {
+ zwarnnam("private", "can't change scope of existing param: %s",
+ pm->node.nam);
+ makeprivate_error = 1;
+ return;
+ }
+ struct gsu_closure *gsu = zhalloc(sizeof(struct gsu_closure));
+ switch (PM_TYPE(pm->node.flags)) {
+ case PM_SCALAR:
+ gsu->g = (void *)(pm->gsu.s);
+ gsu->u.s = scalar_private_gsu;
+ pm->gsu.s = (GsuScalar)gsu;
+ break;
+ case PM_INTEGER:
+ gsu->g = (void *)(pm->gsu.i);
+ gsu->u.i = integer_private_gsu;
+ pm->gsu.i = (GsuInteger)gsu;
+ break;
+ case PM_EFLOAT:
+ case PM_FFLOAT:
+ gsu->g = (void *)(pm->gsu.f);
+ gsu->u.f = float_private_gsu;
+ pm->gsu.f = (GsuFloat)gsu;
+ break;
+ case PM_ARRAY:
+ gsu->g = (void *)(pm->gsu.a);
+ gsu->u.a = array_private_gsu;
+ pm->gsu.a = (GsuArray)gsu;
+ break;
+ case PM_HASHED:
+ gsu->g = (void *)(pm->gsu.h);
+ gsu->u.h = hash_private_gsu;
+ pm->gsu.h = (GsuHash)gsu;
+ break;
+ default:
+ makeprivate_error = 1;
+ break;
+ }
+ /* PM_HIDE so new parameters in deeper scopes do not shadow */
+ pm->node.flags |= (PM_HIDE|PM_SPECIAL|PM_REMOVABLE);
+ pm->level -= 1;
+ }
+}
+
+/**/
+static int
+is_private(Param pm)
+{
+ switch (PM_TYPE(pm->node.flags)) {
+ case PM_SCALAR:
+ if (!pm->gsu.s || pm->gsu.s->unsetfn != pps_unsetfn)
+ return 0;
+ break;
+ case PM_INTEGER:
+ if (!pm->gsu.i || pm->gsu.i->unsetfn != ppi_unsetfn)
+ return 0;
+ break;
+ case PM_EFLOAT:
+ case PM_FFLOAT:
+ if (!pm->gsu.f || pm->gsu.f->unsetfn != ppf_unsetfn)
+ return 0;
+ break;
+ case PM_ARRAY:
+ if (!pm->gsu.a || pm->gsu.a->unsetfn != ppa_unsetfn)
+ return 0;
+ break;
+ case PM_HASHED:
+ if (!pm->gsu.h || pm->gsu.h->unsetfn != pph_unsetfn)
+ return 0;
+ break;
+ default:
+ /* error */
+ return 0;
+ }
+ return 1;
+}
+
+static int fakelevel;
+
+/**/
+static int
+bin_private(char *nam, char **args, LinkList assigns, Options ops, int func)
+{
+ int from_typeset = 1;
+ makeprivate_error = 0;
+
+ if (!OPT_ISSET(ops, 'P'))
+ return bin_typeset(nam, args, assigns, ops, func);
+ else if (OPT_ISSET(ops, 'T')) {
+ zwarn("bad option: -T");
+ return 1;
+ }
+
+ if (locallevel == 0) {
+ if (isset(WARNCREATEGLOBAL))
+ zwarnnam(nam, "invalid local scope, using globals");
+ return bin_typeset("private", args, assigns, ops, func);
+ }
+
+ ops->ind['g'] = 2; /* force bin_typeset() to behave as "local" */
+
+ queue_signals();
+ fakelevel = locallevel;
+ startparamscope();
+ from_typeset = bin_typeset("private", args, assigns, ops, func);
+ scanhashtable(paramtab, 0, 0, 0, makeprivate, 0);
+ endparamscope();
+ fakelevel = 0;
+ unqueue_signals();
+
+ return makeprivate_error | from_typeset;
+}
+
+static void
+setfn_error(Param pm)
+{
+ pm->node.flags |= PM_UNSET;
+ zerr("%s: attempt to assign private in nested scope", pm->node.nam);
+}
+
+/*
+ * How the GSU functions work:
+ *
+ * The getfn and setfn family compare to locallevel and then call through
+ * to the original getfn or setfn. This means you can't assign at a
+ * deeper scope to any parameter declared private unless you first declare
+ * it local again at the new scope. Testing locallevel in getfn is most
+ * likely unnecessary given the scopeprivate() wrapper installed below.
+ *
+ * The unsetfn family compare locallevel and restore the old GSU before
+ * calling the original unsetfn. This assures that if the old unsetfn
+ * wants to use its getfn or setfn, they're unconditionally present.
+ *
+ */
+
+/**/
+static char *
+pps_getfn(Param pm)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.s);
+ GsuScalar gsu = (GsuScalar)(c->g);
+
+ if (locallevel >= pm->level)
+ return gsu->getfn(pm);
+ else
+ return (char *) hcalloc(1);
+}
+
+/**/
+static void
+pps_setfn(Param pm, char *x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.s);
+ GsuScalar gsu = (GsuScalar)(c->g);
+ if (locallevel == pm->level)
+ gsu->setfn(pm, x);
+ else
+ setfn_error(pm);
+}
+
+/**/
+static void
+pps_unsetfn(Param pm, int x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.s);
+ GsuScalar gsu = (GsuScalar)(c->g);
+ pm->gsu.s = gsu;
+ if (locallevel <= pm->level)
+ gsu->unsetfn(pm, x);
+}
+
+/**/
+static zlong
+ppi_getfn(Param pm)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.i);
+ GsuInteger gsu = (GsuInteger)(c->g);
+ if (locallevel >= pm->level)
+ return gsu->getfn(pm);
+ else
+ return 0;
+}
+
+/**/
+static void
+ppi_setfn(Param pm, zlong x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.i);
+ GsuInteger gsu = (GsuInteger)(c->g);
+ if (locallevel == pm->level)
+ gsu->setfn(pm, x);
+ else
+ setfn_error(pm);
+}
+
+/**/
+static void
+ppi_unsetfn(Param pm, int x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.i);
+ GsuInteger gsu = (GsuInteger)(c->g);
+ pm->gsu.i = gsu;
+ if (locallevel <= pm->level)
+ gsu->unsetfn(pm, x);
+}
+
+/**/
+static double
+ppf_getfn(Param pm)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.f);
+ GsuFloat gsu = (GsuFloat)(c->g);
+ if (locallevel >= pm->level)
+ return gsu->getfn(pm);
+ else
+ return 0;
+}
+
+/**/
+static void
+ppf_setfn(Param pm, double x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.f);
+ GsuFloat gsu = (GsuFloat)(c->g);
+ if (locallevel == pm->level)
+ gsu->setfn(pm, x);
+ else
+ setfn_error(pm);
+}
+
+/**/
+static void
+ppf_unsetfn(Param pm, int x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.f);
+ GsuFloat gsu = (GsuFloat)(c->g);
+ pm->gsu.f = gsu;
+ if (locallevel <= pm->level)
+ gsu->unsetfn(pm, x);
+}
+
+/**/
+static char **
+ppa_getfn(Param pm)
+{
+ static char *nullarray = NULL;
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.a);
+ GsuArray gsu = (GsuArray)(c->g);
+ if (locallevel >= pm->level)
+ return gsu->getfn(pm);
+ else
+ return &nullarray;
+}
+
+/**/
+static void
+ppa_setfn(Param pm, char **x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.a);
+ GsuArray gsu = (GsuArray)(c->g);
+ if (locallevel == pm->level)
+ gsu->setfn(pm, x);
+ else
+ setfn_error(pm);
+}
+
+/**/
+static void
+ppa_unsetfn(Param pm, int x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.a);
+ GsuArray gsu = (GsuArray)(c->g);
+ pm->gsu.a = gsu;
+ if (locallevel <= pm->level)
+ gsu->unsetfn(pm, x);
+}
+
+static HashTable emptytable;
+
+/**/
+static HashTable
+pph_getfn(Param pm)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.h);
+ GsuHash gsu = (GsuHash)(c->g);
+ if (locallevel >= pm->level)
+ return gsu->getfn(pm);
+ else
+ return emptytable;
+}
+
+/**/
+static void
+pph_setfn(Param pm, HashTable x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.h);
+ GsuHash gsu = (GsuHash)(c->g);
+ if (locallevel == pm->level)
+ gsu->setfn(pm, x);
+ else
+ setfn_error(pm);
+}
+
+/**/
+static void
+pph_unsetfn(Param pm, int x)
+{
+ struct gsu_closure *c = (struct gsu_closure *)(pm->gsu.h);
+ GsuHash gsu = (GsuHash)(c->g);
+ pm->gsu.h = gsu;
+ if (locallevel <= pm->level)
+ gsu->unsetfn(pm, x);
+}
+
+/*
+ * How visibility works:
+ *
+ * Upon entering a new function scope, we find all the private parameters
+ * at this locallevel. Any that we find are marked PM_UNSET. If they are
+ * already unset, they are also marked as PM_NORESTORE.
+ *
+ * On exit from the scope, we find the same parameters again and remove
+ * the PM_UNSET and PM_NORESTORE flags as appropriate. We're guaraneed
+ * by makeprivate() that PM_NORESTORE won't conflict with anything here.
+ *
+ */
+
+static void
+scopeprivate(HashNode hn, int onoff)
+{
+ Param pm = (Param)hn;
+ if (pm->level == locallevel) {
+ if (!is_private(pm))
+ return;
+ if (onoff == PM_UNSET)
+ if (pm->node.flags & PM_UNSET)
+ pm->node.flags |= PM_NORESTORE;
+ else
+ pm->node.flags |= PM_UNSET;
+ else if (!(pm->node.flags & PM_NORESTORE))
+ pm->node.flags &= ~PM_UNSET;
+ pm->node.flags &= ~PM_NORESTORE;
+ }
+}
+
+static struct funcwrap wrapper[] = {
+ WRAPDEF(wrap_private)
+};
+
+/**/
+static int
+wrap_private(Eprog prog, FuncWrap w, char *name)
+{
+ static int wraplevel = 0;
+
+ if (wraplevel < locallevel /* && strcmp(name, "(anon)") != 0 */) {
+ int owl = wraplevel;
+ wraplevel = locallevel;
+ scanhashtable(paramtab, 0, 0, 0, scopeprivate, PM_UNSET);
+ runshfunc(prog, w, name);
+ scanhashtable(paramtab, 0, 0, 0, scopeprivate, 0);
+ wraplevel = owl;
+ return 0;
+ }
+ return 1;
+}
+
+static HashNode (*getparamnode) _((HashTable, const char *));
+
+/**/
+static HashNode
+getprivatenode(HashTable ht, const char *nam)
+{
+ HashNode hn = getparamnode(ht, nam);
+ Param pm = (Param) hn;
+
+ while (!fakelevel && pm && locallevel > pm->level && is_private(pm))
+ pm = pm->old;
+ return (HashNode)pm;
+}
+
+/**/
+static HashNode
+getprivatenode2(HashTable ht, const char *nam)
+{
+ /* getparamnode() would follow autoloads, we must not do that here */
+ HashNode hn = gethashnode2(ht, nam);
+ Param pm = (Param) hn;
+
+ while (!fakelevel && pm && locallevel > pm->level && is_private(pm))
+ pm = pm->old;
+ return (HashNode)pm;
+}
+
+/**/
+static void
+printprivatenode(HashNode hn, int printflags)
+{
+ Param pm = (Param) hn;
+ while (pm && (!fakelevel ||
+ (fakelevel > pm->level && (pm->node.flags & PM_UNSET))) &&
+ locallevel > pm->level && is_private(pm))
+ pm = pm->old;
+ /* Ideally, we'd print the word "private" here instead of "typeset"
+ * when the parameter is in fact a private, but that would require
+ * re-implementing the entirety of printparamnode(). */
+ if (pm)
+ printparamnode((HashNode)pm, printflags);
+}
+
+/*
+ * Standard module configuration/linkage
+ */
+
+static struct builtin bintab[] = {
+ /* Copied from BUILTIN("local"), "P" added */
+ BUILTIN("private", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_private, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lprtux", "P")
+};
+
+static struct features module_features = {
+ bintab, sizeof(bintab)/sizeof(*bintab),
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ 0
+};
+
+static struct builtin save_local;
+static struct reswd reswd_private = {{NULL, "private", 0}, TYPESET};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+ HashNode hn = builtintab->getnode(builtintab, "local");
+
+ /* Horrible, horrible hack */
+ getparamnode = realparamtab->getnode;
+ realparamtab->getnode = getprivatenode;
+ realparamtab->getnode2 = getprivatenode2;
+ realparamtab->printnode = printprivatenode;
+
+ /* Even more horrible hack */
+ save_local = *(Builtin)hn;
+ ((Builtin)hn)->handlerfunc = bintab[0].handlerfunc;
+ ((Builtin)hn)->optstr = bintab[0].optstr;
+
+ reswdtab->addnode(reswdtab, reswd_private.node.nam, &reswd_private);
+
+ return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+ *features = featuresarray(m, &module_features);
+ return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+ return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(Module m)
+{
+ emptytable = newparamtable(1, "private");
+ return addwrapper(m, wrapper);
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+ HashNode hn = builtintab->getnode(builtintab, "local");
+ *(Builtin)hn = save_local;
+
+ removehashnode(reswdtab, "private");
+
+ realparamtab->getnode = getparamnode;
+ realparamtab->getnode2 = gethashnode2;
+ realparamtab->printnode = printparamnode;
+
+ deletewrapper(m, wrapper);
+ return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+ deletehashtable(emptytable);
+ return 0;
+}
diff --git a/Src/Modules/param_private.mdd b/Src/Modules/param_private.mdd
new file mode 100644
index 000000000..e6eb3228f
--- /dev/null
+++ b/Src/Modules/param_private.mdd
@@ -0,0 +1,7 @@
+name=zsh/param/private
+link=dynamic
+load=yes
+
+autofeatures="b:private"
+
+objects="param_private.o"
diff --git a/Src/Modules/socket.c b/Src/Modules/socket.c
index 65b87d7dd..7c3fb5ebe 100644
--- a/Src/Modules/socket.c
+++ b/Src/Modules/socket.c
@@ -115,6 +115,8 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
+ addmodulefd(sfd, FDT_EXTERNAL);
+
if (targetfd) {
sfd = redup(sfd, targetfd);
}
@@ -127,7 +129,10 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
- setiparam("REPLY", sfd);
+ /* allow to be closed explicitly */
+ fdtable[sfd] = FDT_EXTERNAL;
+
+ setiparam_no_convert("REPLY", (zlong)sfd);
if (verbose)
printf("%s listener is on fd %d\n", soun.sun_path, sfd);
@@ -200,18 +205,22 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
+ addmodulefd(rfd, FDT_EXTERNAL);
+
if (targetfd) {
sfd = redup(rfd, targetfd);
if (sfd < 0) {
zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
+ zclose(rfd);
return 1;
}
+ fdtable[sfd] = FDT_EXTERNAL;
}
else {
sfd = rfd;
}
- setiparam("REPLY", sfd);
+ setiparam_no_convert("REPLY", (zlong)sfd);
if (verbose)
printf("new connection from %s is on fd %d\n", soun.sun_path, sfd);
@@ -240,15 +249,19 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
}
else
{
+ addmodulefd(sfd, FDT_EXTERNAL);
+
if (targetfd) {
- sfd = redup(sfd, targetfd);
- if (sfd < 0) {
+ if (redup(sfd, targetfd) < 0) {
zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
+ zclose(sfd);
return 1;
}
+ sfd = targetfd;
+ fdtable[sfd] = FDT_EXTERNAL;
}
- setiparam("REPLY", sfd);
+ setiparam_no_convert("REPLY", (zlong)sfd);
if (verbose)
printf("%s is now on fd %d\n", soun.sun_path, sfd);
diff --git a/Src/Modules/tcp.c b/Src/Modules/tcp.c
index bc1765da1..9fc1b29a2 100644
--- a/Src/Modules/tcp.c
+++ b/Src/Modules/tcp.c
@@ -236,6 +236,8 @@ tcp_socket(int domain, int type, int protocol, int ztflags)
if (!sess) return NULL;
sess->fd = socket(domain, type, protocol);
+ /* We'll check failure and tidy up in caller */
+ addmodulefd(sess->fd, FDT_MODULE);
return sess;
}
@@ -298,7 +300,7 @@ tcp_close(Tcp_session sess)
{
if (sess->fd != -1)
{
- err = close(sess->fd);
+ err = zclose(sess->fd);
if (err)
zwarn("connection close failed: %e", errno);
}
@@ -459,7 +461,7 @@ bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
- setiparam("REPLY", sess->fd);
+ setiparam_no_convert("REPLY", (zlong)sess->fd);
if (verbose)
printf("%d listener is on fd %d\n", ntohs(sess->sock.in.sin_port), sess->fd);
@@ -546,6 +548,9 @@ bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
return 1;
}
+ /* redup expects fd is already registered */
+ addmodulefd(rfd, FDT_MODULE);
+
if (targetfd) {
sess->fd = redup(rfd, targetfd);
if (sess->fd < 0) {
@@ -557,7 +562,7 @@ bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
sess->fd = rfd;
}
- setiparam("REPLY", sess->fd);
+ setiparam_no_convert("REPLY", (zlong)sess->fd);
if (verbose)
printf("%d is on fd %d\n", ntohs(sess->peer.in.sin_port), sess->fd);
@@ -676,7 +681,7 @@ bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
}
}
- setiparam("REPLY", sess->fd);
+ setiparam_no_convert("REPLY", (zlong)sess->fd);
if (verbose)
printf("%s:%d is now on fd %d\n",
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index bd51512f9..b4081df5f 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -409,7 +409,7 @@ zfalarm(int tmout)
/**/
static void
-zfpipe()
+zfpipe(void)
{
/* Just ignore SIGPIPE and rely on getting EPIPE from the write. */
signal(SIGPIPE, SIG_IGN);
@@ -450,7 +450,7 @@ zfunalarm(void)
/**/
static void
-zfunpipe()
+zfunpipe(void)
{
if (sigtrapped[SIGPIPE]) {
if (siglists[SIGPIPE] || (sigtrapped[SIGPIPE] & ZSIG_FUNC))
@@ -1298,7 +1298,7 @@ zfstarttrans(char *nam, int recv, off_t sz)
/**/
static void
-zfendtrans()
+zfendtrans(void)
{
zfunsetparam("ZFTP_SIZE");
zfunsetparam("ZFTP_FILE");
@@ -2834,7 +2834,7 @@ newsession(char *nm)
/* Save the existing session: this just means saving the parameters. */
static void
-savesession()
+savesession(void)
{
char **ps, **pd, *val;
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 9741ee287..3b8366076 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -464,7 +464,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
#endif
errno == EINTR));
- setiparam("REPLY", master);
+ setiparam_no_convert("REPLY", (zlong)master);
return 0;
}
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index bac533e7e..8381867d0 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -2116,7 +2116,7 @@ getreal(char *str)
noerrs = 1;
addlinknode(l, dupstring(str));
- prefork(l, 0);
+ prefork(l, 0, NULL);
noerrs = ne;
if (!errflag && nonempty(l) &&
((char *) peekfirst(l)) && ((char *) peekfirst(l))[0])
@@ -3728,7 +3728,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
errflag &= ~ERRFLAG_ERROR;
zcontext_restore();
/* Fine, now do full expansion. */
- prefork(foo, 0);
+ prefork(foo, 0, NULL);
if (!errflag) {
globlist(foo, 0);
if (!errflag)
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 01bcb7cf8..29aaee82a 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -499,7 +499,7 @@ filecol(char *col)
*/
static void
-getcols()
+getcols(void)
{
char *s;
int i, l;
@@ -602,7 +602,7 @@ zcoff(void)
static void
-initiscol()
+initiscol(void)
{
int i;
@@ -868,7 +868,7 @@ putmatchcol(char *group, char *n)
nrefs = MAX_POS - 1;
if ((!pc->prog || !group || pattry(pc->prog, group)) &&
- pattryrefs(pc->pat, n, -1, -1, 0, &nrefs, begpos, endpos)) {
+ pattryrefs(pc->pat, n, -1, -1, NULL, 0, &nrefs, begpos, endpos)) {
if (pc->cols[1]) {
patcols = pc->cols;
@@ -900,7 +900,8 @@ putfilecol(char *group, char *filename, mode_t m, int special)
nrefs = MAX_POS - 1;
if ((!pc->prog || !group || pattry(pc->prog, group)) &&
- pattryrefs(pc->pat, filename, -1, -1, 0, &nrefs, begpos, endpos)) {
+ pattryrefs(pc->pat, filename, -1, -1, NULL,
+ 0, &nrefs, begpos, endpos)) {
if (pc->cols[1]) {
patcols = pc->cols;
@@ -1908,7 +1909,7 @@ singlecalc(int *cp, int l, int *lcp)
}
static void
-singledraw()
+singledraw(void)
{
Cmgroup g;
int mc1, mc2, ml1, ml2, md1, md2, mcc1, mcc2, lc1, lc2, t1, t2;
@@ -3300,7 +3301,7 @@ domenuselect(Hookdef dummy, Chdata dat)
int len;
memset(&mbs, 0, sizeof(mbs));
- len = wcrtomb(s, lastchar_wide, &mbs);
+ len = wcrtomb(toins, lastchar_wide, &mbs);
if (len < 0)
len = 0;
insert[len] = '\0';
diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c
index 05ae43ae6..0e41ac3a5 100644
--- a/Src/Zle/compmatch.c
+++ b/Src/Zle/compmatch.c
@@ -338,8 +338,15 @@ add_match_str(Cmatcher m, char *l, char *w, int wl, int sfx)
char *buf;
buf = (char *) zalloc(blen);
- memcpy(buf, matchbuf, matchbuflen);
- zfree(matchbuf, matchbuflen);
+ if (matchbuf) {
+ memcpy(buf, matchbuf, matchbuflen);
+ zfree(matchbuf, matchbuflen);
+ }
+#ifdef DEBUG
+ else {
+ DPUTS(matchbuflen, "matchbuflen with no matchbuf");
+ }
+#endif
matchbuf = buf;
matchbuflen = blen;
}
@@ -813,10 +820,12 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
continue;
else if (mp->right)
t = pattern_match(mp->right,
- tl + mp->llen - mp->ralen,
+ /* tl + mp->llen - mp->ralen, */
+ tl + mp->llen,
NULL, NULL) &&
pattern_match(mp->right,
- tw + mp->wlen - mp->ralen,
+ /* tw + mp->wlen - mp->ralen, */
+ tw + mp->wlen,
NULL, NULL) &&
(!mp->lalen ||
pattern_match(mp->left, tw + mp->wlen -
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index e5db0867b..60fb096be 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -185,7 +185,7 @@ cd_group(int maxg)
* descriptions. */
static void
-cd_calc()
+cd_calc(void)
{
Cdset set;
Cdstr str;
@@ -236,7 +236,7 @@ cd_sort(const void *a, const void *b)
}
static int
-cd_prep()
+cd_prep(void)
{
Cdrun run, *runp;
Cdset set;
@@ -1693,10 +1693,13 @@ ca_get_opt(Cadef d, char *line, int full, char **end)
for (p = d->opts; p; p = p->next)
if (p->active && ((!p->args || p->type == CAO_NEXT) ?
!strcmp(p->name, line) : strpfx(p->name, line))) {
+ int l = strlen(p->name);
+ if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
+ line[l] && line[l] != '=')
+ continue;
+
if (end) {
/* Return a pointer to the end of the option. */
- int l = strlen(p->name);
-
if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
line[l] == '=')
l++;
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index c61b4ef0e..95d96c95c 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -1306,8 +1306,8 @@ doisearch(char **args, int dir, int pattern)
* this mode.
*/
if (!skip_pos &&
- pattryrefs(patprog, zt, -1, -1, 0, NULL, NULL,
- &end_pos))
+ pattryrefs(patprog, zt, -1, -1, NULL, 0,
+ NULL, NULL, &end_pos))
t = zt;
} else {
if (!matchlist && !skip_pos) {
@@ -1643,7 +1643,7 @@ doisearch(char **args, int dir, int pattern)
} else if (cmd == Th(z_selfinsert)) {
#ifdef MULTIBYTE_SUPPORT
if (!lastchar_wide_valid)
- if (getrestchar(lastchar) == WEOF) {
+ if (getrestchar(lastchar, NULL, NULL) == WEOF) {
handlefeep(zlenoargs);
continue;
}
@@ -1877,7 +1877,7 @@ getvisrchstr(void)
} else {
#ifdef MULTIBYTE_SUPPORT
if (!lastchar_wide_valid)
- if (getrestchar(lastchar) == WEOF) {
+ if (getrestchar(lastchar, NULL, NULL) == WEOF) {
handlefeep(zlenoargs);
continue;
}
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 5b4189faa..069580f8a 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -1501,6 +1501,20 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
* they wait till a key is pressed for the movement anyway */
timeout = !(!virangeflag && !region_active && f && f->widget &&
f->widget->flags & ZLE_VIOPER);
+#ifdef MULTIBYTE_SUPPORT
+ if ((f == Th(z_selfinsert) || f == Th(z_selfinsertunmeta)) &&
+ !lastchar_wide_valid) {
+ int len;
+ VARARR(char, mbc, MB_CUR_MAX);
+ ZLE_INT_T inchar = getrestchar(lastchar, mbc, &len);
+ if (inchar != WEOF && len) {
+ char *ptr = mbc;
+ while (len--)
+ addkeybuf(STOUC(*ptr++));
+ lastlen = keybuflen;
+ }
+ }
+#endif
}
if (!ispfx)
break;
@@ -1521,6 +1535,20 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
return keybuf;
}
+/**/
+static void
+addkeybuf(int c)
+{
+ if(keybuflen + 3 > keybufsz)
+ keybuf = realloc(keybuf, keybufsz *= 2);
+ if(imeta(c)) {
+ keybuf[keybuflen++] = Meta;
+ keybuf[keybuflen++] = c ^ 32;
+ } else
+ keybuf[keybuflen++] = c;
+ keybuf[keybuflen] = 0;
+}
+
/*
* Add a (possibly metafied) byte to the key input so far.
* This handles individual bytes of a multibyte string separately;
@@ -1542,14 +1570,7 @@ getkeybuf(int w)
if(c < 0)
return EOF;
- if(keybuflen + 3 > keybufsz)
- keybuf = realloc(keybuf, keybufsz *= 2);
- if(imeta(c)) {
- keybuf[keybuflen++] = Meta;
- keybuf[keybuflen++] = c ^ 32;
- } else
- keybuf[keybuflen++] = c;
- keybuf[keybuflen] = 0;
+ addkeybuf(c);
return c;
}
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index ec3d2c354..593d636cc 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -933,7 +933,7 @@ getfullchar(int do_keytmout)
int inchar = getbyte((long)do_keytmout, NULL);
#ifdef MULTIBYTE_SUPPORT
- return getrestchar(inchar);
+ return getrestchar(inchar, NULL, NULL);
#else
return inchar;
#endif
@@ -951,7 +951,7 @@ getfullchar(int do_keytmout)
/**/
mod_export ZLE_INT_T
-getrestchar(int inchar)
+getrestchar(int inchar, char *outstr, int *outcount)
{
char c = inchar;
wchar_t outchar;
@@ -965,6 +965,8 @@ getrestchar(int inchar)
*/
lastchar_wide_valid = 1;
+ if (outcount)
+ *outcount = 0;
if (inchar == EOF) {
/* End of input, so reset the shift state. */
memset(&mbs, 0, sizeof mbs);
@@ -1013,6 +1015,10 @@ getrestchar(int inchar)
return lastchar_wide = WEOF;
}
c = inchar;
+ if (outstr) {
+ *outstr++ = c;
+ (*outcount)++;
+ }
}
return lastchar_wide = (ZLE_INT_T)outchar;
}
@@ -1396,7 +1402,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
opts[XTRACE] = oxt;
sfcontext = osc;
endparamscope();
- lastcmd = 0;
+ lastcmd = w->flags;
+ w->flags = 0;
r = 1;
redup(osi, 0);
}
@@ -1975,7 +1982,7 @@ zle_main_entry(int cmd, va_list ap)
static struct builtin bintab[] = {
BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaM:ldDANmrsLRp", NULL),
BUILTIN("vared", 0, bin_vared, 1, 1, 0, "aAcef:hi:M:m:p:r:t:", NULL),
- BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDFgGIKlLmMNrRTUw", NULL),
+ BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDfFgGIKlLmMNrRTUw", NULL),
};
/* The order of the entries in this table has to match the *HOOK
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 2d1862813..0483f758d 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -115,8 +115,9 @@ selfinsert(UNUSED(char **args))
ZLE_CHAR_T tmp;
#ifdef MULTIBYTE_SUPPORT
+ /* may be redundant with getkeymapcmd(), but other widgets call here too */
if (!lastchar_wide_valid)
- if (getrestchar(lastchar) == WEOF)
+ if (getrestchar(lastchar, NULL, NULL) == WEOF)
return 1;
#endif
tmp = LASTFULLCHAR;
@@ -787,12 +788,6 @@ bracketedpaste(char **args)
zmult = 1;
if (region_active)
killregion(zlenoargs);
- /* Chop a final newline if its insertion would be hard to
- * distinguish by the user from the line being accepted. */
- else if (n > 1 && zlecontext != ZLCON_VARED &&
- (zlecs + (insmode ? 0 : n - 1)) >= zlell &&
- wpaste[n-1] == ZWC('\n'))
- n--;
yankcs = yankb = zlecs;
doinsert(wpaste, n);
yanke = zlecs;
@@ -1431,7 +1426,7 @@ executenamedcommand(char *prmt)
else {
#ifdef MULTIBYTE_SUPPORT
if (!lastchar_wide_valid)
- getrestchar(lastchar);
+ getrestchar(lastchar, NULL, NULL);
if (lastchar_wide == WEOF)
feep = 1;
else
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index 000bc388c..b5bb288f1 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -98,9 +98,9 @@ static const struct gsu_integer undo_change_no_gsu =
static const struct gsu_integer undo_limit_no_gsu =
{ get_undo_limit_change, set_undo_limit_change, zleunsetfn };
static const struct gsu_integer yankstart_gsu =
-{ get_yankstart, NULL, zleunsetfn };
+{ get_yankstart, set_yankstart, zleunsetfn };
static const struct gsu_integer yankend_gsu =
-{ get_yankend, NULL, zleunsetfn };
+{ get_yankend, set_yankend, zleunsetfn };
static const struct gsu_integer yankactive_gsu =
{ get_yankactive, NULL, zleunsetfn };
@@ -149,8 +149,8 @@ static struct zleparam {
{ "WIDGET", PM_SCALAR | PM_READONLY, GSU(widget_gsu), NULL },
{ "WIDGETFUNC", PM_SCALAR | PM_READONLY, GSU(widgetfunc_gsu), NULL },
{ "WIDGETSTYLE", PM_SCALAR | PM_READONLY, GSU(widgetstyle_gsu), NULL },
- { "YANK_START", PM_INTEGER | PM_READONLY, GSU(yankstart_gsu), NULL },
- { "YANK_END", PM_INTEGER | PM_READONLY, GSU(yankend_gsu), NULL },
+ { "YANK_START", PM_INTEGER, GSU(yankstart_gsu), NULL },
+ { "YANK_END", PM_INTEGER, GSU(yankend_gsu), NULL },
{ "YANK_ACTIVE", PM_INTEGER | PM_READONLY, GSU(yankactive_gsu), NULL },
{ "ZLE_STATE", PM_SCALAR | PM_READONLY, GSU(zle_state_gsu), NULL },
{ NULL, 0, NULL, NULL }
@@ -503,7 +503,21 @@ get_yankend(UNUSED(Param pm))
static zlong
get_yankactive(UNUSED(Param pm))
{
- return lastcmd & ZLE_YANK;
+ return !!(lastcmd & ZLE_YANK) + !!(lastcmd & ZLE_YANKAFTER);
+}
+
+/**/
+static void
+set_yankstart(UNUSED(Param pm), zlong i)
+{
+ yankb = i;
+}
+
+/**/
+static void
+set_yankend(UNUSED(Param pm), zlong i)
+{
+ yanke = i;
}
/**/
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 0c28c0a2d..6facff429 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -372,7 +372,8 @@ zle_set_highlight(void)
region_highlights[1].atr = TXTUNDERLINE;
if (!suffix_atr_on_set)
region_highlights[2].atr = TXTBOLDFACE;
- /* paste defaults to 0 */
+ if (!paste_atr_on_set)
+ region_highlights[3].atr = TXTSTANDOUT;
allocate_colour_buffer();
}
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 7fd3a5941..271fd8efc 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -352,6 +352,7 @@ bin_zle(char *name, char **args, Options ops, UNUSED(int func))
{ 'U', bin_zle_unget, 1, 1 },
{ 'K', bin_zle_keymap, 1, 1 },
{ 'I', bin_zle_invalidate, 0, 0 },
+ { 'f', bin_zle_flags, 1, -1 },
{ 'F', bin_zle_fd, 0, 2 },
{ 'T', bin_zle_transform, 0, 2},
{ 0, bin_zle_call, 0, -1 },
@@ -466,7 +467,7 @@ bin_zle_mesg(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
static int
bin_zle_unget(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
{
- char *b = *args, *p = b + strlen(b);
+ char *b = unmeta(*args), *p = b + strlen(b);
if (!zleactive) {
zwarnnam(name, "can only be called from widget function");
@@ -625,7 +626,7 @@ bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func)
/**/
static int
-zle_usable()
+zle_usable(void)
{
return zleactive && !incompctlfunc && !incompfunc
#if 0
@@ -642,6 +643,48 @@ zle_usable()
/**/
static int
+bin_zle_flags(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
+{
+ int ret = 0;
+ char **flag;
+
+ if (!zle_usable()) {
+ zwarnnam(name, "can only set flags from a widget");
+ return 1;
+ }
+
+ if (bindk) {
+ Widget w = bindk->widget;
+ if (w) {
+ for (flag = args; *flag; flag++) {
+ if (!strcmp(*flag, "yank")) {
+ w->flags |= ZLE_YANKAFTER;
+ } else if (!strcmp(*flag, "yankbefore"))
+ w->flags |= ZLE_YANKBEFORE;
+ else if (!strcmp(*flag, "kill"))
+ w->flags |= ZLE_KILL;
+ /*
+ * These won't do anything yet, because of how execzlefunc
+ * handles user widgets
+ } else if (!strcmp(*flag, "menucmp"))
+ w->flags |= ZLE_MENUCMP;
+ else if (!strcmp(*flag, "linemove"))
+ w->flags |= ZLE_LINEMOVE;
+ else if (!strcmp(*flag, "keepsuffix"))
+ w->flags |= ZLE_KEEPSUFFIX;
+ */
+ else {
+ zwarnnam(name, "invalid flag `%s' given to zle -f", *flag);
+ ret = 1;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+/**/
+static int
bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func))
{
Thingy t;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index b1a6f9e7e..cc4b7d673 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -1878,6 +1878,7 @@ get_comp_string(void)
if (!isset(IGNOREBRACES)) {
/* Try and deal with foo{xxx etc. */
+ /*}*/
char *curs = s + (isset(COMPLETEINWORD) ? offs : (int)strlen(s));
char *predup = dupstring(s), *dp = predup;
char *bbeg = NULL, *bend = NULL, *dbeg = NULL;
@@ -1889,6 +1890,7 @@ get_comp_string(void)
* we try to get braces after a parameter expansion right,
* but this may fail sometimes. sorry.
*/
+ /*}*/
if (*p == String || *p == Qstring) {
if (p[1] == Inbrace || p[1] == Inpar || p[1] == Inbrack) {
char *tp = p + 1;
@@ -2223,7 +2225,7 @@ doexpansion(char *s, int lst, int olst, int explincmd)
else if (*ts == '\'')
*ts = Snull;
addlinknode(vl, ss);
- prefork(vl, 0);
+ prefork(vl, 0, NULL);
if (errflag)
goto end;
if (lst == COMP_LIST_EXPAND || lst == COMP_EXPAND) {
@@ -2952,6 +2954,9 @@ getcurcmd(void)
return s;
}
+/* Run '$WIDGET $commandword' and then restore the command-line using push-line.
+ */
+
/**/
int
processcmd(UNUSED(char **args))
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 9751f7a1f..6e9a98bde 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -166,13 +166,13 @@ zlecharasstring(ZLE_CHAR_T inchar, char *buf)
}
/*
- * Input a line in internal zle format, possibly using wide characters,
+ * Input: a line in internal zle format, possibly using wide characters,
* possibly not, together with its length and the cursor position.
* The length must be accurate and includes all characters (no NULL
* termination is expected). The input cursor position is only
* significant if outcs is non-NULL.
*
- * Output an ordinary NULL-terminated string, using multibyte characters
+ * Output: an ordinary NULL-terminated string, using multibyte characters
* instead of wide characters where appropriate and with the contents
* metafied.
*
@@ -1436,6 +1436,8 @@ freeundo(void)
freechanges(changes);
freechanges(nextchanges);
zfree(lastline, lastlinesz);
+ lastline = NULL;
+ lastlinesz = 0;
}
/**/
@@ -1739,9 +1741,26 @@ zlecallhook(char *name, char *arg)
zlong
get_undo_current_change(UNUSED(Param pm))
{
+ int remetafy;
+
+ /*
+ * Yuk: we call this from within the completion system,
+ * so we need to convert back to the form which can be
+ * copied into undo entries.
+ */
+ if (zlemetaline != NULL) {
+ unmetafy_line();
+ remetafy = 1;
+ } else
+ remetafy = 0;
+
/* add entry for any pending changes */
mkundoent();
setlastline();
+
+ if (remetafy)
+ metafy_line();
+
return undo_changeno;
}
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index 42dc46e7e..86840bdd6 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -151,7 +151,7 @@ vigetkey(void)
#ifdef MULTIBYTE_SUPPORT
if (!lastchar_wide_valid)
{
- getrestchar(lastchar);
+ getrestchar(lastchar, NULL, NULL);
}
#endif
return LASTFULLCHAR;
diff --git a/Src/builtin.c b/Src/builtin.c
index 97022addf..01eb5b84c 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -58,7 +58,7 @@ static struct builtin builtins[] =
BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmprs", NULL),
BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
BUILTIN("echo", BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"),
- BUILTIN("emulate", 0, bin_emulate, 0, -1, 0, "LR", NULL),
+ BUILTIN("emulate", 0, bin_emulate, 0, -1, 0, "lLR", NULL),
BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", NULL),
BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
@@ -2090,7 +2090,9 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
tc = 0; /* but don't do a normal conversion */
}
} else if (!setsecondstype(pm, on, off)) {
- if (asg->value.scalar && !(pm = setsparam(pname, ztrdup(asg->value.scalar))))
+ if (asg->value.scalar &&
+ !(pm = assignsparam(
+ pname, ztrdup(asg->value.scalar), 0)))
return NULL;
usepm = 1;
err = 0;
@@ -2202,12 +2204,13 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if (pm->env && !(pm->node.flags & PM_HASHELEM))
delenv(pm);
DPUTS(ASG_ARRAYP(asg), "BUG: typeset got array value where scalar expected");
- if (asg->value.scalar && !(pm = setsparam(pname, ztrdup(asg->value.scalar))))
+ if (asg->value.scalar &&
+ !(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
return NULL;
} else if (asg->is_array) {
- if (!(pm = setaparam(pname, asg->value.array ?
+ if (!(pm = assignaparam(pname, asg->value.array ?
zlinklist2array(asg->value.array) :
- mkarray(NULL))))
+ mkarray(NULL), 0)))
return NULL;
}
pm->node.flags |= (on & PM_READONLY);
@@ -2331,7 +2334,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if ((on & PM_LOCAL) && locallevel) {
*subscript = 0;
pm = (Param) (paramtab == realparamtab ?
- gethashnode2(paramtab, pname) :
+ /* getnode2() to avoid autoloading */
+ paramtab->getnode2(paramtab, pname) :
paramtab->getnode(paramtab, pname));
*subscript = '[';
if (!pm || pm->level != locallevel) {
@@ -2347,16 +2351,18 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
* creating a stray parameter along the way via createparam(),
* now called below in the isident() branch.
*/
- if (!(pm = setsparam(pname, ztrdup(asg->value.scalar ? asg->value.scalar : ""))))
+ if (!(pm = assignsparam(
+ pname,
+ ztrdup(asg->value.scalar ? asg->value.scalar : ""), 0)))
return NULL;
dont_set = 1;
asg->is_array = 0;
keeplocal = 0;
on = pm->node.flags;
} else if (PM_TYPE(on) == PM_ARRAY && ASG_ARRAYP(asg)) {
- if (!(pm = setaparam(pname, asg->value.array ?
- zlinklist2array(asg->value.array) :
- mkarray(NULL))))
+ if (!(pm = assignaparam(pname, asg->value.array ?
+ zlinklist2array(asg->value.array) :
+ mkarray(NULL), 0)))
return NULL;
dont_set = 1;
keeplocal = 0;
@@ -2432,14 +2438,30 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
if (ASG_VALUEP(asg) && !dont_set) {
Param ipm = pm;
if (pm->node.flags & (PM_ARRAY|PM_HASHED)) {
- DPUTS(!ASG_ARRAYP(asg), "BUG: inconsistent scalar value for array");
- if (!(pm=setaparam(pname, asg->value.array ?
- zlinklist2array(asg->value.array) :
- mkarray(NULL))))
+ char **arrayval;
+ if (!ASG_ARRAYP(asg)) {
+ /*
+ * Attempt to assign a scalar value to an array.
+ * This can happen if the array is special.
+ * We'll be lenient and guess what the user meant.
+ * This is how normal assigment works.
+ */
+ if (*asg->value.scalar) {
+ /* Array with one value */
+ arrayval = mkarray(ztrdup(asg->value.scalar));
+ } else {
+ /* Empty array */
+ arrayval = mkarray(NULL);
+ }
+ } else if (asg->value.array)
+ arrayval = zlinklist2array(asg->value.array);
+ else
+ arrayval = mkarray(NULL);
+ if (!(pm=assignaparam(pname, arrayval, 0)))
return NULL;
} else {
DPUTS(ASG_ARRAYP(asg), "BUG: inconsistent array value for scalar");
- if (!(pm = setsparam(pname, ztrdup(asg->value.scalar))))
+ if (!(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
return NULL;
}
if (pm != ipm) {
@@ -2687,9 +2709,10 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
/* Update join character */
tdp->joinchar = joinchar;
if (asg0.value.scalar)
- setsparam(asg0.name, ztrdup(asg0.value.scalar));
+ assignsparam(asg0.name, ztrdup(asg0.value.scalar), 0);
else if (asg->value.array)
- setaparam(asg->name, zlinklist2array(asg->value.array));
+ assignaparam(
+ asg->name, zlinklist2array(asg->value.array), 0);
return 0;
} else {
zwarnnam(name, "can't tie already tied scalar: %s",
@@ -2750,9 +2773,9 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
zsfree(apm->ename);
apm->ename = ztrdup(asg0.name);
if (asg->value.array)
- setaparam(asg->name, zlinklist2array(asg->value.array));
+ assignaparam(asg->name, zlinklist2array(asg->value.array), 0);
else if (oldval)
- setsparam(asg0.name, oldval);
+ assignsparam(asg0.name, oldval, 0);
unqueue_signals();
return 0;
@@ -2819,11 +2842,12 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
/* Take arguments literally. Don't glob */
while ((asg = getasg(&argv, assigns))) {
HashNode hn = (paramtab == realparamtab ?
- gethashnode2(paramtab, asg->name) :
+ /* getnode2() to avoid autoloading */
+ paramtab->getnode2(paramtab, asg->name) :
paramtab->getnode(paramtab, asg->name));
if (OPT_ISSET(ops,'p')) {
if (hn)
- printparamnode(hn, printflags);
+ paramtab->printnode(hn, printflags);
else {
zwarnnam(name, "no such variable: %s", asg->name);
returnval = 1;
@@ -3313,7 +3337,8 @@ bin_unset(char *name, char **argv, Options ops, int func)
*ss = 0;
}
pm = (Param) (paramtab == realparamtab ?
- gethashnode2(paramtab, s) :
+ /* getnode2() to avoid autoloading */
+ paramtab->getnode2(paramtab, s) :
paramtab->getnode(paramtab, s));
/*
* Unsetting an unset variable is not an error.
@@ -5419,10 +5444,11 @@ eval(char **argv)
/**/
int
-bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
+bin_emulate(char *nam, char **argv, Options ops, UNUSED(int func))
{
int opt_L = OPT_ISSET(ops, 'L');
int opt_R = OPT_ISSET(ops, 'R');
+ int opt_l = OPT_ISSET(ops, 'l');
int saveemulation, savehackchar;
int ret = 1, new_emulation;
unsigned int savepatterns;
@@ -5437,7 +5463,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
/* without arguments just print current emulation */
if (!shname) {
if (opt_L || opt_R) {
- zwarnnam("emulate", "not enough arguments");
+ zwarnnam(nam, "not enough arguments");
return 1;
}
@@ -5465,27 +5491,43 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
/* with single argument set current emulation */
if (!argv[1]) {
- emulate(shname, opt_R, &emulation, opts);
+ char *cmdopts;
+ if (opt_l) {
+ cmdopts = (char *)zhalloc(OPT_SIZE);
+ memcpy(cmdopts, opts, OPT_SIZE);
+ } else
+ cmdopts = opts;
+ emulate(shname, opt_R, &emulation, cmdopts);
if (opt_L)
- opts[LOCALOPTIONS] = opts[LOCALTRAPS] = opts[LOCALPATTERNS] = 1;
+ cmdopts[LOCALOPTIONS] = cmdopts[LOCALTRAPS] =
+ cmdopts[LOCALPATTERNS] = 1;
+ if (opt_l) {
+ list_emulate_options(cmdopts, opt_R);
+ return 0;
+ }
clearpatterndisables();
return 0;
}
+ if (opt_l) {
+ zwarnnam(nam, "too many arguments for -l");
+ return 1;
+ }
+
argv++;
memcpy(saveopts, opts, sizeof(opts));
memcpy(new_opts, opts, sizeof(opts));
savehackchar = keyboardhackchar;
emulate(shname, opt_R, &new_emulation, new_opts);
optlist = newlinklist();
- if (parseopts("emulate", &argv, new_opts, &cmd, optlist)) {
+ if (parseopts(nam, &argv, new_opts, &cmd, optlist)) {
ret = 1;
goto restore;
}
/* parseopts() has consumed anything that looks like an option */
if (*argv) {
- zwarnnam("emulate", "unknown argument %s", *argv);
+ zwarnnam(nam, "unknown argument %s", *argv);
goto restore;
}
@@ -5504,7 +5546,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
*/
if (cmd) {
if (opt_L) {
- zwarnnam("emulate", "option -L incompatible with -c");
+ zwarnnam(nam, "option -L incompatible with -c");
goto restore2;
}
*--argv = cmd; /* on stack, never free()d, see execbuiltin() */
diff --git a/Src/cond.c b/Src/cond.c
index df9065660..c5ab65eea 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -43,7 +43,7 @@ static void cond_subst(char **strp, int glob_ok)
checkglobqual(*strp, strlen(*strp), 1, NULL)) {
LinkList args = newlinklist();
addlinknode(args, *strp);
- prefork(args, 0);
+ prefork(args, 0, NULL);
while (!errflag && args && nonempty(args) &&
has_token((char *)peekfirst(args)))
zglob(args, firstnode(args), 0);
diff --git a/Src/exec.c b/Src/exec.c
index 109a04a26..c0ee527b7 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -176,7 +176,8 @@ mod_export int sfcontext;
/**/
struct execstack *exstack;
-/* Stack with names of functions currently active. */
+/* Stack with names of function calls, 'source' calls, and 'eval' calls
+ * currently active. */
/**/
mod_export Funcstack funcstack;
@@ -1363,7 +1364,8 @@ sublist_done:
* we hit execcmd on the way down. We're now
* on the way back up, so don't restore it.
*/
- noerrexit = (oldnoerrexit == 2) ? 0 : oldnoerrexit;
+ if (oldnoerrexit != 2)
+ noerrexit = oldnoerrexit;
if (sigtrapped[SIGDEBUG] && !isset(DEBUGBEFORECMD) && !donedebug) {
/*
@@ -2288,7 +2290,7 @@ addvars(Estate state, Wordcode pc, int addflags)
if (vl && htok) {
prefork(vl, (isstr ? (PREFORK_SINGLE|PREFORK_ASSIGN) :
- PREFORK_ASSIGN));
+ PREFORK_ASSIGN), NULL);
if (errflag) {
state->pc = opc;
return;
@@ -2414,7 +2416,7 @@ void
execsubst(LinkList strs)
{
if (strs) {
- prefork(strs, esprefork);
+ prefork(strs, esprefork, NULL);
if (esglob && !errflag) {
LinkList ostrs = strs;
globlist(strs, 0);
@@ -2719,7 +2721,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
/* Do prefork substitutions */
esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0;
if (args && htok)
- prefork(args, esprefork);
+ prefork(args, esprefork, NULL);
if (type == WC_SIMPLE || type == WC_TYPESET) {
int unglobbed = 0;
@@ -3556,7 +3558,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
*/
/* Unused dummy value for name */
(void)ecgetstr(state, EC_DUPTOK, &htok);
- prefork(&svl, PREFORK_TYPESET);
+ prefork(&svl, PREFORK_TYPESET, NULL);
if (errflag) {
state->pc = opc;
break;
@@ -3582,7 +3584,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
}
continue;
}
- prefork(&svl, PREFORK_SINGLE);
+ prefork(&svl, PREFORK_SINGLE, NULL);
name = empty(&svl) ? "" :
(char *)getdata(firstnode(&svl));
}
@@ -3598,7 +3600,9 @@ execcmd(Estate state, int input, int output, int how, int last1)
} else {
if (htok) {
init_list1(svl, val);
- prefork(&svl, PREFORK_SINGLE|PREFORK_ASSIGN);
+ prefork(&svl,
+ PREFORK_SINGLE|PREFORK_ASSIGN,
+ NULL);
if (errflag) {
state->pc = opc;
break;
@@ -3620,7 +3624,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
EC_DUPTOK, &htok);
if (asg->value.array)
{
- prefork(asg->value.array, PREFORK_ASSIGN);
+ prefork(asg->value.array, PREFORK_ASSIGN, NULL);
if (errflag) {
state->pc = opc;
break;
@@ -5065,230 +5069,230 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
#ifdef MAX_FUNCTION_DEPTH
static int funcdepth;
#endif
+ Heap funcheap;
queue_signals(); /* Lots of memory and global state changes coming */
- pushheap();
+ NEWHEAPS(funcheap) {
+ oargv0 = NULL;
+ obreaks = breaks;
+ ocontflag = contflag;
+ oloops = loops;
+ if (trap_state == TRAP_STATE_PRIMED)
+ trap_return--;
+ oldlastval = lastval;
+ oldnumpipestats = numpipestats;
+ if (noreturnval) {
+ /*
+ * Easiest to use the heap here since we're bracketed
+ * immediately by a pushheap/popheap pair.
+ */
+ size_t bytes = sizeof(int)*numpipestats;
+ oldpipestats = (int *)zhalloc(bytes);
+ memcpy(oldpipestats, pipestats, bytes);
+ }
- oargv0 = NULL;
- obreaks = breaks;
- ocontflag = contflag;
- oloops = loops;
- if (trap_state == TRAP_STATE_PRIMED)
- trap_return--;
- oldlastval = lastval;
- oldnumpipestats = numpipestats;
- if (noreturnval) {
- /*
- * Easiest to use the heap here since we're bracketed
- * immediately by a pushheap/popheap pair.
- */
- size_t bytes = sizeof(int)*numpipestats;
- oldpipestats = (int *)zhalloc(bytes);
- memcpy(oldpipestats, pipestats, bytes);
- }
+ starttrapscope();
+ startpatternscope();
+
+ pptab = pparams;
+ if (!(flags & PM_UNDEFINED))
+ scriptname = dupstring(name);
+ oldzoptind = zoptind;
+ oldoptcind = optcind;
+ if (!isset(POSIXBUILTINS)) {
+ zoptind = 1;
+ optcind = 0;
+ }
- starttrapscope();
- startpatternscope();
-
- pptab = pparams;
- if (!(flags & PM_UNDEFINED))
- scriptname = dupstring(name);
- oldzoptind = zoptind;
- oldoptcind = optcind;
- if (!isset(POSIXBUILTINS)) {
- zoptind = 1;
- optcind = 0;
- }
+ /* We need to save the current options even if LOCALOPTIONS is *
+ * not currently set. That's because if it gets set in the *
+ * function we need to restore the original options on exit. */
+ memcpy(saveopts, opts, sizeof(opts));
+ saveemulation = emulation;
+ save_sticky = sticky;
- /* We need to save the current options even if LOCALOPTIONS is *
- * not currently set. That's because if it gets set in the *
- * function we need to restore the original options on exit. */
- memcpy(saveopts, opts, sizeof(opts));
- saveemulation = emulation;
- save_sticky = sticky;
+ if (sticky_emulation_differs(shfunc->sticky)) {
+ /*
+ * Function is marked for sticky emulation.
+ * Enable it now.
+ *
+ * We deliberately do not do this if the sticky emulation
+ * in effect is the same as that requested. This enables
+ * option setting naturally within emulation environments.
+ * Note that a difference in EMULATE_FULLY (emulate with
+ * or without -R) counts as a different environment.
+ *
+ * This propagates the sticky emulation to subfunctions.
+ */
+ sticky = sticky_emulation_dup(shfunc->sticky, 1);
+ emulation = sticky->emulation;
+ restore_sticky = 1;
+ installemulation(emulation, opts);
+ if (sticky->n_on_opts) {
+ OptIndex *onptr;
+ for (onptr = sticky->on_opts;
+ onptr < sticky->on_opts + sticky->n_on_opts;
+ onptr++)
+ opts[*onptr] = 1;
+ }
+ if (sticky->n_off_opts) {
+ OptIndex *offptr;
+ for (offptr = sticky->off_opts;
+ offptr < sticky->off_opts + sticky->n_off_opts;
+ offptr++)
+ opts[*offptr] = 0;
+ }
+ /* All emulations start with pattern disables clear */
+ clearpatterndisables();
+ } else
+ restore_sticky = 0;
- if (sticky_emulation_differs(shfunc->sticky)) {
+ if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
+ opts[XTRACE] = 1;
+ else if (oflags & PM_TAGGED_LOCAL)
+ opts[XTRACE] = 0;
+ ooflags = oflags;
/*
- * Function is marked for sticky emulation.
- * Enable it now.
- *
- * We deliberately do not do this if the sticky emulation
- * in effect is the same as that requested. This enables
- * option setting naturally within emulation environments.
- * Note that a difference in EMULATE_FULLY (emulate with
- * or without -R) counts as a different environment.
- *
- * This propagates the sticky emulation to subfunctions.
+ * oflags is static, because we compare it on the next recursive
+ * call. Hence also we maintain ooflags for restoring the previous
+ * value of oflags after the call.
*/
- sticky = sticky_emulation_dup(shfunc->sticky, 1);
- emulation = sticky->emulation;
- restore_sticky = 1;
- installemulation(emulation, opts);
- if (sticky->n_on_opts) {
- OptIndex *onptr;
- for (onptr = sticky->on_opts;
- onptr < sticky->on_opts + sticky->n_on_opts;
- onptr++)
- opts[*onptr] = 1;
- }
- if (sticky->n_off_opts) {
- OptIndex *offptr;
- for (offptr = sticky->off_opts;
- offptr < sticky->off_opts + sticky->n_off_opts;
- offptr++)
- opts[*offptr] = 0;
- }
- /* All emulations start with pattern disables clear */
- clearpatterndisables();
- } else
- restore_sticky = 0;
-
- if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
- opts[XTRACE] = 1;
- else if (oflags & PM_TAGGED_LOCAL)
- opts[XTRACE] = 0;
- ooflags = oflags;
- /*
- * oflags is static, because we compare it on the next recursive
- * call. Hence also we maintain ooflags for restoring the previous
- * value of oflags after the call.
- */
- oflags = flags;
- opts[PRINTEXITVALUE] = 0;
- if (doshargs) {
- LinkNode node;
-
- node = firstnode(doshargs);
- pparams = x = (char **) zshcalloc(((sizeof *x) *
- (1 + countlinknodes(doshargs))));
- if (isset(FUNCTIONARGZERO)) {
- oargv0 = argzero;
- argzero = ztrdup(getdata(node));
- }
- /* first node contains name regardless of option */
- node = node->next;
- for (; node; node = node->next, x++)
- *x = ztrdup(getdata(node));
- } else {
- pparams = (char **) zshcalloc(sizeof *pparams);
- if (isset(FUNCTIONARGZERO)) {
- oargv0 = argzero;
- argzero = ztrdup(argzero);
+ oflags = flags;
+ opts[PRINTEXITVALUE] = 0;
+ if (doshargs) {
+ LinkNode node;
+
+ node = firstnode(doshargs);
+ pparams = x = (char **) zshcalloc(((sizeof *x) *
+ (1 + countlinknodes(doshargs))));
+ if (isset(FUNCTIONARGZERO)) {
+ oargv0 = argzero;
+ argzero = ztrdup(getdata(node));
+ }
+ /* first node contains name regardless of option */
+ node = node->next;
+ for (; node; node = node->next, x++)
+ *x = ztrdup(getdata(node));
+ } else {
+ pparams = (char **) zshcalloc(sizeof *pparams);
+ if (isset(FUNCTIONARGZERO)) {
+ oargv0 = argzero;
+ argzero = ztrdup(argzero);
+ }
}
- }
#ifdef MAX_FUNCTION_DEPTH
- if(++funcdepth > MAX_FUNCTION_DEPTH)
- {
- zerr("maximum nested function level reached");
- goto undoshfunc;
- }
+ if(++funcdepth > MAX_FUNCTION_DEPTH)
+ {
+ zerr("maximum nested function level reached");
+ goto undoshfunc;
+ }
#endif
- fstack.name = dupstring(name);
- /*
- * The caller is whatever is immediately before on the stack,
- * unless we're at the top, in which case it's the script
- * or interactive shell name.
- */
- fstack.caller = funcstack ? funcstack->name :
- dupstring(oargv0 ? oargv0 : argzero);
- fstack.lineno = lineno;
- fstack.prev = funcstack;
- fstack.tp = FS_FUNC;
- funcstack = &fstack;
-
- fstack.flineno = shfunc->lineno;
- fstack.filename = dupstring(shfunc->filename);
-
- prog = shfunc->funcdef;
- if (prog->flags & EF_RUN) {
- Shfunc shf;
+ fstack.name = dupstring(name);
+ /*
+ * The caller is whatever is immediately before on the stack,
+ * unless we're at the top, in which case it's the script
+ * or interactive shell name.
+ */
+ fstack.caller = funcstack ? funcstack->name :
+ dupstring(oargv0 ? oargv0 : argzero);
+ fstack.lineno = lineno;
+ fstack.prev = funcstack;
+ fstack.tp = FS_FUNC;
+ funcstack = &fstack;
- prog->flags &= ~EF_RUN;
+ fstack.flineno = shfunc->lineno;
+ fstack.filename = dupstring(shfunc->filename);
- runshfunc(prog, NULL, fstack.name);
+ prog = shfunc->funcdef;
+ if (prog->flags & EF_RUN) {
+ Shfunc shf;
- if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
- (name = fname)))) {
- zwarn("%s: function not defined by file", name);
- if (noreturnval)
- errflag |= ERRFLAG_ERROR;
- else
- lastval = 1;
- goto doneshfunc;
+ prog->flags &= ~EF_RUN;
+
+ runshfunc(prog, NULL, fstack.name);
+
+ if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
+ (name = fname)))) {
+ zwarn("%s: function not defined by file", name);
+ if (noreturnval)
+ errflag |= ERRFLAG_ERROR;
+ else
+ lastval = 1;
+ goto doneshfunc;
+ }
+ prog = shf->funcdef;
}
- prog = shf->funcdef;
- }
- runshfunc(prog, wrappers, fstack.name);
- doneshfunc:
- funcstack = fstack.prev;
+ runshfunc(prog, wrappers, fstack.name);
+ doneshfunc:
+ funcstack = fstack.prev;
#ifdef MAX_FUNCTION_DEPTH
- undoshfunc:
- --funcdepth;
+ undoshfunc:
+ --funcdepth;
#endif
- if (retflag) {
- retflag = 0;
- breaks = obreaks;
- }
- freearray(pparams);
- if (oargv0) {
- zsfree(argzero);
- argzero = oargv0;
- }
- pparams = pptab;
- if (!isset(POSIXBUILTINS)) {
- zoptind = oldzoptind;
- optcind = oldoptcind;
- }
- scriptname = oldscriptname;
- oflags = ooflags;
+ if (retflag) {
+ retflag = 0;
+ breaks = obreaks;
+ }
+ freearray(pparams);
+ if (oargv0) {
+ zsfree(argzero);
+ argzero = oargv0;
+ }
+ pparams = pptab;
+ if (!isset(POSIXBUILTINS)) {
+ zoptind = oldzoptind;
+ optcind = oldoptcind;
+ }
+ scriptname = oldscriptname;
+ oflags = ooflags;
- endpatternscope(); /* before restoring old LOCALPATTERNS */
+ endpatternscope(); /* before restoring old LOCALPATTERNS */
- if (restore_sticky) {
- /*
- * If we switched to an emulation environment just for
- * this function, we interpret the option and emulation
- * switch as being a firewall between environments.
- */
- memcpy(opts, saveopts, sizeof(opts));
- emulation = saveemulation;
- sticky = save_sticky;
- } else if (isset(LOCALOPTIONS)) {
- /* restore all shell options except PRIVILEGED and RESTRICTED */
- saveopts[PRIVILEGED] = opts[PRIVILEGED];
- saveopts[RESTRICTED] = opts[RESTRICTED];
- memcpy(opts, saveopts, sizeof(opts));
- emulation = saveemulation;
- } else {
- /* just restore a couple. */
- opts[XTRACE] = saveopts[XTRACE];
- opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
- opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
- opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
- }
+ if (restore_sticky) {
+ /*
+ * If we switched to an emulation environment just for
+ * this function, we interpret the option and emulation
+ * switch as being a firewall between environments.
+ */
+ memcpy(opts, saveopts, sizeof(opts));
+ emulation = saveemulation;
+ sticky = save_sticky;
+ } else if (isset(LOCALOPTIONS)) {
+ /* restore all shell options except PRIVILEGED and RESTRICTED */
+ saveopts[PRIVILEGED] = opts[PRIVILEGED];
+ saveopts[RESTRICTED] = opts[RESTRICTED];
+ memcpy(opts, saveopts, sizeof(opts));
+ emulation = saveemulation;
+ } else {
+ /* just restore a couple. */
+ opts[XTRACE] = saveopts[XTRACE];
+ opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
+ opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
+ opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
+ }
- if (opts[LOCALLOOPS]) {
- if (contflag)
- zwarn("`continue' active at end of function scope");
- if (breaks)
- zwarn("`break' active at end of function scope");
- breaks = obreaks;
- contflag = ocontflag;
- loops = oloops;
- }
+ if (opts[LOCALLOOPS]) {
+ if (contflag)
+ zwarn("`continue' active at end of function scope");
+ if (breaks)
+ zwarn("`break' active at end of function scope");
+ breaks = obreaks;
+ contflag = ocontflag;
+ loops = oloops;
+ }
- endtrapscope();
+ endtrapscope();
- if (trap_state == TRAP_STATE_PRIMED)
- trap_return++;
- ret = lastval;
- if (noreturnval) {
- lastval = oldlastval;
- numpipestats = oldnumpipestats;
- memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
- }
- popheap();
+ if (trap_state == TRAP_STATE_PRIMED)
+ trap_return++;
+ ret = lastval;
+ if (noreturnval) {
+ lastval = oldlastval;
+ numpipestats = oldnumpipestats;
+ memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
+ }
+ } OLDHEAPS;
unqueue_signals();
diff --git a/Src/glob.c b/Src/glob.c
index dea1bf50e..94b3f620d 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -634,8 +634,10 @@ scanner(Complist q, int shortcircuit)
} else {
/* if the last filename component, just add it */
insert(fn, 1);
- if (shortcircuit && shortcircuit == matchct)
+ if (shortcircuit && shortcircuit == matchct) {
+ closedir(lock);
return;
+ }
}
}
}
@@ -680,25 +682,32 @@ parsecomplist(char *instr)
char *str;
int compflags = gf_noglobdots ? (PAT_FILE|PAT_NOGLD) : PAT_FILE;
- if (instr[0] == Star && instr[1] == Star &&
- (instr[2] == '/' || (instr[2] == Star && instr[3] == '/'))) {
- /* Match any number of directories. */
- int follow;
+ if (instr[0] == Star && instr[1] == Star) {
+ int shortglob = 0;
+ if (instr[2] == '/' || (instr[2] == Star && instr[3] == '/')
+ || (shortglob = isset(GLOBSTARSHORT))) {
+ /* Match any number of directories. */
+ int follow;
- /* with three stars, follow symbolic links */
- follow = (instr[2] == Star);
- instr += (3 + follow);
+ /* with three stars, follow symbolic links */
+ follow = (instr[2] == Star);
+ /*
+ * With GLOBSTARSHORT, leave a star in place for the
+ * pattern inside the directory.
+ */
+ instr += ((shortglob ? 1 : 3) + follow);
- /* Now get the next path component if there is one. */
- l1 = (Complist) zhalloc(sizeof *l1);
- if ((l1->next = parsecomplist(instr)) == NULL) {
- errflag |= ERRFLAG_ERROR;
- return NULL;
+ /* Now get the next path component if there is one. */
+ l1 = (Complist) zhalloc(sizeof *l1);
+ if ((l1->next = parsecomplist(instr)) == NULL) {
+ errflag |= ERRFLAG_ERROR;
+ return NULL;
+ }
+ l1->pat = patcompile(NULL, compflags | PAT_ANY, NULL);
+ l1->closure = 1; /* ...zero or more times. */
+ l1->follow = follow;
+ return l1;
}
- l1->pat = patcompile(NULL, compflags | PAT_ANY, NULL);
- l1->closure = 1; /* ...zero or more times. */
- l1->follow = follow;
- return l1;
}
/* Parse repeated directories such as (dir/)# and (dir/)## */
@@ -2084,7 +2093,7 @@ xpandredir(struct redir *fn, LinkList redirtab)
/* Stick the name in a list... */
init_list1(fake, fn->name);
/* ...which undergoes all the usual shell expansions */
- prefork(&fake, isset(MULTIOS) ? 0 : PREFORK_SINGLE);
+ prefork(&fake, isset(MULTIOS) ? 0 : PREFORK_SINGLE, NULL);
/* Globbing is only done for multios. */
if (!errflag && isset(MULTIOS))
globlist(&fake, 0);
@@ -2448,29 +2457,43 @@ matchpat(char *a, char *b)
/* please do not laugh at this code. */
/* Having found a match in getmatch, decide what part of string
- * to return. The matched part starts b characters into string s
- * and finishes e characters in: 0 <= b <= e <= strlen(s)
+ * to return. The matched part starts b characters into string imd->ustr
+ * and finishes e characters in: 0 <= b <= e <= imd->ulen on input
* (yes, empty matches should work).
- * fl is a set of the SUB_* matches defined in zsh.h from SUB_MATCH onwards;
- * the lower parts are ignored.
- * replstr is the replacement string for a substitution
+ *
+ * imd->flags is a set of the SUB_* matches defined in zsh.h from
+ * SUB_MATCH onwards; the lower parts are ignored.
+ *
+ * imd->replstr is the replacement string for a substitution
+ *
+ * imd->replstr is metafied and the values put in imd->repllist are metafied.
*/
/**/
static char *
-get_match_ret(char *s, int b, int e, int fl, char *replstr,
- LinkList repllist)
+get_match_ret(Imatchdata imd, int b, int e)
{
- char buf[80], *r, *p, *rr;
- int ll = 0, l = strlen(s), bl = 0, t = 0, i;
-
+ char buf[80], *r, *p, *rr, *replstr = imd->replstr;
+ int ll = 0, bl = 0, t = 0, add = 0, fl = imd->flags, i;
+
+ /* Account for b and e referring to unmetafied string */
+ for (p = imd->ustr; p < imd->ustr + b; p++)
+ if (imeta(*p))
+ add++;
+ b += add;
+ for (; p < imd->ustr + e; p++)
+ if (imeta(*p))
+ add++;
+ e += add;
+
+ /* Everything now refers to metafied lengths. */
if (replstr || (fl & SUB_LIST)) {
if (fl & SUB_DOSUBST) {
replstr = dupstring(replstr);
singsub(&replstr);
untokenize(replstr);
}
- if ((fl & (SUB_GLOBAL|SUB_LIST)) && repllist) {
+ if ((fl & (SUB_GLOBAL|SUB_LIST)) && imd->repllist) {
/* We are replacing the chunk, just add this to the list */
Repldata rd = (Repldata)
((fl & SUB_LIST) ? zalloc(sizeof(*rd)) : zhalloc(sizeof(*rd)));
@@ -2478,30 +2501,32 @@ get_match_ret(char *s, int b, int e, int fl, char *replstr,
rd->e = e;
rd->replstr = replstr;
if (fl & SUB_LIST)
- zaddlinknode(repllist, rd);
+ zaddlinknode(imd->repllist, rd);
else
- addlinknode(repllist, rd);
- return s;
+ addlinknode(imd->repllist, rd);
+ return imd->mstr;
}
ll += strlen(replstr);
}
if (fl & SUB_MATCH) /* matched portion */
ll += 1 + (e - b);
if (fl & SUB_REST) /* unmatched portion */
- ll += 1 + (l - (e - b));
+ ll += 1 + (imd->mlen - (e - b));
if (fl & SUB_BIND) {
/* position of start of matched portion */
- sprintf(buf, "%d ", b + 1);
+ sprintf(buf, "%d ", MB_METASTRLEN2END(imd->mstr, 0, imd->mstr+b) + 1);
ll += (bl = strlen(buf));
}
if (fl & SUB_EIND) {
/* position of end of matched portion */
- sprintf(buf + bl, "%d ", e + 1);
+ sprintf(buf + bl, "%d ",
+ MB_METASTRLEN2END(imd->mstr, 0, imd->mstr+e) + 1);
ll += (bl = strlen(buf));
}
if (fl & SUB_LEN) {
/* length of matched portion */
- sprintf(buf + bl, "%d ", e - b);
+ sprintf(buf + bl, "%d ", MB_METASTRLEN2END(imd->mstr+b, 0,
+ imd->mstr+e));
ll += (bl = strlen(buf));
}
if (bl)
@@ -2511,7 +2536,7 @@ get_match_ret(char *s, int b, int e, int fl, char *replstr,
if (fl & SUB_MATCH) {
/* copy matched portion to new buffer */
- for (i = b, p = s + b; i < e; i++)
+ for (i = b, p = imd->mstr + b; i < e; i++)
*rr++ = *p++;
t = 1;
}
@@ -2521,12 +2546,12 @@ get_match_ret(char *s, int b, int e, int fl, char *replstr,
if (t)
*rr++ = ' ';
/* there may be unmatched bits at both beginning and end of string */
- for (i = 0, p = s; i < b; i++)
+ for (i = 0, p = imd->mstr; i < b; i++)
*rr++ = *p++;
if (replstr)
for (p = replstr; *p; )
*rr++ = *p++;
- for (i = e, p = s + e; i < l; i++)
+ for (i = e, p = imd->mstr + e; i < imd->mlen; i++)
*rr++ = *p++;
t = 1;
}
@@ -2708,26 +2733,18 @@ set_pat_end(Patprog p, char null_me)
/*
* Increment *tp over character which may be multibyte.
- * Return number of bytes that remain in the character after unmetafication.
+ * Return number of bytes.
+ * All unmetafied here.
*/
/**/
-static int iincchar(char **tp)
+static int iincchar(char **tp, int left)
{
char *t = *tp;
- int mbclen = mb_metacharlenconv(t, NULL);
- int umlen = 0;
-
- while (mbclen--) {
- umlen++;
- if (*t++ == Meta) {
- t++;
- mbclen--;
- }
- }
- *tp = t;
+ int mbclen = mb_charlenconv(t, left, NULL);
+ *tp = t + mbclen;
- return umlen;
+ return mbclen;
}
/**/
@@ -2735,7 +2752,7 @@ static int
igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
LinkList *repllistp)
{
- char *s = *sp, *t, *tmatch;
+ char *s = *sp, *t, *tmatch, *send;
/*
* Note that ioff counts (possibly multibyte) characters in the
* character set (Meta's are not included), while l counts characters in
@@ -2750,36 +2767,51 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
*/
int ioff, l = strlen(*sp), matched = 1, umltot = ztrlen(*sp);
int umlen, nmatches;
- /*
- * List of bits of matches to concatenate with replacement string.
- * The data is a struct repldata. It is not used in cases like
- * ${...//#foo/bar} even though SUB_GLOBAL is set, since the match
- * is anchored. It goes on the heap.
- */
- LinkList repllist = NULL;
+ struct patstralloc patstralloc;
+ struct imatchdata imd;
+
+ (void)patallocstr(p, s, l, umltot, 1, &patstralloc);
+ s = patstralloc.alloced;
+ DPUTS(!s, "forced patallocstr failed");
+ send = s + umltot;
+
+ imd.mstr = *sp;
+ imd.mlen = l;
+ imd.ustr = s;
+ imd.ulen = umltot;
+ imd.flags = fl;
+ imd.replstr = replstr;
+ imd.repllist = NULL;
/* perform must-match test for complex closures */
if (p->mustoff)
{
- /*
- * Yuk. Probably we should rewrite this whole function to
- * use an unmetafied test string.
- *
- * Use META_HEAPDUP because we need a terminating NULL.
- */
- char *muststr = metafy((char *)p + p->mustoff,
- p->patmlen, META_HEAPDUP);
+ char *muststr = (char *)p + p->mustoff;
- if (!strstr(s, muststr))
- matched = 0;
+ matched = 0;
+ if (p->patmlen <= umltot)
+ {
+ for (t = s; t <= send - p->patmlen; t++)
+ {
+ if (!memcmp(muststr, t, p->patmlen)) {
+ matched = 1;
+ break;
+ }
+ }
+ }
}
/* in case we used the prog before... */
p->flags &= ~(PAT_NOTSTART|PAT_NOTEND);
if (fl & SUB_ALL) {
- int i = matched && pattry(p, s);
- *sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0, NULL);
+ int i = matched && pattrylen(p, s, umltot, 0, &patstralloc, 0);
+ if (!i) {
+ /* Perform under no-match conditions */
+ umltot = 0;
+ imd.replstr = NULL;
+ }
+ *sp = get_match_ret(&imd, 0, umltot);
if (! **sp && (((fl & SUB_MATCH) && !i) || ((fl & SUB_REST) && i)))
return 0;
return 1;
@@ -2807,25 +2839,26 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
* Largest/smallest possible match at head of string.
* First get the longest match...
*/
- if (pattry(p, s)) {
- /* patmatchlen returns metafied length, as we need */
+ if (pattrylen(p, s, umltot, 0, &patstralloc, 0)) {
+ /* patmatchlen returns unmetafied length in this case */
int mlen = patmatchlen();
if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
+ send = s + mlen;
/*
* ... now we know whether it's worth looking for the
* shortest, which we do by brute force.
*/
mb_charinit();
- for (t = s, umlen = 0; t < s + mlen; ) {
+ for (t = s, umlen = 0; t < send; ) {
set_pat_end(p, *t);
- if (pattrylen(p, s, t - s, umlen, 0)) {
+ if (pattrylen(p, s, umlen, 0, &patstralloc, 0)) {
mlen = patmatchlen();
break;
}
- umlen += iincchar(&t);
+ umlen += iincchar(&t, send - t);
}
}
- *sp = get_match_ret(*sp, 0, mlen, fl, replstr, NULL);
+ *sp = get_match_ret(&imd, 0, mlen);
return 1;
}
break;
@@ -2843,20 +2876,21 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
*/
mb_charinit();
tmatch = NULL;
- for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) {
+ for (ioff = 0, t = s, umlen = umltot; t < send; ioff++) {
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff))
+ if (pattrylen(p, t, umlen, 0, &patstralloc, ioff))
tmatch = t;
if (fl & SUB_START)
break;
- umlen -= iincchar(&t);
+ umlen -= iincchar(&t, send - t);
}
if (tmatch) {
- *sp = get_match_ret(*sp, tmatch - s, l, fl, replstr, NULL);
+ *sp = get_match_ret(&imd, tmatch - s, umltot);
return 1;
}
- if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, ioff)) {
- *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
+ if (!(fl & SUB_START) && pattrylen(p, s + umltot, 0, 0,
+ &patstralloc, ioff)) {
+ *sp = get_match_ret(&imd, umltot, umltot);
return 1;
}
break;
@@ -2866,18 +2900,19 @@ 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 < s + l; ioff++) {
+ for (ioff = 0, t = s, umlen = umltot; t < send ; ioff++) {
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff)) {
- *sp = get_match_ret(*sp, t-s, l, fl, replstr, NULL);
+ if (pattrylen(p, t, umlen, 0, &patstralloc, ioff)) {
+ *sp = get_match_ret(&imd, t-s, umltot);
return 1;
}
if (fl & SUB_START)
break;
- umlen -= iincchar(&t);
+ umlen -= iincchar(&t, send - t);
}
- if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, ioff)) {
- *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
+ if (!(fl & SUB_START) && pattrylen(p, send, 0, 0,
+ &patstralloc, ioff)) {
+ *sp = get_match_ret(&imd, umltot, umltot);
return 1;
}
break;
@@ -2885,17 +2920,19 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
case SUB_SUBSTR:
/* Smallest at start, but matching substrings. */
set_pat_start(p, l);
- if (!(fl & SUB_GLOBAL) && pattry(p, s + l) && !--n) {
- *sp = get_match_ret(*sp, 0, 0, fl, replstr, NULL);
+ if (!(fl & SUB_GLOBAL) &&
+ pattrylen(p, send, 0, 0, &patstralloc, 0) &&
+ !--n) {
+ *sp = get_match_ret(&imd, 0, 0);
return 1;
} /* fall through */
case (SUB_SUBSTR|SUB_LONG):
/* longest or smallest at start with substrings */
t = s;
if (fl & SUB_GLOBAL) {
- repllist = (fl & SUB_LIST) ? znewlinklist() : newlinklist();
+ imd.repllist = (fl & SUB_LIST) ? znewlinklist() : newlinklist();
if (repllistp)
- *repllistp = repllist;
+ *repllistp = imd.repllist;
}
ioff = 0; /* offset into string */
umlen = umltot;
@@ -2903,10 +2940,10 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
do {
/* loop over all matches for global substitution */
matched = 0;
- for (; t < s + l; ioff++) {
+ for (; t < send; ioff++) {
/* Find the longest match from this position. */
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff)) {
+ if (pattrylen(p, t, umlen, 0, &patstralloc, ioff)) {
char *mpos = t + patmatchlen();
if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
char *ptr;
@@ -2920,18 +2957,18 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
*/
for (ptr = t, umlen2 = 0; ptr < mpos;) {
set_pat_end(p, *ptr);
- if (pattrylen(p, t, ptr - t, umlen2, ioff)) {
+ if (pattrylen(p, t, umlen2, 0,
+ &patstralloc, ioff)) {
mpos = t + patmatchlen();
break;
}
- umlen2 += iincchar(&ptr);
+ umlen2 += iincchar(&ptr, mpos - ptr);
}
}
if (!--n || (n <= 0 && (fl & SUB_GLOBAL))) {
- *sp = get_match_ret(*sp, t-s, mpos-s, fl,
- replstr, repllist);
+ *sp = get_match_ret(&imd, t-s, mpos-s);
if (mpos == t)
- mpos += mb_metacharlenconv(mpos, NULL);
+ mpos += mb_charlenconv(mpos, send - mpos, NULL);
}
if (!(fl & SUB_GLOBAL)) {
if (n) {
@@ -2941,7 +2978,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
* the next character, even if it overlaps
* with what we just found.
*/
- umlen -= iincchar(&t);
+ umlen -= iincchar(&t, send - t);
continue;
} else {
return 1;
@@ -2954,11 +2991,11 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
matched = 1;
while (t < mpos) {
ioff++;
- umlen -= iincchar(&t);
+ umlen -= iincchar(&t, send - t);
}
break;
}
- umlen -= iincchar(&t);
+ umlen -= iincchar(&t, send - t);
}
} while (matched);
/*
@@ -2968,8 +3005,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
*/
set_pat_start(p, l);
if ((fl & (SUB_LONG|SUB_GLOBAL)) == SUB_LONG &&
- pattry(p, s + l) && !--n) {
- *sp = get_match_ret(*sp, 0, 0, fl, replstr, repllist);
+ pattrylen(p, send, 0, 0, &patstralloc, 0) && !--n) {
+ *sp = get_match_ret(&imd, 0, 0);
return 1;
}
break;
@@ -2979,8 +3016,9 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
/* Longest/shortest at end, matching substrings. */
if (!(fl & SUB_LONG)) {
set_pat_start(p, l);
- if (pattrylen(p, s + l, 0, 0, umltot) && !--n) {
- *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
+ if (pattrylen(p, send, 0, 0, &patstralloc, umltot) &&
+ !--n) {
+ *sp = get_match_ret(&imd, umltot, umltot);
return 1;
}
}
@@ -2997,13 +3035,13 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
nmatches = 0;
tmatch = NULL;
mb_charinit();
- for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) {
+ for (ioff = 0, t = s, umlen = umltot; t < send; ioff++) {
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff)) {
+ if (pattrylen(p, t, umlen, 0, &patstralloc, ioff)) {
nmatches++;
tmatch = t;
}
- umlen -= iincchar(&t);
+ umlen -= iincchar(&t, send - t);
}
if (nmatches) {
char *mpos;
@@ -3013,14 +3051,14 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
*/
n = nmatches - n;
mb_charinit();
- for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) {
+ for (ioff = 0, t = s, umlen = umltot; t < send; ioff++) {
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff) &&
+ if (pattrylen(p, t, umlen, 0, &patstralloc, ioff) &&
!n--) {
tmatch = t;
break;
}
- umlen -= iincchar(&t);
+ umlen -= iincchar(&t, send - t);
}
}
mpos = tmatch + patmatchlen();
@@ -3028,27 +3066,29 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
for (t = tmatch, umlen = 0; t < mpos; ) {
set_pat_end(p, *t);
- if (pattrylen(p, tmatch, t - tmatch, umlen, ioff)) {
+ if (pattrylen(p, tmatch, umlen, 0,
+ &patstralloc, ioff)) {
mpos = tmatch + patmatchlen();
break;
}
- umlen += iincchar(&t);
+ umlen += iincchar(&t, mpos - t);
}
}
- *sp = get_match_ret(*sp, tmatch-s, mpos-s, fl,
- replstr, NULL);
+ *sp = get_match_ret(&imd, tmatch-s, mpos-s);
return 1;
}
set_pat_start(p, l);
- if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, umltot) && !--n) {
- *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
+ if ((fl & SUB_LONG) && pattrylen(p, send, 0, 0,
+ &patstralloc, umltot) &&
+ !--n) {
+ *sp = get_match_ret(&imd, umltot, umltot);
return 1;
}
break;
}
}
- if (repllist && nonempty(repllist)) {
+ if (imd.repllist && nonempty(imd.repllist)) {
/* Put all the bits of a global search and replace together. */
LinkNode nd;
Repldata rd;
@@ -3056,10 +3096,15 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
char *ptr, *start;
int i;
+ /*
+ * Use metafied string again.
+ * Results from get_match_ret in repllist are all metafied.
+ */
+ s = *sp;
if (!(fl & SUB_LIST)) {
lleft = 0; /* size of returned string */
- i = 0; /* start of last chunk we got from *sp */
- for (nd = firstnode(repllist); nd; incnode(nd)) {
+ i = 0; /* start of last chunk we got from *sp */
+ for (nd = firstnode(imd.repllist); nd; incnode(nd)) {
rd = (Repldata) getdata(nd);
lleft += rd->b - i; /* previous chunk of *sp */
lleft += strlen(rd->replstr); /* the replaced bit */
@@ -3068,7 +3113,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
lleft += l - i; /* final chunk from *sp */
start = t = zhalloc(lleft+1);
i = 0;
- for (nd = firstnode(repllist); nd; incnode(nd)) {
+ for (nd = firstnode(imd.repllist); nd; incnode(nd)) {
rd = (Repldata) getdata(nd);
memcpy(t, s + i, rd->b - i);
t += rd->b - i;
@@ -3083,11 +3128,14 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
}
return 1;
}
- if (fl & SUB_LIST) /* safety: don't think this can happen */
+ if (fl & SUB_LIST) { /* safety: don't think this can happen */
return 0;
+ }
/* munge the whole string: no match, so no replstr */
- *sp = get_match_ret(*sp, 0, 0, fl, 0, 0);
+ imd.replstr = NULL;
+ imd.repllist = NULL;
+ *sp = get_match_ret(&imd, 0, 0);
return (fl & SUB_RETFAIL) ? 0 : 1;
}
@@ -3105,7 +3153,7 @@ static int
igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
LinkList *repllistp)
{
- char *s = *sp, *t;
+ char *s = *sp, *t, *send;
/*
* Note that ioff and uml count characters in the character
* set (Meta's are not included), while l counts characters in the
@@ -3113,36 +3161,48 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
* lengths.
*/
int ioff, l = strlen(*sp), uml = ztrlen(*sp), matched = 1, umlen;
- /*
- * List of bits of matches to concatenate with replacement string.
- * The data is a struct repldata. It is not used in cases like
- * ${...//#foo/bar} even though SUB_GLOBAL is set, since the match
- * is anchored. It goes on the heap.
- */
- LinkList repllist = NULL;
+ struct patstralloc patstralloc;
+ struct imatchdata imd;
+
+ (void)patallocstr(p, s, l, uml, 1, &patstralloc);
+ s = patstralloc.alloced;
+ DPUTS(!s, "forced patallocstr failed");
+ send = s + uml;
+
+ imd.mstr = *sp;
+ imd.mlen = l;
+ imd.ustr = s;
+ imd.ulen = uml;
+ imd.flags = fl;
+ imd.replstr = replstr;
+ imd.repllist = NULL;
/* perform must-match test for complex closures */
if (p->mustoff)
{
- /*
- * Yuk. Probably we should rewrite this whole function to
- * use an unmetafied test string.
- *
- * Use META_HEAPDUP because we need a terminating NULL.
- */
- char *muststr = metafy((char *)p + p->mustoff,
- p->patmlen, META_HEAPDUP);
+ char *muststr = (char *)p + p->mustoff;
- if (!strstr(s, muststr))
- matched = 0;
+ matched = 0;
+ if (p->patmlen <= uml)
+ {
+ for (t = s; t <= send - p->patmlen; t++)
+ {
+ if (!memcmp(muststr, t, p->patmlen)) {
+ matched = 1;
+ break;
+ }
+ }
+ }
}
/* in case we used the prog before... */
p->flags &= ~(PAT_NOTSTART|PAT_NOTEND);
if (fl & SUB_ALL) {
- int i = matched && pattry(p, s);
- *sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0, NULL);
+ int i = matched && pattrylen(p, s, uml, 0, &patstralloc, 0);
+ if (!i)
+ imd.replstr = NULL;
+ *sp = get_match_ret(&imd, 0, i ? l : 0);
if (! **sp && (((fl & SUB_MATCH) && !i) || ((fl & SUB_REST) && i)))
return 0;
return 1;
@@ -3155,23 +3215,24 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
* Largest/smallest possible match at head of string.
* First get the longest match...
*/
- if (pattry(p, s)) {
+ if (pattrylen(p, s, uml, 0, &patstralloc, 0)) {
/* patmatchlen returns metafied length, as we need */
int mlen = patmatchlen();
if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
+ send = s + mlen;
/*
* ... now we know whether it's worth looking for the
* shortest, which we do by brute force.
*/
for (t = s, umlen = 0; t < s + mlen; METAINC(t), umlen++) {
set_pat_end(p, *t);
- if (pattrylen(p, s, t - s, umlen, 0)) {
+ if (pattrylen(p, s, umlen, 0, &patstralloc, 0)) {
mlen = patmatchlen();
break;
}
}
}
- *sp = get_match_ret(*sp, 0, mlen, fl, replstr, NULL);
+ *sp = get_match_ret(&imd, 0, mlen);
return 1;
}
break;
@@ -3180,17 +3241,13 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
/* Smallest possible match at tail of string: *
* move back down string until we get a match. *
* There's no optimization here. */
- for (ioff = uml, t = s + l, umlen = 0; t >= s;
+ for (ioff = uml, t = send, umlen = 0; t >= s;
t--, ioff--, umlen++) {
- if (t > s && t[-1] == Meta)
- t--;
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff)) {
- *sp = get_match_ret(*sp, t - s, l, fl, replstr, NULL);
+ if (pattrylen(p, t, umlen, 0, &patstralloc, ioff)) {
+ *sp = get_match_ret(&imd, t - s, uml);
return 1;
}
- if (t > s+1 && t[-2] == Meta)
- t--;
}
break;
@@ -3198,60 +3255,59 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
/* Largest possible match at tail of string: *
* move forward along string until we get a match. *
* Again there's no optimisation. */
- for (ioff = 0, t = s, umlen = uml; t < s + l;
- ioff++, METAINC(t), umlen--) {
+ for (ioff = 0, t = s, umlen = uml; t < send;
+ ioff++, t++, umlen--) {
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff)) {
- *sp = get_match_ret(*sp, t-s, l, fl, replstr, NULL);
+ if (pattrylen(p, t, send - t, umlen, &patstralloc, ioff)) {
+ *sp = get_match_ret(&imd, t-s, uml);
return 1;
}
- if (*t == Meta)
- t++;
}
break;
case SUB_SUBSTR:
/* Smallest at start, but matching substrings. */
set_pat_start(p, l);
- if (!(fl & SUB_GLOBAL) && pattry(p, s + l) && !--n) {
- *sp = get_match_ret(*sp, 0, 0, fl, replstr, NULL);
+ if (!(fl & SUB_GLOBAL) &&
+ pattrylen(p, send, 0, 0, &patstralloc, 0) && !--n) {
+ *sp = get_match_ret(&imd, 0, 0);
return 1;
} /* fall through */
case (SUB_SUBSTR|SUB_LONG):
/* longest or smallest at start with substrings */
t = s;
if (fl & SUB_GLOBAL) {
- repllist = newlinklist();
+ imd.repllist = newlinklist();
if (repllistp)
- *repllistp = repllist;
+ *repllistp = imd.repllist;
}
ioff = 0; /* offset into string */
umlen = uml;
do {
/* loop over all matches for global substitution */
matched = 0;
- for (; t < s + l; METAINC(t), ioff++, umlen--) {
+ for (; t < send; t++, ioff++, umlen--) {
/* Find the longest match from this position. */
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff)) {
+ if (pattrylen(p, t, send - t, umlen, &patstralloc, ioff)) {
char *mpos = t + patmatchlen();
if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
char *ptr;
int umlen2;
for (ptr = t, umlen2 = 0; ptr < mpos;
- METAINC(ptr), umlen2++) {
+ ptr++, umlen2++) {
set_pat_end(p, *ptr);
- if (pattrylen(p, t, ptr - t, umlen2, ioff)) {
+ if (pattrylen(p, t, ptr - t, umlen2,
+ &patstralloc, ioff)) {
mpos = t + patmatchlen();
break;
}
}
}
if (!--n || (n <= 0 && (fl & SUB_GLOBAL))) {
- *sp = get_match_ret(*sp, t-s, mpos-s, fl,
- replstr, repllist);
+ *sp = get_match_ret(&imd, t-s, mpos-s);
if (mpos == t)
- METAINC(mpos);
+ mpos++;
}
if (!(fl & SUB_GLOBAL)) {
if (n) {
@@ -3271,13 +3327,13 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
* which is already marked for replacement.
*/
matched = 1;
- for ( ; t < mpos; t++, ioff++, umlen--)
- if (*t == Meta)
- t++;
+ while (t < mpos) {
+ ioff++;
+ umlen--;
+ t++;
+ }
break;
}
- if (*t == Meta)
- t++;
}
} while (matched);
/*
@@ -3287,8 +3343,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
*/
set_pat_start(p, l);
if ((fl & (SUB_LONG|SUB_GLOBAL)) == SUB_LONG &&
- pattry(p, s + l) && !--n) {
- *sp = get_match_ret(*sp, 0, 0, fl, replstr, repllist);
+ pattrylen(p, send, 0, 0, &patstralloc, 0) && !--n) {
+ *sp = get_match_ret(&imd, 0, 0);
return 1;
}
break;
@@ -3298,46 +3354,47 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
/* Longest/shortest at end, matching substrings. */
if (!(fl & SUB_LONG)) {
set_pat_start(p, l);
- if (pattrylen(p, s + l, 0, 0, uml) && !--n) {
- *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
+ if (pattrylen(p, send, 0, 0, &patstralloc, uml) && !--n) {
+ *sp = get_match_ret(&imd, uml, uml);
return 1;
}
}
- for (ioff = uml - 1, t = s + l - 1, umlen = 1; t >= s;
+ for (ioff = uml - 1, t = send - 1, umlen = 1; t >= s;
t--, ioff--, umlen++) {
- if (t > s && t[-1] == Meta)
- t--;
set_pat_start(p, t-s);
- if (pattrylen(p, t, s + l - t, umlen, ioff) && !--n) {
+ if (pattrylen(p, t, send - t, umlen, &patstralloc, ioff) &&
+ !--n) {
/* Found the longest match */
char *mpos = t + patmatchlen();
if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
char *ptr;
int umlen2;
for (ptr = t, umlen2 = 0; ptr < mpos;
- METAINC(ptr), umlen2++) {
+ ptr++, umlen2++) {
set_pat_end(p, *ptr);
- if (pattrylen(p, t, ptr - t, umlen2, ioff)) {
+ if (pattrylen(p, t, umlen2, 0, &patstralloc,
+ ioff)) {
mpos = t + patmatchlen();
break;
}
}
}
- *sp = get_match_ret(*sp, t-s, mpos-s, fl,
- replstr, NULL);
+ *sp = get_match_ret(&imd, t-s, mpos-s);
return 1;
}
}
set_pat_start(p, l);
- if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, uml) && !--n) {
- *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
+ if ((fl & SUB_LONG) && pattrylen(p, send, 0, 0,
+ &patstralloc, uml) &&
+ !--n) {
+ *sp = get_match_ret(&imd, uml, uml);
return 1;
}
break;
}
}
- if (repllist && nonempty(repllist)) {
+ if (imd.repllist && nonempty(imd.repllist)) {
/* Put all the bits of a global search and replace together. */
LinkNode nd;
Repldata rd;
@@ -3345,8 +3402,13 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
char *ptr, *start;
int i;
+ /*
+ * Use metafied string again.
+ * Results from get_match_ret in repllist are all metafied.
+ */
+ s = *sp;
i = 0; /* start of last chunk we got from *sp */
- for (nd = firstnode(repllist); nd; incnode(nd)) {
+ for (nd = firstnode(imd.repllist); nd; incnode(nd)) {
rd = (Repldata) getdata(nd);
lleft += rd->b - i; /* previous chunk of *sp */
lleft += strlen(rd->replstr); /* the replaced bit */
@@ -3355,7 +3417,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
lleft += l - i; /* final chunk from *sp */
start = t = zhalloc(lleft+1);
i = 0;
- for (nd = firstnode(repllist); nd; incnode(nd)) {
+ for (nd = firstnode(imd.repllist); nd; incnode(nd)) {
rd = (Repldata) getdata(nd);
memcpy(t, s + i, rd->b - i);
t += rd->b - i;
@@ -3371,7 +3433,9 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
}
/* munge the whole string: no match, so no replstr */
- *sp = get_match_ret(*sp, 0, 0, fl, 0, 0);
+ imd.replstr = NULL;
+ imd.repllist = NULL;
+ *sp = get_match_ret(&imd, 0, 0);
return 1;
}
diff --git a/Src/hist.c b/Src/hist.c
index 9c42d85c9..007366a49 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -2254,7 +2254,7 @@ static char *
getargs(Histent elist, int arg1, int arg2)
{
short *words = elist->words;
- int pos1, nwords = elist->nwords;
+ int pos1, pos2, nwords = elist->nwords;
if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) {
/* remember, argN is indexed from 0, nwords is total no. of words */
@@ -2263,8 +2263,22 @@ getargs(Histent elist, int arg1, int arg2)
return NULL;
}
+ /* optimization for accessing entire history event */
+ if (arg1 == 0 && arg2 == nwords - 1)
+ return dupstring(elist->node.nam);
+
pos1 = words[2*arg1];
- return dupstrpfx(elist->node.nam + pos1, words[2*arg2+1] - pos1);
+ pos2 = words[2*arg2+1];
+
+ /* a word has to be at least one character long, so if the position
+ * of a word is less than its index, we've overflowed our signed
+ * short integer word range and the recorded position is garbage. */
+ if (pos1 < 0 || pos1 < arg1 || pos2 < 0 || pos2 < arg2) {
+ herrflush();
+ zerr("history event too long, can't index requested words");
+ return NULL;
+ }
+ return dupstrpfx(elist->node.nam + pos1, pos2 - pos1);
}
/**/
diff --git a/Src/init.c b/Src/init.c
index 22db4b3b2..dcce1d7ce 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -790,8 +790,10 @@ init_term(void)
tcstr[TCCLEARSCREEN] = ztrdup("\14");
tclen[TCCLEARSCREEN] = 1;
}
- /* This might work, but there may be more to it */
- rprompt_indent = ((hasam && !hasbw) || hasye || !tccan(TCLEFT));
+ rprompt_indent = 1;
+ /* The following is an attempt at a heuristic,
+ * but it fails in some cases */
+ /* rprompt_indent = ((hasam && !hasbw) || hasye || !tccan(TCLEFT)); */
}
return 1;
}
diff --git a/Src/lex.c b/Src/lex.c
index 70f3d142a..0f260d08f 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -783,6 +783,15 @@ gettok(void)
*/
tokstr = NULL;
return INPAR;
+
+ case CMD_OR_MATH_ERR:
+ /*
+ * LEXFLAGS_ACTIVE means we came from bufferwords(),
+ * so we treat as an incomplete math expression
+ */
+ if (lexflags & LEXFLAGS_ACTIVE)
+ tokstr = dyncat("((", tokstr ? tokstr : "");
+ /* fall through */
default:
return LEXERR;
@@ -1608,7 +1617,7 @@ parsestrnoerr(char **s)
mod_export char *
parse_subscript(char *s, int sub, int endchar)
{
- int l = strlen(s), err;
+ int l = strlen(s), err, toklen;
char *t;
if (!*s || *s == endchar)
@@ -1617,18 +1626,34 @@ parse_subscript(char *s, int sub, int endchar)
untokenize(t = dupstring(s));
inpush(t, 0, NULL);
strinbeg(0);
+ /*
+ * Warning to Future Generations:
+ *
+ * This way of passing the subscript through the lexer is brittle.
+ * Code above this for several layers assumes that when we tokenise
+ * the input it goes into the same place as the original string.
+ * However, the lexer may overwrite later bits of the string or
+ * reallocate it, in particular when expanding aliaes. To get
+ * around this, we copy the string and then copy it back. This is a
+ * bit more robust but still relies on the underlying assumption of
+ * length preservation.
+ */
lexbuf.len = 0;
- lexbuf.ptr = tokstr = s;
+ lexbuf.ptr = tokstr = dupstring(s);
lexbuf.siz = l + 1;
err = dquote_parse(endchar, sub);
+ toklen = (int)(lexbuf.ptr - tokstr);
+ DPUTS(toklen > l, "Bad length for parsed subscript");
+ memcpy(s, tokstr, toklen);
if (err) {
- err = *lexbuf.ptr;
- *lexbuf.ptr = '\0';
+ char *strend = s + toklen;
+ err = *strend;
+ *strend = '\0';
untokenize(s);
- *lexbuf.ptr = err;
+ *strend = err;
s = NULL;
} else {
- s = lexbuf.ptr;
+ s += toklen;
}
strinend();
inpop();
@@ -1997,7 +2022,9 @@ 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
@@ -2115,6 +2142,7 @@ skipcomm(void)
SETPAREND
cmdpop();
infor = save_infor;
+ noaliases = noalias;
return lexstop;
#endif
diff --git a/Src/math.c b/Src/math.c
index 977e92345..37981cf22 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -535,7 +535,7 @@ lexconstant(void)
for (ptr2 = ptr; ptr2 < nptr; ptr2++) {
if (*ptr2 == '_') {
int len = nptr - ptr;
- ptr = strdup(ptr);
+ ptr = ztrdup(ptr);
for (ptr2 = ptr; len; len--) {
if (*ptr2 == '_')
chuck(ptr2);
@@ -893,7 +893,6 @@ getcvar(char *s)
return mn;
}
-
/**/
static mnumber
setmathvar(struct mathvalue *mvp, mnumber v)
diff --git a/Src/mem.c b/Src/mem.c
index b9569ea0c..e31145e1e 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -79,6 +79,12 @@
#include <sys/mman.h>
+/*
+ * This definition is designed to enable use of memory mapping on MacOS.
+ * However, performance tests indicate that MacOS mapped regions are
+ * somewhat slower to allocate than memory from malloc(), so whether
+ * using this improves performance depends on details of zhalloc().
+ */
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
#define MAP_ANONYMOUS MAP_ANON
#endif
@@ -294,7 +300,7 @@ pushheap(void)
#endif
for (h = heaps; h; h = h->next) {
- DPUTS(!h->used, "BUG: empty heap");
+ DPUTS(!h->used && h->next, "BUG: empty heap");
hs = (Heapstack) zalloc(sizeof(*hs));
hs->next = h->sp;
h->sp = hs;
@@ -334,16 +340,20 @@ freeheap(void)
*
* Whenever fheap is NULL here, the loop below sweeps back over the
* entire heap list again, resetting the free space in every arena to
- * the amount stashed by pushheap() and finding the first arena with
+ * the amount stashed by pushheap() and finding the arena with the most
* free space to optimize zhalloc()'s next search. When there's a lot
* of stuff already on the heap, this is an enormous amount of work,
* and performance goes to hell.
*
+ * Therefore, we defer freeing the most recently allocated arena until
+ * we reach popheap().
+ *
* However, if the arena to which fheap points is unused, we want to
- * free it, so we have no choice but to do the sweep for a new fheap.
+ * reclaim space in earlier arenas, so we have no choice but to do the
+ * sweep for a new fheap.
*/
if (fheap && !fheap->sp)
- fheap = NULL; /* We used to do this unconditionally */
+ fheap = NULL; /* We used to do this unconditionally */
/*
* In other cases, either fheap is already correct, or it has never
* been set and this loop will do it, or it'll be reset from scratch
@@ -361,7 +371,11 @@ freeheap(void)
memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used);
#endif
h->used = h->sp->used;
- if (!fheap && h->used < ARENA_SIZEOF(h))
+ if (!fheap) {
+ if (h->used < ARENA_SIZEOF(h))
+ fheap = h;
+ } else if (ARENA_SIZEOF(h) - h->used >
+ ARENA_SIZEOF(fheap) - fheap->used)
fheap = h;
hl = h;
#ifdef ZSH_HEAP_DEBUG
@@ -384,6 +398,26 @@ freeheap(void)
VALGRIND_MEMPOOL_TRIM((char *)h, (char *)arena(h), h->used);
#endif
} else {
+ if (fheap == h)
+ fheap = NULL;
+ if (h->next) {
+ /* We want to cut this out of the arena list if we can */
+ if (h == heaps)
+ hl = heaps = h->next;
+ else if (hl && hl->next == h)
+ hl->next = h->next;
+ else {
+ DPUTS(hl, "hl->next != h when freeing");
+ hl = h;
+ continue;
+ }
+ h->next = NULL;
+ } else {
+ /* Leave an empty arena at the end until popped */
+ h->used = 0;
+ fheap = hl = h;
+ break;
+ }
#ifdef USE_MMAP
munmap((void *) h, h->size);
#else
@@ -441,12 +475,29 @@ popheap(void)
#ifdef ZSH_VALGRIND
VALGRIND_MEMPOOL_TRIM((char *)h, (char *)arena(h), h->used);
#endif
- if (!fheap && h->used < ARENA_SIZEOF(h))
+ if (!fheap) {
+ if (h->used < ARENA_SIZEOF(h))
+ fheap = h;
+ } else if (ARENA_SIZEOF(h) - h->used >
+ ARENA_SIZEOF(fheap) - fheap->used)
fheap = h;
zfree(hs, sizeof(*hs));
hl = h;
} else {
+ if (h->next) {
+ /* We want to cut this out of the arena list if we can */
+ if (h == heaps)
+ hl = heaps = h->next;
+ else if (hl && hl->next == h)
+ hl->next = h->next;
+ else {
+ DPUTS(hl, "hl->next != h when popping");
+ hl = h;
+ continue;
+ }
+ h->next = NULL;
+ }
#ifdef USE_MMAP
munmap((void *) h, h->size);
#else
@@ -524,7 +575,7 @@ zheapptr(void *p)
mod_export void *
zhalloc(size_t size)
{
- Heap h;
+ Heap h, hp = NULL;
size_t n;
#ifdef ZSH_VALGRIND
size_t req_size = size;
@@ -543,9 +594,15 @@ zhalloc(size_t size)
/* find a heap with enough free space */
- for (h = ((fheap && ARENA_SIZEOF(fheap) >= (size + fheap->used))
- ? fheap : heaps);
- h; h = h->next) {
+ /*
+ * This previously assigned:
+ * h = ((fheap && ARENA_SIZEOF(fheap) >= (size + fheap->used))
+ * ? fheap : heaps);
+ * but we think that nothing upstream of fheap has more free space,
+ * so why start over at heaps just because fheap has too little?
+ */
+ for (h = (fheap ? fheap : heaps); h; h = h->next) {
+ hp = h;
if (ARENA_SIZEOF(h) >= (n = size + h->used)) {
void *ret;
@@ -566,7 +623,6 @@ zhalloc(size_t size)
}
}
{
- Heap hp;
/* not found, allocate new heap */
#if defined(ZSH_MEM) && !defined(USE_MMAP)
static int called = 0;
@@ -575,7 +631,6 @@ zhalloc(size_t size)
#endif
n = HEAP_ARENA_SIZE > size ? HEAPSIZE : size + sizeof(*h);
- for (hp = NULL, h = heaps; h; hp = h, h = h->next);
#ifdef USE_MMAP
h = mmap_heap_alloc(&n);
@@ -607,6 +662,7 @@ zhalloc(size_t size)
VALGRIND_MEMPOOL_ALLOC((char *)h, (char *)arena(h), req_size);
#endif
+ DPUTS(hp && hp->next, "failed to find end of chain in zhalloc");
if (hp)
hp->next = h;
else
@@ -1611,8 +1667,13 @@ realloc(MALLOC_RET_T p, MALLOC_ARG_T size)
int i, l = 0;
/* some system..., see above */
- if (!p && size)
- return (MALLOC_RET_T) malloc(size);
+ if (!p && size) {
+ queue_signals();
+ r = malloc(size);
+ unqueue_signals();
+ return (MALLOC_RET_T) r;
+ }
+
/* and some systems even do this... */
if (!p || !size)
return (MALLOC_RET_T) p;
diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh
index 002160910..3ccf9c5e5 100644
--- a/Src/mkmakemod.sh
+++ b/Src/mkmakemod.sh
@@ -21,12 +21,8 @@
# moddeps modules on which this module depends (default none)
# nozshdep non-empty indicates no dependence on the `zsh/main' pseudo-module
# alwayslink if non-empty, always link the module into the executable
-# autobins builtins defined by the module, for autoloading
-# autoinfixconds infix condition codes defined by the module, for
-# autoloading (without the leading `-')
-# autoprefixconds like autoinfixconds, but for prefix condition codes
-# autoparams parameters defined by the module, for autoloading
-# automathfuncs math functions defined by the module, for autoloading
+# autofeatures features defined by the module, for autoloading
+# autofeatures_emu As autofeatures, but for non-zsh emulation modes
# objects .o files making up this module (*must* be defined)
# proto .syms files for this module (default generated from $objects)
# headers extra headers for this module (default none)
@@ -189,7 +185,7 @@ if $first_stage; then
for mddname in $here_mddnames; do
unset name moddeps nozshdep alwayslink hasexport
- unset autobins autoinfixconds autoprefixconds autoparams automathfuncs
+ unset autofeatures autofeatures_emu
unset objects proto headers hdrdeps otherincs
. $top_srcdir/$the_subdir/${mddname}.mdd
q_name=`echo $name | sed 's,Q,Qq,g;s,_,Qu,g;s,/,Qs,g'`
diff --git a/Src/options.c b/Src/options.c
index 1fb102f1d..2678626c7 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -140,6 +140,7 @@ static struct optname optns[] = {
{{NULL, "globassign", OPT_EMULATE|OPT_CSH}, GLOBASSIGN},
{{NULL, "globcomplete", 0}, GLOBCOMPLETE},
{{NULL, "globdots", OPT_EMULATE}, GLOBDOTS},
+{{NULL, "globstarshort", OPT_EMULATE}, GLOBSTARSHORT},
{{NULL, "globsubst", OPT_EMULATE|OPT_NONZSH}, GLOBSUBST},
{{NULL, "hashcmds", OPT_ALL}, HASHCMDS},
{{NULL, "hashdirs", OPT_ALL}, HASHDIRS},
@@ -901,3 +902,33 @@ printoptionlist_printequiv(int optno)
optno *= (isneg ? -1 : 1);
printf(" equivalent to --%s%s\n", isneg ? "no-" : "", optns[optno-1].node.nam);
}
+
+/**/
+static char *print_emulate_opts;
+
+/**/
+static void
+print_emulate_option(HashNode hn, int fully)
+{
+ Optname on = (Optname) hn;
+
+ if (!(on->node.flags & OPT_ALIAS) &&
+ ((fully && !(on->node.flags & OPT_SPECIAL)) ||
+ (on->node.flags & OPT_EMULATE)))
+ {
+ if (!print_emulate_opts[on->optno])
+ fputs("no", stdout);
+ puts(on->node.nam);
+ }
+}
+
+/*
+ * List the settings of options associated with an emulation
+ */
+
+/**/
+void list_emulate_options(char *cmdopts, int fully)
+{
+ print_emulate_opts = cmdopts;
+ scanhashtable(optiontab, 1, 0, 0, print_emulate_option, fully);
+}
diff --git a/Src/params.c b/Src/params.c
index de151a4cd..b121bd6ad 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -447,7 +447,7 @@ newparamtable(int size, char const *name)
ht->cmpnodes = strcmp;
ht->addnode = addhashnode;
ht->getnode = getparamnode;
- ht->getnode2 = getparamnode;
+ ht->getnode2 = gethashnode2;
ht->removenode = removehashnode;
ht->disablenode = NULL;
ht->enablenode = NULL;
@@ -775,17 +775,18 @@ createparamtable(void)
#endif
opts[ALLEXPORT] = oae;
+ /*
+ * For native emulation we always set the variable home
+ * (see setupvals()).
+ */
+ pm = (Param) paramtab->getnode(paramtab, "HOME");
if (EMULATION(EMULATE_ZSH))
{
- /*
- * For native emulation we always set the variable home
- * (see setupvals()).
- */
- pm = (Param) paramtab->getnode(paramtab, "HOME");
pm->node.flags &= ~PM_UNSET;
if (!(pm->node.flags & PM_EXPORTED))
addenv(pm, home);
- }
+ } else if (!home)
+ pm->node.flags |= PM_UNSET;
pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
if (!(pm->node.flags & PM_EXPORTED))
addenv(pm, pm->u.str);
@@ -868,6 +869,7 @@ createparam(char *name, int flags)
if (name != nulstring) {
oldpm = (Param) (paramtab == realparamtab ?
+ /* gethashnode2() for direct table read */
gethashnode2(paramtab, name) :
paramtab->getnode(paramtab, name));
@@ -2694,6 +2696,37 @@ gethkparam(char *s)
}
/**/
+static void
+check_warn_create(Param pm, const char *pmtype)
+{
+ Funcstack i;
+ const char *name;
+
+ if (pm->level != 0 || (pm->node.flags & PM_SPECIAL))
+ return;
+
+ name = NULL;
+ for (i = funcstack; i; i = i->prev) {
+ if (i->tp == FS_FUNC) {
+ DPUTS(!i->name, "funcstack entry with no name");
+ name = i->name;
+ break;
+ }
+ }
+
+ if (name)
+ {
+ zwarn("%s parameter %s created globally in function %s",
+ pmtype, pm->node.nam, name);
+ }
+ else
+ {
+ zwarn("%s parameter %s created globally in function",
+ pmtype, pm->node.nam);
+ }
+}
+
+/**/
mod_export Param
assignsparam(char *s, char *val, int flags)
{
@@ -2746,9 +2779,8 @@ assignsparam(char *s, char *val, int flags)
zsfree(val);
return NULL;
}
- if ((flags & ASSPM_WARN_CREATE) && v->pm->level == 0)
- zwarn("scalar parameter %s created globally in function",
- v->pm->node.nam);
+ if (flags & ASSPM_WARN_CREATE)
+ check_warn_create(v->pm, "scalar");
if (flags & ASSPM_AUGMENT) {
if (v->start == 0 && v->end == -1) {
switch (PM_TYPE(v->pm->node.flags)) {
@@ -2827,6 +2859,15 @@ assignsparam(char *s, char *val, int flags)
/**/
mod_export Param
+setsparam(char *s, char *val)
+{
+ return assignsparam(
+ s, val, isset(WARNCREATEGLOBAL) && locallevel > 0 ?
+ ASSPM_WARN_CREATE : 0);
+}
+
+/**/
+mod_export Param
assignaparam(char *s, char **val, int flags)
{
struct value vbuf;
@@ -2888,9 +2929,8 @@ assignaparam(char *s, char **val, int flags)
return NULL;
}
- if ((flags & ASSPM_WARN_CREATE) && v->pm->level == 0)
- zwarn("array parameter %s created globally in function",
- v->pm->node.nam);
+ if (flags & ASSPM_WARN_CREATE)
+ check_warn_create(v->pm, "array");
if (flags & ASSPM_AUGMENT) {
if (v->start == 0 && v->end == -1) {
if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
@@ -2913,6 +2953,16 @@ assignaparam(char *s, char **val, int flags)
return v->pm;
}
+
+/**/
+mod_export Param
+setaparam(char *s, char **aval)
+{
+ return assignaparam(
+ s, aval, isset(WARNCREATEGLOBAL) && locallevel >0 ?
+ ASSPM_WARN_CREATE : 0);
+}
+
/**/
mod_export Param
sethparam(char *s, char **val)
@@ -2936,11 +2986,14 @@ sethparam(char *s, char **val)
if (unset(EXECOPT))
return NULL;
queue_signals();
- if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
+ if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) {
createparam(t, PM_HASHED);
- else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) &&
+ if (isset(WARNCREATEGLOBAL) && locallevel > 0)
+ check_warn_create(v->pm, "associative array");
+ } 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;
}
@@ -2967,6 +3020,7 @@ setnparam(char *s, mnumber val)
Value v;
char *t = s, *ss;
Param pm;
+ int was_unset = 0;
if (!isident(s)) {
zerr("not an identifier: %s", s);
@@ -2986,6 +3040,7 @@ setnparam(char *s, mnumber val)
*/
unset(KSHARRAYS) && !ss) {
unsetparam_pm(v->pm, 0, 1);
+ was_unset = 1;
s = t;
v = NULL;
}
@@ -3006,6 +3061,8 @@ setnparam(char *s, mnumber val)
}
v = getvalue(&vbuf, &t, 1);
DPUTS(!v, "BUG: value not found for new parameter");
+ if (!was_unset && isset(WARNCREATEGLOBAL) && locallevel > 0)
+ check_warn_create(v->pm, "numeric");
}
setnumvalue(v, val);
unqueue_signals();
@@ -3024,6 +3081,26 @@ setiparam(char *s, zlong val)
return setnparam(s, mnval);
}
+/*
+ * Set an integer parameter without forcing creation of an integer type.
+ * This is useful if the integer is going to be set to a parmaeter which
+ * would usually be scalar but may not exist.
+ */
+
+/**/
+mod_export Param
+setiparam_no_convert(char *s, zlong val)
+{
+ /*
+ * If the target is already an integer, thisgets converted
+ * back. Low technology rules.
+ */
+ char buf[BDIGBUFSIZE];
+ convbase(buf, val, 10);
+ return assignsparam(
+ s, ztrdup(buf),
+ isset(WARNCREATEGLOBAL) && locallevel > 0 ? ASSPM_WARN_CREATE : 0);
+}
/* Unset a parameter */
@@ -3035,7 +3112,8 @@ unsetparam(char *s)
queue_signals();
if ((pm = (Param) (paramtab == realparamtab ?
- gethashnode2(paramtab, s) :
+ /* getnode2() to avoid autoloading */
+ paramtab->getnode2(paramtab, s) :
paramtab->getnode(paramtab, s))))
unsetparam_pm(pm, 0, 1);
unqueue_signals();
diff --git a/Src/parse.c b/Src/parse.c
index 7c2d20250..83ba396b0 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -530,7 +530,7 @@ empty_eprog(Eprog p)
}
static void
-clear_hdocs()
+clear_hdocs(void)
{
struct heredocs *p, *n;
@@ -3227,6 +3227,8 @@ build_dump(char *nam, char *dump, char **files, int ali, int map, int flags)
noaliases = ali;
for (hlen = FD_PRELEN, tlen = 0; *files; files++) {
+ struct stat st;
+
if (!strcmp(*files, "-k")) {
flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD;
continue;
@@ -3235,6 +3237,7 @@ build_dump(char *nam, char *dump, char **files, int ali, int map, int flags)
continue;
}
if ((fd = open(*files, O_RDONLY)) < 0 ||
+ fstat(fd, &st) != 0 || !S_ISREG(st.st_mode) ||
(flen = lseek(fd, 0, 2)) == -1) {
if (fd >= 0)
close(fd);
diff --git a/Src/pattern.c b/Src/pattern.c
index 3b55ccf1c..9e8a80ae1 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -220,8 +220,10 @@ typedef union upat *Upat;
#if defined(ZSH_64_BIT_TYPE) || defined(LONG_IS_64_BIT)
typedef zlong zrange_t;
#define ZRANGE_T_IS_SIGNED (1)
+#define ZRANGE_MAX ZLONG_MAX
#else
typedef unsigned long zrange_t;
+#define ZRANGE_MAX ULONG_MAX
#endif
#ifdef MULTIBYTE_SUPPORT
@@ -2021,124 +2023,127 @@ pattrystart(void)
}
/*
- * Test prog against null-terminated, metafied string.
+ * Fix up string length stuff.
+ *
+ * If we call patallocstr() with "force" to set things up early, it's
+ * done there, else it's done in pattryrefs(). The reason for the
+ * difference is in the latter case we may not be relying on
+ * patallocstr() having an effect.
*/
/**/
-mod_export int
-pattry(Patprog prog, char *string)
+static void
+patmungestring(char **string, int *stringlen, int *unmetalenin)
{
- return pattryrefs(prog, string, -1, -1, 0, NULL, NULL, NULL);
-}
-
-/*
- * Test prog against string of given length, no null termination
- * but still metafied at this point. offset gives an offset
- * to include in reported match indices
- */
+ /*
+ * Special signalling of empty tokenised string.
+ */
+ if (*stringlen > 0 && **string == Nularg) {
+ (*string)++;
+ /*
+ * If we don't have an unmetafied length
+ * and need it (we may not) we'll get it later.
+ */
+ if (*unmetalenin > 0)
+ (*unmetalenin)--;
+ if (*stringlen > 0)
+ (*stringlen)--;
+ }
-/**/
-mod_export int
-pattrylen(Patprog prog, char *string, int len, int unmetalen, int offset)
-{
- return pattryrefs(prog, string, len, unmetalen, offset, NULL, NULL, NULL);
+ /* Ensure we have a metafied length */
+ if (*stringlen < 0)
+ *stringlen = strlen(*string);
}
/*
- * Test prog against string with given lengths. The input
- * string is metafied; stringlen is the raw string length, and
- * unmetalen the number of characters in the original string (some
- * of which may now be metafied). Either value may be -1
- * to indicate a null-terminated string which will be counted. Note
- * there may be a severe penalty for this if a lot of matching is done
- * on one string.
+ * Allocate memeory for pattern match. Note this is specific to use
+ * of pattern *and* trial string.
*
- * offset is the position in the original string (not seen by
- * the pattern module) at which we are trying to match.
- * This is added in to the positions recorded in patbeginp and patendp
- * when we are looking for substrings. Currently this only happens
- * in the parameter substitution code.
+ * Unmetafy a trial string for use in pattern matching, if needed.
*
- * Note this is a character offset, i.e. a metafied character
- * counts as 1.
+ * If it is needed, returns a heap allocated string; if not needed,
+ * returns NULL.
*
- * The last three arguments are used to report the positions for the
- * backreferences. On entry, *nump should contain the maximum number
- * of positions to report. In this case the match, mbegin, mend
- * arrays are not altered.
- *
- * If nump is NULL but endp is not NULL, then *endp is set to the
- * end position of the match, taking into account patinstart.
+ * prog is the pattern to be executed.
+ * string is the metafied trial string.
+ * stringlen is it's length; it will be calculated if it's negative
+ * (this is a simple strlen()).
+ * unmetalen is the unmetafied length of the string, may be -1.
+ * force is 1 if we always unmetafy: this is useful if we are going
+ * to try again with different versions of the string. If this is
+ * called from pattryrefs() we don't force unmetafication as it won't
+ * be optimal. This option should be used if the resulting
+ * patstralloc is going to be passed to pattrylen() / pattryrefs().
+ * In patstralloc (supplied by caller, must last until last pattry is done)
+ * unmetalen is the unmetafied length of the string; it will be
+ * calculated if the input value is negative.
+ * unmetalenp is the umetafied length of a path segment preceeding
+ * the trial string needed for file mananagement; it is calculated as
+ * needed so does not need to be initialised.
+ * alloced is the memory allocated on the heap --- same as return value from
+ * function.
*/
-
/**/
-mod_export int
-pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
- int patoffset,
- int *nump, int *begp, int *endp)
+mod_export
+char *patallocstr(Patprog prog, char *string, int stringlen, int unmetalen,
+ int force, Patstralloc patstralloc)
{
- int i, maxnpos = 0, ret, needfullpath, unmetalenp;
- int origlen;
- char **sp, **ep, *tryalloced, *ptr;
- char *progstr = (char *)prog + prog->startoff;
+ int needfullpath;
- if (nump) {
- maxnpos = *nump;
- *nump = 0;
- }
- /* inherited from domatch, but why, exactly? */
- if (*string == Nularg) {
- string++;
- unmetalen--;
- }
+ if (force)
+ patmungestring(&string, &stringlen, &unmetalen);
- if (stringlen < 0)
- stringlen = strlen(string);
- origlen = stringlen;
-
- patflags = prog->flags;
/*
* For a top-level ~-exclusion, we will need the full
* path to exclude, so copy the path so far and append the
* current test string.
*/
- needfullpath = (patflags & PAT_HAS_EXCLUDP) && pathpos;
+ needfullpath = (prog->flags & PAT_HAS_EXCLUDP) && pathpos;
/* Get the length of the full string when unmetafied. */
if (unmetalen < 0)
- unmetalen = ztrsub(string + stringlen, string);
- if (needfullpath)
- unmetalenp = ztrsub(pathbuf + pathpos, pathbuf);
+ patstralloc->unmetalen = ztrsub(string + stringlen, string);
else
- unmetalenp = 0;
+ patstralloc->unmetalen = unmetalen;
+ if (needfullpath) {
+ patstralloc->unmetalenp = ztrsub(pathbuf + pathpos, pathbuf);
+ if (!patstralloc->unmetalenp)
+ needfullpath = 0;
+ } else
+ patstralloc->unmetalenp = 0;
+ /* Initialise cache area */
+ patstralloc->progstrunmeta = NULL;
+ patstralloc->progstrunmetalen = 0;
- DPUTS(needfullpath && (patflags & (PAT_PURES|PAT_ANY)),
+ DPUTS(needfullpath && (prog->flags & (PAT_PURES|PAT_ANY)),
"rum sort of file exclusion");
/*
* Partly for efficiency, and partly for the convenience of
* globbing, we don't unmetafy pure string patterns, and
* there's no reason to if the pattern is just a *.
*/
- if (!(patflags & (PAT_PURES|PAT_ANY))
- && (needfullpath || unmetalen != stringlen)) {
+ if (force ||
+ (!(prog->flags & (PAT_PURES|PAT_ANY))
+ && (needfullpath || patstralloc->unmetalen != stringlen))) {
/*
* We need to copy if we need to prepend the path so far
* (in which case we copy both chunks), or if we have
* Meta characters.
*/
- char *dst;
- int icopy, ncopy;
+ char *dst, *ptr;
+ int i, icopy, ncopy;
- dst = tryalloced = zalloc(unmetalen + unmetalenp);
+ dst = patstralloc->alloced =
+ zhalloc(patstralloc->unmetalen + patstralloc->unmetalenp);
if (needfullpath) {
/* loop twice, copy path buffer first time */
ptr = pathbuf;
- ncopy = unmetalenp;
+ ncopy = patstralloc->unmetalenp;
} else {
/* just loop once, copy string with unmetafication */
ptr = string;
- ncopy = unmetalen;
+ ncopy = patstralloc->unmetalen;
}
for (icopy = 0; icopy < 2; icopy++) {
for (i = 0; i < ncopy; i++) {
@@ -2153,22 +2158,136 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
break;
/* next time append test string to path so far */
ptr = string;
- ncopy = unmetalen;
+ ncopy = patstralloc->unmetalen;
}
+ }
+ else
+ {
+ patstralloc->alloced = NULL;
+ }
- if (needfullpath) {
- patinstart = tryalloced + unmetalenp;
- patinpath = tryalloced;
- } else {
- patinstart = tryalloced;
- patinpath = NULL;
- }
- stringlen = unmetalen;
- } else {
+ return patstralloc->alloced;
+}
+
+
+/*
+ * Test prog against null-terminated, metafied string.
+ */
+
+/**/
+mod_export int
+pattry(Patprog prog, char *string)
+{
+ return pattryrefs(prog, string, -1, -1, NULL, 0, NULL, NULL, NULL);
+}
+
+/*
+ * Test prog against string of given length, no null termination
+ * but still metafied at this point. offset gives an offset
+ * to include in reported match indices
+ */
+
+/**/
+mod_export int
+pattrylen(Patprog prog, char *string, int len, int unmetalen,
+ Patstralloc patstralloc, int offset)
+{
+ return pattryrefs(prog, string, len, unmetalen, patstralloc, offset,
+ NULL, NULL, NULL);
+}
+
+/*
+ * Test prog against string with given lengths. The input
+ * string is metafied; stringlen is the raw string length, and
+ * unmetalen the number of characters in the original string (some
+ * of which may now be metafied). Either value may be -1
+ * to indicate a null-terminated string which will be counted. Note
+ * there may be a severe penalty for this if a lot of matching is done
+ * on one string.
+ *
+ * If patstralloc is not NULL it is used to optimise unmetafication
+ * of a trial string that may be passed (or any substring may be passed) to
+ * pattryrefs multiple times or the same pattern (N.B. so patstralloc
+ * depends on both prog *and* the trial string). This should only be
+ * done if there is no path prefix (pathpos == 0) as otherwise the path
+ * buffer and unmetafied string may not match. To do this,
+ * patallocstr() is callled (use force = 1 to ensure it is alway
+ * unmetafied); paststralloc points to existing storage. Memory is
+ * on the heap.
+ *
+ * patstralloc->alloced and patstralloc->unmetalen contain the
+ * unmetafied string and its length. In that case, the rules for the
+ * earlier arguments change:
+ * - string is an unmetafied string
+ * - stringlen is its unmetafied (i.e. actual) length
+ * - unmetalenin is not used.
+ * string and stringlen may refer to arbitrary substrings of
+ * patstralloc->alloced without any internal modification to patstralloc.
+ *
+ * patoffset is the position in the original string (not seen by
+ * the pattern module) at which we are trying to match.
+ * This is added in to the positions recorded in patbeginp and patendp
+ * when we are looking for substrings. Currently this only happens
+ * in the parameter substitution code. It refers to a real character
+ * offset, i.e. is already in the form ready for presentation to the
+ * general public --- this is necessary as we don't have the
+ * information to convert it down here.
+ *
+ * Note this is a character offset, i.e. a single possibly metafied and
+ * possibly multibyte character counts as 1.
+ *
+ * The last three arguments are used to report the positions for the
+ * backreferences. On entry, *nump should contain the maximum number
+ * of positions to report. In this case the match, mbegin, mend
+ * arrays are not altered.
+ *
+ * If nump is NULL but endp is not NULL, then *endp is set to the
+ * end position of the match, taking into account patinstart.
+ */
+
+/**/
+mod_export int
+pattryrefs(Patprog prog, char *string, int stringlen, int unmetalenin,
+ Patstralloc patstralloc, int patoffset,
+ int *nump, int *begp, int *endp)
+{
+ int i, maxnpos = 0, ret;
+ int origlen;
+ char **sp, **ep, *ptr;
+ char *progstr = (char *)prog + prog->startoff;
+ struct patstralloc patstralloc_struct;
+
+ if (nump) {
+ maxnpos = *nump;
+ *nump = 0;
+ }
+
+ if (!patstralloc)
+ patmungestring(&string, &stringlen, &unmetalenin);
+ origlen = stringlen;
+
+ if (patstralloc) {
+ DPUTS(!patstralloc->alloced,
+ "External unmetafy didn't actually unmetafy.");
+ DPUTS(patstralloc->unmetalenp,
+ "Ooh-err: pathpos with external unmetafy. I have bad vibes.");
+ patinpath = NULL;
patinstart = string;
- tryalloced = patinpath = NULL;
+ /* stringlen is unmetafied length; unmetalenin is ignored */
+ } else {
+ patstralloc = &patstralloc_struct;
+ if (patallocstr(prog, string, stringlen, unmetalenin, 0, patstralloc)) {
+ patinstart = patstralloc->alloced + patstralloc->unmetalenp;
+ stringlen = patstralloc->unmetalen;
+ } else
+ patinstart = string;
+ if (patstralloc->unmetalenp)
+ patinpath = patstralloc->alloced;
+ else
+ patinpath = NULL;
}
+ patflags = prog->flags;
patinend = patinstart + stringlen;
/*
* From now on we do not require NULL termination of
@@ -2181,7 +2300,31 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
* Either we are testing against a pure string,
* or we can match anything at all.
*/
- int ret;
+ int ret, pstrlen;
+ char *pstr;
+ if (patstralloc->alloced)
+ {
+ /*
+ * Unmetafied; we need pattern sring that's also unmetafied.
+ * We'll cache it in the patstralloc structure.
+ * Note it's on the heap.
+ */
+ if (!patstralloc->progstrunmeta)
+ {
+ patstralloc->progstrunmeta =
+ dupstrpfx(progstr, (int)prog->patmlen);
+ unmetafy(patstralloc->progstrunmeta,
+ &patstralloc->progstrunmetalen);
+ }
+ pstr = patstralloc->progstrunmeta;
+ pstrlen = patstralloc->progstrunmetalen;
+ }
+ else
+ {
+ /* Metafied. */
+ pstr = progstr;
+ pstrlen = (int)prog->patmlen;
+ }
if (prog->flags & PAT_ANY) {
/*
* Optimisation for a single "*": always matches
@@ -2193,11 +2336,11 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
* Testing a pure string. See if initial
* components match.
*/
- int lendiff = stringlen - prog->patmlen;
+ int lendiff = stringlen - pstrlen;
if (lendiff < 0) {
/* No, the pattern string is too long. */
ret = 0;
- } else if (!memcmp(progstr, patinstart, prog->patmlen)) {
+ } else if (!memcmp(pstr, patinstart, pstrlen)) {
/*
* Initial component matches. Matches either
* if lengths are the same or we are not anchored
@@ -2219,24 +2362,36 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
} else {
/*
* Remember the length in case used for ${..#..} etc.
- * In this case, we didn't unmetafy the string.
+ * In this case, we didn't unmetafy the pattern string
+ * In the orignal structure, but it might be unmetafied
+ * for use with an unmetafied test string.
*/
- patinlen = (int)prog->patmlen;
+ patinlen = pstrlen;
/* if matching files, must update globbing flags */
patglobflags = prog->globend;
if ((patglobflags & GF_MATCHREF) &&
!(patflags & PAT_FILE)) {
- char *str = ztrduppfx(patinstart, patinlen);
+ char *str;
int mlen;
- /*
- * Count the characters. We're not using CHARSUB()
- * because the string is still metafied.
- */
- MB_METACHARINIT();
- mlen = MB_METASTRLEN2END(patinstart, 0,
- patinstart + patinlen);
+ if (patstralloc->alloced) {
+ /*
+ * Unmetafied: pstrlen contains unmetafied
+ * length in bytes.
+ */
+ str = metafy(patinstart, pstrlen, META_DUP);
+ mlen = CHARSUB(patinstart, patinstart + pstrlen);
+ } else {
+ str = ztrduppfx(patinstart, patinlen);
+ /*
+ * Count the characters. We're not using CHARSUB()
+ * because the string is still metafied.
+ */
+ MB_METACHARINIT();
+ mlen = MB_METASTRLEN2END(patinstart, 0,
+ patinstart + patinlen);
+ }
setsparam("MATCH", str);
setiparam("MBEGIN",
@@ -2248,9 +2403,6 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
}
}
- if (tryalloced)
- zfree(tryalloced, unmetalen + unmetalenp);
-
return ret;
} else {
int q = queue_signal_level();
@@ -2287,8 +2439,6 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
}
}
if (!ret) {
- if (tryalloced)
- zfree(tryalloced, unmetalen + unmetalenp);
return 0;
}
@@ -2320,8 +2470,11 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
/*
* Optimization: if we didn't find any Meta characters
* to begin with, we don't need to look for them now.
+ *
+ * For patstralloc pased in, we want the unmetafied length.
*/
- if (unmetalen != origlen) {
+ if (patstralloc == &patstralloc_struct &&
+ patstralloc->unmetalen != origlen) {
for (ptr = patinstart; ptr < patinput; ptr++)
if (imeta(*ptr))
patinlen++;
@@ -2442,16 +2595,15 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
restore_queue_signals(q);
- if (tryalloced)
- zfree(tryalloced, unmetalen + unmetalenp);
-
return ret;
}
}
/*
* Return length of previous succesful match. This is
- * in metafied bytes, i.e. includes a count of Meta characters.
+ * in metafied bytes, i.e. includes a count of Meta characters,
+ * unless the match was done on an unmetafied string using
+ * a patstralloc stuct, in which case it, too is unmetafed.
* Unusual and futile attempt at modular encapsulation.
*/
@@ -2641,19 +2793,30 @@ patmatch(Upat prog)
start = compend = patinput;
comp = 0;
while (patinput < patinend && idigit(*patinput)) {
- if (comp)
- comp *= 10;
- comp += *patinput - '0';
+ int out_of_range = 0;
+ int digit = *patinput - '0';
+ if (comp > ZRANGE_MAX / (zlong)10) {
+ out_of_range = 1;
+ } else {
+ zrange_t c10 = comp ? comp * 10 : 0;
+ if (ZRANGE_MAX - c10 < digit) {
+ out_of_range = 1;
+ } else {
+ comp = c10;
+ comp += digit;
+ }
+ }
patinput++;
compend++;
- if (comp & ((zrange_t)1 << (sizeof(comp)*8 -
+ if (out_of_range ||
+ (comp & ((zrange_t)1 << (sizeof(comp)*8 -
#ifdef ZRANGE_T_IS_SIGNED
2
#else
1
#endif
- ))) {
+ )))) {
/*
* Out of range (allowing for signedness, which
* we need if we are using zlongs).
@@ -3213,6 +3376,7 @@ patmatch(Upat prog)
scan[P_CT_CURRENT].l = cur + 1;
if (patmatch(scan + P_CT_OPERAND))
return 1;
+ scan[P_CT_CURRENT].l = cur;
patinput = patinput_thistime;
}
if (cur < min)
diff --git a/Src/subst.c b/Src/subst.c
index 021d23444..b7f8338c7 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -44,15 +44,23 @@ char nulstring[] = {Nularg, '\0'};
* - Brace expansion
* - Tilde and equals substitution
*
- * PREFORK_* flags are defined in zsh.h
+ * "flag"s contains PREFORK_* flags, defined in zsh.h.
+ *
+ * "ret_flags" is used to return values from nested parameter
+ * substitions. It may be NULL in which case PREFORK_SUBEXP
+ * must not appear in flags; any return value from below
+ * will be discarded.
*/
/**/
mod_export void
-prefork(LinkList list, int flags)
+prefork(LinkList list, int flags, int *ret_flags)
{
LinkNode node, stop = 0;
int keep = 0, asssub = (flags & PREFORK_TYPESET) && isset(KSHTYPESET);
+ int ret_flags_local = 0;
+ if (!ret_flags)
+ ret_flags = &ret_flags_local; /* will be discarded */
queue_signals();
for (node = firstnode(list); node; incnode(node)) {
@@ -75,10 +83,8 @@ prefork(LinkList list, int flags)
setdata(node, cptr);
}
if (!(node = stringsubst(list, node,
- flags & (PREFORK_SINGLE|PREFORK_SPLIT|
- PREFORK_SHWORDSPLIT|
- PREFORK_NOSHWORDSPLIT),
- asssub))) {
+ flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
+ ret_flags, asssub))) {
unqueue_signals();
return;
}
@@ -149,7 +155,8 @@ stringsubstquote(char *strstart, char **pstrdpos)
/**/
static LinkNode
-stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub)
+stringsubst(LinkList list, LinkNode node, int pf_flags, int *ret_flags,
+ int asssub)
{
int qt;
char *str3 = (char *)getdata(node);
@@ -235,7 +242,8 @@ stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub)
pf_flags |= PREFORK_SHWORDSPLIT;
node = paramsubst(
list, node, &str, qt,
- pf_flags & (PREFORK_SINGLE|PREFORK_SHWORDSPLIT));
+ pf_flags & (PREFORK_SINGLE|PREFORK_SHWORDSPLIT|
+ PREFORK_SUBEXP), ret_flags);
if (errflag || !node)
return NULL;
str3 = (char *)getdata(node);
@@ -413,7 +421,7 @@ singsub(char **s)
init_list1(foo, *s);
- prefork(&foo, PREFORK_SINGLE);
+ prefork(&foo, PREFORK_SINGLE, NULL);
if (errflag)
return;
*s = (char *) ugetnode(&foo);
@@ -430,11 +438,15 @@ singsub(char **s)
* set to 1. Otherwise, *isarr is set to 0, and the result is put into *s,
* with any necessary joining of multiple elements using sep (which can be
* NULL to use IFS). The return value is true iff the expansion resulted
- * in an empty list. */
+ * in an empty list.
+ *
+ * *ms_flags is set to bits in the enum above as neeed.
+ */
/**/
static int
-multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep)
+multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep,
+ int *ms_flags)
{
int l;
char **r, **p, *x = *s;
@@ -450,6 +462,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep)
l++;
if (!iwsep(STOUC(c)))
break;
+ *ms_flags |= MULTSUB_WS_AT_START;
}
}
@@ -481,8 +494,10 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep)
if (!WC_ZISTYPE(c, ISEP))
break;
}
- if (!*x)
+ if (!*x) {
+ *ms_flags |= MULTSUB_WS_AT_END;
break;
+ }
insertlinknode(&foo, n, (void *)x), incnode(n);
}
}
@@ -509,7 +524,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep)
}
}
- prefork(&foo, pf_flags);
+ prefork(&foo, pf_flags, ms_flags);
if (errflag) {
if (isarr)
*isarr = 0;
@@ -1494,7 +1509,8 @@ check_colon_subscript(char *str, char **endp)
/**/
static LinkNode
-paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
+paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
+ int *ret_flags)
{
char *aptr = *str, c, cc;
char *s = aptr, *fstr, *idbeg, *idend, *ostr = (char *) getdata(n);
@@ -1717,6 +1733,20 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
* This is for compatibility.
*/
int horrible_offset_hack = 0;
+ /*
+ * Signal back from multsub: with something like
+ * x${:- $foo}
+ * with word-splitting active we need to split on that leading
+ * whitespace. However, if there's no "x" the whitespace is
+ * simply removed.
+ */
+ int ms_flags = 0;
+ /*
+ * We need to do an extra fetch to honour the (P) flag.
+ * Complicated by the use of subexpressions that may have
+ * nested (P) flags.
+ */
+ int fetch_needed;
*s++ = '\0';
/*
@@ -2265,7 +2295,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
* remove the aspar test and extract a value from an array, if
* necessary, when we handle (P) lower down.
*/
- if (multsub(&val, 0, (aspar ? NULL : &aval), &isarr, NULL) && quoted) {
+ if (multsub(&val, PREFORK_SUBEXP, (aspar ? NULL : &aval), &isarr, NULL,
+ &ms_flags) && quoted) {
/* Empty quoted string --- treat as null string, not elided */
isarr = -1;
aval = (char **) hcalloc(sizeof(char *));
@@ -2279,8 +2310,39 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
*/
while (inull(*s))
s++;
+ if (ms_flags & MULTSUB_PARAM_NAME) {
+ /*
+ * Downbelow has told us this is a parameter name, e.g.
+ * ${${(P)name}...}. We're going to behave as if
+ * we have exactly that name followed by the rest of
+ * the parameter for subscripting etc.
+ *
+ * See below for where we set the flag in the nested
+ * substitution.
+ */
+ if (isarr) {
+ if (aval[0] && aval[1]) {
+ zerr("parameter name reference used with array");
+ return NULL;
+ }
+ val = aval[0];
+ isarr = 0;
+ }
+ s = dyncat(val, s);
+ /* Now behave po-faced as if it was always like that... */
+ subexp = 0;
+ /*
+ * If this is a (P) (first test) and at the top level
+ * (second test) we can't rely on the caller fetching
+ * the result from the pending aspar. So do it below.
+ */
+ fetch_needed = aspar && !(pf_flags & PREFORK_SUBEXP);
+ } else
+ fetch_needed = 0; /* any initial aspar fetch already done */
v = (Value) NULL;
- } else if (aspar) {
+ } else
+ fetch_needed = aspar; /* aspar fetch still needed */
+ if (fetch_needed) {
/*
* No subexpression, but in any case the value is going
* to give us the name of a parameter on which we do
@@ -2296,6 +2358,17 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
} else
vunset = 1;
}
+ if (aspar && (pf_flags & PREFORK_SUBEXP)) {
+ /*
+ * This is the inner handling for the case referred to above
+ * where we have something like ${${(P)name}...}.
+ *
+ * Treat this as as a normal value here; all transformations on
+ * result are in outer instance.
+ */
+ aspar = 0;
+ *ret_flags |= MULTSUB_PARAM_NAME;
+ }
/*
* We need to retrieve a value either if we haven't already
* got it from a subexpression, or if the processing so
@@ -2736,7 +2809,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
split_flags = PREFORK_NOSHWORDSPLIT;
}
multsub(&val, split_flags, (aspar ? NULL : &aval),
- &isarr, NULL);
+ &isarr, NULL, &ms_flags);
copied = 1;
spbreak = 0;
/* Leave globsubst on if forced */
@@ -2765,13 +2838,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
* behavior on caller choice of PREFORK_SHWORDSPLIT. */
multsub(&val,
spbreak ? PREFORK_SINGLE : PREFORK_NOSHWORDSPLIT,
- NULL, &isarr, NULL);
+ NULL, &isarr, NULL, &ms_flags);
} else {
if (spbreak)
split_flags = PREFORK_SPLIT|PREFORK_SHWORDSPLIT;
else
split_flags = PREFORK_NOSHWORDSPLIT;
- multsub(&val, split_flags, &aval, &isarr, NULL);
+ multsub(&val, split_flags, &aval, &isarr, NULL,
+ &ms_flags);
spbreak = 0;
}
if (arrasg) {
@@ -3303,6 +3377,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
}
if (haserr || errflag)
return NULL;
+ ms_flags = 0;
}
/*
* This handles taking a length with ${#foo} and variations.
@@ -3341,6 +3416,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
sprintf(buf, "%ld", len);
val = dupstring(buf);
isarr = 0;
+ ms_flags = 0;
}
/* At this point we make sure that our arrayness has affected the
* arrayness of the linked list. Then, we can turn our value into
@@ -3370,6 +3446,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
if (isarr) {
val = sepjoin(aval, sep, 1);
isarr = 0;
+ ms_flags = 0;
}
if (!ssub && (spbreak || spsep)) {
aval = sepsplit(val, spsep, 0, 1);
@@ -3649,6 +3726,20 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
* equivalent and only locally decide if we need to treat it
* as a scalar.)
*/
+
+ /*
+ * 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.
+ */
+ if ((ms_flags & MULTSUB_WS_AT_START) && aptr > ostr) {
+ insertlinknode(l, n, dupstrpfx(ostr, aptr - ostr)), incnode(n);
+ ostr = aptr;
+ }
+ /* Likewise at the end */
+ if ((ms_flags & MULTSUB_WS_AT_END) && *fstr) {
+ insertlinknode(l, n, dupstring(fstr)); /* appended, no incnode */
+ *fstr = '\0';
+ }
if (isarr) {
char *x;
char *y;
@@ -3727,7 +3818,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
*--fstr = Marker;
init_list1(tl, fstr);
- if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, 0))
+ if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, ret_flags, 0))
return NULL;
*str = aptr;
tn = firstnode(&tl);
diff --git a/Src/text.c b/Src/text.c
index 7e65f43a4..9421d70ce 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -632,8 +632,10 @@ gettext2(Estate state)
taddstr(" in ");
taddlist(state, *state->pc++);
}
- tindent++;
taddnl(0);
+ taddstr("do");
+ taddnl(0);
+ tindent++;
tpush(code, 1);
} else {
dec_tindent();
diff --git a/Src/utils.c b/Src/utils.c
index ca68eae32..0afa8c908 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -692,9 +692,23 @@ ispwd(char *s)
{
struct stat sbuf, tbuf;
- if (stat(unmeta(s), &sbuf) == 0 && stat(".", &tbuf) == 0)
- if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
- return 1;
+ /* POSIX: environment PWD must be absolute */
+ if (*s != '/')
+ return 0;
+
+ if (stat((s = unmeta(s)), &sbuf) == 0 && stat(".", &tbuf) == 0)
+ if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino) {
+ /* POSIX: No element of $PWD may be "." or ".." */
+ while (*s) {
+ if (s[0] == '.' &&
+ (!s[1] || s[1] == '/' ||
+ (s[1] == '.' && (!s[2] || s[2] == '/'))))
+ break;
+ while (*s++ != '/' && *s)
+ continue;
+ }
+ return !*s;
+ }
return 0;
}
@@ -1878,6 +1892,37 @@ redup(int x, int y)
}
/*
+ * Add an fd opened ithin a module.
+ *
+ * fdt is the type of the fd; see the FDT_ definitions in zsh.h.
+ * The most likely falures are:
+ *
+ * FDT_EXTERNAL: the fd can be used within the shell for normal I/O but
+ * it will not be closed automatically or by normal shell syntax.
+ *
+ * FDT_MODULE: as FDT_EXTERNAL, but it can only be closed by the module
+ * (which should included zclose() as part of the sequence), not by
+ * the standard shell syntax for closing file descriptors.
+ *
+ * FDT_INTERNAL: fd is treated like others created by the shell for
+ * internal use; it can be closed and will be closed by the shell if it
+ * exec's or performs an exec with a fork optimised out.
+ *
+ * Safe if fd is -1 to indicate failure.
+ */
+/**/
+mod_export void
+addmodulefd(int fd, int fdt)
+{
+ if (fd >= 0) {
+ check_fd_table(fd);
+ fdtable[fd] = fdt;
+ }
+}
+
+/**/
+
+/*
* Indicate that an fd has a file lock; if cloexec is 1 it will be closed
* on exec.
* The fd should already be known to fdtable (e.g. by movefd).
@@ -2798,7 +2843,7 @@ spckword(char **s, int hist, int cmd, int ask)
* as used in spscan(), so that an autocd is chosen *
* only when it is better than anything so far, and *
* so we prefer directories earlier in the cdpath. */
- if ((thisdist = mindist(*pp, *s, bestcd)) < d) {
+ if ((thisdist = mindist(*pp, *s, bestcd, 1)) < d) {
best = dupstring(bestcd);
d = thisdist;
}
@@ -4043,7 +4088,8 @@ spname(char *oldname)
thresh = 3;
else if (thresh > 100)
thresh = 100;
- if ((thisdist = mindist(newname, spnameguess, spnamebest)) >= thresh) {
+ thisdist = mindist(newname, spnameguess, spnamebest, *old == '/');
+ if (thisdist >= thresh) {
/* The next test is always true, except for the first path *
* component. We could initialize bestdist to some large *
* constant instead, and then compare to that constant here, *
@@ -4068,42 +4114,52 @@ spname(char *oldname)
/**/
static int
-mindist(char *dir, char *mindistguess, char *mindistbest)
+mindist(char *dir, char *mindistguess, char *mindistbest, int wantdir)
{
int mindistd, nd;
DIR *dd;
char *fn;
char *buf;
+ struct stat st;
+ size_t dirlen;
if (dir[0] == '\0')
dir = ".";
mindistd = 100;
- buf = zalloc(strlen(dir) + strlen(mindistguess) + 2);
+ if (!(buf = zalloc((dirlen = strlen(dir)) + strlen(mindistguess) + 2)))
+ return 0;
sprintf(buf, "%s/%s", dir, mindistguess);
- if (access(unmeta(buf), F_OK) == 0) {
+ if (stat(unmeta(buf), &st) == 0 && (!wantdir || S_ISDIR(st.st_mode))) {
strcpy(mindistbest, mindistguess);
free(buf);
return 0;
}
- free(buf);
- if (!(dd = opendir(unmeta(dir))))
- return mindistd;
- while ((fn = zreaddir(dd, 0))) {
- if (spnamepat && pattry(spnamepat, fn))
- continue;
- nd = spdist(fn, mindistguess,
- (int)strlen(mindistguess) / 4 + 1);
- if (nd <= mindistd) {
- strcpy(mindistbest, fn);
- mindistd = nd;
- if (mindistd == 0)
- break;
+ if ((dd = opendir(unmeta(dir)))) {
+ while ((fn = zreaddir(dd, 0))) {
+ if (spnamepat && pattry(spnamepat, fn))
+ continue;
+ nd = spdist(fn, mindistguess,
+ (int)strlen(mindistguess) / 4 + 1);
+ if (nd <= mindistd) {
+ if (wantdir) {
+ if (!(buf = zrealloc(buf, dirlen + strlen(fn) + 2)))
+ continue;
+ sprintf(buf, "%s/%s", dir, fn);
+ if (stat(unmeta(buf), &st) != 0 || !S_ISDIR(st.st_mode))
+ continue;
+ }
+ strcpy(mindistbest, fn);
+ mindistd = nd;
+ if (mindistd == 0)
+ break;
+ }
}
+ closedir(dd);
}
- closedir(dd);
+ free(buf);
return mindistd;
}
@@ -5385,6 +5441,12 @@ quotestring(const char *s, char **e, int instring)
u = s;
if (instring == QT_DOLLARS) {
/*
+ * The only way to get Nularg here is when
+ * it is placeholding for the empty string?
+ */
+ if (inull(*u))
+ u++;
+ /*
* As we test for printability here we need to be able
* to look for multibyte characters.
*/
diff --git a/Src/zsh.h b/Src/zsh.h
index 4e2cb656e..d3bfcefcc 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -36,6 +36,16 @@
*/
#ifdef ZSH_64_BIT_TYPE
typedef ZSH_64_BIT_TYPE zlong;
+#if defined(ZLONG_IS_LONG_LONG) && defined(LLONG_MAX)
+#define ZLONG_MAX LLONG_MAX
+#else
+#ifdef ZLONG_IS_LONG_64
+#define ZLONG_MAX LONG_MAX
+#else
+/* umm... */
+#define ZLONG_MAX ((zlong)9223372036854775807)
+#endif
+#endif
#ifdef ZSH_64_BIT_UTYPE
typedef ZSH_64_BIT_UTYPE zulong;
#else
@@ -44,6 +54,7 @@ typedef unsigned zlong zulong;
#else
typedef long zlong;
typedef unsigned long zulong;
+#define ZLONG_MAX LONG_MAX
#endif
/*
@@ -395,25 +406,32 @@ enum {
*/
#define FDT_EXTERNAL 2
/*
+ * Entry visible to other processes but controlled by a module.
+ * The difference from FDT_EXTERNAL is that closing this using
+ * standard fd syntax will fail as there is some tidying up that
+ * needs to be done by the module's own mechanism.
+ */
+#define FDT_MODULE 3
+/*
* Entry used by output from the XTRACE option.
*/
-#define FDT_XTRACE 3
+#define FDT_XTRACE 4
/*
* Entry used for file locking.
*/
-#define FDT_FLOCK 4
+#define FDT_FLOCK 5
/*
* As above, but the fd is not marked for closing on exec,
* so the shell can still exec the last process.
*/
-#define FDT_FLOCK_EXEC 5
+#define FDT_FLOCK_EXEC 6
#ifdef PATH_DEV_FD
/*
* Entry used by a process substition.
* This marker is not tested internally as we associated the file
* descriptor with a job for closing.
*/
-#define FDT_PROC_SUBST 6
+#define FDT_PROC_SUBST 7
#endif
/* Flags for input stack */
@@ -469,6 +487,7 @@ typedef struct heap *Heap;
typedef struct heapstack *Heapstack;
typedef struct histent *Histent;
typedef struct hookdef *Hookdef;
+typedef struct imatchdata *Imatchdata;
typedef struct jobfile *Jobfile;
typedef struct job *Job;
typedef struct linkedmod *Linkedmod;
@@ -480,6 +499,7 @@ typedef struct options *Options;
typedef struct optname *Optname;
typedef struct param *Param;
typedef struct paramdef *Paramdef;
+typedef struct patstralloc *Patstralloc;
typedef struct patprog *Patprog;
typedef struct prepromptfn *Prepromptfn;
typedef struct process *Process;
@@ -1459,6 +1479,15 @@ struct patprog {
char patstartch;
};
+struct patstralloc {
+ int unmetalen; /* Unmetafied length of trial string */
+ int unmetalenp; /* Unmetafied length of path prefix.
+ If 0, no path prefix. */
+ char *alloced; /* Allocated string, may be NULL */
+ char *progstrunmeta; /* Unmetafied pure string in pattern, cached */
+ int progstrunmetalen; /* Length of the foregoing */
+};
+
/* Flags used in pattern matchers (Patprog) and passed down to patcompile */
#define PAT_FILE 0x0001 /* Pattern is a file name */
@@ -1572,6 +1601,31 @@ typedef struct zpc_disables_save *Zpc_disables_save;
/* Range: token followed by the (possibly multibyte) start and end */
#define PP_RANGE 21
+/*
+ * Argument to get_match_ret() in glob.c
+ */
+struct imatchdata {
+ /* Metafied trial string */
+ char *mstr;
+ /* Its length */
+ int mlen;
+ /* Unmetafied string */
+ char *ustr;
+ /* Its length */
+ int ulen;
+ /* Flags (SUB_*) */
+ int flags;
+ /* Replacement string (metafied) */
+ char *replstr;
+ /*
+ * List of bits of matches to concatenate with replacement string.
+ * The data is a struct repldata. It is not used in cases like
+ * ${...//#foo/bar} even though SUB_GLOBAL is set, since the match
+ * is anchored. It goes on the heap.
+ */
+ LinkList repllist;
+};
+
/* Globbing flags: lower 8 bits gives approx count */
#define GF_LCMATCHUC 0x0100
#define GF_IGNCASE 0x0200
@@ -1812,18 +1866,45 @@ enum {
};
/* Flags as the second argument to prefork */
-/* argument handled like typeset foo=bar */
-#define PREFORK_TYPESET 0x01
-/* argument handled like the RHS of foo=bar */
-#define PREFORK_ASSIGN 0x02
-/* single word substitution */
-#define PREFORK_SINGLE 0x04
-/* explicitly split nested substitution */
-#define PREFORK_SPLIT 0x08
-/* SHWORDSPLIT in parameter expn */
-#define PREFORK_SHWORDSPLIT 0x10
-/* SHWORDSPLIT forced off in nested subst */
-#define PREFORK_NOSHWORDSPLIT 0x20
+enum {
+ /* argument handled like typeset foo=bar */
+ PREFORK_TYPESET = 0x01,
+ /* argument handled like the RHS of foo=bar */
+ PREFORK_ASSIGN = 0x02,
+ /* single word substitution */
+ PREFORK_SINGLE = 0x04,
+ /* explicitly split nested substitution */
+ PREFORK_SPLIT = 0x08,
+ /* SHWORDSPLIT in parameter expn */
+ PREFORK_SHWORDSPLIT = 0x10,
+ /* SHWORDSPLIT forced off in nested subst */
+ PREFORK_NOSHWORDSPLIT = 0x20,
+ /* Prefork is part of a parameter subexpression */
+ PREFORK_SUBEXP = 0x40
+};
+
+/*
+ * Bit flags passed back from multsub() to paramsubst().
+ * Some flags go from a nested parmsubst() through the enclosing
+ * stringsubst() and prefork().
+ */
+enum {
+ /*
+ * Set if the string had whitespace at the start
+ * that should cause word splitting against any preceeding string.
+ */
+ MULTSUB_WS_AT_START = 1,
+ /*
+ * Set if the string had whitespace at the end
+ * that should cause word splitting against any following string.
+ */
+ MULTSUB_WS_AT_END = 2,
+ /*
+ * Set by nested paramsubst() to indicate the return
+ * value is a parameter name, rather than a value.
+ */
+ MULTSUB_PARAM_NAME = 4
+};
/*
* Structure for adding parameters in a module.
@@ -1885,9 +1966,6 @@ struct paramdef {
{ name, flags | PM_SPECIAL | PM_HIDE | PM_HIDEVAL, \
NULL, gsufn, getfn, scanfn, NULL }
-#define setsparam(S,V) assignsparam(S,V,0)
-#define setaparam(S,V) assignaparam(S,V,0)
-
/*
* Flags for assignsparam and assignaparam.
*/
@@ -2164,6 +2242,7 @@ enum {
GLOBASSIGN,
GLOBCOMPLETE,
GLOBDOTS,
+ GLOBSTARSHORT,
GLOBSUBST,
HASHCMDS,
HASHDIRS,
diff --git a/Src/zsh.mdd b/Src/zsh.mdd
index c2e59c910..86dd58866 100644
--- a/Src/zsh.mdd
+++ b/Src/zsh.mdd
@@ -7,7 +7,7 @@ functions='Functions/Chpwd/* Functions/Exceptions/* Functions/Misc/* Functions/M
nozshdep=1
alwayslink=1
-# autobins not specified because of alwayslink
+# autofeatures not specified because of alwayslink
objects="builtin.o compat.o cond.o context.o \
exec.o glob.o hashtable.o hashnameddir.o \
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index d179dc46d..4b2843a47 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -450,6 +450,20 @@
fn
1:ERRRETURN in "else" branch (regression test)
+ $ZTST_testdir/../Src/zsh -f =(<<<"
+ if false; then
+ :
+ else
+ if [[ -n '' ]]; then
+ a=2
+ fi
+ print Yes
+ fi
+ ")
+0:ERRRETURN when false "if" is the first statement in an "else" (regression)
+>Yes
+F:Must be tested with a top-level script rather than source or function
+
%clean
rm -f TRAPEXIT
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index 3e2095a0c..f944a4fbd 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -574,3 +574,11 @@
0:Optimisation to squeeze multiple *'s used as ordinary glob wildcards.
>glob.tmp/ra=1.0_et=3.5
>glob.tmp/ra=1.0_et=3.5
+
+ [[ 1_2_ = (*_)(#c1) ]] && print 1 OK # because * matches 1_2
+ [[ 1_2_ = (*_)(#c2) ]] && print 2 OK
+ [[ 1_2_ = (*_)(#c3) ]] || print 3 OK
+0:Some more complicated backtracking with match counts.
+>1 OK
+>2 OK
+>3 OK
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index c7d506a51..a3c5d71df 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -413,6 +413,10 @@
>$'playing \'stupid\' "games" \\w\\i\\t\\h $quoting.'
>'playing '\'stupid\'' "games" \w\i\t\h $quoting.'
+ print -r ${(qqqq):-""}
+0:workers/36551: literal empty string in ${(qqqq)...}
+>$''
+
x=( a '' '\b' 'c d' '$e' )
print -r ${(q)x}
print -r ${(q-)x}
@@ -568,6 +572,12 @@
>echo
>three
+ print -rl - ${(z):-":;(( echo 42 "}
+0:${(z)} with incomplete math expressions
+>:
+>;
+>(( echo 42
+
psvar=(dog)
setopt promptsubst
foo='It shouldn'\''t $(happen) to a %1v.'
@@ -1725,3 +1735,134 @@
0:History modifier works the same for scalar and array substitution
>ddd bdb cdc
>ddd bdb cdc
+
+ a=1_2_3_4_5_6
+ print ${a#(*_)(#c2)}
+ print ${a#(*_)(#c5)}
+ print ${a#(*_)(#c7)}
+0:Complicated backtracking with match counts
+>3_4_5_6
+>6
+>1_2_3_4_5_6
+
+ (setopt shwordsplit
+ do_test() {
+ print $#: "$@"
+ }
+ foo=bar
+ foo2="bar bar"
+ do_test ${:- foo }
+ do_test ${:- foo bar }
+ do_test ${:- $foo }
+ do_test ${:- $foo2 }
+ do_test x${:- foo }y
+ do_test x${:- foo bar }y
+ do_test x${:- $foo }y
+ do_test x${:- $foo2 }y
+ do_test x${foo:+ $foo }y
+ )
+0:We Love SH_WORD_SPLIT Day celebrated with space at start of internal subst
+>1: foo
+>2: foo bar
+>1: bar
+>2: bar bar
+>3: x foo y
+>4: x foo bar y
+>3: x bar y
+>4: x bar bar y
+>3: x bar y
+
+ (unsetopt shwordsplit # default, for clarity
+ do_test() {
+ print $#: "$@"
+ }
+ foo=bar
+ foo2="bar bar"
+ do_test ${:- foo }
+ do_test ${:- foo bar }
+ do_test ${:- $foo }
+ do_test ${:- $foo2 }
+ do_test x${:- foo }y
+ do_test x${:- foo bar }y
+ do_test x${:- $foo }y
+ do_test x${:- $foo2 }y
+ do_test x${foo:+ $foo }y
+ )
+0:We Love NO_SH_WORD_SPLIT Even More Day celebrated as sanity check
+>1: foo
+>1: foo bar
+>1: bar
+>1: bar bar
+>1: x foo y
+>1: x foo bar y
+>1: x bar y
+>1: x bar bar y
+>1: x bar y
+
+ testfn() {
+ local scalar=obfuscation
+ local -a array=(alpha bravo charlie delta echo foxtrot)
+ local -A assoc=(one eins two zwei three drei four vier)
+ local name subscript
+ for name subscript in scalar 3 array 5 assoc three; do
+ print ${${(P)name}[$subscript]}
+ done
+ }
+ testfn
+0:${(P)...} with normal subscripting
+>f
+>echo
+>drei
+
+ testfn() {
+ local s1=foo s2=bar
+ local -a val=(s1)
+ print ${${(P)val}[1,3]}
+ val=(s1 s2)
+ print ${${(P)val}[1,3]}
+ }
+ testfn
+1:${(P)...} with array as name
+>foo
+?testfn:5: parameter name reference used with array
+
+ testfn() {
+ local -A assoc=(one buckle two show three knock four door)
+ local name='assoc[two]'
+ print ${${(P)name}[2,3]}
+ }
+ testfn
+0:${(P)...} with internal subscripting
+>ho
+
+ testfn() {
+ local one=two
+ local two=three
+ local three=four
+ local -a four=(all these worlds belong to foo)
+ print ${(P)${(P)${(P)one}}}
+ print ${${(P)${(P)${(P)one}}}[3]}
+ }
+ testfn
+0:nested parameter name references
+>all these worlds belong to foo
+>worlds
+
+ (
+ path=(/random /value)
+ testfn1() {
+ local path=
+ print $#path
+ }
+ testfn1
+ testfn2() {
+ local path=/somewhere
+ print $#path $path
+ }
+ testfn2
+ print $#path $path
+ )
+0:Local special variables with loose typing
+>0
+>1 /somewhere
+>2 /random /value
diff --git a/Test/D06subscript.ztst b/Test/D06subscript.ztst
index cffca742e..144923667 100644
--- a/Test/D06subscript.ztst
+++ b/Test/D06subscript.ztst
@@ -249,3 +249,20 @@
string[0]=!
1:Can't set only element zero of string
?(eval):1: string: assignment to invalid subscript range
+
+ typeset -A assoc=(leader topcat officer dibble sidekick choochoo)
+ alias myind='echo leader' myletter='echo 1' myletter2='echo 4'
+ print ${assoc[$(myind)]}
+ print $assoc[$(myind)]
+ print ${assoc[$(myind)][$(myletter)]}${assoc[$(myind)][$(myletter2)]}
+ assoc[$(myind)]='of the gang'
+ print ${assoc[$(myind)]}
+ print $assoc[$(myind)]
+ print $assoc[leader]
+0: Parsing subscript with non-trivial tokenisation
+>topcat
+>topcat
+>tc
+>of the gang
+>of the gang
+>of the gang
diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index ace191f06..dff2ec12f 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -293,6 +293,21 @@
>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ ἦν ὁ λόγος
>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ
+ a="1ë34ë6"
+ print ${(BEN)a#*4}
+ print ${(BEN)a##*ë}
+ print ${(BEN)a%4*}
+ print ${(BEN)a%%ë*}
+ print ${(SBEN)a#ë3}
+ print ${(SBEN)a%4ë}
+0:Flags B, E, N and S in ${...#...} and ${...%...}
+>1 5 4
+>1 6 5
+>4 7 3
+>2 7 5
+>2 4 2
+>4 6 2
+
foo=(κατέβην χθὲς εἰς Πειραιᾶ)
print ${(l.3..¥.r.3..£.)foo}
print ${(l.4..¥.r.2..£.)foo}
@@ -528,6 +543,6 @@
[[ $'\xe3' == [[:INCOMPLETE:]] ]] || print fail 1
[[ $'\xe3\x83' == [[:INCOMPLETE:]][[:INVALID:]] ]] || print fail 2
- [[ $'\xe3\x83\x9b' != [[:INCOMPLETE:][:NVALID:]] ]] || print fail 3
+ [[ $'\xe3\x83\x9b' != [[:INCOMPLETE:][:INVALID:]] ]] || print fail 3
[[ $'\xe3\x83\x9b' = ? ]] || print fail 4
0:Testing incomplete and invalid multibyte character components
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index 2b91b21fa..c9427c755 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1110,11 +1110,15 @@
foo3=bar6
}
foo4=bar7 =true
+ (( foo5=8 ))
+ integer foo6=9
+ (( foo6=10 ))
}
fn
0:WARN_CREATE_GLOBAL option
-?fn:3: scalar parameter foo1 created globally in function
-?fn:5: scalar parameter foo1 created globally in function
+?fn:3: scalar parameter foo1 created globally in function fn
+?fn:5: scalar parameter foo1 created globally in function fn
+?fn:15: numeric parameter foo5 created globally in function fn
# This really just tests if XTRACE is egregiously broken.
# To test it properly would need a full set of its own.
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
new file mode 100644
index 000000000..6c38e3974
--- /dev/null
+++ b/Test/V10private.ztst
@@ -0,0 +1,268 @@
+# Tests for the zsh/param/private module
+
+%prep
+
+ if ! (zmodload zsh/param/private >/dev/null 2>/dev/null); then
+ ZTST_unimplemented="can't load the zsh/param/private module for testing"
+ fi
+ zmodload zsh/param/private
+
+%test
+
+ (zmodload -u zsh/param/private && zmodload zsh/param/private)
+0:unload and reload the module without crashing
+
+ typeset scalar_test=toplevel
+ () {
+ print $scalar_test
+ private scalar_test
+ print $+scalar_test
+ unset scalar_test
+ print $+scalar_test
+ }
+ print $scalar_test
+0:basic scope hiding
+>toplevel
+>1
+>0
+>toplevel
+
+ typeset scalar_test=toplevel
+ print $scalar_test
+ () {
+ private scalar_test=function
+ print $scalar_test
+ }
+ print $scalar_test
+0:enter and exit a scope
+>toplevel
+>function
+>toplevel
+
+ print $+unset_test
+ () {
+ private unset_test
+ print $+unset_test
+ unset_test=setme
+ print $unset_test
+ }
+ print $+unset_test
+0:variable defined only in scope
+>0
+>1
+>setme
+>0
+
+ # Depends on zsh-5.0.9 typeset keyword
+ typeset -a array_test=(top level)
+ () {
+ local -Pa array_test=(in function)
+ () {
+ private array_test
+ print $+array_test
+ }
+ print $array_test
+ }
+ print $array_test
+0:nested scope with different type, correctly restored
+>1
+>in function
+>top level
+
+ typeset -a array_test=(top level)
+ () {
+ private array_test
+ array_test=(in function)
+ }
+1:type of private may not be changed by assignment
+?(anon):2: array_test: attempt to assign array value to non-array
+
+ typeset -A hash_test=(top level)
+ () {
+ setopt localoptions noglob
+ private hash_test[top]
+ }
+1:associative array fields may not be private
+?(anon):private:2: hash_test[top]: can't create local array elements
+
+ () {
+ private path
+ }
+1:tied params may not be private, part 1
+?(anon):private:1: can't change scope of existing param: path
+
+ () {
+ private PATH
+ }
+1:tied params may not be private, part 2
+?(anon):private:1: can't change scope of existing param: PATH
+
+ () {
+ private -h path
+ print X$path
+ }
+0:privates may hide tied paramters
+>X
+
+ # Deliberate type mismatch here
+ typeset -a hash_test=(top level)
+ typeset -p hash_test
+ inner () {
+ private -p hash_test
+ print ${(t)hash_test} ${(kv)hash_test}
+ }
+ outer () {
+ local -PA hash_test=(in function)
+ typeset -p hash_test
+ inner
+ }
+ outer
+ print ${(kv)hash_test}
+0:private hides value from surrounding scope in nested scope
+>typeset -a hash_test
+>hash_test=( top level )
+>typeset -A hash_test
+>hash_test=( in function )
+>typeset -a hash_test
+>hash_test=( top level )
+>array-local top level
+>top level
+F:note "typeset" rather than "private" in output from outer
+
+ () {
+ private -a array_test
+ local array_test=scalar
+ }
+1:private cannot be re-declared as local
+?(anon):local:2: array_test: inconsistent type for assignment
+
+ () {
+ local hash_test=scalar
+ private -A hash_test
+ }
+1:local cannot be re-declared as private
+?(anon):private:2: can't change scope of existing param: hash_test
+
+ inner () {
+ print $+scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ }
+ () {
+ private -x scalar_test=whaat
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ inner
+ print Y $scalar_test
+ }
+0:exported private behaves like a local, part 1
+>X whaat
+>0
+>X whaat
+>Y whaat
+
+ inner () {
+ typeset -p array_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $array_test'
+ }
+ () {
+ local -Pax array_test=(whaat)
+ print Y $array_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $array_test'
+ inner
+ }
+0:exported private behaves like a local, part 2 (arrays do not export)
+?inner:typeset:1: no such variable: array_test
+>Y whaat
+>X
+>X
+
+ inner () {
+ print $+scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ }
+ () {
+ private scalar_test=whaat
+ export scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ inner
+ () {
+ print $+scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ }
+ print Y $scalar_test
+ }
+0:exported private behaves like a local, part 3 (export does not change scope)
+>X whaat
+>0
+>X whaat
+>0
+>X whaat
+>Y whaat
+
+ typeset -A hash_test=(top level)
+ () {
+ local -PA hash_test=(in function)
+ () {
+ print X ${(kv)hash_test}
+ }
+ print Y ${(kv)hash_test}
+ }
+ print ${(kv)hash_test}
+0:privates are not visible in anonymous functions, part 1
+>X top level
+>Y in function
+>top level
+
+ typeset -A hash_test=(top level)
+ () {
+ local -PA hash_test=(in function)
+ () {
+ print X ${(kv)hash_test}
+ hash_test[in]=deeper
+ }
+ print Y ${(kv)hash_test}
+ }
+ print ${(okv)hash_test}
+0:privates are not visible in anonymous functions, part 2
+>X top level
+>Y in function
+>deeper in level top
+
+ typeset -A hash_test=(top level)
+ () {
+ local -Pa array_test=(in function)
+ local -PA hash_test=($array_test)
+ () {
+ print X ${(kv)hash_test}
+ hash_test=(even deeper)
+ array_test+=(${(kv)hash_test})
+ }
+ print Y ${(kv)hash_test} Z $array_test
+ }
+ print ${(kv)hash_test}
+0:privates are not visible in anonymous functions, part 3
+>X top level
+>Y in function Z in function
+>even deeper
+
+ typeset -A hash_test=(top level)
+ () {
+ local -PA hash_test=(in function)
+ () {
+ print X ${(kv)hash_test}
+ unset hash_test
+ }
+ print Y ${(kv)hash_test}
+ }
+ print ${(t)hash_test} ${(kv)hash_test}
+0:privates are not visible in anonymous functions, part 4
+>X top level
+>Y in function
+>
+
+ # Subshell because otherwise this silently dumps core when broken
+ ( () { private SECONDS } )
+1:special parameters cannot be made private
+?(anon):private: can't change scope of existing param: SECONDS
+
+ () { private -h SECONDS }
+0:private parameter may hide a special parameter
diff --git a/configure.ac b/configure.ac
index d7db8ba8d..c3bd713c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1079,9 +1079,15 @@ main() { return sizeof(ino_t) < 8; }
fi
AH_TEMPLATE([ZLONG_IS_LONG_LONG],
[Define to 1 if the zlong type uses long long int.])
+AH_TEMPLATE([ZLONG_IS_LONG_64],
+[Define to 1 if the zlong type uses 64-bit long int.])
if test "$zsh_cv_64_bit_type" = "long long"; then
dnl Remember this so we can get (s)printf output right.
AC_DEFINE(ZLONG_IS_LONG_LONG)
+else
+ if test "$zsh_cv_64_bit_type" = "long"; then
+ AC_DEFINE(ZLONG_IS_LONG_64)
+ fi
fi
dnl We'll blithely assume (f)printf supports the same types as sprintf.