summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog369
-rw-r--r--Completion/BSD/Command/_cu7
-rw-r--r--Completion/BSD/Command/_fw_update10
-rw-r--r--Completion/BSD/Command/_rcctl42
-rw-r--r--Completion/Debian/Command/_apt4
-rw-r--r--Completion/Debian/Command/_aptitude2
-rw-r--r--Completion/Redhat/Command/_dnf416
-rw-r--r--Completion/Unix/Command/_bibtex5
-rw-r--r--Completion/Unix/Command/_dig85
-rw-r--r--Completion/Unix/Command/_elfdump6
-rw-r--r--[-rwxr-xr-x]Completion/Unix/Command/_getent0
-rw-r--r--Completion/Unix/Command/_git23
-rw-r--r--Completion/Unix/Command/_man21
-rw-r--r--[-rwxr-xr-x]Completion/Unix/Command/_mtools0
-rw-r--r--Completion/Unix/Command/_nm6
-rw-r--r--Completion/Unix/Command/_objdump7
-rw-r--r--Completion/Unix/Command/_readelf6
-rw-r--r--Completion/Unix/Type/_absolute_command_paths29
-rw-r--r--Completion/Unix/Type/_list_files2
-rw-r--r--[-rwxr-xr-x]Completion/Unix/Type/_mime_types0
-rw-r--r--Completion/Unix/Type/_object_files11
-rw-r--r--Completion/Unix/Type/_path_commands3
-rw-r--r--[-rwxr-xr-x]Completion/X/Command/_kfmclient0
-rw-r--r--Completion/X/Command/_mplayer4
-rw-r--r--[-rwxr-xr-x]Completion/Zsh/Command/_zed0
-rw-r--r--Config/version.mk4
-rw-r--r--Doc/Zsh/builtins.yo20
-rw-r--r--Doc/Zsh/compsys.yo12
-rw-r--r--Doc/Zsh/expn.yo5
-rw-r--r--Doc/Zsh/options.yo6
-rw-r--r--Doc/Zsh/params.yo5
-rw-r--r--Doc/Zsh/zle.yo7
-rw-r--r--Functions/Chpwd/zsh_directory_name_generic4
-rw-r--r--Functions/Misc/is-at-least20
-rw-r--r--Functions/Newuser/zsh-newuser-install2
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_detect_p44
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_git4
-rw-r--r--Functions/VCS_Info/VCS_INFO_maxexports2
-rw-r--r--Functions/VCS_Info/VCS_INFO_nvcsformats1
-rw-r--r--Functions/VCS_Info/VCS_INFO_set2
-rw-r--r--Functions/VCS_Info/vcs_info2
-rw-r--r--Functions/Zle/backward-kill-word-match2
-rw-r--r--Functions/Zle/edit-command-line10
-rw-r--r--Functions/Zle/kill-word-match2
-rw-r--r--Functions/Zle/match-words-by-style6
-rw-r--r--Functions/Zle/transpose-words-match11
-rw-r--r--Functions/Zle/url-quote-magic2
-rw-r--r--NEWS7
-rw-r--r--README34
-rw-r--r--Src/Modules/clone.c2
-rw-r--r--Src/Modules/pcre.c33
-rw-r--r--Src/Modules/zpty.c26
-rw-r--r--Src/Zle/complist.c6
-rw-r--r--Src/Zle/zle.h2
-rw-r--r--Src/Zle/zle_hist.c2
-rw-r--r--Src/Zle/zle_keymap.c111
-rw-r--r--Src/Zle/zle_main.c53
-rw-r--r--Src/Zle/zle_refresh.c6
-rw-r--r--Src/Zle/zle_thingy.c7
-rw-r--r--Src/builtin.c256
-rw-r--r--Src/exec.c20
-rw-r--r--Src/glob.c17
-rw-r--r--Src/hashtable.c9
-rw-r--r--Src/hashtable.h2
-rw-r--r--Src/init.c30
-rw-r--r--Src/lex.c49
-rw-r--r--Src/options.c2
-rw-r--r--Src/params.c64
-rw-r--r--Src/parse.c34
-rw-r--r--Src/pattern.c17
-rw-r--r--Src/subst.c14
-rw-r--r--Src/text.c32
-rw-r--r--Src/utils.c429
-rw-r--r--Src/zsh.h34
-rw-r--r--Test/A02alias.ztst8
-rw-r--r--Test/A06assign.ztst15
-rw-r--r--Test/B02typeset.ztst29
-rw-r--r--Test/B03print.ztst9
-rw-r--r--Test/C01arith.ztst11
-rw-r--r--Test/C02cond.ztst14
-rw-r--r--Test/D02glob.ztst73
-rw-r--r--Test/D04parameter.ztst16
-rw-r--r--Test/D07multibyte.ztst7
-rw-r--r--Test/E01options.ztst9
-rw-r--r--Test/V07pcre.ztst11
-rw-r--r--Test/V09datetime.ztst2
-rw-r--r--Test/V10private.ztst9
-rw-r--r--Test/X03zlebindkey.ztst128
-rw-r--r--Test/comptest2
-rw-r--r--debian/changelog25
-rw-r--r--debian/control2
-rw-r--r--debian/gbp.conf2
-rw-r--r--debian/patches/fix-aptitude-completion-for-0.7.5-807906.patch18
-rw-r--r--debian/patches/fix-segfault-in-is_cond_binary_op.patch18
-rw-r--r--debian/patches/series3
-rw-r--r--debian/patches/update-apt-completion-808317.patch22
96 files changed, 2228 insertions, 694 deletions
diff --git a/ChangeLog b/ChangeLog
index 45945d254..fc371399b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,372 @@
+2016-01-20 Peter Stephenson <p.stephenson@samsung.com>
+
+ * unspoted: Config/version.mk: incremented version to 5.2-dev-1
+ because of parsing change.
+
+2016-01-20 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37666: Completion/Unix/Command/_git: Completion: git:
+ 'send-email --smtp-server=' takes absolute path to sendmail.
+
+ * 37665: Completion/Unix/Command/_git,
+ Completion/Unix/Type/_absolute_command_paths, Doc/Zsh/compsys.yo:
+ Completion: New helper _absolute_command_paths.
+
+ * 37664: Completion/Unix/Type/_path_commands, Doc/Zsh/compsys.yo:
+ docs: Document the completion function _command_names.
+
+2016-01-19 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37693: Src/glob.c: turn Dash into '-' in glob qualifiers.
+
+ * 37689: README, Src/glob.c, Src/lex.c, Src/pattern.c,
+ Src/zsh.h, Test/D02glob.ztst: also ! and ^ need to be tokenised
+ in character set.
+
+2016-01-18 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37682: Src/lex.c: when SH_GLOB is set (e.g. in "sh" emulation)
+ do not parse bare parentheses in arguments as a pattern grouping.
+
+2016-01-18 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37678: Src/glob.c, Src/lex.c, Src/pattern.c, Src/utils.c,
+ Src/zsh.h, Test/D02glob.ztst: Now possible to quote "-" in
+ a pattern range.
+
+ * 37634: Completion/Unix/Command/_man: _man: Support subsection
+ names such as '3p'.
+
+ * 37634: Completion/Unix/Command/_man: _man: Disentangle a local
+ variable that had two distinct semantics. No functional change
+
+ * 37663: Completion/Unix/Command/_bibtex: New bibtex completion
+ (very minimal).
+
+ * unposted: Doc/Zsh/zle.yo: docs: zshzle(1): Trivial
+ clarification to $CONTEXT.
+
+2016-01-15 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37646: Src/builtin.c, Test/B02typeset.ztst: typeset should
+ return non-zero status on attempt to set readonly variable.
+
+ * 37643: Src/Zle/complist.c: Reset interrupt after getkeycmd()
+ in menu selection.
+
+ * 37512: Src/params.c: overeager WARN_CREATE_GLOBAL with
+ strftime.
+
+2016-01-15 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: Src/utils.c: Extend docstring of callhookfunc().
+
+ * unposted: Functions/VCS_Info/Backends/VCS_INFO_detect_p4:
+ Fix typo in comment.
+
+ * 37612: Functions/VCS_Info/Backends/VCS_INFO_get_data_git:
+ vcs_info git: Set $git_patches_unapplied correctly for
+ 'rebase-apply' case.
+
+2016-01-14 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37590: Src/Zle/zle_hist.c, Src/Zle/zle_main.c: Invoke
+ zle-line-pre-redraw during isearch.
+
+2016-01-13 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37570: Functions/Zle/transpose-words-match: give truth to the
+ doc assertion this is a drop-in replacement for transpose-words
+
+ * 37567: Functions/Zle/match-words-by-style: use (Z:n:) to split
+ the buffer into words so line breaks are treated as whitespace
+
+2016-01-13 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37591: Src/hashtable.c, Test/A02alias.ztst: 37591: 'alias -L':
+ skip with a warning aliases with '=' in their LHS
+
+ * 37550: Completion/BSD/Command/_cu: _cu: Support Linux
+ line-device names; fail gracefully on OSes matching no known
+ line-device name pattern.
+
+2016-01-10 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37551: Src/builtin.c: Include the builtin's name in a "bad
+ option" error message.
+
+2016-01-10 Eric Cook <llua@gmx.com>
+ * 37534: Matthew Martin: Completion/BSD/Command/_cu,
+ Completion/BSD/Command/_fw_update, Completion/BSD/Command/_rcctl
+
+2016-01-08 Barton E. Schaefer <schaefer@zsh.org>
+
+ * Jun T.: 37515: Src/Modules/pcre.c, Test/V07pcre.ztst: multibyte
+ handling as per 35448.
+
+ * unposted (cf. Jun T.: 37516): Src/builtin.c: refine READ_MSTREAM
+ to avoid unsequenced evaluation
+
+2016-01-06 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37513 (cf. Jun T.: 37508): Src/builtin.c: fix typos; improve
+ error cleanup in tempfile case of ASSIGN_MSTREAM(); simplify
+ READ_MSTREAM() and correct for signed/unsigned compiler warning
+
+2016-01-04 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37504: Src/builtin.c: refactor code using/simulating memstream
+ to capture output for "print -v"
+
+ * 37503: Src/builtin.c: detect incompatible "print" options, fix
+ metafication and possible memory leak, miscellaneous cosmetics
+
+ * Jun T. (+ revise test): 37501: Src/builtin.c, Test/B03print.ztst:
+ correct byte counts when simulating memstream via temp file
+
+2016-01-03 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 37489, tweaked: Doc/Zsh/options.yo, Src/params.c,
+ Test/C01arith.ztst: with POSIX_IDENTIFIERS create math var as
+ scalar
+
+2016-01-02 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37497: Src/builtin.c: handle NUL bytes in "printf -v".
+
+ * 37493: Doc/Zsh/builtins.yo, Src/builtin.c, Src/hashtable.h,
+ Test/B02typeset.ztst: readonly + POSIX_BUILTINS == typeset -gr
+
+2016-01-01 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37483: Src/glob.c: save and possibly restore cshnullglob failure
+ state around each evaluation of an (e:...:) glob qualifier.
+
+ * 37473: Src/exec.c: check for cshnullglob in command position.
+
+2015-12-31 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37469: Src/parse.c: do NOT allow semicolons in place of line breaks
+ in conditionals
+
+ * unposted: Src/builtin.c: enable WARN_CREATE_GLOBAL for print -v
+
+ * 37468: Src/parse.c: allow line breaks in more places in [[ ... ]]
+
+ * 37467: Doc/Zsh/builtins.yo, Src/builtin.c, Test/B03print.ztst:
+ add "print -v var" / "printf -v var"
+
+2015-12-31 Oliver Kiddle <opk@zsh.org>
+
+ * 37453 (with Bart, started by Baptiste Daroussin, 37315)
+ Test/C02cond.ztst: try to improve detection of noatime filesystem
+
+ * users/21114: Completion/Unix/Command/_dig: new completion
+
+2015-12-30 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37460: Test/X03zlebindkey.ztst: make sure the default keymap is
+ emacs before using that keymap to test bindings
+
+2015-12-31 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted: NEWS: Document how to disable paste highlighting.
+
+ * 37456: Src/Zle/zle_refresh.c: Have zle_highlight=(none)
+ disable paste highlighting
+
+2015-12-30 Frank Terbeck <ft@bewatermyfriend.org>
+
+ * 37451: Functions/VCS_Info/vcs_info: vcs_info: Declare "msgs" in
+ early context
+
+2015-12-27 Axel Beckert <abe@deuxchevaux.org>
+
+ * 37438: Completion/Debian/Command/_aptitude: Also parse --help/-h
+ output of aptitude 0.7.5 and later.
+
+2015-12-26 Axel Beckert <abe@deuxchevaux.org>
+
+ * 37436: Felipe Sateler: Completion/Debian/Command/_apt:
+ Add missing apt purge and autoremove subcommands.
+
+2015-12-25 Barton E. Schaefer <schaefer@zsh.org>
+
+ * 37435 (+ fix typo): Src/exec.c: allow execution of empty files
+ as "sh" scripts
+
+ * 37434: Src/exec.c: POSIXBUILTINS "command" should prevent shell
+ exit on errors from special builtins
+
+2015-12-23 Philip Sequeira <phsequei@gmail.com>
+
+ * 37345: Functions/VCS_Info/VCS_INFO_maxexports,
+ Functions/VCS_Info/VCS_INFO_set: VCS_INFO functions break with
+ setopt no_unset
+
+2015-12-19 Barton E. Schaefer <schaefer@zsh.org>
+
+ * users/21082 (expanded): Functions/Misc/is-at-least: do a more
+ complete job of sorting version strings that are not in the form
+ of zsh version numbers; additional explanatory comment
+
+ * unposted (cf. 37387): Src/options.c: emulate turns off
+ WARN_CREATE_GLOBAL
+
+ * users/21068: Functions/Newuser/zsh-newuser-install: use emacs
+ keymap in vared by default (less surprising than vi modes)
+
+2015-12-19 Mikael Magnusson <mikachu@gmail.com>
+
+ * 36650: Doc/Zsh/zle.yo, Src/Zle/zle_main.c: Add
+ zle-line-pre-redraw hook for highlighting
+
+2015-12-19 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * unposted (after users/20873): Functions/Zle/edit-command-line:
+ Theoretical fix: don't parse print/echo escape sequences in
+ $zle_bracketed_paste.
+
+ * 37257 (in part): Test/A06assign.ztst: Add array assignment tests.
+
+2015-12-16 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37411: Test/X03zlebindkey.ztst: more bindkey tests.
+
+2015-12-15 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37405: Src/Zle/zle_keymap.c, Test/X03zlebindkey.ztst: fix
+ binding of self-insert to full or partial multibyte sequences
+ longer than a one byte prefix and add test.
+
+2015-12-14 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37401: Completion/Unix/Type/_list_files: fix pattern error
+ causing too much use of zstat.
+
+ * 37400: Functions/Chpwd/zsh_directory_name_generic: fix typo
+ that caused unwanted error message.
+
+2015-12-13 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 37397: Adrien Vergé: Completion/Redhat/Command/_dnf: update
+ with optimisations.
+
+2015-12-11 Peter Stephenson <p.stephenson@samsung.com>
+
+ * Functions/Zle/url-quote-magic: match, mbegin, mend should be
+ locally.
+
+2015-12-11 Oliver Kiddle <opk@zsh.org>
+
+ * 37383: Matthew Martin: Completion/Unix/Command/_elfdump,
+ Completion/Unix/Command/_nm, Completion/Unix/Command/_objdump,
+ Completion/Unix/Command/_readelf, Completion/Unix/Type/_object_files:
+ add completion type for object files
+
+ * 37260: Simon Hafner: Completion/X/Command/_mplayer:
+ add opus to mplayer audio completions
+
+ * users/20873: Functions/Zle/edit-command-line: disable bracketed
+ paste while running external editor from zle
+
+2015-12-10 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37378: Src/Modules/zpty.c, Test/X03zlebindkey.ztst,
+ Test/comptest: New bindkey tests; also fix Meta bug with pattern
+ match on zpty -r.
+
+2015-12-09 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37364: Src/builtin.c, Src/text.c, Test/C02cond.ztst: "test"
+ and "[" need to prefer binary operators to parentheses in
+ three-argument expressions.
+
+2015-12-08 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37348: Src/utils.c, Test/D04parameter.ztst,
+ Test/D07multibyte.ztst: tests for ${(q+)...} and extra
+ dupstring() needed for empty string case.
+
+ * 37347: Functions/VCS_Info/VCS_INFO_nvcsformats: msgs
+ shouldn't be local here, but in caller (where it already is).
+
+ * users/21071: Src/Zle/zle_keymap.c: Multibyte key sequences
+ couldn't be bound if the initial byte was the start of any
+ self-insert sequence.
+
+2015-12-07 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 37344: Doc/Zsh/expn.yo, Src/subst.c, Src/utils.c, Src/zsh.h,
+ Test/D04parameter.ztst, Test/V09datetime.ztst: restore old
+ printable quoting of characters when not used from quotedzputs()
+ and add ${(q+)...} to output the new form.
+
+ * 37331: Src/utils.c: use a single character to represent an
+ MB_INCOMPLETE string even if multiple octets.
+
+2015-12-07 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37337: Src/Zle/zle.h, Src/Zle/zle_main.c,
+ Src/Zle/zle_thingy.c: Delay freeing widget until not in use.
+
+ * 37335: Test/D04parameter.ztst, Test/V09datetime.ztst: fix
+ tests after 37314.
+
+ * 37310: Doc/Zsh/builtins.yo: effect of disabling typeset
+ reserved word.
+
+2015-12-06 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 37326: Src/utils.c: comment how counting for multibyte string
+ lengths and widths is supposed to work.
+
+ * 37314: Src/utils.c, Src/zsh.h: upgrade quotedzputs() to use
+ nicechar() where necessary. Regularise nicechar() etc. to prodduce
+ $'...' compatible output.
+
+2015-12-05 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37150: Completion/Unix/Command/_git: _git: Autocomplete .. for
+ commit ranges
+
+ * 36957: Completion/Unix/Command/_git: _git: Apply matchspecs to
+ filename completion such as 'git log f/b<TAB>' → 'foo/bar.txt's
+
+2015-12-04 Peter Stephenson <p.stephenson@samsung.com>
+
+ * 37305: Src/params.c, Test/A06assign.ztst,
+ Test/B02typeset.ztst, Test/V10private.ztst: typeset -p
+ can now output arrays on one line.
+
+ * unposted: Src/exec.c, Src/init.c: fix up init_io() calls
+ in previous change.
+
+ * 37294: Doc/Zsh/params.yo, Src/init.c: Add $ZSH_EXECUTION_STRING
+ to give argument to shell -c option.
+
+2015-12-03 Daniel Shahaf <d.s@daniel.shahaf.name>
+
+ * 37253: Src/params.c: Constify two local variables.
+
+ * unposted: Completion/Unix/Command/_getent,
+ Completion/Unix/Command/_mtools,
+ Completion/Unix/Type/_mime_types,
+ Completion/X/Command/_kfmclient, Completion/Zsh/Command/_zed:
+ Remove uneeded executability bits.
+
+ * 37296: Src/utils.c: Avoid needless calloc().
+
+ * 37295: Functions/Zle/backward-kill-word-match,
+ Functions/Zle/kill-word-match: Join kills
+
+2015-12-03 Peter Stephenson <p.stephenson@samsung.com>
+
+ * unposted: Config/version.mk: update to 5.2-dev-0.
+
+ * unposted: Config/version.mk: release zsh 5.2 (N.B. this entry
+ added ex post facto as a marker).
+
2015-11-30 Daniel Shahaf <d.s@daniel.shahaf.name>
* 37256: Completion/Debian/Command/_debchange: _debchange
diff --git a/Completion/BSD/Command/_cu b/Completion/BSD/Command/_cu
new file mode 100644
index 000000000..bdd579519
--- /dev/null
+++ b/Completion/BSD/Command/_cu
@@ -0,0 +1,7 @@
+#compdef cu
+
+_arguments -s -A '-*' \
+ '-d[do not block waiting for a carrier to be detected]' \
+ '-l[line to use]:line:(/dev/(cuaU#<->|ttyS<->)(N%c))' \
+ '-s[line speed]:line speed:(75 110 300 1200 2400 4800 9600 19200 38400 57600 115200)' \
+ '(-*)1:host:'
diff --git a/Completion/BSD/Command/_fw_update b/Completion/BSD/Command/_fw_update
new file mode 100644
index 000000000..b01749f3f
--- /dev/null
+++ b/Completion/BSD/Command/_fw_update
@@ -0,0 +1,10 @@
+#compdef fw_update
+
+_arguments -s -S -A "-*" \
+ '(*)-a[install or update firmware for all drivers]' \
+ '-d[delete drivers instead of adding them]' \
+ '-i[display information]' \
+ '-n[dry run]' \
+ '-p[use the firmware at specified path]:path:' \
+ '*-v[verbose output]' \
+ '(-a)*:driver:'
diff --git a/Completion/BSD/Command/_rcctl b/Completion/BSD/Command/_rcctl
new file mode 100644
index 000000000..0a030f486
--- /dev/null
+++ b/Completion/BSD/Command/_rcctl
@@ -0,0 +1,42 @@
+#compdef rcctl
+
+local context state line
+local -a actions subcmds variables
+
+actions=(check reload restart start stop)
+subcmds=(disable enable get getdef ls order set)
+variables=(class flags status timeout user)
+
+if [[ $service == "rcctl" ]]; then
+ _arguments -C \
+ '-d[print debug information]' \
+ '-f[forcibly start the daemon]' \
+ ':subcommand:('"$actions ${${${+words[(r)-[df]]}#1}/0/$subcmds}"\) \
+ '*:: :->subcmd' && return
+ service="$words[1]"
+fi
+
+case $service in
+ get|getdef)
+ _arguments \
+ ':service:_services' \
+ ':variable:compadd -a variables'
+ ;;
+ ls)
+ _arguments ':display a list of services and daemons matching:(all faulty off on started stopped)'
+ ;;
+ order)
+ _arguments \
+ ':service to start first:_services'
+ '*:service to start next:_services'
+ ;;
+ set)
+ _arguments \
+ ':service:_services' \
+ ':variable:compadd -a variables' \
+ '*:argument:'
+ ;;
+ ${(~j:|:)actions}|disable|enable)
+ _arguments "*:service to $words[2]:_services"
+ ;;
+esac
diff --git a/Completion/Debian/Command/_apt b/Completion/Debian/Command/_apt
index db4ceef10..0bc20c6df 100644
--- a/Completion/Debian/Command/_apt
+++ b/Completion/Debian/Command/_apt
@@ -407,10 +407,12 @@ _apt-cmd () {
/$'install\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" avail' \# \
/$'[^\0/]#/'/ /$'[^\0/]#\0'/ ':release name::_apt_releases' \) \| \
/$'remove\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" installed' \# \| \
+ /$'purge\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" installed' \# \| \
/$'upgrade\0'/ \| \
+ /$'autoremove\0'/ \| \
/$'full-upgrade\0'/ \| \
/$'edit-sources\0'/ \| \
- /"[]"/ ':argument-1::compadd "$expl_action[@]" list search show update install remove upgrade full-upgrade edit-sources'
+ /"[]"/ ':argument-1::compadd "$expl_action[@]" list search show update install remove upgrade full-upgrade edit-sources autoremove purge'
_apt-cmd () {
local expl_action expl_packages
diff --git a/Completion/Debian/Command/_aptitude b/Completion/Debian/Command/_aptitude
index 2cb211149..b2b54599f 100644
--- a/Completion/Debian/Command/_aptitude
+++ b/Completion/Debian/Command/_aptitude
@@ -80,7 +80,7 @@ _arguments -C \
case $state in
cmds)
- cmds=( ${${(M)${(f)"$(LC_ALL=C _call_program commands aptitude -h 2>/dev/null)"}:#* - *}/(#b) (*[^ ]) #- (*)/$match[1]:$match[2]:l})
+ cmds=( ${${(M)${(f)"$(LC_ALL=C _call_program commands aptitude -h 2>/dev/null)"}:# [^- ][^ ]## *}/(#b) ([^ ]##) ##(- )#([^- ]*)/$match[1]:$match[3]:l})
_describe -t commands 'aptitude command' cmds && ret=0
;;
diff --git a/Completion/Redhat/Command/_dnf b/Completion/Redhat/Command/_dnf
index 297c95ae9..35b5aa27b 100644
--- a/Completion/Redhat/Command/_dnf
+++ b/Completion/Redhat/Command/_dnf
@@ -1,278 +1,198 @@
-#compdef dnf
+#compdef dnf dnf-2 dnf-3
-# Main dispatcher
-_dnf() {
- _arguments -s \
- '(- *)'{-h,--help}'[show the help message]' \
- '(-t --tolerant)'{-t,--tolerant}'[be tolerant of errors]' \
- '(-C --cacheonly)'{-C,--cacheonly}'[run entirely from cache]' \
- '(-c --config)'{-c,--config=}'[config file location]:config file:_files' \
- '(-R --randomwait)'{-R,--randomwait=}'[maximum command wait time (in minutes)]:max wait time' \
- '(-d --debuglevel)'{-d,--debuglevel=}'[debug level (0-10)]:debug level' \
- '(-e --errorlevel)'{-e,--errorlevel=}'[error level (0-10)]:error level' \
- '(-y --assumeyes)'{-y,--assumeyes}'[answer yes for all questions]' \
- '--installroot=[set install root]:install root:_files -/' \
- '*--enablerepo=[enable or or more repositories]:repos to enable:_dnf_disabled_repos_list' \
- '*--disablerepo=[disable one or more repositories]:disable repos:_dnf_enabled_repos_list' \
- {*-x,*--exclude=}'[exclude package(s) by name or glob]:exclude packages' \
- '--version[show dnf version]' \
- '--obsoletes[enable obsoletes processing during updates]' \
- '--nogpgcheck[disable gpg signature checking]' \
- '--noplugins[disable dnf plugins]' \
- '--disablepresto[disable Presto plugin and don''''t download any deltarpms]' \
- '*::dnf command:_dnf_command'
-}
-
-(( $+functions[_dnf_command] )) || _dnf_command() {
- local -a _dnf_cmds
- _dnf_cmds=(
- "install:install the latest version of a package or group of packages"
- "erase:remove an installed package (with its dependencies)"
- "remove:remove an installed package (with its dependencies)"
- "clean:clean local dnf cache"
- "check-update:check if any updates are available"
- "info:get description of available packages"
- "list:is used to list various information about packages"
- "groupinfo:get info on package groups"
- "groupinstall:install a package group or groups"
- "groupremove:remove a package group or groups"
- "grouplist:list package groups"
- "groupupdate:update a package group or groups"
- "localinstall:install packages with local rpm files"
- "localupdate:update packages with local rpm files"
- "makecache:makes a local dnf cache"
- "provides:find out which package provides some feature or file"
- "whatprovides:find out which package provides some feature or file"
- "search:find any packages matching pattern"
- "shell:enter the 'dnf shell'"
- "update:update one or more packages"
- "upgrade:upgrade one or more packages"
- )
-
- if (( CURRENT == 1 )); then
- _describe -t commands 'dnf command' _dnf_cmds || compadd "$@"
- else
- local curcontext="$curcontext"
-
- cmd="${${_dnf_cmds[(r)$words[1]:*]%%:*}}"
- # Deal with any aliases
- case $cmd in
- remove) cmd="erase";;
- whatprovides) cmd="provides";;
- upgrade) cmd="update";;
- esac
-
- if (( $#cmd )); then
- curcontext="${curcontext%:*:*}:dnf-${cmd}:"
-
- local update_policy
- zstyle -s ":completion:${curcontext}:" cache-policy update_policy
- if [[ -z "$update_policy" ]]; then
- zstyle ":completion:${curcontext}:" cache-policy _dnf_caching_policy
- fi
-
- _call_function ret _dnf_$cmd || _message 'no more arguments'
- else
- _message "unknown dnf command: $words[1]"
- fi
- return ret
- fi
+_dnf_helper() {
+ compadd $($python_exec $helper "$@" -d 0 -q -C 2>/dev/null)
}
-# Fills the all pkg cache
-_dnf_all_pkgs() {
- if ( [[ ${+_all_pkgs} -eq 0 ]] || _cache_invalid ALL ) &&
- ! _retrieve_cache ALL;
- then
- _all_pkgs=( $(dnf -C list all | sed 's/\s.*//' | grep '\.' 2>/dev/null) )
- _store_cache ALL _all_pkgs
- fi
+_dnf_query_db() {
+ sqlite3 -batch -init /dev/null "$cache_file" "$1"
}
-# Fills the installed pkg cache
-_dnf_installed_pkgs() {
- if ( [[ ${+_installed_pkgs} -eq 0 ]] || _cache_invalid INSTALLED ) &&
- ! _retrieve_cache INSTALLED;
- then
- _installed_pkgs=( $(dnf -C list installed | sed 's/\s.*//' | grep '\.' 2>/dev/null) )
- _store_cache INSTALLED _installed_pkgs
- fi
+_dnf_disabled_repos() {
+ _dnf_helper repolist disabled ""
}
-# Fills the available pkg cache
-_dnf_available_pkgs() {
- if ( [[ ${+_available_pkgs} -eq 0 ]] || _cache_invalid AVAILABLE ) &&
- ! _retrieve_cache AVAILABLE;
- then
- _available_pkgs=( $(dnf -C list available | sed 's/\s.*//' | grep '\.' 2>/dev/null) )
- _store_cache AVAILABLE _available_pkgs
- fi
+_dnf_enabled_repos() {
+ _dnf_helper repolist enabled ""
}
-# Fills the upgrade pkg cache
-_dnf_upgrade_pkgs()
-{
- if ( [[ ${+_upgrade_pkgs} -eq 0 ]] || _cache_invalid UPGRADE ) &&
- ! _retrieve_cache UPGRADE;
- then
- _upgrade_pkgs=( $(dnf -C list upgrade | sed 's/\s.*//' | grep '\.' 2>/dev/null) )
- _store_cache UPGRADE _upgrade_pkgs
+_dnf_available_packages() {
+ if [ -r $cache_file ]; then
+ compadd $(_dnf_query_db "select pkg from available WHERE pkg LIKE \"$1%\"")
+ else
+ _dnf_helper install "$1"
fi
}
-# Gets the list of defined repos
-__dnf_repos() {
- local trepo
- local -a tarray
- tarray=( $(egrep -h '(^\[.*\]|^enabled.*=)' /etc/dnf.repos.d/*.repo /etc/dnf.conf 2>/dev/null | sed -e 's/ //g' | sed -e 's/\[//g' | sed -e 's/\].*$//g' 2>/dev/null) )
- local -i eindex=0
- local -i dindex=0
- for line in $tarray; do
- if [[ "$line" = "enabled=1" ]]; then
- enabled_dnf_repos+=($trepo)
- elif [[ "$line" = "enabled=0" ]]; then
- disabled_dnf_repos+=($trepo)
- elif [[ "$line" != "main" ]]; then
- trepo=$line
- fi
- done
-}
-
-(( $+functions[_dnf_disabled_repos_list] )) || _dnf_disabled_repos_list() {
- local -a enabled_dnf_repos disabled_dnf_repos
- __dnf_repos
- _sequence compadd "$@" - -a disabled_dnf_repos
-}
-
-(( $+functions[_dnf_enabled_repos_list] )) || _dnf_enabled_repos_list() {
- local -a enabled_dnf_repos disabled_dnf_repos
- __dnf_repos
- _sequence compadd "$@" - -a enabled_dnf_repos
-}
-
-# Completion function for erase|remove
-(( $+functions[_dnf_erase] )) || _dnf_erase() {
- _dnf_installed_pkgs
- compadd "$@" -a -- _installed_pkgs
-}
-
-# Completion function for install
-(( $+functions[_dnf_install] )) || _dnf_install() {
- if ! [[ $PREFIX == */* ]]; then
- _dnf_available_pkgs
+_dnf_installed_packages() {
+ if [ -r $cache_file ]; then
+ compadd $(_dnf_query_db "select pkg from installed WHERE pkg LIKE \"$1%\"")
+ else
+ _dnf_helper remove "$1"
fi
-
- local ret=1
- _tags files packages
- while _tags; do
- if _requested files; then
- compadd "$@" -a -- _available_pkgs
- fi
- if _requested packages; then
- _call_function - _dnf_localinstall
- fi
- (( ret )) || break
- done
- return ret
}
-# Completion function for localinstall
-(( $+functions[_dnf_localinstall] )) || _dnf_localinstall() {
+_dnf_local_packages() {
_files -/ -g '(#i)*.rpm(-.)'
}
-# Completion function for localupdate
-(( $+functions[_dnf_localupdate] )) || _dnf_localupdate() {
- _files -/ -g '(#i)*.rpm(-.)'
-}
-
-# Completion function for update/upgrade
-(( $+functions[_dnf_update] )) || _dnf_update() {
- _dnf_upgrade_pkgs
- compadd "$@" -a -- _upgrade_pkgs
-}
-
-_dnf_all() {
- _dnf_all_pkgs
- compadd "$@" -a -- _all_pkgs
-}
-
-_dnf_list_or_info() {
- local -a listlist
- listlist=(
- "all:all packages in repositories"
- "available:packages available in repositories"
- "updates:packages with updates available"
- "installed:installed packages"
- "extras:packages installed that are not available in any dnf repository"
- "obsoletes:packages installed that are obsoleted"
- "recent:packages recently added to repositories"
- )
-
- if (( CURRENT == 2 )); then
- _describe -t dnf-list-subcmds "dnf info/list sub-commands" listlist || _dnf_all
+_dnf() {
+ if [[ "$(readlink /usr/bin/dnf)" == "dnf-2" ]]; then
+ local python_exec="python2"
else
- local subcmd
- subcmd="${${listlist[(r)$words[2]:*]%%:*}}"
- # offer packages selected by the subcommand
- case $subcmd in
- all) _dnf_all;;
- installed) _dnf_erase;;
- available) _dnf_install;;
- updates) _dnf_update;;
- esac
+ local python_exec="python3"
fi
-}
-
-# Completion function for list
-(( $+functions[_dnf_list] )) || _dnf_list() {
- _dnf_list_or_info
-}
-
-# Completion function for info
-(( $+functions[_dnf_info] )) || _dnf_info() {
- _dnf_list_or_info
-}
+ local helper=$(${python_exec} -c "import dnf.cli; print('{}/completion_helper.py'.format(dnf.cli.__path__[0]))")
+ local cache_file="/var/cache/dnf/packages.db"
-# Completion function for provides|whatprovides
-(( $+functions[_dnf_provides] )) || _dnf_provides() {
- _files
+ _arguments -s \
+ '(- *)'{-h,--help}'[show the help message]' \
+ '--version[show dnf version]' \
+ '(-v --verbose)'{-v,--verbose}'[set verbose, show debug messages]' \
+ '(-q --quiet)'{-q,--quiet}'[show just the relevant content]' \
+ '--allowerasing[allow erasing of installed packages]' \
+ '(-y --assumeyes)'{-y,--assumeyes}'[answer yes for all questions]' \
+ '(-C --cacheonly)'{-C,--cacheonly}'[run entirely from cache]' \
+ '(-c --config)'{-c,--config=}'[config file location]:config file:_files' \
+ '(-R --randomwait)'{-R,--randomwait=}'[maximum command wait time (in minutes)]:max wait time' \
+ '--releasever=[configure DNF for another release]:release' \
+ '--refresh[set metadata as expired before running the command]' \
+ '--nogpgcheck[skip checking GPG signatures on package]' \
+ '--installroot=[set install root]:install root:_files -/' \
+ '*--enablerepo=[enable one or more repositories]:repos to enable:_dnf_disabled_repos' \
+ '*--disablerepo=[disable one or more repositories]:disable repos:_dnf_enabled_repos' \
+ '*::dnf command:_dnf_command'
}
-# Completion function for clean
-(( $+functions[_dnf_clean] )) || _dnf_clean() {
- local -a cleanlist
- cleanlist=(
- "all:all cache"
- "cache:all cache"
- "dbcache:DB cache"
- "headers:cache headers"
- "packages:cache packages"
- "metadata:cache meta-data"
+_dnf_command() {
+ local -a _dnf_cmds
+ _dnf_cmds=(
+ "autoremove:automatically remove no longer required packages"
+ "check-update:check for available package upgrades"
+ "clean:remove cached data"
+ "distro-sync:synchronize installed packages to the latest available versions"
+ "downgrade:downgrade a package"
+ "erase:deprecated alias for remove"
+ "group:display, or use, the groups information"
+ "help:display a helpful usage message"
+ "history:display, or use, the transaction history"
+ "info:display details about a package or group of packages"
+ "install:install a package or packages on your system"
+ "list:list a package or groups of packages"
+ "makecache:generate the metadata cache"
+ "mark:mark or unmark installed packages as installed by user"
+ "provides:find what package provides the given value"
+ "reinstall:reinstall a package"
+ "remove:remove a package or packages from your system"
+ "repolist:display the configured software repositories"
+ "repository-packages:run commands on top of all packages in given repository"
+ "search:search package details for the given string"
+ "update:deprecated alias for upgrade"
+ "updateinfo:display advisories about packages"
+ "upgrade:upgrade a package or packages on your system"
+ "upgrade-to:upgrade a package on your system to the specified version"
)
- if (( CURRENT == 2 )); then
- _describe -t dnf-clean-subcmds "dnf clean sub-commands" cleanlist
- fi
-}
-
-_dnf_caching_policy() {
- local _dnfrepomds
- local -a oldp
-
- # rebuild if cache is more than a week old
- oldp=( "$1"(mw+1) )
- (( $#oldp )) && return 0
-
- _dnfrepomds=( /var/cache/dnf/**/repomd.xml )
+ if (( CURRENT == 1 )); then
+ _describe -t commands 'dnf command' _dnf_cmds || compadd "$@"
+ else
+ local command="${${_dnf_cmds[(r)$words[1]:*]%%:*}}"
+ # Deal with any aliases
+ case $command in
+ erase) command="remove";;
+ whatprovides) command="provides";;
+ update) command="upgrade";;
+ esac
- if (( $#_dnfrepomds )); then
- for repo in $_dnfrepomds; do
- [[ "$repo" -nt "$1" ]] && return 0
- done
+ _is_path() {
+ [[ "$1" == *\/* ]] || [[ "$1" == \~* ]]
+ }
+
+ local cur=$words[CURRENT]
+ local prev=""
+ [[ $CURRENT > 2 ]] && prev=$words[$((CURRENT - 1))]
+
+ case $command in
+ install|upgrade|reinstall|info|check-update|distro-sync)
+ if ! _is_path "$cur"; then
+ _dnf_available_packages "$cur"
+ else
+ _dnf_local_packages
+ fi
+ ;;
+ remove|downgrade)
+ if ! _is_path "$cur"; then
+ _dnf_installed_packages "$cur"
+ elif [[ "$command" == downgrade ]]; then
+ _dnf_local_packages
+ fi
+ ;;
+ list|clean)
+ _dnf_helper $command "$prev" "$cur"
+ ;;
+ group)
+ local -a _dnf_group_cmds
+ _dnf_group_cmds=(
+ "summary:display groups overview"
+ "info:display package lists of a group"
+ "install:install packages from a group"
+ "list:list all matching groups"
+ "remove:mark the group removed"
+ "upgrade:upgrades the group and its packages"
+ "mark:mark a group for installation or removal"
+ )
+ if (( CURRENT == 2 )); then
+ _describe -t commands 'dnf group command' _dnf_group_cmds
+ fi
+ ;;
+ help)
+ if (( CURRENT == 2 )); then
+ _dnf_helper '_cmds' ''
+ fi
+ ;;
+ history)
+ local -a _dnf_history_cmds
+ _dnf_history_cmds=(
+ "list:list transactions"
+ "info:describe the given transactions"
+ "redo:repeat the specified transaction"
+ "rollback:undo all since the given transaction"
+ "undo:undo transactions"
+ "userinstalled:list names of all packages installed by a user"
+ )
+ if (( CURRENT == 2 )); then
+ _describe -t commands 'dnf history command' _dnf_history_cmds
+ else
+ _dnf_helper $command "$prev" "$cur"
+ fi
+ ;;
+ makecache)
+ if (( CURRENT == 2 )); then
+ _values 'make cache' 'timer'
+ fi
+ ;;
+ mark)
+ if (( CURRENT == 2 )); then
+ _values 'mark' 'install' 'remove'
+ else
+ _dnf_installed_packages "$cur"
+ fi
+ ;;
+ provides)
+ _files
+ ;;
+ repolist)
+ if (( CURRENT == 2 )); then
+ _values 'repolist' 'enabled' 'disabled' 'all'
+ fi
+ ;;
+ search)
+ if (( CURRENT == 2 )); then
+ _values 'search' 'all'
+ fi
+ ;;
+ esac
fi
-
- return 1
}
_dnf "$@"
diff --git a/Completion/Unix/Command/_bibtex b/Completion/Unix/Command/_bibtex
new file mode 100644
index 000000000..8db38a244
--- /dev/null
+++ b/Completion/Unix/Command/_bibtex
@@ -0,0 +1,5 @@
+#compdef bibtex
+
+# bibtex only works when the *.aux file exists, but complete the *.tex file in
+# case it hasn't been compiled yet.
+_files -g '*.(aux|tex)(:r)'
diff --git a/Completion/Unix/Command/_dig b/Completion/Unix/Command/_dig
new file mode 100644
index 000000000..2b851c91f
--- /dev/null
+++ b/Completion/Unix/Command/_dig
@@ -0,0 +1,85 @@
+#compdef dig
+
+_dns_types() {
+ local expl
+ _description dns-types expl 'DNS type'
+ compadd "$@" "$expl[@]" -M 'm:{a-z}={A-Z}' \
+ ANY A AAAA AFSDB APL AXFR CAA CDNSKEY CDS CERT CNAME DHCID DLV DNAME \
+ DNSKEY DS HIP HINFO IPSECKEY IXFR KEY KX LOC MX NAPTR NS NSEC NSEC3 \
+ NSEC3PARAM OPT PTR RRSIG RP SIG SOA SPF SRV SSHFP TA TKEY TLSA TSIG TXT
+}
+
+local curcontext="$curcontext" state line expl
+local -a alts args
+[[ -prefix + ]] && args=(
+ '*+'{no,}'tcp[use TCP instead of UDP for queries]'
+ '*+'{no,}'ignore[ignore truncation in UDP responses]'
+ '*+domain=[set search list to single domain]:domain:_hosts'
+ '*+'{no,}'search[use search list defined in resolv.conf]'
+ '*+'{no,}'showsearch[show intermediate results in domain search]'
+ '*+'{no,}'aaonly[set aa flag in the query]'
+ '*+'{no,}'adflag[set the AD (authentic data) bit in the query]'
+ '*+'{no,}'cdflag[set the CD (checking disabled) bit in the query]'
+ '*+'{no,}'cl[display the CLASS whening printing the record]'
+ '*+'{no,}'ttlid[display the TTL whening printing the record]'
+ '*+'{no,}'recurse[set the RD (recursion desired) bit in the query]'
+ '*+'{no,}'nssearch[search all authoritative nameservers]'
+ '*+'{no,}'trace[trace delegation down from root]'
+ '*+'{no,}'cmd[print initial comment in output]'
+ '*+'{no,}'short[print terse output]'
+ '*+'{no,}'identify[print IP and port of responder]'
+ '*+'{no,}'comments[print comment lines in output]'
+ '*+'{no,}'stats[print statistics]'
+ '*+'{no,}'qr[print query as it was sent]'
+ '*+'{no,}'question[print question section of a query]'
+ '*+'{no,}'answer[print answer section of a reply]'
+ '*+'{no,}'authority[print authority section of a reply]'
+ '*+'{no,}'additional[print additional section of a reply]'
+ '*+'{no,}'all[set all print/display flags]'
+ '*+time=[set query timeout]:timeout (seconds)'
+ '*+tries=[specify number of UDP query attempts]:tries'
+ '*+retry=[specify number of UDP query retries]:retries'
+ '*+ndots=[specify number of dots to be considered absolute]:dots'
+ '*+bufsize=[specify UDP buffer size]:size (bytes)'
+ '*+edns=[specify EDNS version for query]:version (0-255)'
+ '*+noedns[clean EDNS version]'
+ '*+'{no,}'multiline[verbose multi-line output]'
+ '*+'{no,}'onesoa[AXFR prints only one soa record]'
+ '*+'{no,}"fail[don't try next server on SERVFAIL]"
+ '*+'{no,}'besteffort[try to parse even malformed messages]'
+ '*+'{no,}'dnssec[request DNSSEC records]'
+ '*+'{no,}'sigchase[chase DNSSEC signature chains]'
+ '*+trusted-key=[specify file conrtaing trusted kets]:file:_files'
+ '*+'{no,}'topdown[do DNSSEC validation in top down mode]'
+ '*+'{no,}'nsid[include EDNS name server ID request in query]'
+)
+_arguments -s -C $args \
+ '(- *)-h[display help information]' \
+ '(- *)-v[display version information]' \
+ '*-c+[specify class]:class:compadd -M "m:{a-z}={A-Z}" - IN CS CH HS' \
+ '*-b+[specify source IP]:IP' \
+ '*-f+[batch mode, read arguments from file]:file:_files' \
+ '*-m[enable memory usage debugging]' \
+ '*-p+[specify port number]:port:_ports' \
+ '*-4[use IPv4 only]' \
+ '*-6[use IPv6 only]' \
+ '*-t+[specify type]:type:_dns_types' \
+ '*-q+[specify host name to query]:host:_hosts' \
+ '*-x+[reverse lookup]:IP address' \
+ '*-k+[specify TSIG key file]:file:_files' \
+ '*-y+[specify TSIG key]:hmac\:name\:key' \
+ '*: :->args' && ret=0
+
+if [[ -n $state ]]; then
+ if compset -P @; then
+ _wanted hosts expl 'DNS server' _hosts && ret=0;
+ else
+ case $#line in
+ <3->) alts+=( 'classes:query class:compadd -M "m:{a-z}={A-Z}" - IN CS CH HS' ) ;&
+ 2) alts+=( 'types:query type:_dns_types' ) ;;
+ esac
+ _alternative 'hosts:host:_hosts' $alts && ret=0
+ fi
+fi
+
+return ret
diff --git a/Completion/Unix/Command/_elfdump b/Completion/Unix/Command/_elfdump
index ee92402d2..065f4b97f 100644
--- a/Completion/Unix/Command/_elfdump
+++ b/Completion/Unix/Command/_elfdump
@@ -2,10 +2,6 @@
local -a args
-_elf_file() {
- [[ -x $REPLY || $REPLY = (core*|*.([ao]|so|elf)) ]]
-}
-
args=(
'-c[dump section header information]'
'-d[dump .dynamic section]'
@@ -38,7 +34,7 @@ case $OSTYPE in
'-l[show long section names without truncation]'
'-O[specify osabi to apply]:osabi'
'-P[use alternative section header]'
- "*:elf file:_files -g '*(-.e:_elf_file:)'"
+ "*:elf file:_object_files"
)
;;
freebsd*) args+=( '-a[dump all information]' ) ;;
diff --git a/Completion/Unix/Command/_getent b/Completion/Unix/Command/_getent
index b9aff6642..b9aff6642 100755..100644
--- a/Completion/Unix/Command/_getent
+++ b/Completion/Unix/Command/_getent
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 6e8e9c665..5f137d009 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -1941,7 +1941,7 @@ _git-config () {
'branch.*.pushremote:what remote git push should push to::__git_remotes'
'branch.*.rebase:rebase on top of fetched branch::->bool:false'
'browser.*.cmd:browser command to use:browser:_cmdstring'
- 'browser.*.path:path to use for the browser:absolute browser path:_files -g "*(*)"'
+ 'browser.*.path:path to use for the browser:absolute browser path:_absolute_command_paths'
clean.requireForce:'require --force for git clean to actually do something::->bool:true'
color.branch:'color output of git branch::->color-bool:false'
color.branch.current:'color of the current branch::->color'
@@ -2013,7 +2013,7 @@ _git-config () {
diff.suppressBlankEmpty:'inhibit printing space before empty output lines::->bool:false'
diff.tool:'diff tool to use::__git_difftools'
'difftool.*.cmd:command to invoke for the diff tool::_cmdstring'
- 'difftool.*.path:path to use for the diff tool:absolute diff tool path:_files -g "*(*)"'
+ 'difftool.*.path:path to use for the diff tool:absolute diff tool path:_absolute_command_paths'
difftool.prompt:'prompt before each invocation of the diff tool::->bool:true'
diff.wordRegex:'regex used to determine what a word is when performing word-by-word diff:regular expression:->string'
diff.guitool:'diff tool with gui to use::__git_difftools'
@@ -2180,7 +2180,7 @@ _git-config () {
mailmap.file:'augmenting mailmap file:mailmap file:_files'
man.viewer:'man viewer to use for help in man format::__git_man_viewers'
'man.*.cmd:the command to invoke the specified man viewer:man command:_cmdstring'
- 'man.*.path:path to use for the man viewer:absolute man tool path:_files -g "*(*)"'
+ 'man.*.path:path to use for the man viewer:absolute man tool path:_absolute_command_paths'
merge.branchdesc:'populate the log message with the branch description text as well::->bool:false'
merge.conflictstyle:'style used for conflicted hunks::->merge.conflictstyle:merge'
merge.defaultToUpstream:'merge the upstream branches configured for the current branch by default::->bool:true'
@@ -2194,7 +2194,7 @@ _git-config () {
'merge.*.name:human-readable name for custom low-level merge driver:name:->string'
'merge.*.driver:command that implements a custom low-level merge driver:merge command:_cmdstring'
'merge.*.recursive:low-level merge driver to use when performing internal merge between common ancestors::__git_builtin_merge_drivers'
- 'mergetool.*.path:path to use for the merge tool:absolute merge tool path:_files -g "*(*)"'
+ 'mergetool.*.path:path to use for the merge tool:absolute merge tool path:_absolute_command_paths'
'mergetool.*.cmd:command to invoke for the merge tool:merge command:_cmdstring'
'mergetool.*.trustExitCode:trust the exit code of the merge tool::->bool:false'
mergetool.keepBackup:'keep the original file with conflict markers::->bool:true'
@@ -3710,7 +3710,7 @@ _git-send-email () {
'--smtp-encryption=[specify encryption method to use]: :__git_sendemail_smtpencryption_values' \
'--smtp-domain=[specify FQDN used in HELO/EHLO]: :_domains' \
'--smtp-pass=[specify password to use for SMTP-AUTH]::password' \
- '--smtp-server=[specify SMTP server to connect to]:smtp server:_hosts' \
+ '--smtp-server=[specify SMTP server to connect to, or sendmail command]: : __git_sendmail_smtpserver_values' \
'--smtp-server-port=[specify port to connect to SMTP server on]:smtp port:_ports' \
'--smtp-server-option=[specify the outgoing SMTP server option to use]:SMPT server option' \
'--smtp-ssl-cert-path=[path to ca-certificates (directory or file)]:ca certificates path:_files' \
@@ -5623,8 +5623,8 @@ __git_commits () {
(( $+functions[__git_heads] )) ||
__git_heads () {
- __git_heads_local
- __git_heads_remote
+ __git_heads_local "$@"
+ __git_heads_remote "$@"
}
(( $+functions[__git_heads_local] )) ||
@@ -5815,7 +5815,7 @@ __git_commit_ranges () {
if [[ ${PREFIX} = (#b)((\\|)\^)* ]]; then
compset -p ${#match[1]}
else
- suf=( -S .. -r '.@~ ^:\t\n\-' )
+ suf=( -S .. -r '@~ \^:\t\n\-' )
fi
fi
expl=( $* $suf )
@@ -6119,7 +6119,7 @@ __git_tree_files () {
shift
(( at_least_one_tree_added = 0 ))
for tree in $*; do
- tree_files+=(${(ps:\0:)"$(_call_program tree-files git ls-tree $extra_args --name-only -z $tree $Path 2>/dev/null)"})
+ tree_files+=(${(ps:\0:)"$(_call_program tree-files git ls-tree -r $extra_args --name-only -z $tree 2>/dev/null)"})
__git_command_successful $pipestatus && (( at_least_one_tree_added = 1 ))
done
@@ -6859,6 +6859,11 @@ __git_sendemail_suppresscc_values () {
all:'avoid all auto Cc values'
}
+(( $+functions[__git_sendmail_smtpserver_values] )) ||
+__git_sendmail_smtpserver_values() {
+ _alternative "smtp hosts:host:_hosts" "sendmail command: :_absolute_command_paths"
+}
+
(( $+functions[__git_colors] )) ||
__git_colors () {
declare -a expl
diff --git a/Completion/Unix/Command/_man b/Completion/Unix/Command/_man
index 81ac40bc2..0534db753 100644
--- a/Completion/Unix/Command/_man
+++ b/Completion/Unix/Command/_man
@@ -37,7 +37,10 @@ _man() {
mrd=(${^_manpath/\%L/${LANG:-En_US.ASCII}}/mandb(N))
- local sect
+ # $sect is from the command line, the "3p" in "man 3p memcpy"
+ # $sect_dirname is from the filesystem, the "3" in "/usr/share/man/man3"
+ # These are used by _man_pages
+ local sect sect_dirname
if [[ $OSTYPE = solaris* ]]; then
sect=${${words[(R)-s*]#-s}:-$words[$words[(i)-s]+1]}
elif [[ -n ${sect:=$words[$words[(i)-S]+1]} || -n ${sect:=$MANSECT} ]]; then
@@ -49,7 +52,7 @@ _man() {
fi
if [[ $sect = (<->*|1M|l|n) || $sect = \(*\|*\) ]]; then
- dirs=( $^_manpath/(sman|man|cat)${~sect}/ )
+ dirs=( $^_manpath/(sman|man|cat)${~sect%%[^0-9]#}/ )
awk="\$2 == \"$sect\" {print \$1}"
else
dirs=( $^_manpath/(sman|man|cat)*/ )
@@ -69,8 +72,8 @@ _man() {
_tags manuals.${^sects}
while _tags; do
- for sect in $sects; do
- _requested manuals.$sect expl "manual page, section $sect" _man_pages &&
+ for sect_dirname in $sects; do
+ _requested manuals.$sect_dirname expl "manual page, section $sect_dirname" _man_pages &&
ret=0
done
(( ret )) || return 0
@@ -78,7 +81,7 @@ _man() {
return 1
else
- sect=
+ sect_dirname=
_wanted manuals expl 'manual page' _man_pages
fi
}
@@ -107,8 +110,8 @@ _man_pages() {
matcher=
fi
- pages=( ${(M)dirs:#*$sect/} )
- compfiles -p pages '' '' "$matcher" '' dummy '*'
+ pages=( ${(M)dirs:#*$sect_dirname/} )
+ compfiles -p pages '' '' "$matcher" '' dummy "*${(b)sect}*"
pages=( ${^~pages}(N:t) )
(($#mrd)) && pages[$#pages+1]=($(awk $awk $mrd))
@@ -119,11 +122,11 @@ _man_pages() {
[[ $OSTYPE = solaris* ]] && sopt='-s '
if ((CURRENT > 2)) ||
- ! zstyle -t ":completion:${curcontext}:manuals.$sect" insert-sections
+ ! zstyle -t ":completion:${curcontext}:manuals.$sect_dirname" insert-sections
then
compadd "$@" - ${pages%$~suf}
else
- compadd "$@" -P "$sopt$sect " - ${pages%$~suf}
+ compadd "$@" -P "$sopt$sect_dirname " - ${pages%$~suf}
fi
}
diff --git a/Completion/Unix/Command/_mtools b/Completion/Unix/Command/_mtools
index 63851b86f..63851b86f 100755..100644
--- a/Completion/Unix/Command/_mtools
+++ b/Completion/Unix/Command/_mtools
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index d171ef5a3..73d7508b4 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -2,11 +2,7 @@
local args files variant
-_nm_object_file() {
- [[ -x $REPLY || $REPLY = *.([ao]|so|elf) ]]
-}
-
-files="*:object file:_files -g '*(-.e,_nm_object_file,)'"
+files="*:object file:_object_files"
args=(
'(-A -o --print-file-name)'{-A,-o,--print-file-name}'[print name of input file on each line]'
'(--demangle)-C[decode symbol names]'
diff --git a/Completion/Unix/Command/_objdump b/Completion/Unix/Command/_objdump
index 607719a19..cc213d911 100644
--- a/Completion/Unix/Command/_objdump
+++ b/Completion/Unix/Command/_objdump
@@ -1,8 +1,3 @@
#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,)"'
+_arguments -- '*:object file:_object_files'
diff --git a/Completion/Unix/Command/_readelf b/Completion/Unix/Command/_readelf
index 9312ea864..a474a8dc4 100644
--- a/Completion/Unix/Command/_readelf
+++ b/Completion/Unix/Command/_readelf
@@ -2,10 +2,6 @@
local variant args sections
-_elf_file() {
- [[ -x $REPLY || $REPLY = (core*|*.([ao]|so|elf)) ]]
-}
-
sections=( .bss .data .dynamic .dynsym .got .interp .shstrtab .symtab .text )
_pick_variant -r variant elftoolchain=elftoolchain elfutils=elfutils binutils --version
@@ -29,7 +25,7 @@ args=(
'(-W --wide)'{-W,--wide}'[allow output width to exceed 80 characters]'
'(- *)'{-H,--help}'[display help information]'
'(- *)'{-v,--version}'[display version information]'
- "*:elf file:_files -g '*(-.e:_elf_file:)'"
+ "*:elf file:_object_files"
)
case $variant in
diff --git a/Completion/Unix/Type/_absolute_command_paths b/Completion/Unix/Type/_absolute_command_paths
new file mode 100644
index 000000000..e9ab17023
--- /dev/null
+++ b/Completion/Unix/Type/_absolute_command_paths
@@ -0,0 +1,29 @@
+#autoload
+
+# This function completes 'ls' to '/bin/ls'
+_hashed_absolute_command_paths() {
+ local -aU set_of_dirs_of_hashed_commands=( ${^commands%/*}/ )
+ local i
+ integer ret=1
+ for i in $set_of_dirs_of_hashed_commands
+ do
+ compadd -M "l:|=$i" "$expl[@]" -a 'commands[(R)${~i}[^/]#]'
+ ret=0
+ done
+ return ret
+}
+
+# This function completes absolute pathnames of executables, e.g., /etc/rc.local
+_typed-in_absolute_command_paths() {
+ # TODO: the description "full path to an executable" and tag in the caller are ignored by _path_files
+ _path_files -/ -g '*(-*)' -P / -W /
+}
+
+_absolute_command_paths() {
+ _alternative \
+ 'commands:hashed command by absolute path:_hashed_absolute_command_paths' \
+ 'commands:full path to an executable:_typed-in_absolute_command_paths'
+}
+
+
+_absolute_command_paths "$@"
diff --git a/Completion/Unix/Type/_list_files b/Completion/Unix/Type/_list_files
index e04392d1d..6c52bc1f4 100644
--- a/Completion/Unix/Type/_list_files
+++ b/Completion/Unix/Type/_list_files
@@ -36,7 +36,7 @@ for elt in $stylevals; do
break
;;
- (*($what|all|true|1|yes)[^=]#)
+ ([^=]#($what|all|true|1|yes)[^=]#)
# always use long format
(( ok = 1 ))
break
diff --git a/Completion/Unix/Type/_mime_types b/Completion/Unix/Type/_mime_types
index 18a332e09..18a332e09 100755..100644
--- a/Completion/Unix/Type/_mime_types
+++ b/Completion/Unix/Type/_mime_types
diff --git a/Completion/Unix/Type/_object_files b/Completion/Unix/Type/_object_files
new file mode 100644
index 000000000..31a13aefc
--- /dev/null
+++ b/Completion/Unix/Type/_object_files
@@ -0,0 +1,11 @@
+#autoload
+
+local expl
+
+_description files expl 'object file'
+
+__object_file() {
+ [[ -x $REPLY || $REPLY = *.([ao]|so|elf)(.<->)## || $REPLY = (core*|*.core) ]]
+}
+
+_files -g '*(-.e,__object_file,)'
diff --git a/Completion/Unix/Type/_path_commands b/Completion/Unix/Type/_path_commands
index 423563c0d..66795ae0f 100644
--- a/Completion/Unix/Type/_path_commands
+++ b/Completion/Unix/Type/_path_commands
@@ -82,6 +82,9 @@ if [[ -n $need_desc ]]; then
else
_wanted commands expl 'external command' compadd "$@" -k commands && ret=0
fi
+# TODO: this is called from '_command_names -e' which is typically used in
+# contexts (such as _env) that don't accept directory names. Should this
+# 'if' block move up to the "_command_names -" branch of _command_names?
if [[ -o path_dirs ]]; then
local -a path_dirs
path_dirs=(${^path}/*(/N:t))
diff --git a/Completion/X/Command/_kfmclient b/Completion/X/Command/_kfmclient
index 87080cf90..87080cf90 100755..100644
--- a/Completion/X/Command/_kfmclient
+++ b/Completion/X/Command/_kfmclient
diff --git a/Completion/X/Command/_mplayer b/Completion/X/Command/_mplayer
index f2f4c3d45..a913960fe 100644
--- a/Completion/X/Command/_mplayer
+++ b/Completion/X/Command/_mplayer
@@ -14,7 +14,7 @@ _x_arguments -C -s \
'-aofile:file:_files' \
'(-nosound)*-aop[specify audio output filter]:audio output filter:->audio-plugins' \
'-aspect:ratio' \
- '-audiofile:audio file:_files -g "(#i)*.(wav|mp3|ogg)(-.)"' \
+ '-audiofile:audio file:_files -g "(#i)*.(wav|mp3|ogg|opus)(-.)"' \
-autoq:quality -autosync:factor \
-bandwidth:bandwidth\ value -benchmark -bpp:depth \
'(-nocache)-cache:cache size (kb)' \
@@ -115,7 +115,7 @@ case "$state" in
_tags files urls
while _tags; do
_requested files expl 'media file' _files -g \
- "*.(#i)(asf|asx|avi|flac|flv|m1v|m2p|m2v|m4a|m4v|mjpg|mka|mkv|mov|mp3|mp4|mpe|mpeg|mpg|ogg|ogm|ogv|qt|rm|ts|vob|wav|webm|wma|wmv)(-.)" && ret=0
+ "*.(#i)(asf|asx|avi|flac|flv|m1v|m2p|m2v|m4a|m4v|mjpg|mka|mkv|mov|mp3|mp4|mpe|mpeg|mpg|ogg|ogm|ogv|opus|qt|rm|ts|vob|wav|webm|wma|wmv)(-.)" && ret=0
if _requested urls; then
while _next_label urls expl URL; do
_urls "$expl[@]" && ret=0
diff --git a/Completion/Zsh/Command/_zed b/Completion/Zsh/Command/_zed
index 184234b02..184234b02 100755..100644
--- a/Completion/Zsh/Command/_zed
+++ b/Completion/Zsh/Command/_zed
diff --git a/Config/version.mk b/Config/version.mk
index 64c7b6b39..5577f4a0b 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.2
-VERSION_DATE='December 2, 2015'
+VERSION=5.2-dev-1
+VERSION_DATE='January 20, 2015'
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 49806e4d8..fb630a713 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1124,7 +1124,7 @@ tt(popd) that do not change the environment seen by an interactive user.
)
findex(print)
xitem(tt(print )[ tt(-abcDilmnNoOpPrsSz) ] [ tt(-u) var(n) ] [ tt(-f) var(format) ] [ tt(-C) var(cols) ])
-item(SPACES()[ tt(-xX) var(tab-stop) ] [ tt(-R) [ tt(-en) ]] [ var(arg) ... ])(
+item(SPACES()[ tt(-v) var(name) ] [ tt(-xX) var(tabstop) ] [ tt(-R) [ tt(-en) ]] [ var(arg) ... ])(
With the `tt(-f)' option the arguments are printed as described by tt(printf).
With no flags or with the flag `tt(-)', the arguments are printed on
the standard output as described by tt(echo), with the following differences:
@@ -1219,6 +1219,9 @@ tt(HIST_LEX_WORDS) option active.
item(tt(-u) var(n))(
Print the arguments to file descriptor var(n).
)
+item(tt(-v) var(name))(
+Store the printed arguments as the value of the parameter var(name).
+)
item(tt(-x) var(tab-stop))(
Expand leading tabs on each line of output in the printed string
assuming a tab stop every var(tab-stop) characters. This is appropriate
@@ -1250,7 +1253,7 @@ If any of `tt(-m)', `tt(-o)' or `tt(-O)' are used in combination with
case of `tt(-m)') then nothing is printed.
)
findex(printf)
-item(tt(printf) var(format) [ var(arg) ... ])(
+item(tt(printf) [ -v var(name) ] var(format) [ var(arg) ... ])(
Print the arguments according to the format specification. Formatting
rules are the same as used in C. The same escape sequences as for tt(echo)
are recognised in the format. All C conversion specifications ending in
@@ -1279,6 +1282,9 @@ until all arguments have been consumed. With the tt(print) builtin, this
can be suppressed by using the tt(-r) option. If more arguments are
required by the format than have been specified, the behaviour is as if
zero or an empty string had been specified as the argument.
+
+The tt(-v) option causes the output to be stored as the value of the
+parameter var(name), instead of printed.
)
findex(pushd)
pindex(PUSHD_TO_HOME, use of)
@@ -1459,7 +1465,10 @@ cancels both tt(-p) and tt(-u).
The tt(-c) or tt(-l) flags cancel any and all of tt(-kpquz).
)
cindex(parameters, marking readonly)
-alias(readonly)(typeset -r)
+item(tt(readonly))(
+Same as tt(typeset -r). With the tt(POSIX_BUILTINS) option set, same
+as tt(typeset -gr).
+)
alias(rehash)(hash -r)
findex(return)
cindex(functions, returning from)
@@ -1812,7 +1821,10 @@ this means.
Note that each interface to any of the commands my be disabled
separately. For example, `tt(disable -r typeset)' disables the reserved
word interface to tt(typeset), exposing the builtin interface, while
-`tt(disable typeset)' disables the builtin.
+`tt(disable typeset)' disables the builtin. Note that disabling the
+reserved word interface for tt(typeset) may cause problems with the
+output of `tt(typeset -p)', which assumes the reserved word interface is
+available in order to restore array and associative array values.
If the shell option tt(TYPESET_SILENT) is not set, for each remaining
var(name) that refers to a parameter that is already set, the name and
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index d6b180301..2aa0740b8 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -3461,6 +3461,12 @@ completion has been tried. A function will only be called once unless
it explicitly reinserts itself into the array.
startitem()
+findex(_absolute_command_paths)
+item(tt(_absolute_command_paths))(
+This function completes external commands as absolute paths (unlike
+tt(_command_names -e) which completes their basenames). It takes no
+arguments.
+)
findex(_all_labels)
item(tt(_all_labels) [ tt(-x) ] [ tt(-12VJ) ] var(tag) var(name) var(descr) [ var(command) var(arg) ... ])(
This is a convenient interface to the tt(_next_label) function below,
@@ -4203,6 +4209,12 @@ All arguments after the required field name are passed to
tt(compadd) when generating matches from the style value, or to
the functions for the fields if they are called.
)
+findex(_command_names)
+item(tt(_command_names) [ tt(-e) | tt(-) ])(
+This function completes words that are valid at command position: names of
+aliases, builtins, hashed commands, functions, and so on. With the tt(-e)
+flag, only hashed commands are completed. The tt(-) flag is ignored.
+)
findex(_describe)
redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ @ @ ))ifnztexi( )))
xitem(tt(_describe )[tt(-12JVx)] [ tt(-oO) | tt(-t) var(tag) ] var(descr) var(name1) [ var(name2) ] [ var(opt) ... ])
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 564c70dd1..c6e7b6f16 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1067,6 +1067,11 @@ If a tt(q-) is given (only a single tt(q) may appear), a minimal
form of single quoting is used that only quotes the string if needed to
protect special characters. Typically this form gives the most readable
output.
+
+If a tt(q+) is given, an extended form of minmal quoting is used that
+causes unprintable characters to be rendered using tt($')var(...)tt(').
+This quoting is similar to that used by the output of values by the
+tt(typeset) family of commands.
)
item(tt(Q))(
Remove one level of quotes from the resulting words.
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index f37753991..2fce10780 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2098,6 +2098,12 @@ When it is unset, zsh allows expressions of the form tt($#)var(name)
to refer to the length of tt($)var(name), even for special variables,
for example in expressions such as tt($#-) and tt($#*).
+Another difference is that with the option set assignment to an
+unset variable in arithmetic context causes the variable to be created
+as a scalar rather than a numeric type. So after `tt(unset t; (( t = 3
+)))'. without tt(POSIX_IDENTIFIERS) set tt(t) has integer type, while with
+it set it has scalar type.
+
When the option is unset and multibyte character support is enabled (i.e. it
is compiled in and the option tt(MULTIBYTE) is set), then additionally any
alphanumeric characters in the local character set may be used in
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index 21bb87442..672209267 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -933,6 +933,11 @@ tt(zsh/zutil) module.
)
enditem()
)
+vindex(ZSH_EXECUTION_STRING)
+item(tt(ZSH_EXECUTION_STRING))(
+If the shell was started with the option tt(-c), this contains
+the argument passed to the option. Otherwise it is not set.
+)
vindex(ZSH_NAME)
item(tt(ZSH_NAME))(
Expands to the basename of the command used to invoke this instance
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 7047b43d9..414c8dd65 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -802,7 +802,7 @@ item(tt(cont))(
A continuation to a command line (at prompt tt(PS2)).
)
item(tt(select))(
-In a tt(select) loop.
+In a tt(select) loop (at prompt tt(PS3)).
)
item(tt(vared))(
Editing a variable in tt(vared).
@@ -1087,6 +1087,11 @@ widget:
example(zle-isearch-exit+LPAR()RPAR() { zle -M ""; }
zle -N zle-isearch-exit)
)
+tindex(zle-line-pre-redraw)
+item(tt(zle-line-pre-redraw))(
+Executed whenever the input line is about to be redrawn, providing an
+opportunity to update the region_highlight array.
+)
tindex(zle-line-init)
item(tt(zle-line-init))(
Executed every time the line editor is started to read a new line
diff --git a/Functions/Chpwd/zsh_directory_name_generic b/Functions/Chpwd/zsh_directory_name_generic
index 9430c95e4..aa4bf9b84 100644
--- a/Functions/Chpwd/zsh_directory_name_generic
+++ b/Functions/Chpwd/zsh_directory_name_generic
@@ -16,7 +16,7 @@ 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
+ print -r -- "$0: $_zdn_topvar is not set" >&2
return 1
fi
@@ -43,7 +43,7 @@ if [[ $1 = n ]]; then
if [[ -z $_zdn_cpt ]]; then
# If top level component, just try another expansion
- if [[ $_zdn_var != $_zdn_top ]]; then
+ if [[ $_zdn_var != $_zdn_topvar ]]; then
# Committed to this expansion, so report failure.
print -r -- "$0: no expansion for directory name \`$_zdn_name'" >&2
fi
diff --git a/Functions/Misc/is-at-least b/Functions/Misc/is-at-least
index d4b0e2fe0..d4ff3552a 100644
--- a/Functions/Misc/is-at-least
+++ b/Functions/Misc/is-at-least
@@ -13,10 +13,16 @@
# is-at-least 3.1.0 && setopt HIST_REDUCE_BLANKS
# is-at-least 586 $MACHTYPE && echo 'You could be running Mandrake!'
# is-at-least $ZSH_VERSION || print 'Something fishy here.'
+#
+# Note that segments that contain no digits at all are ignored, and leading
+# text is discarded if trailing digits follow, because this was the meaning
+# of certain zsh version strings in the early 2000s. Other segments that
+# begin with digits are compared using NUMERIC_GLOB_SORT semantics, and any
+# other segments starting with text are compared lexically.
emulate -L zsh
-local IFS=".-" min_cnt=0 ver_cnt=0 part min_ver version
+local IFS=".-" min_cnt=0 ver_cnt=0 part min_ver version order
min_ver=(${=1})
version=(${=2:-$ZSH_VERSION} 0)
@@ -24,6 +30,18 @@ version=(${=2:-$ZSH_VERSION} 0)
while (( $min_cnt <= ${#min_ver} )); do
while [[ "$part" != <-> ]]; do
(( ++ver_cnt > ${#version} )) && return 0
+ if [[ ${version[ver_cnt]} = *[0-9][^0-9]* ]]; then
+ # Contains a number followed by text. Not a zsh version string.
+ order=( ${version[ver_cnt]} ${min_ver[ver_cnt]} )
+ if [[ ${version[ver_cnt]} = <->* ]]; then
+ # Leading digits, compare by sorting with numeric order.
+ [[ $order != ${${(On)order}} ]] && return 1
+ else
+ # No leading digits, compare by sorting in lexical order.
+ [[ $order != ${${(O)order}} ]] && return 1
+ fi
+ [[ $order[1] != $order[2] ]] && return 0
+ fi
part=${version[ver_cnt]##*[^0-9]}
done
diff --git a/Functions/Newuser/zsh-newuser-install b/Functions/Newuser/zsh-newuser-install
index 37c60293a..e4028fd50 100644
--- a/Functions/Newuser/zsh-newuser-install
+++ b/Functions/Newuser/zsh-newuser-install
@@ -512,7 +512,7 @@ $default_options[$match[2]])
fi
print -r "Edit a value. If it is left blank, nothing will be saved:"
edval=$match[2]
- if vared -p "$match[1]> " -h edval; then
+ if vared -M emacs -p "$match[1]> " -h edval; then
# check this assignment doesn't produce multiple words
# e.g. "HISTFILE=never rm -f ~" does produce multiple words...
# this isn't perfect, e.g. "(this would get split on assignment)",
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_p4 b/Functions/VCS_Info/Backends/VCS_INFO_detect_p4
index 377453f6a..95a534786 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_detect_p4
+++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_p4
@@ -2,7 +2,7 @@
## perforce support by: Phil Pennock
## Distributed under the same BSD-ish license as zsh itself.
-# If user-server is true in the :vcs_info:p4:... context, contact the
+# If use-server is true in the :vcs_info:p4:... context, contact the
# server to decide whether the directory is handled by Perforce. This can
# cause a delay if the network times out, in particular if looking up the
# server name failed. Hence this is not the default. If a timeout
@@ -10,7 +10,7 @@
# vcs_info_p4_dead_servers and the server is never contacted again. The
# array must be edited by hand to remove it.
#
-# If user-server is false or not set, the function looks to see if there is
+# If use-server is false or not set, the function looks to see if there is
# a file $P4CONFIG somewhere above in the hierarchy. This is far from
# foolproof; in fact it relies on you using the particular working practice
# of having such files in all client root directories and nowhere above.
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
index e1cee7439..472c10d5d 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
@@ -247,7 +247,9 @@ elif [[ -d "${gitdir}/rebase-apply" ]]; then
fi
fi
local last="$(< "${patchdir}/last")"
- git_patches_unapplied=( {$cur..$last} )
+ if (( cur+1 <= last )); then
+ git_patches_unapplied=( {$((cur+1))..$last} )
+ fi
fi
VCS_INFO_git_handle_patches
diff --git a/Functions/VCS_Info/VCS_INFO_maxexports b/Functions/VCS_Info/VCS_INFO_maxexports
index ea952517f..d697b9abd 100644
--- a/Functions/VCS_Info/VCS_INFO_maxexports
+++ b/Functions/VCS_Info/VCS_INFO_maxexports
@@ -2,7 +2,7 @@
## Written by Frank Terbeck <ft@bewatermyfriend.org>
## Distributed under the same BSD-ish license as zsh itself.
-setopt localoptions NO_shwordsplit
+setopt localoptions NO_shwordsplit unset
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" "max-exports" maxexports || maxexports=2
if [[ ${maxexports} != <-> ]] || (( maxexports < 1 )); then
diff --git a/Functions/VCS_Info/VCS_INFO_nvcsformats b/Functions/VCS_Info/VCS_INFO_nvcsformats
index 203a86d23..581aa5a97 100644
--- a/Functions/VCS_Info/VCS_INFO_nvcsformats
+++ b/Functions/VCS_Info/VCS_INFO_nvcsformats
@@ -4,7 +4,6 @@
setopt localoptions noksharrays NO_shwordsplit
local c v rr
-local -a msgs
if [[ $1 == '-preinit-' ]] ; then
c='default'
diff --git a/Functions/VCS_Info/VCS_INFO_set b/Functions/VCS_Info/VCS_INFO_set
index 484c7937d..e3f62ceef 100644
--- a/Functions/VCS_Info/VCS_INFO_set
+++ b/Functions/VCS_Info/VCS_INFO_set
@@ -2,7 +2,7 @@
## Written by Frank Terbeck <ft@bewatermyfriend.org>
## Distributed under the same BSD-ish license as zsh itself.
-setopt localoptions noksharrays NO_shwordsplit
+setopt localoptions noksharrays NO_shwordsplit unset
local -i i j
if [[ $1 == '--nvcs' ]] ; then
diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info
index 628dde9b1..f13f6b501 100644
--- a/Functions/VCS_Info/vcs_info
+++ b/Functions/VCS_Info/vcs_info
@@ -10,7 +10,7 @@
setopt localoptions noksharrays extendedglob NO_shwordsplit
local file func sys
-local -a static_functions
+local -a static_functions msgs
local -i maxexports
static_functions=(
diff --git a/Functions/Zle/backward-kill-word-match b/Functions/Zle/backward-kill-word-match
index ded4db2b5..f04614c87 100644
--- a/Functions/Zle/backward-kill-word-match
+++ b/Functions/Zle/backward-kill-word-match
@@ -32,4 +32,6 @@ while (( count-- )); do
done=1
done
+zle -f 'kill'
+
return 0
diff --git a/Functions/Zle/edit-command-line b/Functions/Zle/edit-command-line
index 103a1c1a5..353f2609a 100644
--- a/Functions/Zle/edit-command-line
+++ b/Functions/Zle/edit-command-line
@@ -1,8 +1,8 @@
# Edit the command line using your usual editor.
-# Binding this to 'v' in the vi command mode map,
+# Binding this to '!' in the vi command mode map,
# autoload -Uz edit-command-line
# zle -N edit-command-line
-# bindkey -M vicmd v edit-command-line
+# bindkey -M vicmd '!' edit-command-line
# will give ksh-like behaviour for that key,
# except that it will handle multi-line buffers properly.
@@ -10,7 +10,9 @@
exec </dev/tty
# Compute the cursor's position in bytes, not characters.
- setopt localoptions nomultibyte
+ setopt localoptions nomultibyte noksharrays
+
+ (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2]
# Open the editor, placing the cursor at the right place if we know how.
local editor=${${VISUAL:-${EDITOR:-vi}}}
@@ -24,6 +26,8 @@
(*) ${=editor} $1;;
esac
+ (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[1]
+
# Replace the buffer with the editor output.
print -Rz - "$(<$1)"
} =(<<<"$PREBUFFER$BUFFER")
diff --git a/Functions/Zle/kill-word-match b/Functions/Zle/kill-word-match
index 30db5ab35..ffc5be72b 100644
--- a/Functions/Zle/kill-word-match
+++ b/Functions/Zle/kill-word-match
@@ -31,4 +31,6 @@ while (( count-- )); do
done=1
done
+zle -f 'kill'
+
return 0
diff --git a/Functions/Zle/match-words-by-style b/Functions/Zle/match-words-by-style
index b387828f3..54e019d23 100644
--- a/Functions/Zle/match-words-by-style
+++ b/Functions/Zle/match-words-by-style
@@ -111,20 +111,20 @@ done
case $wordstyle in
(*shell*) local bufwords
# This splits the line into words as the shell understands them.
- bufwords=(${(z)LBUFFER})
+ bufwords=(${(Z:n:)LBUFFER})
nwords=${#bufwords}
wordpat1="${(q)bufwords[-1]}"
# Take substring of RBUFFER to skip over $skip characters
# from the cursor position.
- bufwords=(${(z)RBUFFER[1+$skip,-1]})
+ bufwords=(${(Z:n:)RBUFFER[1+$skip,-1]})
wordpat2="${(q)bufwords[1]}"
spacepat='[[:space:]]#'
# Assume the words are at the top level, i.e. if we are inside
# 'something with spaces' then we need to ignore the embedded
# spaces and consider the whole word.
- bufwords=(${(z)BUFFER})
+ bufwords=(${(Z:n:)BUFFER})
if (( ${#bufwords[$nwords]} > ${#wordpat1} )); then
# Yes, we're in the middle of a shell word.
# Find out what's in front.
diff --git a/Functions/Zle/transpose-words-match b/Functions/Zle/transpose-words-match
index c1db310c1..4d2ac71f1 100644
--- a/Functions/Zle/transpose-words-match
+++ b/Functions/Zle/transpose-words-match
@@ -11,14 +11,23 @@
# on X would be turned into `barXfoo' with the cursor still on the X,
# regardless of what the character X is.
+emulate -L zsh
autoload -Uz match-words-by-style
-local curcontext=":zle:$WIDGET" skip
+local curcontext=":zle:$WIDGET"
local -a matched_words
integer count=${NUMERIC:-1} neg
(( count < 0 )) && (( count = -count, neg = 1 ))
+if [[ $WIDGET == transpose-words ]]; then
+ # default is to be a drop-in replacement, check styles for change
+ zstyle -m $curcontext skip-chars \* ||
+ zstyle -m $curcontext word-style '*subword*' ||
+ { [[ $LBUFFER[-1] != [[:space:]] && $RBUFFER[1] != [[:space:]] ||
+ -z ${RBUFFER//[[:space:]]/} ]] && zle backward-word }
+fi
+
while (( count-- > 0 )); do
match-words-by-style
diff --git a/Functions/Zle/url-quote-magic b/Functions/Zle/url-quote-magic
index 0e49573db..7ee281ea4 100644
--- a/Functions/Zle/url-quote-magic
+++ b/Functions/Zle/url-quote-magic
@@ -115,7 +115,7 @@ alias globurl='noglob urlglobber '
function url-quote-magic {
setopt localoptions noksharrays extendedglob
local qkey="${(q)KEYS}"
- local -a reply
+ local -a reply match mbegin mend
if [[ "$KEYS" != "$qkey" ]]
then
local lbuf="$LBUFFER$qkey"
diff --git a/NEWS b/NEWS
index 3964da732..15822ad34 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,13 @@ 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.
+Paste highlighting (added in 5.1) is now enabled by default to signal
+that accept-line hasn't occurred. Paste highlighting may be disabled
+via
+ zle_highlight+=(paste:none)
+. Disabling paste highlighting will retain the "bracketed paste"
+behaviour, unless that is separately disabled via zle_bracketed_paste.
+
Changes from 5.1 to 5.1.1
-------------------------
diff --git a/README b/README
index 2e2ebce2b..6e5b73067 100644
--- a/README
+++ b/README
@@ -29,17 +29,43 @@ Zsh is a shell with lots of features. For a list of some of these, see the
file FEATURES, and for the latest changes see NEWS. For more
details, see the documentation.
-Incompatibilities between 5.1 and 5.2
+Incompatibilities between 5.2 and 5.3
-------------------------------------
+In character classes delimited by "[" and "]" within patterns, whether
+used for filename generation (globbing) or other forms of pattern
+matching, it used not to be possible to quote "-" when used for a range,
+or "^" and "!" when used for negating a character set. The characters can
+now be quoted by any of the standard shell means, but note that
+the "[" and "]" must not be quoted. For example,
+
+ [[ $a = ['a-z'] ]]
+
+matches if the variable a contains just one of the characters "a", "-"
+or "z" only. Previously this would have matched any lower case ASCII
+letter. Note therefore the useful fact that
+
+ [[ $a = ["$cset"] ]]
+
+matches any character contained in the variable "cset". A consequence
+of this change is that variables that should have active ranges need
+(with default zsh options) to be indicated explicitly, e.g.
+
+ cset="a-z"
+ [[ b = [${~cset}] ]]
+
+The "~" causes the "-" character to be active. In sh emulation the
+"~" is unncessary in this example and double quotes must be used to
+suppress the range behaviour of the "-".
+
+Incompatibilities between 5.0.8 and 5.2
+---------------------------------------
+
The behaviour of the parameter flag (P) has changed when it appears
in a nested parameter group, in order to make it more useful in
such cases. A (P) in the outermost parameter group behaves as
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
that doesn't support this mode). Now, the new "bracketed paste mode"
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index 5db1c9222..930429248 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -93,7 +93,7 @@ bin_clone(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
/* Clear mygrp so that acquire_pgrp() gets the new process group.
* (acquire_pgrp() is called from init_io()) */
mypgrp = 0;
- init_io();
+ init_io(NULL);
setsparam("TTY", ztrdup(ttystrname));
}
close(ttyfd);
diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c
index 2393cd1e7..aa5c8ed5b 100644
--- a/Src/Modules/pcre.c
+++ b/Src/Modules/pcre.c
@@ -190,18 +190,25 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar,
if (want_begin_end) {
char *ptr = arg;
zlong offs = 0;
+ int clen, leftlen;
/* Count the characters before the match */
- MB_METACHARINIT();
- while (ptr < arg + ovec[0]) {
+ MB_CHARINIT();
+ leftlen = ovec[0];
+ while (leftlen) {
offs++;
- ptr += MB_METACHARLEN(ptr);
+ clen = MB_CHARLEN(ptr, leftlen);
+ ptr += clen;
+ leftlen -= clen;
}
setiparam("MBEGIN", offs + !isset(KSHARRAYS));
/* Add on the characters in the match */
- while (ptr < arg + ovec[1]) {
+ leftlen = ovec[1] - ovec[0];
+ while (leftlen) {
offs++;
- ptr += MB_METACHARLEN(ptr);
+ clen = MB_CHARLEN(ptr, leftlen);
+ ptr += clen;
+ leftlen -= clen;
}
setiparam("MEND", offs + !isset(KSHARRAYS) - 1);
if (nelem) {
@@ -219,17 +226,23 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar,
ptr = arg;
offs = 0;
/* Find the start offset */
- MB_METACHARINIT();
- while (ptr < arg + ipair[0]) {
+ MB_CHARINIT();
+ leftlen = ipair[0];
+ while (leftlen) {
offs++;
- ptr += MB_METACHARLEN(ptr);
+ clen = MB_CHARLEN(ptr, leftlen);
+ ptr += clen;
+ leftlen -= clen;
}
convbase(buf, offs + !isset(KSHARRAYS), 10);
*bptr = ztrdup(buf);
/* Continue to the end offset */
- while (ptr < arg + ipair[1]) {
+ leftlen = ipair[1] - ipair[0];
+ while (leftlen) {
offs++;
- ptr += MB_METACHARLEN(ptr);
+ clen = MB_CHARLEN(ptr, leftlen);
+ ptr += clen;
+ leftlen -= clen;
}
convbase(buf, offs + !isset(KSHARRAYS) - 1, 10);
*eptr = ztrdup(buf);
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 3b8366076..63ff7578c 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -399,7 +399,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
close(master);
close(coprocin);
close(coprocout);
- init_io();
+ init_io(NULL);
setsparam("TTY", ztrdup(ttystrname));
opts[INTERACTIVE] = 0;
@@ -614,14 +614,23 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch)
break;
}
if (cmd->read != -1 || (ret = read(cmd->fd, buf + used, 1)) == 1) {
+ int readchar;
if (cmd->read != -1) {
ret = 1;
- buf[used] = (char) cmd->read;
+ readchar = cmd->read;
cmd->read = -1;
- }
+ } else
+ readchar = STOUC(buf[used]);
+ if (imeta(readchar)) {
+ buf[used++] = Meta;
+ buf[used++] = (char) (readchar ^ 32);
+ } else
+ buf[used++] = (char) readchar;
seen = 1;
- if (++used == blen) {
+ if (used >= blen-1) {
if (!*args) {
+ buf[used] = '\0';
+ unmetafy(buf, &used);
write_loop(1, buf, used);
used = 0;
} else {
@@ -633,7 +642,8 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch)
buf[used] = '\0';
if (!prog) {
- if (ret <= 0 || (*args && buf[used - 1] == '\n'))
+ if (ret <= 0 || (*args && buf[used - 1] == '\n' &&
+ (used < 2 || buf[used-2] != Meta)))
break;
} else {
if (ret < 0
@@ -666,9 +676,11 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch)
return 1;
}
if (*args)
- setsparam(*args, ztrdup(metafy(buf, used, META_HREALLOC)));
- else if (used)
+ setsparam(*args, ztrdup(buf));
+ else if (used) {
+ unmetafy(buf, &used);
write_loop(1, buf, used);
+ }
if (seen && (!prog || matchok || !mustmatch))
return 0;
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 29aaee82a..0ccb88505 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -2584,6 +2584,12 @@ domenuselect(Hookdef dummy, Chdata dat)
if (!do_last_key) {
zmult = 1;
cmd = getkeycmd();
+ /*
+ * On interrupt, we'll exit due to cmd being empty.
+ * Don't propagate the interrupt any further, which
+ * can screw up redrawing.
+ */
+ errflag &= ~ERRFLAG_INT;
if (mtab_been_reallocated) {
do_last_key = 1;
continue;
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 2d672de3b..e9b14281d 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -213,6 +213,8 @@ struct widget {
#define ZLE_KEEPSUFFIX (1<<9) /* DON'T remove added suffix */
#define ZLE_NOTCOMMAND (1<<10) /* widget should not alter lastcmd */
#define ZLE_ISCOMP (1<<11) /* usable for new style completion */
+#define WIDGET_INUSE (1<<12) /* widget is in use */
+#define WIDGET_FREE (1<<13) /* request to free when no longer in use */
/* thingies */
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index 95d96c95c..abd6e1749 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -1480,6 +1480,7 @@ doisearch(char **args, int dir, int pattern)
isearch_active = 0;
ref:
zlecallhook("zle-isearch-update", NULL);
+ redrawhook();
zrefresh();
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
int i;
@@ -1694,6 +1695,7 @@ doisearch(char **args, int dir, int pattern)
statusline = NULL;
unmetafy_line();
zlecallhook("zle-isearch-exit", NULL);
+ redrawhook();
if (exitfn)
exitfn(zlenoargs);
selectkeymap(okeymap, 1);
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 069580f8a..382eb8d41 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -1449,6 +1449,104 @@ default_bindings(void)
/*************************/
/* reading key sequences */
/*************************/
+/**/
+#ifdef MULTIBYTE_SUPPORT
+/*
+ * Get the remainder of a character if we support multibyte
+ * input strings. It may not require any more input, but
+ * we haven't yet checked. What's read in so far is available
+ * in keybuf; if we read more we will top keybuf up.
+ *
+ * This version is used when we are still resolving the input key stream
+ * into bindings. Once that has been done this function shouldn't be
+ * used: instead, see getrestchar() in zle_main.c.
+ *
+ * This supports a self-insert binding at any stage of a key sequence.
+ * Typically we handle 8-bit characters by having only the first byte
+ * bound to self insert; then we immediately get here and read in as
+ * many further bytes as necessary. However, it's possible that any set
+ * of bytes up to full character is bound to self-insert; then we get
+ * here later and read as much as possible, which could be a complete
+ * character, from keybuf before attempting further input.
+ *
+ * At the end of the process, the full multibyte character is available
+ * in keybuf, so the return value may be superfluous.
+ */
+
+/**/
+mod_export ZLE_INT_T
+getrestchar_keybuf(void)
+{
+ char c;
+ wchar_t outchar;
+ int inchar, timeout, bufind = 0, buflen = keybuflen;
+ static mbstate_t mbs;
+ size_t cnt;
+
+ /*
+ * We are guaranteed to set a valid wide last character,
+ * although it may be WEOF (which is technically not
+ * a wide character at all...)
+ */
+ lastchar_wide_valid = 1;
+ memset(&mbs, 0, sizeof mbs);
+
+ /*
+ * Return may be zero if we have a NULL; handle this like
+ * any other character.
+ */
+ while (1) {
+ if (bufind < buflen) {
+ c = STOUC(keybuf[bufind++]);
+ if (c == Meta) {
+ DPUTS(bufind == buflen, "Meta at end of keybuf");
+ c = STOUC(keybuf[bufind++]) ^ 32;
+ }
+ } else {
+ /*
+ * Always apply KEYTIMEOUT to the remains of the input
+ * character. The parts of a multibyte character should
+ * arrive together. If we don't do this the input can
+ * get stuck if an invalid byte sequence arrives.
+ */
+ inchar = getbyte(1L, &timeout);
+ /* getbyte deliberately resets lastchar_wide_valid */
+ lastchar_wide_valid = 1;
+ if (inchar == EOF) {
+ memset(&mbs, 0, sizeof mbs);
+ if (timeout)
+ {
+ /*
+ * This case means that we got a valid initial byte
+ * (since we tested for EOF above), but the followup
+ * timed out. This probably indicates a duff character.
+ * Return a '?'.
+ */
+ lastchar = '?';
+ return lastchar_wide = L'?';
+ }
+ else
+ return lastchar_wide = WEOF;
+ }
+ c = inchar;
+ addkeybuf(inchar);
+ }
+
+ cnt = mbrtowc(&outchar, &c, 1, &mbs);
+ if (cnt == MB_INVALID) {
+ /*
+ * Invalid input. Hmm, what's the right thing to do here?
+ */
+ memset(&mbs, 0, sizeof mbs);
+ return lastchar_wide = WEOF;
+ }
+ if (cnt != MB_INCOMPLETE)
+ break;
+ }
+ return lastchar_wide = (ZLE_INT_T)outchar;
+}
+/**/
+#endif
/* read a sequence of keys that is bound to some command in a keymap */
@@ -1503,16 +1601,9 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
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;
- }
+ !lastchar_wide_valid && !ispfx) {
+ (void)getrestchar_keybuf();
+ lastlen = keybuflen;
}
#endif
}
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 38427e8e3..6e2bfded8 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1025,6 +1025,32 @@ getrestchar(int inchar, char *outstr, int *outcount)
/**/
#endif
+/**/
+void redrawhook(void)
+{
+ Thingy initthingy;
+ if ((initthingy = rthingy_nocreate("zle-line-pre-redraw"))) {
+ int lastcmd_prev = lastcmd;
+ int old_incompfunc = incompfunc;
+ char *args[2];
+ Thingy lbindk_save = lbindk, bindk_save = bindk;
+ refthingy(lbindk_save);
+ refthingy(bindk_save);
+ args[0] = initthingy->nam;
+ args[1] = NULL;
+ incompfunc = 0;
+ execzlefunc(initthingy, args, 0);
+ incompfunc = old_incompfunc;
+ unrefthingy(initthingy);
+ unrefthingy(lbindk);
+ unrefthingy(bindk);
+ lbindk = lbindk_save;
+ bindk = bindk_save;
+ /* we can't set ZLE_NOTCOMMAND since it's not a legit widget, so
+ * restore lastcmd manually so that we don't mess up the global state */
+ lastcmd = lastcmd_prev;
+ }
+}
/**/
void
@@ -1084,6 +1110,8 @@ zlecore(void)
errflag |= ERRFLAG_ERROR;
break;
}
+
+ redrawhook();
#ifdef HAVE_POLL
if (baud && !(lastcmd & ZLE_MENUCMP)) {
struct pollfd pfd;
@@ -1113,6 +1141,7 @@ zlecore(void)
zrefresh();
freeheap();
+
}
region_active = 0;
@@ -1191,7 +1220,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
vistartchange = -1;
zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE);
*zleline = ZWC('\0');
- virangeflag = lastcmd = done = zlecs = zlell = mark = 0;
+ virangeflag = lastcmd = done = zlecs = zlell = mark = yankb = yanke = 0;
vichgflag = 0;
viinsbegin = 0;
statusline = NULL;
@@ -1344,6 +1373,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
eofsent = 1;
ret = 1;
} else {
+ int inuse = wflags & WIDGET_INUSE;
+ w->flags |= WIDGET_INUSE;
if(!(wflags & ZLE_KEEPSUFFIX))
removesuffix();
if(!(wflags & ZLE_MENUCMP)) {
@@ -1367,6 +1398,12 @@ execzlefunc(Thingy func, char **args, int set_bindk)
ret = w->u.fn(args);
unqueue_signals();
}
+ if (!inuse) {
+ if (w->flags & WIDGET_FREE)
+ freewidget(w);
+ else
+ w->flags &= ~WIDGET_INUSE;
+ }
if (!(wflags & ZLE_NOTCOMMAND))
lastcmd = wflags;
}
@@ -1387,6 +1424,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
int osc = sfcontext, osi = movefd(0);
int oxt = isset(XTRACE);
LinkList largs = NULL;
+ int inuse = w->flags & WIDGET_INUSE;
+ w->flags |= WIDGET_INUSE;
if (*args) {
largs = newlinklist();
@@ -1402,8 +1441,15 @@ execzlefunc(Thingy func, char **args, int set_bindk)
opts[XTRACE] = oxt;
sfcontext = osc;
endparamscope();
- lastcmd = w->flags;
- w->flags = 0;
+ lastcmd = w->flags & ~(WIDGET_INUSE|WIDGET_FREE);
+ if (inuse) {
+ w->flags &= WIDGET_INUSE|WIDGET_FREE;
+ } else {
+ if (w->flags & WIDGET_FREE)
+ freewidget(w);
+ else
+ w->flags = 0;
+ }
r = 1;
redup(osi, 0);
}
@@ -1795,6 +1841,7 @@ recursiveedit(UNUSED(char **args))
{
int locerror;
+ redrawhook();
zrefresh();
zlecore();
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 6facff429..3d2471e27 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -338,9 +338,9 @@ zle_set_highlight(void)
for (; *atrs; atrs++) {
if (!strcmp(*atrs, "none")) {
/* reset attributes for consistency... usually unnecessary */
- special_atr_on = default_atr_on =
- paste_atr_on_set = 0;
- special_atr_on_set = region_atr_on_set =
+ special_atr_on = default_atr_on = 0;
+ special_atr_on_set = 1;
+ paste_atr_on_set = region_atr_on_set =
isearch_atr_on_set = suffix_atr_on_set = 1;
} else if (strpfx("default:", *atrs)) {
match_highlight(*atrs + 8, &default_atr_on);
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 271fd8efc..21495b6f2 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -253,9 +253,14 @@ unbindwidget(Thingy t, int override)
/* Free a widget. */
/**/
-static void
+void
freewidget(Widget w)
{
+ if (w->flags & WIDGET_INUSE) {
+ w->flags |= WIDGET_FREE;
+ return;
+ }
+
if (w->flags & WIDGET_NCOMP) {
zsfree(w->u.comp.wid);
zsfree(w->u.comp.func);
diff --git a/Src/builtin.c b/Src/builtin.c
index cac4f42f9..dd20f9eab 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -62,7 +62,7 @@ static struct builtin builtins[] =
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),
- BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"),
+ BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"),
BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
/*
* We used to behave as if the argument to -e was optional.
@@ -99,14 +99,14 @@ static struct builtin builtins[] =
#endif
BUILTIN("popd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 1, BIN_POPD, "q", NULL),
- BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "abcC:Df:ilmnNoOpPrRsSu:x:X:z-", NULL),
- BUILTIN("printf", 0, bin_print, 1, -1, BIN_PRINTF, NULL, NULL),
+ BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "abcC:Df:ilmnNoOpPrRsSu:v:x:X:z-", NULL),
+ BUILTIN("printf", 0, bin_print, 1, -1, BIN_PRINTF, "v:", NULL),
BUILTIN("pushd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_PUSHD, "qsPL", NULL),
BUILTIN("pushln", 0, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"),
BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL),
BUILTIN("r", 0, bin_fc, 0, -1, BIN_R, "IlLnr", NULL),
BUILTIN("read", 0, bin_read, 0, -1, 0, "cd:ek:%lnpqrst:%zu:AE", NULL),
- BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"),
+ BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_READONLY, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"),
BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "df", "r"),
BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL),
BUILTIN("set", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_set, 0, -1, 0, NULL, NULL),
@@ -387,7 +387,7 @@ execbuiltin(LinkList args, LinkList assigns, Builtin bn)
if (*arg) {
if(*arg == Meta)
*++arg ^= 32;
- zwarn("bad option: -%c", *arg);
+ zwarnnam(name, "bad option: -%c", *arg);
return 1;
}
arg = *++argv;
@@ -2213,6 +2213,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
mkarray(NULL), 0)))
return NULL;
}
+ if (errflag)
+ return NULL;
pm->node.flags |= (on & PM_READONLY);
if (OPT_ISSET(ops,'p'))
paramtab->printnode(&pm->node, PRINT_TYPESET);
@@ -2533,6 +2535,10 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
if (OPT_ISSET(ops,'f'))
return bin_functions(name, argv, ops, func);
+ /* POSIX handles "readonly" specially */
+ if (func == BIN_READONLY && isset(POSIXBUILTINS) && !OPT_PLUS(ops, 'g'))
+ ops->ind['g'] = 1;
+
/* Translate the options into PM_* flags. *
* Unfortunately, this depends on the order *
* these flags are defined in zsh.h */
@@ -4019,12 +4025,62 @@ bin_print(char *name, char **args, Options ops, int func)
char *start, *endptr, *c, *d, *flag, *buf = NULL, spec[14], *fmt = NULL;
char **first, **argp, *curarg, *flagch = "'0+- #", save = '\0', nullstr = '\0';
size_t rcount, count = 0;
+ FILE *fout = stdout;
#ifdef HAVE_OPEN_MEMSTREAM
size_t mcount;
+#define ASSIGN_MSTREAM(BUF,FOUT) \
+ do { \
+ if ((FOUT = open_memstream(&BUF, &mcount)) == NULL) { \
+ zwarnnam(name, "open_memstream failed"); \
+ return 1; \
+ } \
+ } while (0)
+ /*
+ * Some implementations of open_memstream() have a bug such that,
+ * if fflush() is followed by fclose(), another NUL byte is written
+ * to the buffer at the wrong position. Therefore we must fclose()
+ * before reading.
+ */
+#define READ_MSTREAM(BUF,FOUT) \
+ ((fclose(FOUT) == 0) ? mcount : (size_t)-1)
+#define CLOSE_MSTREAM(FOUT) 0
+
+#else /* simulate HAVE_OPEN_MEMSTREAM */
+
+#define ASSIGN_MSTREAM(BUF,FOUT) \
+ do { \
+ int tempfd; \
+ char *tmpf; \
+ if ((tempfd = gettempfile(NULL, 1, &tmpf)) < 0) { \
+ zwarnnam(name, "can't open temp file: %e", errno); \
+ return 1; \
+ } \
+ unlink(tmpf); \
+ if ((fout = fdopen(tempfd, "w+")) == NULL) { \
+ close(tempfd); \
+ zwarnnam(name, "can't open temp file: %e", errno); \
+ return 1; \
+ } \
+ } while (0)
+#define READ_MSTREAM(BUF,FOUT) \
+ ((((count = ftell(FOUT)), (BUF = (char *)zalloc(count + 1))) && \
+ ((fseek(FOUT, 0L, SEEK_SET) == 0) && !(BUF[count] = '\0')) && \
+ (fread(BUF, 1, count, FOUT) == count)) ? count : (size_t)-1)
+#define CLOSE_MSTREAM(FOUT) fclose(FOUT)
+
#endif
- FILE *fout = stdout;
- Histent ent;
+#define IS_MSTREAM(FOUT) \
+ (FOUT != stdout && \
+ (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s') || OPT_ISSET(ops,'v')))
+
+ /* Testing EBADF special-cases >&- redirections */
+#define CLOSE_CLEANLY(FOUT) \
+ (IS_MSTREAM(FOUT) ? CLOSE_MSTREAM(FOUT) == 0 : \
+ ((FOUT == stdout) ? (fflush(FOUT) == 0 || errno == EBADF) : \
+ (fclose(FOUT) == 0))) /* implies error for -u on a closed fd */
+
+ Histent ent;
mnumber mnumval;
double doubleval;
int intval;
@@ -4032,6 +4088,47 @@ bin_print(char *name, char **args, Options ops, int func)
zulong zulongval;
char *stringval;
+ /* Error check option combinations and option arguments */
+
+ if (OPT_ISSET(ops, 'z') +
+ OPT_ISSET(ops, 's') + OPT_ISSET(ops, 'S') +
+ OPT_ISSET(ops, 'v') > 1) {
+ zwarnnam(name, "only one of -s, -S, -v, or -z allowed");
+ return 1;
+ }
+ if ((OPT_ISSET(ops, 'z') | OPT_ISSET(ops, 's') | OPT_ISSET(ops, 'S')) +
+ (OPT_ISSET(ops, 'c') | OPT_ISSET(ops, 'C')) > 1) {
+ zwarnnam(name, "-c or -C not allowed with -s, -S, or -z");
+ return 1;
+ }
+ if ((OPT_ISSET(ops, 'z') | OPT_ISSET(ops, 'v') |
+ OPT_ISSET(ops, 's') | OPT_ISSET(ops, 'S')) +
+ (OPT_ISSET(ops, 'p') | OPT_ISSET(ops, 'u')) > 1) {
+ zwarnnam(name, "-p or -u not allowed with -s, -S, -v, or -z");
+ return 1;
+ }
+ /*
+ if (OPT_ISSET(ops, 'f') &&
+ (OPT_ISSET(ops, 'S') || OPT_ISSET(ops, 'c') || OPT_ISSET(ops, 'C'))) {
+ zwarnnam(name, "-f not allowed with -c, -C, or -S");
+ return 1;
+ }
+ */
+
+ /* -C -- number of columns */
+ if (!fmt && OPT_ISSET(ops,'C')) {
+ char *eptr, *argptr = OPT_ARG(ops,'C');
+ nc = (int)zstrtol(argptr, &eptr, 10);
+ if (*eptr) {
+ zwarnnam(name, "number expected after -%c: %s", 'C', argptr);
+ return 1;
+ }
+ if (nc <= 0) {
+ zwarnnam(name, "invalid number of columns: %s", argptr);
+ return 1;
+ }
+ }
+
if (func == BIN_PRINTF) {
if (!strcmp(*args, "--") && !*++args) {
zwarnnam(name, "not enough arguments");
@@ -4096,7 +4193,7 @@ bin_print(char *name, char **args, Options ops, int func)
}
}
/* -P option -- interpret as a prompt sequence */
- if(OPT_ISSET(ops,'P')) {
+ if (OPT_ISSET(ops,'P')) {
/*
* promptexpand uses permanent storage: to avoid
* messy memory management, stick it on the heap
@@ -4110,13 +4207,13 @@ bin_print(char *name, char **args, Options ops, int func)
free(str);
}
/* -D option -- interpret as a directory, and use ~ */
- if(OPT_ISSET(ops,'D')) {
+ if (OPT_ISSET(ops,'D')) {
Nameddir d;
queue_signals();
/* TODO: finddir takes a metafied file */
d = finddir(args[n]);
- if(d) {
+ if (d) {
int dirlen = strlen(d->dir);
char *arg = zhalloc(len[n] - dirlen + strlen(d->node.nam) + 2);
sprintf(arg, "~%s%s", d->node.nam, args[n] + dirlen);
@@ -4139,26 +4236,12 @@ bin_print(char *name, char **args, Options ops, int func)
strmetasort(args, flags, len);
}
- /* -C -- number of columns */
- if (!fmt && OPT_ISSET(ops,'C')) {
- char *eptr, *argptr = OPT_ARG(ops,'C');
- nc = (int)zstrtol(argptr, &eptr, 10);
- if (*eptr) {
- zwarnnam(name, "number expected after -%c: %s", 'C', argptr);
- return 1;
- }
- if (nc <= 0) {
- zwarnnam(name, "invalid number of columns: %s", argptr);
- return 1;
- }
- }
-
/* -u and -p -- output to other than standard output */
if ((OPT_HASARG(ops,'u') || OPT_ISSET(ops,'p')) &&
/* rule out conflicting options -- historical precedence */
((!fmt && (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C'))) ||
- !(OPT_ISSET(ops, 'z') ||
- OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')))) {
+ !(OPT_ISSET(ops, 'z') || OPT_ISSET(ops, 'v') ||
+ OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')))) {
int fdarg, fd;
if (OPT_ISSET(ops, 'p')) {
@@ -4179,8 +4262,7 @@ bin_print(char *name, char **args, Options ops, int func)
} else {
fdarg = (int)zstrtol(argptr, &eptr, 10);
if (*eptr) {
- zwarnnam(name, "number expected after -%c: %s", 'u',
- argptr);
+ zwarnnam(name, "number expected after -u: %s", argptr);
return 1;
}
}
@@ -4197,6 +4279,10 @@ bin_print(char *name, char **args, Options ops, int func)
}
}
+ if (OPT_ISSET(ops, 'v') ||
+ (fmt && (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s'))))
+ ASSIGN_MSTREAM(buf,fout);
+
/* -c -- output in columns */
if (!fmt && (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C'))) {
int l, nr, sc, n, t, i;
@@ -4348,18 +4434,29 @@ bin_print(char *name, char **args, Options ops, int func)
}
fputc(OPT_ISSET(ops,'N') ? '\0' : '\n', fout);
}
- /* Testing EBADF special-cases >&- redirections */
- if ((fout != stdout) ? (fclose(fout) != 0) :
- (fflush(fout) != 0 && errno != EBADF)) {
+ if (IS_MSTREAM(fout) && (rcount = READ_MSTREAM(buf,fout)) == -1)
+ ret = 1;
+ if (!CLOSE_CLEANLY(fout) || ret) {
zwarnnam(name, "write error: %e", errno);
ret = 1;
}
+ if (buf) {
+ /* assert: we must be doing -v at this point */
+ queue_signals();
+ if (ret)
+ free(buf);
+ else
+ setsparam(OPT_ARG(ops, 'v'),
+ metafy(buf, rcount, META_REALLOC));
+ unqueue_signals();
+ }
return ret;
}
/* normal output */
if (!fmt) {
- if (OPT_ISSET(ops, 'z') || OPT_ISSET(ops, 's')) {
+ if (OPT_ISSET(ops, 'z') || OPT_ISSET(ops, 'v') ||
+ OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')) {
/*
* We don't want the arguments unmetafied after all.
*/
@@ -4457,14 +4554,24 @@ bin_print(char *name, char **args, Options ops, int func)
OPT_ISSET(ops,'N') ? '\0' : ' ', fout);
}
}
- if (!(OPT_ISSET(ops,'n') || nnl))
+ if (!(OPT_ISSET(ops,'n') || OPT_ISSET(ops, 'v') || nnl))
fputc(OPT_ISSET(ops,'N') ? '\0' : '\n', fout);
- /* Testing EBADF special-cases >&- redirections */
- if ((fout != stdout) ? (fclose(fout) != 0) :
- (fflush(fout) != 0 && errno != EBADF)) {
+ if (IS_MSTREAM(fout) && (rcount = READ_MSTREAM(buf,fout)) == -1)
+ ret = 1;
+ if (!CLOSE_CLEANLY(fout) || ret) {
zwarnnam(name, "write error: %e", errno);
ret = 1;
}
+ if (buf) {
+ /* assert: we must be doing -v at this point */
+ queue_signals();
+ if (ret)
+ free(buf);
+ else
+ setsparam(OPT_ARG(ops, 'v'),
+ metafy(buf, rcount, META_REALLOC));
+ unqueue_signals();
+ }
return ret;
}
@@ -4474,20 +4581,6 @@ bin_print(char *name, char **args, Options ops, int func)
* special cases of printing to a ZLE buffer or the history, however.
*/
- if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) {
-#ifdef HAVE_OPEN_MEMSTREAM
- if ((fout = open_memstream(&buf, &mcount)) == NULL)
- zwarnnam(name, "open_memstream failed");
-#else
- int tempfd;
- char *tmpf;
- if ((tempfd = gettempfile(NULL, 1, &tmpf)) < 0
- || (fout = fdopen(tempfd, "w+")) == NULL)
- zwarnnam(name, "can't open temp file: %e", errno);
- unlink(tmpf);
-#endif
- }
-
/* printf style output */
*spec = '%';
argp = args;
@@ -4751,11 +4844,9 @@ bin_print(char *name, char **args, Options ops, int func)
}
zwarnnam(name, "%s: invalid directive", start);
if (*c) c[1] = save;
- /* Testing EBADF special-cases >&- redirections */
- if ((fout != stdout) ? (fclose(fout) != 0) :
- (fflush(fout) != 0 && errno != EBADF)) {
+ /* Why do we care about a clean close here? */
+ if (!CLOSE_CLEANLY(fout))
zwarnnam(name, "write error: %e", errno);
- }
#ifdef HAVE_OPEN_MEMSTREAM
if (buf)
free(buf);
@@ -4853,41 +4944,34 @@ bin_print(char *name, char **args, Options ops, int func)
/* if there are remaining args, reuse format string */
} while (*argp && argp != first && !fmttrunc && !OPT_ISSET(ops,'r'));
- if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) {
-#ifdef HAVE_OPEN_MEMSTREAM
- putc(0, fout);
- fclose(fout);
- fout = NULL;
-#else
- rewind(fout);
- buf = (char *)zalloc(count + 1);
- fread(buf, count, 1, fout);
- buf[count] = '\0';
-#endif
+ if (IS_MSTREAM(fout)) {
queue_signals();
- if (OPT_ISSET(ops,'z')) {
- zpushnode(bufstack, buf);
+ if ((rcount = READ_MSTREAM(buf,fout)) == -1) {
+ zwarnnam(name, "i/o error: %e", errno);
+ if (buf)
+ free(buf);
} else {
- ent = prepnexthistent();
- ent->node.nam = buf;
- ent->stim = ent->ftim = time(NULL);
- ent->node.flags = 0;
- ent->words = (short *)NULL;
- addhistnode(histtab, ent->node.nam, ent);
+ stringval = metafy(buf, rcount, META_REALLOC);
+ if (OPT_ISSET(ops,'z')) {
+ zpushnode(bufstack, stringval);
+ } else if (OPT_ISSET(ops,'v')) {
+ setsparam(OPT_ARG(ops, 'v'), stringval);
+ } else {
+ ent = prepnexthistent();
+ ent->node.nam = stringval;
+ ent->stim = ent->ftim = time(NULL);
+ ent->node.flags = 0;
+ ent->words = (short *)NULL;
+ addhistnode(histtab, ent->node.nam, ent);
+ }
}
unqueue_signals();
}
-#ifdef HAVE_OPEN_MEMSTREAM
- if (fout)
-#endif
+ if (!CLOSE_CLEANLY(fout))
{
- /* Testing EBADF special-cases >&- redirections */
- if ((fout != stdout) ? (fclose(fout) != 0) :
- (fflush(fout) != 0 && errno != EBADF)) {
- zwarnnam(name, "write error: %e", errno);
- ret = 1;
- }
+ zwarnnam(name, "write error: %e", errno);
+ ret = 1;
}
return ret;
}
@@ -6463,7 +6547,13 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
nargs = arrlen(argv);
if (nargs == 3 || nargs == 4)
{
- if (*argv[0] == '(' && *argv[nargs-1] == ')') {
+ /*
+ * As parentheses are an extension, we need to be careful ---
+ * if this is a three-argument expression that could
+ * be a binary operator, prefer that.
+ */
+ if (!strcmp(argv[0], "(") && !strcmp(argv[nargs-1],")") &&
+ (nargs != 3 || !is_cond_binary_op(argv[1]))) {
argv[nargs-1] = NULL;
argv++;
}
diff --git a/Src/exec.c b/Src/exec.c
index c0ee527b7..352615c83 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -471,9 +471,10 @@ zexecve(char *pth, char **argv, char **newenvp)
if ((fd = open(pth, O_RDONLY|O_NOCTTY)) >= 0) {
argv0 = *argv;
*argv = pth;
+ execvebuf[0] = '\0';
ct = read(fd, execvebuf, POUNDBANGLIMIT);
close(fd);
- if (ct > 0) {
+ if (ct >= 0) {
if (execvebuf[0] == '#') {
if (execvebuf[1] == '!') {
for (t0 = 0; t0 != ct; t0++)
@@ -2264,7 +2265,7 @@ addvars(Estate state, Wordcode pc, int addflags)
* is implicitly scoped.
*/
flags = (!(addflags & ADDVAR_RESTORE) &&
- locallevel > 0 && isset(WARNCREATEGLOBAL)) ?
+ locallevel > forklevel && isset(WARNCREATEGLOBAL)) ?
ASSPM_WARN_CREATE : 0;
xtr = isset(XTRACE);
if (xtr) {
@@ -2784,6 +2785,11 @@ execcmd(Estate state, int input, int output, int how, int last1)
* arguments before and no command substitution
* has provided a status.
*/
+ if (badcshglob == 1) {
+ zerr("no match");
+ lastval = 1;
+ return;
+ }
cmdoutval = use_cmdoutval ? lastval : 0;
if (varspc)
addvars(state, varspc, 0);
@@ -3225,7 +3231,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
* not terminal, unless `file' is a terminal. */
if (nullexec == 1 && fn->fd1 == 0 &&
isset(SHINSTDIN) && interact && !zleactive)
- init_io();
+ init_io(NULL);
break;
case REDIR_CLOSE:
if (fn->varid) {
@@ -3475,10 +3481,10 @@ execcmd(Estate state, int input, int output, int how, int last1)
restore_queue_signals(q);
} else if (is_builtin || is_shfunc) {
LinkList restorelist = 0, removelist = 0;
+ int do_save = 0;
/* builtin or shell function */
- if (!forked && varspc) {
- int do_save = 0;
+ if (!forked) {
if (isset(POSIXBUILTINS)) {
/*
* If it's a function or special builtin --- save
@@ -3497,7 +3503,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
if ((cflags & BINF_COMMAND) || !assign)
do_save = 1;
}
- if (do_save)
+ if (do_save && varspc)
save_params(state, varspc, &restorelist, &removelist);
}
if (varspc) {
@@ -3643,6 +3649,8 @@ execcmd(Estate state, int input, int output, int how, int last1)
}
dont_queue_signals();
lastval = execbuiltin(args, assigns, (Builtin) hn);
+ if (do_save & BINF_COMMAND)
+ errflag &= ~ERRFLAG_ERROR;
restore_queue_signals(q);
fflush(stdout);
if (save[1] == -2) {
diff --git a/Src/glob.c b/Src/glob.c
index 94b3f620d..69de15544 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1230,7 +1230,7 @@ zglob(LinkList list, LinkNode np, int nountok)
char *s;
int sense, qualsfound;
off_t data;
- char *sdata, *newcolonmod;
+ char *sdata, *newcolonmod, *ptr;
int (*func) _((char *, Statptr, off_t, char *));
/*
@@ -1273,6 +1273,9 @@ zglob(LinkList list, LinkNode np, int nountok)
*s++ = 0;
if (qualsfound == 2)
s += 2;
+ for (ptr = s; *ptr; ptr++)
+ if (*ptr == Dash)
+ *ptr = '-';
while (*s && !newcolonmod) {
func = (int (*) _((char *, Statptr, off_t, char *)))0;
if (idigit(*s)) {
@@ -3512,6 +3515,7 @@ zshtokenize(char *s, int flags)
case ')':
if (flags & ZSHTOK_SHGLOB)
break;
+ /*FALLTHROUGH*/
case '>':
case '^':
case '#':
@@ -3521,7 +3525,9 @@ zshtokenize(char *s, int flags)
case '*':
case '?':
case '=':
- for (t = ztokens; *t; t++)
+ case '-':
+ case '!':
+ for (t = ztokens; *t; t++) {
if (*t == *s) {
if (bslash)
s[-1] = (flags & ZSHTOK_SUBST) ? Bnullkeep : Bnull;
@@ -3529,6 +3535,8 @@ zshtokenize(char *s, int flags)
*s = (t - ztokens) + Pound;
break;
}
+ }
+ break;
}
bslash = 0;
}
@@ -3802,13 +3810,16 @@ qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str)
if ((prog = parse_string(str, 0))) {
int ef = errflag, lv = lastval, ret;
+ int cshglob = badcshglob;
unsetparam("reply");
setsparam("REPLY", ztrdup(name));
+ badcshglob = 0;
execode(prog, 1, 0, "globqual");
- ret = lastval;
+ if ((ret = lastval))
+ badcshglob |= cshglob;
/* Retain any user interrupt error status */
errflag = ef | (errflag & ERRFLAG_INT);
lastval = lv;
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 2d1ff87cb..0664c3694 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -1276,6 +1276,15 @@ printaliasnode(HashNode hn, int printflags)
}
if (printflags & PRINT_LIST) {
+ /* Fast fail on unrepresentable values. */
+ if (strchr(a->node.nam, '=')) {
+ zwarn("invalid alias '%s' encountered while printing aliases",
+ a->node.nam);
+ /* ### TODO: Return an error status to the C caller */
+ return;
+ }
+
+ /* Normal path. */
printf("alias ");
if (a->node.flags & ALIAS_SUFFIX)
printf("-s ");
diff --git a/Src/hashtable.h b/Src/hashtable.h
index b6346bb9a..3606e9785 100644
--- a/Src/hashtable.h
+++ b/Src/hashtable.h
@@ -53,7 +53,7 @@
#define BIN_LOGOUT 19
#define BIN_TEST 20
#define BIN_BRACKET 21
-#define BIN_EXPORT 22
+#define BIN_READONLY 22
#define BIN_ECHO 23
#define BIN_DISABLE 24
#define BIN_ENABLE 25
diff --git a/Src/init.c b/Src/init.c
index dcce1d7ce..4097327ee 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -240,13 +240,11 @@ loop(int toplevel, int justonce)
return LOOP_OK;
}
-/* Shared among parseargs(), parseopts(), init_io(), and init_misc() */
-static char *cmd;
static int restricted;
/**/
static void
-parseargs(char **argv, char **runscript)
+parseargs(char **argv, char **runscript, char **cmdptr)
{
char **x;
LinkList paramlist;
@@ -272,7 +270,7 @@ parseargs(char **argv, char **runscript)
opts[SHINSTDIN] = 0;
opts[SINGLECOMMAND] = 0;
- if (parseopts(NULL, &argv, opts, &cmd, NULL))
+ if (parseopts(NULL, &argv, opts, cmdptr, NULL))
exit(1);
/*
@@ -290,7 +288,7 @@ parseargs(char **argv, char **runscript)
if (*argv) {
if (unset(SHINSTDIN)) {
posixzero = *argv;
- if (cmd)
+ if (*cmdptr)
argzero = *argv;
else
*runscript = *argv;
@@ -299,7 +297,7 @@ parseargs(char **argv, char **runscript)
}
while (*argv)
zaddlinknode(paramlist, ztrdup(*argv++));
- } else if (!cmd)
+ } else if (!*cmdptr)
opts[SHINSTDIN] = 1;
if(isset(SINGLECOMMAND))
opts[INTERACTIVE] &= 1;
@@ -497,7 +495,7 @@ printhelp(void)
/**/
mod_export void
-init_io(void)
+init_io(char *cmd)
{
static char outbuf[BUFSIZ], errbuf[BUFSIZ];
@@ -521,6 +519,8 @@ init_io(void)
for (i = 3; i < 10; i++)
close(i);
}
+#else
+ (void)cmd;
#endif
if (shout) {
@@ -802,7 +802,7 @@ init_term(void)
/**/
void
-setupvals(void)
+setupvals(char *cmd)
{
#ifdef USE_GETPWUID
struct passwd *pswd;
@@ -1086,6 +1086,9 @@ setupvals(void)
/* Colour sequences for outputting colours in prompts and zle */
set_default_colour_sequences();
+
+ if (cmd)
+ setsparam("ZSH_EXECUTION_STRING", ztrdup(cmd));
}
/*
@@ -1267,7 +1270,7 @@ run_init_scripts(void)
/**/
void
-init_misc(void)
+init_misc(char *cmd)
{
#ifndef RESTRICTED_R
if ( restricted )
@@ -1604,6 +1607,7 @@ mod_export int
zsh_main(UNUSED(int argc), char **argv)
{
char **t, *runscript = NULL;
+ char *cmd; /* argument to -c */
int t0;
#ifdef USE_LOCALE
setlocale(LC_ALL, "");
@@ -1652,18 +1656,18 @@ zsh_main(UNUSED(int argc), char **argv)
opts[LOGINSHELL] = (**argv == '-');
opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
/* sets ZLE, INTERACTIVE, SHINSTDIN and SINGLECOMMAND */
- parseargs(argv, &runscript);
+ parseargs(argv, &runscript, &cmd);
SHTTY = -1;
- init_io();
- setupvals();
+ init_io(cmd);
+ setupvals(cmd);
init_signals();
init_bltinmods();
init_builtins();
run_init_scripts();
setupshin(runscript);
- init_misc();
+ init_misc(cmd);
for (;;) {
/*
diff --git a/Src/lex.c b/Src/lex.c
index 0f260d08f..3ea878c7b 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -35,7 +35,7 @@
/* tokens */
/**/
-mod_export char ztokens[] = "#$^*(())$=|{}[]`<>>?~`,'\"\\\\";
+mod_export char ztokens[] = "#$^*(())$=|{}[]`<>>?~`,-!'\"\\\\";
/* parts of the current token */
@@ -394,8 +394,10 @@ ctxtlex(void)
#define LX2_DQUOTE 15
#define LX2_BQUOTE 16
#define LX2_COMMA 17
-#define LX2_OTHER 18
-#define LX2_META 19
+#define LX2_DASH 18
+#define LX2_BANG 19
+#define LX2_OTHER 20
+#define LX2_META 21
static unsigned char lexact1[256], lexact2[256], lextok2[256];
@@ -405,10 +407,10 @@ initlextabs(void)
{
int t0;
static char *lx1 = "\\q\n;!&|(){}[]<>";
- static char *lx2 = ";)|$[]~({}><=\\\'\"`,";
+ static char *lx2 = ";)|$[]~({}><=\\\'\"`,-!";
for (t0 = 0; t0 != 256; t0++) {
- lexact1[t0] = LX1_OTHER;
+ lexact1[t0] = LX1_OTHER;
lexact2[t0] = LX2_OTHER;
lextok2[t0] = t0;
}
@@ -801,7 +803,7 @@ gettok(void)
return INOUTPAR;
hungetc(d);
lexstop = 0;
- if (!(incond == 1 || incmdpos))
+ if (!(isset(SHGLOB) || incond == 1 || incmdpos))
break;
return INPAR;
case LX1_OUTPAR:
@@ -919,7 +921,7 @@ gettok(void)
static enum lextok
gettokstr(int c, int sub)
{
- int bct = 0, pct = 0, brct = 0, fdpar = 0;
+ int bct = 0, pct = 0, brct = 0, seen_brct = 0, fdpar = 0;
int intpos = 1, in_brace_param = 0;
int inquote, unmatched = 0;
enum lextok peek;
@@ -1033,8 +1035,10 @@ gettokstr(int c, int sub)
}
break;
case LX2_INBRACK:
- if (!in_brace_param)
+ if (!in_brace_param) {
brct++;
+ seen_brct = 1;
+ }
c = Inbrack;
break;
case LX2_OUTBRACK:
@@ -1346,9 +1350,32 @@ gettokstr(int c, int sub)
c = Tick;
SETPAREND
break;
- }
- add(c);
- c = hgetc();
+ case LX2_DASH:
+ /*
+ * - shouldn't be treated as a special character unless
+ * we're in a pattern. Howeve,simply counting "[" doesn't
+ * work as []a-z] is a valid expression and we don't know
+ * down here what this "[" is for as $foo[stuff] is valid
+ * in zsh. So just detect an opening [, which is enough
+ * to turn this into a pattern; the Dash will be harmlessly
+ * untokenised if not wanted.
+ */
+ if (seen_brct)
+ c = Dash;
+ else
+ c = '-';
+ break;
+ case LX2_BANG:
+ /*
+ * Same logic as Dash, for ! to perform negation in range.
+ */
+ if (seen_brct)
+ c = Bang;
+ else
+ c = '!';
+ }
+ add(c);
+ c = hgetc();
if (intpos)
intpos--;
if (lexstop)
diff --git a/Src/options.c b/Src/options.c
index 2678626c7..17c46c311 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -256,7 +256,7 @@ static struct optname optns[] = {
{{NULL, "unset", OPT_EMULATE|OPT_BSHELL}, UNSET},
{{NULL, "verbose", 0}, VERBOSE},
{{NULL, "vi", 0}, VIMODE},
-{{NULL, "warncreateglobal", 0}, WARNCREATEGLOBAL},
+{{NULL, "warncreateglobal", OPT_EMULATE}, WARNCREATEGLOBAL},
{{NULL, "xtrace", 0}, XTRACE},
{{NULL, "zle", OPT_SPECIAL}, USEZLE},
{{NULL, "braceexpand", OPT_ALIAS}, /* ksh/bash */ -IGNOREBRACES},
diff --git a/Src/params.c b/Src/params.c
index d8bf83d0e..b2e889738 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2552,18 +2552,20 @@ setarrvalue(Value v, char **val)
v->pm->node.nam);
return;
} else {
- char **old, **new, **p, **q, **r;
- int pre_assignment_length;
+ char **const old = v->pm->gsu.a->getfn(v->pm);
+ char **new;
+ char **p, **q, **r; /* index variables */
+ const int pre_assignment_length = arrlen(old);
int post_assignment_length;
int i;
+ q = old;
+
if ((v->flags & VALFLAG_INV) && unset(KSHARRAYS)) {
if (v->start > 0)
v->start--;
v->end--;
}
- q = old = v->pm->gsu.a->getfn(v->pm);
- pre_assignment_length = arrlen(old);
if (v->start < 0) {
v->start += pre_assignment_length;
if (v->start < 0)
@@ -2703,30 +2705,18 @@ 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;
+ zwarn("%s parameter %s created globally in function %s",
+ pmtype, pm->node.nam, 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);
- }
}
/**/
@@ -2866,7 +2856,7 @@ mod_export Param
setsparam(char *s, char *val)
{
return assignsparam(
- s, val, isset(WARNCREATEGLOBAL) && locallevel > 0 ?
+ s, val, isset(WARNCREATEGLOBAL) && locallevel > forklevel ?
ASSPM_WARN_CREATE : 0);
}
@@ -2964,7 +2954,7 @@ mod_export Param
setaparam(char *s, char **aval)
{
return assignaparam(
- s, aval, isset(WARNCREATEGLOBAL) && locallevel >0 ?
+ s, aval, isset(WARNCREATEGLOBAL) && locallevel > forklevel ?
ASSPM_WARN_CREATE : 0);
}
@@ -2995,7 +2985,7 @@ sethparam(char *s, char **val)
if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) {
DPUTS(!v, "BUG: assigning to undeclared associative array");
createparam(t, PM_HASHED);
- checkcreate = isset(WARNCREATEGLOBAL) && locallevel > 0;
+ checkcreate = isset(WARNCREATEGLOBAL) && locallevel > forklevel;
} else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) &&
!(v->pm->node.flags & PM_SPECIAL)) {
unsetparam(t);
@@ -3059,6 +3049,7 @@ setnparam(char *s, mnumber val)
if (ss)
*ss = '\0';
pm = createparam(t, ss ? PM_ARRAY :
+ isset(POSIXIDENTIFIERS) ? PM_SCALAR :
(val.type & MN_INTEGER) ? PM_INTEGER : PM_FFLOAT);
if (!pm)
pm = (Param) paramtab->getnode(paramtab, t);
@@ -3073,7 +3064,7 @@ setnparam(char *s, mnumber val)
/* errflag |= ERRFLAG_ERROR; */
return NULL;
}
- if (!was_unset && isset(WARNCREATEGLOBAL) && locallevel > 0)
+ if (!was_unset && isset(WARNCREATEGLOBAL) && locallevel > forklevel)
check_warn_create(v->pm, "numeric");
}
setnumvalue(v, val);
@@ -3111,7 +3102,8 @@ setiparam_no_convert(char *s, zlong val)
convbase(buf, val, 10);
return assignsparam(
s, ztrdup(buf),
- isset(WARNCREATEGLOBAL) && locallevel > 0 ? ASSPM_WARN_CREATE : 0);
+ isset(WARNCREATEGLOBAL) && locallevel > forklevel ?
+ ASSPM_WARN_CREATE : 0);
}
/* Unset a parameter */
@@ -5179,9 +5171,6 @@ printparamvalue(Param p, int printflags)
}
if (printflags & PRINT_KV_PAIR)
putchar(' ');
- else if ((printflags & PRINT_TYPESET) &&
- (PM_TYPE(p->node.flags) == PM_ARRAY || PM_TYPE(p->node.flags) == PM_HASHED))
- printf("%s=", p->node.nam);
else
putchar('=');
@@ -5252,7 +5241,6 @@ mod_export void
printparamnode(HashNode hn, int printflags)
{
Param p = (Param) hn;
- int array_typeset;
if (p->node.flags & PM_UNSET) {
if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) &&
@@ -5277,28 +5265,8 @@ printparamnode(HashNode hn, int printflags)
*/
return;
}
- /*
- * Printing the value of array: this needs to be on
- * a separate line so more care is required.
- */
- array_typeset = (PM_TYPE(p->node.flags) == PM_ARRAY ||
- PM_TYPE(p->node.flags) == PM_HASHED) &&
- !(printflags & PRINT_NAMEONLY);
- if (array_typeset && (p->node.flags & PM_READONLY)) {
- /*
- * We need to create the array before making it
- * readonly.
- */
- printf("typeset -a ");
- zputs(p->node.nam, stdout);
- putchar('\n');
- printparamvalue(p, printflags);
- printflags |= PRINT_NAMEONLY;
- }
printf("typeset ");
}
- else
- array_typeset = 0;
/* Print the attributes of the parameter */
if (printflags & (PRINT_TYPE|PRINT_TYPESET)) {
@@ -5346,8 +5314,6 @@ printparamnode(HashNode hn, int printflags)
} else {
quotedzputs(p->node.nam, stdout);
- if (array_typeset)
- putchar('\n');
printparamvalue(p, printflags);
}
}
diff --git a/Src/parse.c b/Src/parse.c
index 83ba396b0..4829e3a6d 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2252,6 +2252,8 @@ void (*condlex) _((void)) = zshlex;
* cond : cond_1 { SEPER } [ DBAR { SEPER } cond ]
*/
+#define COND_SEP() (tok == SEPER && condlex != testlex && *zshlextext != ';')
+
/**/
static int
par_cond(void)
@@ -2259,11 +2261,11 @@ par_cond(void)
int p = ecused, r;
r = par_cond_1();
- while (tok == SEPER)
+ while (COND_SEP())
condlex();
if (tok == DBAR) {
condlex();
- while (tok == SEPER)
+ while (COND_SEP())
condlex();
ecispace(p, 1);
par_cond();
@@ -2284,11 +2286,11 @@ par_cond_1(void)
int r, p = ecused;
r = par_cond_2();
- while (tok == SEPER)
+ while (COND_SEP())
condlex();
if (tok == DAMPER) {
condlex();
- while (tok == SEPER)
+ while (COND_SEP())
condlex();
ecispace(p, 1);
par_cond_1();
@@ -2348,7 +2350,9 @@ par_cond_2(void)
* We fall through here on any non-numeric infix operator
* or any other time there are at least two arguments.
*/
- }
+ } else
+ while (COND_SEP())
+ condlex();
if (tok == BANG) {
/*
* In "test" compatibility mode, "! -a ..." and "! -o ..."
@@ -2366,10 +2370,10 @@ par_cond_2(void)
int r;
condlex();
- while (tok == SEPER)
+ while (COND_SEP())
condlex();
r = par_cond();
- while (tok == SEPER)
+ while (COND_SEP())
condlex();
if (tok != OUTPAR)
YYERROR(ecused);
@@ -2385,7 +2389,7 @@ par_cond_2(void)
/* Check first argument for [[ STRING ]] re-interpretation */
if (s1 /* tok != DOUTBRACK && tok != DAMPER && tok != DBAR */
&& tok != LEXERR && (!dble || n_testargs)) {
- condlex();
+ do condlex(); while (COND_SEP());
return par_cond_double(dupstring("-n"), s1);
} else
YYERROR(ecused);
@@ -2398,14 +2402,16 @@ par_cond_2(void)
* checked it does have a string representation).
*/
tok = STRING;
- }
+ } else
+ while (COND_SEP())
+ condlex();
if (tok == INANG || tok == OUTANG) {
enum lextok xtok = tok;
- condlex();
+ do condlex(); while (COND_SEP());
if (tok != STRING)
YYERROR(ecused);
s3 = tokstr;
- condlex();
+ do condlex(); while (COND_SEP());
ecadd(WCB_COND((xtok == INANG ? COND_STRLT : COND_STRGTR), 0));
ecstr(s1);
ecstr(s3);
@@ -2428,11 +2434,11 @@ par_cond_2(void)
if (!n_testargs)
dble = (s2 && *s2 == '-' && !s2[2]);
incond++; /* parentheses do globbing */
- condlex();
+ do condlex(); while (COND_SEP());
incond--; /* parentheses do grouping */
if (tok == STRING && !dble) {
s3 = tokstr;
- condlex();
+ do condlex(); while (COND_SEP());
if (tok == STRING) {
LinkList l = newlinklist();
@@ -2441,7 +2447,7 @@ par_cond_2(void)
while (tok == STRING) {
addlinknode(l, tokstr);
- condlex();
+ do condlex(); while (COND_SEP());
}
return par_cond_multi(s1, l);
} else
diff --git a/Src/pattern.c b/Src/pattern.c
index 9e8a80ae1..72c7d97d5 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -247,7 +247,7 @@ typedef unsigned long zrange_t;
*/
static const char zpc_chars[ZPC_COUNT] = {
'/', '\0', Bar, Outpar, Tilde, Inpar, Quest, Star, Inbrack, Inang,
- Hat, Pound, Bnullkeep, Quest, Star, '+', '!', '@'
+ Hat, Pound, Bnullkeep, Quest, Star, '+', Bang, '!', '@'
};
/*
@@ -257,7 +257,7 @@ static const char zpc_chars[ZPC_COUNT] = {
/**/
mod_export const char *zpc_strings[ZPC_COUNT] = {
NULL, NULL, "|", NULL, "~", "(", "?", "*", "[", "<",
- "^", "#", NULL, "?(", "*(", "+(", "!(", "@("
+ "^", "#", NULL, "?(", "*(", "+(", "!(", "\\!(", "@("
};
/*
@@ -481,7 +481,7 @@ patcompcharsset(void)
*/
zpc_special[ZPC_KSH_QUEST] = zpc_special[ZPC_KSH_STAR] =
zpc_special[ZPC_KSH_PLUS] = zpc_special[ZPC_KSH_BANG] =
- zpc_special[ZPC_KSH_AT] = Marker;
+ zpc_special[ZPC_KSH_BANG2] = zpc_special[ZPC_KSH_AT] = Marker;
}
/*
* Note that if we are using KSHGLOB, then we test for a following
@@ -1268,6 +1268,8 @@ patcomppiece(int *flagp, int paren)
kshchar = STOUC('+');
else if (*patparse == zpc_special[ZPC_KSH_BANG])
kshchar = STOUC('!');
+ else if (*patparse == zpc_special[ZPC_KSH_BANG2])
+ kshchar = STOUC('!');
else if (*patparse == zpc_special[ZPC_KSH_AT])
kshchar = STOUC('@');
else if (*patparse == zpc_special[ZPC_KSH_STAR])
@@ -1424,7 +1426,7 @@ patcomppiece(int *flagp, int paren)
DPUTS(zpc_special[ZPC_INBRACK] == Marker,
"Treating '[' as pattern character although disabled");
flags |= P_SIMPLE;
- if (*patparse == Hat || *patparse == '^' || *patparse == '!') {
+ if (*patparse == Hat || *patparse == Bang) {
patparse++;
starter = patnode(P_ANYBUT);
} else
@@ -1459,7 +1461,7 @@ patcomppiece(int *flagp, int paren)
charstart = patparse;
METACHARINC(patparse);
- if (*patparse == '-' && patparse[1] &&
+ if (*patparse == Dash && patparse[1] &&
patparse[1] != Outbrack) {
patadd(NULL, STOUC(Meta)+PP_RANGE, 1, PA_NOALIGN);
if (itok(*charstart)) {
@@ -1468,7 +1470,7 @@ patcomppiece(int *flagp, int paren)
} else {
patadd(charstart, 0, patparse-charstart, PA_NOALIGN);
}
- charstart = ++patparse; /* skip ASCII '-' */
+ charstart = ++patparse; /* skip Dash token */
METACHARINC(patparse);
}
if (itok(*charstart)) {
@@ -4245,7 +4247,8 @@ haswilds(char *str)
((str[-1] == Quest && !zpc_disables[ZPC_KSH_QUEST]) ||
(str[-1] == Star && !zpc_disables[ZPC_KSH_STAR]) ||
(str[-1] == '+' && !zpc_disables[ZPC_KSH_PLUS]) ||
- (str[-1] == '!' && !zpc_disables[ZPC_KSH_BANG]) ||
+ (str[-1] == Bang && !zpc_disables[ZPC_KSH_BANG]) ||
+ (str[-1] == '!' && !zpc_disables[ZPC_KSH_BANG2]) ||
(str[-1] == '@' && !zpc_disables[ZPC_KSH_AT]))))
return 1;
break;
diff --git a/Src/subst.c b/Src/subst.c
index d9c9d24aa..bb1dd8939 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1887,12 +1887,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
if (quotetype == QT_DOLLARS ||
quotetype == QT_BACKSLASH_PATTERN)
goto flagerr;
- if (s[1] == '-') {
+ if (s[1] == '-' || s[1] == '+') {
if (quotemod)
goto flagerr;
s++;
quotemod = 1;
- quotetype = QT_SINGLE_OPTIONAL;
+ quotetype = (*s == '-') ? QT_SINGLE_OPTIONAL :
+ QT_QUOTEDZPUTS;
} else {
if (quotetype == QT_SINGLE_OPTIONAL) {
/* extra q's after '-' not allowed */
@@ -3583,7 +3584,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
ap = aval;
if (quotemod > 0) {
- if (quotetype > QT_BACKSLASH) {
+ if (quotetype == QT_QUOTEDZPUTS) {
+ for (; *ap; ap++)
+ *ap = quotedzputs(*ap, NULL);
+ } else if (quotetype > QT_BACKSLASH) {
int sl;
char *tmp;
@@ -3626,7 +3630,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
if (!copied)
val = dupstring(val), copied = 1;
if (quotemod > 0) {
- if (quotetype > QT_BACKSLASH) {
+ if (quotetype == QT_QUOTEDZPUTS) {
+ val = quotedzputs(val, NULL);
+ } else if (quotetype > QT_BACKSLASH) {
int sl;
char *tmp;
tmp = quotestring(val, NULL, quotetype);
diff --git a/Src/text.c b/Src/text.c
index 9421d70ce..04acd2aac 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -40,9 +40,32 @@
/**/
int text_expand_tabs;
+/*
+ * Binary operators in conditions.
+ * There order is tied to the order of the definitions COND_STREQ
+ * et seq. in zsh.h.
+ */
+static const char *cond_binary_ops[] = {
+ "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
+ "-ne", "-lt", "-gt", "-le", "-ge", "=~"
+};
+
static char *tptr, *tbuf, *tlim, *tpending;
static int tsiz, tindent, tnewlins, tjob;
+/**/
+int
+is_cond_binary_op(const char *str)
+{
+ const char **op;
+ for (op = cond_binary_ops; *op; op++)
+ {
+ if (!strcmp(str, *op))
+ return 1;
+ }
+ return 0;
+}
+
static void
dec_tindent(void)
{
@@ -120,7 +143,7 @@ taddchr(int c)
/**/
static void
-taddstr(char *s)
+taddstr(const char *s)
{
int sl = strlen(s);
char c;
@@ -822,11 +845,6 @@ gettext2(Estate state)
break;
case WC_COND:
{
- static char *c1[] = {
- "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
- "-ne", "-lt", "-gt", "-le", "-ge", "=~"
- };
-
int ctype;
if (!s) {
@@ -912,7 +930,7 @@ gettext2(Estate state)
/* Binary test: `a = b' etc. */
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr(" ");
- taddstr(c1[ctype - COND_STREQ]);
+ taddstr(cond_binary_ops[ctype - COND_STREQ]);
taddstr(" ");
taddstr(ecgetstr(state, EC_NODUP, NULL));
if (ctype == COND_STREQ ||
diff --git a/Src/utils.c b/Src/utils.c
index 464097034..fd0bab320 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -387,6 +387,7 @@ putshout(int c)
return 0;
}
+#ifdef MULTIBYTE_SUPPORT
/*
* Turn a character into a visible representation thereof. The visible
* string is put together in a static buffer, and this function returns
@@ -409,9 +410,76 @@ putshout(int c)
/**/
mod_export char *
+nicechar_sel(int c, int quotable)
+{
+ static char buf[10];
+ char *s = buf;
+ c &= 0xff;
+ if (ZISPRINT(c))
+ goto done;
+ if (c & 0x80) {
+ if (isset(PRINTEIGHTBIT))
+ goto done;
+ *s++ = '\\';
+ *s++ = 'M';
+ *s++ = '-';
+ c &= 0x7f;
+ if(ZISPRINT(c))
+ goto done;
+ }
+ if (c == 0x7f) {
+ if (quotable) {
+ *s++ = '\\';
+ *s++ = 'C';
+ *s++ = '-';
+ } else
+ *s++ = '^';
+ c = '?';
+ } else if (c == '\n') {
+ *s++ = '\\';
+ c = 'n';
+ } else if (c == '\t') {
+ *s++ = '\\';
+ c = 't';
+ } else if (c < 0x20) {
+ if (quotable) {
+ *s++ = '\\';
+ *s++ = 'C';
+ *s++ = '-';
+ } else
+ *s++ = '^';
+ c += 0x40;
+ }
+ done:
+ /*
+ * The resulting string is still metafied, so check if
+ * we are returning a character in the range that needs metafication.
+ * This can't happen if the character is printed "nicely", so
+ * this results in a maximum of two bytes total (plus the null).
+ */
+ if (imeta(c)) {
+ *s++ = Meta;
+ *s++ = c ^ 32;
+ } else
+ *s++ = c;
+ *s = 0;
+ return buf;
+}
+
+/**/
+mod_export char *
nicechar(int c)
{
- static char buf[6];
+ return nicechar_sel(c, 0);
+}
+
+#else /* MULTIBYTE_SUPPORT */
+
+/**/
+mod_export char *
+nicechar(int c)
+{
+ static char buf[10];
char *s = buf;
c &= 0xff;
if (ZISPRINT(c))
@@ -427,7 +495,9 @@ nicechar(int c)
goto done;
}
if (c == 0x7f) {
- *s++ = '^';
+ *s++ = '\\';
+ *s++ = 'C';
+ *s++ = '-';
c = '?';
} else if (c == '\n') {
*s++ = '\\';
@@ -436,7 +506,9 @@ nicechar(int c)
*s++ = '\\';
c = 't';
} else if (c < 0x20) {
- *s++ = '^';
+ *s++ = '\\';
+ *s++ = 'C';
+ *s++ = '-';
c += 0x40;
}
done:
@@ -455,6 +527,24 @@ nicechar(int c)
return buf;
}
+#endif /* MULTIBYTE_SUPPORT */
+
+/*
+ * Return 1 if nicechar() would reformat this character.
+ */
+
+/**/
+mod_export int
+is_nicechar(int c)
+{
+ c &= 0xff;
+ if (ZISPRINT(c))
+ return 0;
+ if (c & 0x80)
+ return !isset(PRINTEIGHTBIT);
+ return (c == 0x7f || c == '\n' || c == '\t' || c < 0x20);
+}
+
/**/
#ifdef MULTIBYTE_SUPPORT
static mbstate_t mb_shiftstate;
@@ -507,7 +597,7 @@ mb_charinit(void)
/**/
mod_export char *
-wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
+wcs_nicechar_sel(wchar_t c, size_t *widthp, char **swidep, int quotable)
{
static char *buf;
static int bufalloc = 0, newalloc;
@@ -532,7 +622,12 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
s = buf;
if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
if (c == 0x7f) {
- *s++ = '^';
+ if (quotable) {
+ *s++ = '\\';
+ *s++ = 'C';
+ *s++ = '-';
+ } else
+ *s++ = '^';
c = '?';
} else if (c == L'\n') {
*s++ = '\\';
@@ -541,7 +636,12 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
*s++ = '\\';
c = 't';
} else if (c < 0x20) {
- *s++ = '^';
+ if (quotable) {
+ *s++ = '\\';
+ *s++ = 'C';
+ *s++ = '-';
+ } else
+ *s++ = '^';
c += 0x40;
} else if (c >= 0x80) {
ret = -1;
@@ -612,6 +712,30 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
}
/**/
+mod_export char *
+wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
+{
+ return wcs_nicechar_sel(c, widthp, swidep, 0);
+}
+
+/*
+ * Return 1 if wcs_nicechar() would reformat this character for display.
+ */
+
+/**/
+mod_export int is_wcs_nicechar(wchar_t c)
+{
+ if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
+ if (c == 0x7f || c == L'\n' || c == L'\t' || c < 0x20)
+ return 1;
+ if (c >= 0x80) {
+ return (c >= 0x100);
+ }
+ }
+ return 0;
+}
+
+/**/
mod_export int
zwcwidth(wint_t wc)
{
@@ -1326,6 +1450,9 @@ time_t lastwatch;
* If "retval" is not NULL, the return value of the first hook function to
* return non-zero is stored in *"retval". The return value is not otherwise
* available as the calling context is restored.
+ *
+ * Returns 0 if at least one function was called (regardless of that function's
+ * exit status), and 1 otherwise.
*/
/**/
@@ -2861,11 +2988,12 @@ spckword(char **s, int hist, int cmd, int ask)
if (strncmp(guess, best, preflen))
return;
/* replace the temporarily expanded prefix with the original */
- u = (char *) hcalloc(t - *s + strlen(best + preflen) + 1);
+ u = (char *) zhalloc(t - *s + strlen(best + preflen) + 1);
strncpy(u, *s, t - *s);
strcpy(u + (t - *s), best + preflen);
} else {
- u = (char *) hcalloc(strlen(best) + 2);
+ u = (char *) zhalloc(strlen(best) + 2);
+ *u = '\0';
strcpy(u + 1, best);
}
best = u;
@@ -3204,7 +3332,7 @@ zjoin(char **arr, int delim, int heap)
len += strlen(*s) + 1 + (imeta(delim) ? 1 : 0);
if (!len)
return heap? "" : ztrdup("");
- ptr = ret = (heap ? (char *) hcalloc(len) : (char *) zshcalloc(len));
+ ptr = ret = (char *) (heap ? zhalloc(len) : zalloc(len));
for (s = arr; *s; s++) {
strucpy(&ptr, *s);
if (imeta(delim)) {
@@ -3290,7 +3418,8 @@ spacesplit(char *s, int allownull, int heap, int quote)
int l = sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1);
char *(*dup)(const char *) = (heap ? dupstring : ztrdup);
- ptr = ret = (heap ? (char **) hcalloc(l) : (char **) zshcalloc(l));
+ /* ### TODO: s/calloc/alloc/ */
+ ptr = ret = (char **) (heap ? hcalloc(l) : zshcalloc(l));
if (quote) {
/*
@@ -3320,8 +3449,8 @@ spacesplit(char *s, int allownull, int heap, int quote)
t = s;
(void)findsep(&s, NULL, quote);
if (s > t || allownull) {
- *ptr = (heap ? (char *) hcalloc((s - t) + 1) :
- (char *) zshcalloc((s - t) + 1));
+ *ptr = (char *) (heap ? zhalloc((s - t) + 1) :
+ zalloc((s - t) + 1));
ztrncpy(*ptr++, t, s - t);
} else
*ptr++ = dup(nulstring);
@@ -3511,7 +3640,7 @@ sepjoin(char **s, char *sep, int heap)
}
sl = strlen(sep);
for (t = s, l = 1 - sl; *t; l += strlen(*t) + sl, t++);
- r = p = (heap ? (char *) hcalloc(l) : (char *) zshcalloc(l));
+ r = p = (char *) (heap ? zhalloc(l) : zalloc(l));
t = s;
while (*t) {
strucpy(&p, *t);
@@ -3538,14 +3667,14 @@ sepsplit(char *s, char *sep, int allownull, int heap)
sl = strlen(sep);
n = wordcount(s, sep, 1);
- r = p = (heap ? (char **) hcalloc((n + 1) * sizeof(char *)) :
- (char **) zshcalloc((n + 1) * sizeof(char *)));
+ r = p = (char **) (heap ? zhalloc((n + 1) * sizeof(char *)) :
+ zalloc((n + 1) * sizeof(char *)));
for (t = s; n--;) {
tt = t;
(void)findsep(&t, sep, 0);
- *p = (heap ? (char *) hcalloc(t - tt + 1) :
- (char *) zshcalloc(t - tt + 1));
+ *p = (char *) (heap ? zhalloc(t - tt + 1) :
+ zalloc(t - tt + 1));
strncpy(*p, tt, t - tt);
(*p)[t - tt] = '\0';
p++;
@@ -3759,7 +3888,7 @@ inittyptab(void)
typtab['\0'] |= IMETA;
typtab[STOUC(Meta) ] |= IMETA;
typtab[STOUC(Marker)] |= IMETA;
- for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Comma); t0++)
+ for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(LAST_NORMAL_TOK); t0++)
typtab[t0] |= ITOK | IMETA;
for (t0 = (int)STOUC(Snull); t0 <= (int)STOUC(Nularg); t0++)
typtab[t0] |= ITOK | IMETA | INULL;
@@ -4832,12 +4961,15 @@ niceztrlen(char const *s)
* If outstrp is not NULL, set *outstrp to a zalloc'd version of
* the output (still metafied).
*
- * If "heap" is non-zero, use the heap for *outstrp, else zalloc.
+ * If flags contains NICEFLAG_HEAP, use the heap for *outstrp, else
+ * zalloc.
+ * If flags contsins NICEFLAG_QUOTE, the output is going to be within
+ * $'...', so quote "'" with a backslash.
*/
/**/
mod_export size_t
-mb_niceformat(const char *s, FILE *stream, char **outstrp, int heap)
+mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags)
{
size_t l = 0, newl;
int umlen, outalloc, outleft, eol = 0;
@@ -4872,7 +5004,7 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int heap)
/* FALL THROUGH */
case MB_INVALID:
/* The byte didn't convert, so output it as a \M-... sequence. */
- fmt = nicechar(*ptr);
+ fmt = nicechar_sel(*ptr, flags & NICEFLAG_QUOTE);
newl = strlen(fmt);
cnt = 1;
/* Get mbs out of its undefined state. */
@@ -4884,7 +5016,10 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int heap)
cnt = 1;
/* FALL THROUGH */
default:
- fmt = wcs_nicechar(c, &newl, NULL);
+ if (c == L'\'' && (flags & NICEFLAG_QUOTE))
+ fmt = "\\'";
+ else
+ fmt = wcs_nicechar_sel(c, &newl, NULL, flags & NICEFLAG_QUOTE);
break;
}
@@ -4918,13 +5053,76 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int heap)
if (outstrp) {
*outptr = '\0';
/* Use more efficient storage for returned string */
- *outstrp = heap ? dupstring(outstr) : ztrdup(outstr);
- free(outstr);
+ if (flags & NICEFLAG_NODUP)
+ *outstrp = outstr;
+ else {
+ *outstrp = (flags & NICEFLAG_HEAP) ? dupstring(outstr) :
+ ztrdup(outstr);
+ free(outstr);
+ }
}
return l;
}
+/*
+ * Return 1 if mb_niceformat() would reformat this string, else 0.
+ */
+
+/**/
+mod_export int
+is_mb_niceformat(const char *s)
+{
+ int umlen, eol = 0, ret = 0;
+ wchar_t c;
+ char *ums, *ptr;
+ mbstate_t mbs;
+
+ ums = ztrdup(s);
+ untokenize(ums);
+ ptr = unmetafy(ums, &umlen);
+
+ memset(&mbs, 0, sizeof mbs);
+ while (umlen > 0) {
+ size_t cnt = eol ? MB_INVALID : mbrtowc(&c, ptr, umlen, &mbs);
+
+ switch (cnt) {
+ case MB_INCOMPLETE:
+ eol = 1;
+ /* FALL THROUGH */
+ case MB_INVALID:
+ /* The byte didn't convert, so output it as a \M-... sequence. */
+ if (is_nicechar(*ptr)) {
+ ret = 1;
+ break;
+ }
+ cnt = 1;
+ /* Get mbs out of its undefined state. */
+ memset(&mbs, 0, sizeof mbs);
+ break;
+ case 0:
+ /* Careful: converting '\0' returns 0, but a '\0' is a
+ * real character for us, so we should consume 1 byte. */
+ cnt = 1;
+ /* FALL THROUGH */
+ default:
+ if (is_wcs_nicechar(c))
+ ret = 1;
+ break;
+ }
+
+ if (ret)
+ break;
+
+ umlen -= cnt;
+ ptr += cnt;
+ }
+
+ free(ums);
+
+ return ret;
+}
+
/* ztrdup multibyte string with nice formatting */
/**/
@@ -4933,7 +5131,7 @@ nicedup(const char *s, int heap)
{
char *retstr;
- (void)mb_niceformat(s, NULL, &retstr, heap);
+ (void)mb_niceformat(s, NULL, &retstr, heap ? NICEFLAG_HEAP : 0);
return retstr;
}
@@ -5072,6 +5270,21 @@ mb_metastrlenend(char *ptr, int width, char *eptr)
ret = mbrtowc(&wc, &inchar, 1, &mb_shiftstate);
if (ret == MB_INCOMPLETE) {
+ /*
+ * "num_in_char" is only used for incomplete characters.
+ * The assumption is that we will output all trailing octets
+ * that form part of an incomplete character as a single
+ * character (of single width) if we don't get a complete
+ * character. This is purely pragmatic --- I'm not aware
+ * of a standard way of dealing with incomplete characters.
+ *
+ * If we do get a complete character, num_in_char
+ * becomes irrelevant and is set to zero
+ *
+ * This is in contrast to "num" which counts the characters
+ * or widths in complete characters. The two are summed,
+ * so we don't count characters twice.
+ */
num_in_char++;
} else {
if (ret == MB_INVALID) {
@@ -5098,8 +5311,8 @@ mb_metastrlenend(char *ptr, int width, char *eptr)
}
}
- /* If incomplete, treat remainder as trailing single bytes */
- return num + num_in_char;
+ /* If incomplete, treat remainder as trailing single character */
+ return num + (num_in_char ? 1 : 0);
}
/*
@@ -5712,25 +5925,76 @@ quotestring(const char *s, char **e, int instring)
return v;
}
-/* Unmetafy and output a string, quoted if it contains special characters. */
+/*
+ * Unmetafy and output a string, quoted if it contains special
+ * characters.
+ *
+ * If stream is NULL, return the same output with any allocation on the
+ * heap.
+ */
/**/
-mod_export int
+mod_export char *
quotedzputs(char const *s, FILE *stream)
{
int inquote = 0, c;
+ char *outstr, *ptr;
/* check for empty string */
- if(!*s)
- return fputs("''", stream);
+ if(!*s) {
+ if (!stream)
+ return dupstring("''");
+ fputs("''", stream);
+ return NULL;
+ }
- if (!hasspecial(s))
- return zputs(s, stream);
+#ifdef MULTIBYTE_SUPPORT
+ if (is_mb_niceformat(s)) {
+ if (stream) {
+ fputs("$'", stream);
+ mb_niceformat(s, stream, NULL, NICEFLAG_QUOTE);
+ fputc('\'', stream);
+ return NULL;
+ } else {
+ char *substr;
+ mb_niceformat(s, NULL, &substr, NICEFLAG_QUOTE|NICEFLAG_NODUP);
+ outstr = (char *)zhalloc(4 + strlen(substr));
+ sprintf(outstr, "$'%s'", substr);
+ free(substr);
+ return outstr;
+ }
+ }
+#endif /* MULTIBYTE_SUPPORT */
+ if (!hasspecial(s)) {
+ if (stream) {
+ zputs(s, stream);
+ return NULL;
+ } else {
+ return dupstring(s);
+ }
+ }
+
+ if (!stream) {
+ const char *cptr;
+ int l = strlen(s) + 2;
+ for (cptr = s; *cptr; cptr++) {
+ if (*cptr == Meta)
+ cptr++;
+ else if (*cptr == '\'')
+ l += isset(RCQUOTES) ? 1 : 3;
+ }
+ ptr = outstr = zhalloc(l + 1);
+ } else {
+ ptr = outstr = NULL;
+ }
if (isset(RCQUOTES)) {
/* use rc-style quotes-within-quotes for the whole string */
- if(fputc('\'', stream) < 0)
- return EOF;
+ if (stream) {
+ if (fputc('\'', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\'';
while(*s) {
if (*s == Meta)
c = *++s ^ 32;
@@ -5738,53 +6002,98 @@ quotedzputs(char const *s, FILE *stream)
c = *s;
s++;
if (c == '\'') {
- if(fputc('\'', stream) < 0)
- return EOF;
- } else if(c == '\n' && isset(CSHJUNKIEQUOTES)) {
- if(fputc('\\', stream) < 0)
- return EOF;
+ if (stream) {
+ if (fputc('\'', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\'';
+ } else if (c == '\n' && isset(CSHJUNKIEQUOTES)) {
+ if (stream) {
+ if (fputc('\\', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\\';
+ }
+ if (stream) {
+ if (fputc(c, stream) < 0)
+ return NULL;
+ } else {
+ if (imeta(c)) {
+ *ptr++ = Meta;
+ *ptr++ = c ^ 32;
+ } else
+ *ptr++ = c;
}
- if(fputc(c, stream) < 0)
- return EOF;
}
- if(fputc('\'', stream) < 0)
- return EOF;
+ if (stream) {
+ if (fputc('\'', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\'';
} else {
/* use Bourne-style quoting, avoiding empty quoted strings */
- while(*s) {
+ while (*s) {
if (*s == Meta)
c = *++s ^ 32;
else
c = *s;
s++;
if (c == '\'') {
- if(inquote) {
- if(fputc('\'', stream) < 0)
- return EOF;
+ if (inquote) {
+ if (stream) {
+ if (putc('\'', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\'';
inquote=0;
}
- if(fputs("\\'", stream) < 0)
- return EOF;
+ if (stream) {
+ if (fputs("\\'", stream) < 0)
+ return NULL;
+ } else {
+ *ptr++ = '\\';
+ *ptr++ = '\'';
+ }
} else {
if (!inquote) {
- if(fputc('\'', stream) < 0)
- return EOF;
+ if (stream) {
+ if (fputc('\'', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\'';
inquote=1;
}
- if(c == '\n' && isset(CSHJUNKIEQUOTES)) {
- if(fputc('\\', stream) < 0)
- return EOF;
+ if (c == '\n' && isset(CSHJUNKIEQUOTES)) {
+ if (stream) {
+ if (fputc('\\', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\\';
+ }
+ if (stream) {
+ if (fputc(c, stream) < 0)
+ return NULL;
+ } else {
+ if (imeta(c)) {
+ *ptr++ = Meta;
+ *ptr++ = c ^ 32;
+ } else
+ *ptr++ = c;
}
- if(fputc(c, stream) < 0)
- return EOF;
}
}
if (inquote) {
- if(fputc('\'', stream) < 0)
- return EOF;
+ if (stream) {
+ if (fputc('\'', stream) < 0)
+ return NULL;
+ } else
+ *ptr++ = '\'';
}
}
- return 0;
+ if (!stream)
+ *ptr++ = '\0';
+
+ return outstr;
}
/* Double-quote a metafied string. */
diff --git a/Src/zsh.h b/Src/zsh.h
index d3bfcefcc..b83b8bdbb 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -192,24 +192,31 @@ struct mathfunc {
#define Tilde ((char) 0x98)
#define Qtick ((char) 0x99)
#define Comma ((char) 0x9a)
+#define Dash ((char) 0x9b) /* Only in patterns */
+#define Bang ((char) 0x9c) /* Only in patterns */
+/*
+ * Marks the last of the group above.
+ * Remaining tokens are even more special.
+ */
+#define LAST_NORMAL_TOK Bang
/*
* Null arguments: placeholders for single and double quotes
* and backslashes.
*/
-#define Snull ((char) 0x9b)
-#define Dnull ((char) 0x9c)
-#define Bnull ((char) 0x9d)
+#define Snull ((char) 0x9d)
+#define Dnull ((char) 0x9e)
+#define Bnull ((char) 0x9f)
/*
* Backslash which will be returned to "\" instead of being stripped
* when we turn the string into a printable format.
*/
-#define Bnullkeep ((char) 0x9e)
+#define Bnullkeep ((char) 0xa0)
/*
* Null argument that does not correspond to any character.
* This should be last as it does not appear in ztokens and
* is used to initialise the IMETA type in inittyptab().
*/
-#define Nularg ((char) 0x9f)
+#define Nularg ((char) 0xa1)
/*
* Take care to update the use of IMETA appropriately when adding
@@ -220,7 +227,7 @@ struct mathfunc {
* Also used in pattern character arrays as guaranteed not to
* mark a character in a string.
*/
-#define Marker ((char) 0xa0)
+#define Marker ((char) 0xa2)
/* chars that need to be quoted if meant literally */
@@ -272,7 +279,12 @@ enum {
/*
* As QT_BACKSLASH, but a NULL string is shown as ''.
*/
- QT_BACKSLASH_SHOWNULL
+ QT_BACKSLASH_SHOWNULL,
+ /*
+ * Quoting as produced by quotedzputs(), used for human
+ * readability of parameter values.
+ */
+ QT_QUOTEDZPUTS
};
#define QT_IS_SINGLE(x) ((x) == QT_SINGLE || (x) == QT_SINGLE_OPTIONAL)
@@ -1538,6 +1550,7 @@ enum zpc_chars {
ZPC_KSH_STAR, /* * for *(...) in KSH_GLOB */
ZPC_KSH_PLUS, /* + for +(...) in KSH_GLOB */
ZPC_KSH_BANG, /* ! for !(...) in KSH_GLOB */
+ ZPC_KSH_BANG2, /* ! for !(...) in KSH_GLOB, untokenised */
ZPC_KSH_AT, /* @ for @(...) in KSH_GLOB */
ZPC_COUNT /* Number of special chararacters */
};
@@ -3051,6 +3064,13 @@ enum {
#define AFTERTRAPHOOK (zshhooks + 2)
#ifdef MULTIBYTE_SUPPORT
+/* Final argument to mb_niceformat() */
+enum {
+ NICEFLAG_HEAP = 1, /* Heap allocation where needed */
+ NICEFLAG_QUOTE = 2, /* Result will appear in $'...' */
+ NICEFLAG_NODUP = 4, /* Leave allocated */
+};
+
/* Metafied input */
#define nicezputs(str, outs) (void)mb_niceformat((str), (outs), NULL, 0)
#define MB_METACHARINIT() mb_charinit()
diff --git a/Test/A02alias.ztst b/Test/A02alias.ztst
index 389617898..49e47567c 100644
--- a/Test/A02alias.ztst
+++ b/Test/A02alias.ztst
@@ -96,3 +96,11 @@
0:unalias -as
>foo is a suffix alias for print
>foo: suffix alias
+
+ aliases[x=y]=z
+ alias -L | grep x=y
+ echo $pipestatus[1]
+0:printing invalid aliases warns
+>0
+?(eval):2: invalid alias 'x=y' encountered while printing aliases
+# Currently, 'alias -L' returns 0 in this case. Perhaps it should return 1.
diff --git a/Test/A06assign.ztst b/Test/A06assign.ztst
index 1e3d2ede9..da4e3b0fe 100644
--- a/Test/A06assign.ztst
+++ b/Test/A06assign.ztst
@@ -437,8 +437,7 @@
typeset -p i n x f)
0:GLOB_ASSIGN with numeric types
>typeset -i i=0
->typeset -a n
->n=( tmpfile1 tmpfile2 )
+>typeset -a n=( tmpfile1 tmpfile2 )
>typeset x=tmpfile2
>typeset -E f=4.000000000e+00
@@ -478,3 +477,15 @@
>first second
>first
>second
+
+ typeset -aU unique_array=(first second)
+ unique_array[1]=second
+ print $unique_array
+0:assignment to unique array
+>second
+
+ typeset -a array=(first)
+ array[1,3]=(FIRST)
+ print $array
+0:slice beyond length of array
+>FIRST
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index fc8b3e46e..d6d24210b 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -454,8 +454,7 @@
fn() { typeset -p array nonexistent; }
fn
1:declare -p shouldn't create scoped values
->typeset -a array
->array=( foo bar )
+>typeset -a array=( foo bar )
?fn:typeset: no such variable: nonexistent
unsetopt typesetsilent
@@ -480,12 +479,12 @@
setopt POSIXBUILTINS
readonly pbro
print ${+pbro} >&2
- (typeset pbro=3)
+ (typeset -g pbro=3)
(pbro=4)
- readonly -p | grep pbro >&2 # shows up as "readonly" although unset
- typeset -r pbro # idempotent (no error)...
+ readonly -p pbro >&2 # shows up as "readonly" although unset
+ typeset -gr pbro # idempotent (no error)...
print ${+pbro} >&2 # ...so still readonly...
- typeset +r pbro # ...can't turn it off
+ typeset -g +r pbro # ...can't turn it off
)
1:readonly with POSIX_BUILTINS
?0
@@ -508,11 +507,8 @@
typeset -pm 'a[12]'
typeset -pm 'r[12]'
0:readonly -p output
->typeset -a a1
->a1=( one two )
->typeset -ar a1
->typeset -a a2
->a2=( three four )
+>typeset -ar a1=( one two )
+>typeset -a a2=( three four )
>typeset -r r1=yes
>typeset -r r2=no
@@ -707,8 +703,11 @@
fn
print $array
0:setting empty array in typeset
->typeset -a array
->array=( '' two '' four )
->typeset -a array
->array=( one '' three )
+>typeset -a array=( '' two '' four )
+>typeset -a array=( one '' three )
>no really nothing here
+
+ readonly isreadonly=yes
+ typeset isreadonly=still
+1:typeset returns status 1 if setting readonly variable
+?(eval):2: read-only variable: isreadonly
diff --git a/Test/B03print.ztst b/Test/B03print.ztst
index eb79c4ddb..befe2f2dd 100644
--- a/Test/B03print.ztst
+++ b/Test/B03print.ztst
@@ -301,3 +301,12 @@
>one two three four
> one two three four
> one two three four
+
+ unset foo
+ print -v foo once more
+ typeset -p foo
+ printf -v foo "%s\0%s-" into the breach
+ typeset -p foo
+0:print and printf into a variable
+>typeset foo='once more'
+>typeset foo=$'into\C-@the-breach\C-@-'
diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst
index c7bd81fc3..61da763ac 100644
--- a/Test/C01arith.ztst
+++ b/Test/C01arith.ztst
@@ -409,3 +409,14 @@
>2
>(eval):6: bad math expression: unexpected ')'
>(eval):7: bad math expression: unexpected ')'
+
+ unset number
+ (( number = 3 ))
+ print ${(t)number}
+ unset number
+ (setopt posix_identifiers
+ (( number = 3 ))
+ print ${(t)number})
+0:type of variable when created in arithmetic context
+>integer
+>scalar
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index 40bbf424a..0b4608a21 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -154,7 +154,7 @@
ZTST_skip="[[ -N file ]] not supported on Cygwin"
elif (( isnfs )); then
ZTST_skip="[[ -N file ]] not supported with NFS"
- elif test -f /etc/mtab && { grep $(df . 2>/dev/null| tail -n1 | awk '{print $1}') /etc/mtab | grep -q noatime; }; then
+ elif { df -k -- ${$({mount || /sbin/mount} | awk '/noatime/ {print $1,$3}'):-""} | tr -s ' ' | fgrep "$(df -k . | tail -1 | tr -s ' ')" } >&/dev/null; then
ZTST_skip="[[ -N file ]] not supported with noatime file system"
else
[[ -N $newnewnew && ! -N $unmodified ]]
@@ -389,6 +389,18 @@ F:Failures in these cases do not indicate a problem in the shell.
>Not zero 5
>Not zero 6
+ [ '(' = ')' ] || print OK 1
+ [ '((' = '))' ] || print OK 2
+ [ '(' = '(' ] && print OK 3
+ [ '(' non-empty-string ')' ] && echo OK 4
+ [ '(' '' ')' ] || echo OK 5
+0:yet more old-fashioned test fix ups: prefer comparison to parentheses
+>OK 1
+>OK 2
+>OK 3
+>OK 4
+>OK 5
+
%clean
# This works around a bug in rm -f in some versions of Cygwin
chmod 644 unmodish
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index f944a4fbd..a6b704a8e 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -582,3 +582,76 @@
>1 OK
>2 OK
>3 OK
+
+ [[ foo = 'f'\o"o" ]]
+0:Stripping of quotes from patterns (1)
+
+ [[ foo = 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (2)
+
+ [[ fob = 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (3)
+
+ [[ fab = 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (4)
+
+ [[ fib != 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (4)
+
+ [[ - != [a-z] ]]
+0:- is a special character in ranges
+
+ [[ - = ['a-z'] ]]
+0:- is not a special character in ranges if quoted
+
+ [[ b-1 = [a-z]-[0-9] ]]
+0:- untokenized following a bracketed subexpression
+
+ [[ b-1 = []a-z]-[]0-9] ]]
+0:- "]" after "[" is normal range character and - still works
+
+ headremove="bcdef"
+ print ${headremove#[a-z]}
+0:active - works in pattern in parameter
+>cdef
+
+ headremove="bcdef"
+ print ${headremove#['a-z']}
+ headremove="-cdef"
+ print ${headremove#['a-z']}
+0:quoted - works in pattern in parameter
+>bcdef
+>cdef
+
+ [[ a != [^a] ]]
+0:^ active in character class if not quoted
+
+ [[ a = ['^a'] ]]
+0:^ not active in character class if quoted
+
+ [[ a != [!a] ]]
+0:! active in character class if not quoted
+
+ [[ a = ['!a'] ]]
+0:! not active in character class if quoted
+
+ # Actually, we don't need the quoting here,
+ # c.f. the next test. This just makes it look
+ # more standard.
+ cset="^a-z"
+ [[ "^" = ["$cset"] ]] || print Fail 1
+ [[ "a" = ["$cset"] ]] || print Fail 2
+ [[ "-" = ["$cset"] ]] || print Fail 3
+ [[ "z" = ["$cset"] ]] || print Fail 4
+ [[ "1" != ["$cset"] ]] || print Fail 5
+ [[ "b" != ["$cset"] ]] || print Fail 6
+0:character set specified as quoted variable
+
+ cset="^a-z"
+ [[ "^" = [$~cset] ]] || print Fail 1
+ [[ "a" != [$~cset] ]] || print Fail 2
+ [[ "-" = [$~cset] ]] || print Fail 3
+ [[ "z" != [$~cset] ]] || print Fail 4
+ [[ "1" = [$~cset] ]] || print Fail 5
+ [[ "b" != [$~cset] ]] || print Fail 6
+0:character set specified as active variabe
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index a3c5d71df..bcea980ad 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -396,7 +396,7 @@
>Instead Here I Am Stuck By The Computer
foo=$'\x7f\x00'
- print ${(V)foo}
+ print -r -- ${(V)foo}
0:${(V)...}
>^?^@
@@ -1866,3 +1866,17 @@
>0
>1 /somewhere
>2 /random /value
+
+ print -r -- ${(q+):-}
+ print -r -- ${(q+)IFS}
+ print -r -- ${(q+):-oneword}
+ print -r -- ${(q+):-two words}
+ print -r -- ${(q+):-three so-called \'words\'}
+ (setopt rcquotes; print -r -- ${(q+):-three so-called \'words\'})
+0:${(q+)...}
+>''
+>$' \t\n\C-@'
+>oneword
+>'two words'
+>'three so-called '\''words'\'
+>'three so-called ''words'''
diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index f95c06d9a..39ba5ef8b 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -546,3 +546,10 @@
[[ $'\xe3\x83\x9b' != [[:INCOMPLETE:][:INVALID:]] ]] || print fail 3
[[ $'\xe3\x83\x9b' = ? ]] || print fail 4
0:Testing incomplete and invalid multibyte character components
+
+ print -r -- ${(q+):-ホ}
+ foo='She said "ホ". I said "You can'\''t '\''ホ'\'' me!'
+ print -r -- ${(q+)foo}
+0:${(q+)...} with printable multibyte characters
+>ホ
+>'She said "ホ". I said "You can'\''t '\''ホ'\'' me!'
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index c9427c755..f27076765 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1120,6 +1120,15 @@
?fn:5: scalar parameter foo1 created globally in function fn
?fn:15: numeric parameter foo5 created globally in function fn
+ fn() {
+ emulate -L zsh
+ setopt warncreateglobal
+ TZ=UTC date >&/dev/null
+ local um=$(TZ=UTC date 2>/dev/null)
+ }
+ fn
+0:WARN_CREATE_GLOBAL negative cases
+
# This really just tests if XTRACE is egregiously broken.
# To test it properly would need a full set of its own.
fn() { print message; }
diff --git a/Test/V07pcre.ztst b/Test/V07pcre.ztst
index ddfd3f5cd..39077564c 100644
--- a/Test/V07pcre.ztst
+++ b/Test/V07pcre.ztst
@@ -37,6 +37,17 @@
>o→b
>→
+ unset match mend
+ s=$'\u00a0'
+ [[ $s =~ '^.$' ]] && print OK
+ [[ A${s}B =~ .(.). && $match[1] == $s ]] && print OK
+ [[ A${s}${s}B =~ A([^[:ascii:]]*)B && $mend[1] == 3 ]] && print OK
+ unset s
+0:Raw IMETA characters in input string
+>OK
+>OK
+>OK
+
[[ foo =~ f.+ ]] ; print $?
[[ foo =~ x.+ ]] ; print $?
[[ ! foo =~ f.+ ]] ; print $?
diff --git a/Test/V09datetime.ztst b/Test/V09datetime.ztst
index 63ff4ee23..7905155d8 100644
--- a/Test/V09datetime.ztst
+++ b/Test/V09datetime.ztst
@@ -69,6 +69,6 @@
>090
>1
- print ${(V)"$(strftime $'%Y\0%m\0%d' 100000000)"}
+ print -r -- ${(V)"$(strftime $'%Y\0%m\0%d' 100000000)"}
0:Embedded nulls
>1973^@03^@03
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index 513a3c43d..320e35764 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -127,12 +127,9 @@
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 )
+>typeset -a hash_test=( top level )
+>typeset -A hash_test=( in function )
+>typeset -a hash_test=( top level )
>array-local top level
>top level
F:note "typeset" rather than "private" in output from outer
diff --git a/Test/X03zlebindkey.ztst b/Test/X03zlebindkey.ztst
new file mode 100644
index 000000000..013d3dfb3
--- /dev/null
+++ b/Test/X03zlebindkey.ztst
@@ -0,0 +1,128 @@
+# Tests of the bindkey command.
+# This concentrates on the command itself and also resolving keystrokes
+# into bindings. The latter is particularly tricky with multibyte sequences.
+
+%prep
+ ZSH_TEST_LANG=
+ langs=(en_{US,GB}.{UTF-,utf}8 en.UTF-8
+ $(locale -a 2>/dev/null | egrep 'utf8|UTF-8'))
+ for LANG in $langs; do
+ if [[ é = ? ]]; then
+ ZSH_TEST_LANG=$LANG
+ break;
+ fi
+ done
+ if [[ $OSTYPE = cygwin ]]; then
+ ZTST_unimplemented="the zsh/zpty module does not work on Cygwin"
+ elif ( zmodload zsh/zpty 2>/dev/null ); then
+ . $ZTST_srcdir/comptest
+ comptestinit -z $ZTST_testdir/../Src/zsh
+ else
+ ZTST_unimplemented="the zsh/zpty module is not available"
+ fi
+
+%test
+
+ zpty_run 'bindkey -s "\C-xy" foo'
+ zletest $'\C-xy'
+ zpty_run 'bindkey -r "\C-xy"'
+0:bindkey -s
+>BUFFER: foo
+>CURSOR: 3
+
+ zpty_run 'bindkey -s "\C-xy" foo'
+ zpty_run 'bindkey -s "\C-x\C-y" bar'
+ zletest $'\C-xy\C-x\C-y'
+ zpty_run 'bindkey -r "\C-xy"'
+ zpty_run 'bindkey -r "\C-x\C-y"'
+0:bindkey with multiple definitions associated with prefix
+>BUFFER: foobar
+>CURSOR: 6
+
+ bindkey -s '\C-xy' bar
+ bindkey '\C-xy'
+ bindkey -r '\C-xy'
+ bindkey '\C-xy'
+0:bindkey output
+>"^Xy" "bar"
+>"^Xy" undefined-key
+
+# As we're only looking at definitions here, we don't
+# bother using the pseudo-terminal; just test in the normal fashion.
+ bindkey -e
+ bindkey -s '\C-xy' foo
+ bindkey -N testmap emacs
+ bindkey -M testmap '\C-xy'
+ bindkey -s -M testmap '\C-xy' bar
+ bindkey -M testmap '\C-xy'
+ bindkey '\C-xy'
+ bindkey -A testmap main
+ bindkey '\C-xy'
+ bindkey -A emacs main
+ bindkey '\C-xy'
+0:creating keymaps from existing keymaps
+>"^Xy" "foo"
+>"^Xy" "bar"
+>"^Xy" "foo"
+>"^Xy" "bar"
+>"^Xy" "foo"
+
+# Depends on the keymap created in the previous test.
+ bindkey -l
+ bindkey -D testmap
+ print Deleted...
+ bindkey -l
+0:deleting keymaps
+>.safe
+>command
+>emacs
+>isearch
+>main
+>testmap
+>vicmd
+>viins
+>viopp
+>visual
+>Deleted...
+>.safe
+>command
+>emacs
+>isearch
+>main
+>vicmd
+>viins
+>viopp
+>visual
+
+# This \M... style display of 8-bit characters is a bit
+# dated in multibyte mode, but no one's complained...
+ if [[ -z $ZSH_TEST_LANG ]]; then
+ ZTST_skip="multibyte not available for bindkey test"
+ else
+ bindkey | grep '\\M.*self-insert'
+ fi
+0:in multibyte mode all bytes with bit 7 set start self-insert
+>"\M-^@"-"\M-^?" self-insert
+
+ if [[ -z $ZSH_TEST_LANG ]]; then
+ ZTST_skip="multibyte not available for bindkey test"
+ else
+ zpty_run 'alias unbind="bindkey -r ホ"'
+ zpty_run 'bindkey -s ホ bar'
+ zletest 'ホ'
+ zpty_run unbind
+ zletest 'ホ'
+ zpty_run 'bindkey ホ self-insert'
+ zletest 'ホ'
+ zpty_run unbind
+ zletest 'ホ'
+ fi
+0:bindkey -s multibyte characters
+>BUFFER: bar
+>CURSOR: 3
+>BUFFER: ホ
+>CURSOR: 1
+>BUFFER: ホ
+>CURSOR: 1
+>BUFFER: ホ
+>CURSOR: 1
diff --git a/Test/comptest b/Test/comptest
index f10739abe..166d0b404 100644
--- a/Test/comptest
+++ b/Test/comptest
@@ -27,7 +27,7 @@ comptestinit () {
}
comptesteval \
-"export LC_ALL=C" \
+"export LC_ALL=${ZSH_TEST_LANG:-C}" \
"emulate -R zsh" \
"export ZDOTDIR=$ZTST_testdir" \
"module_path=( $module_path )" \
diff --git a/debian/changelog b/debian/changelog
index 73aef2ed7..47ef383d4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -33,6 +33,31 @@ zsh (5.2-4) unstable; urgency=low
-- Axel Beckert <abe@debian.org> Fri, 06 May 2016 22:08:29 +0200
+zsh (5.2-dev-1-1) experimental; urgency=low
+
+ [ Axel Beckert ]
+ * [86ca06fb] Import new upstream beta release.
+ * [a25e7f1f] Add "--ddeb-migration=zsh-dbg" to "dh_strip -pzsh" for
+ proper Breaks/Replaces. Thanks to Mattia Rizzolo!
+ * [370659ae] Add rosbash to bug-script's fallback list of packages with
+ code to be sourced in .zshrc.
+ * [9789916e] Remove GCC-4.9-specific workaround on s390x from
+ debian/rules.
+ * [0013070a,3b7e91b3] Enable hardening=+all, fixes multiple
+ hardening-related lintian warnings.
+ * [da1b680b,1600c44d,2d082be2] Remove usage of alternatives system for
+ zsh, rzsh and zsh-static. (Closes: #768079)
+ * [3aa2ccff] Switch Vcs-Git from git:// to https://, fixes lintian
+ warning vcs-field-uses-insecure-uri.
+ * [f3384aaf] Add patch by Bart Schaefer to fix segfault in
+ is_cond_binary_op when compiling with -fPIE (and maybe other cases).
+
+ [ Frank Terbeck ]
+ * [c1e9ec06] zshrc: Make expansion robust with NO_UNSET.
+ Thanks to Marc Chantreux on #pkg-zsh (freenode)
+
+ -- Axel Beckert <abe@debian.org> Mon, 01 Feb 2016 00:42:02 +0100
+
zsh (5.2-3) unstable; urgency=medium
[ Axel Beckert ]
diff --git a/debian/control b/debian/control
index bd2b2a1aa..b447166fe 100644
--- a/debian/control
+++ b/debian/control
@@ -25,7 +25,7 @@ Uploaders: Michael Prokop <mika@debian.org>,
Richard Hartmann <richih@debian.org>
Standards-Version: 3.9.8
Homepage: http://www.zsh.org/
-Vcs-Git: https://anonscm.debian.org/git/collab-maint/zsh.git -b debian-stretch
+Vcs-Git: https://anonscm.debian.org/git/collab-maint/zsh.git -b debian
Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/zsh.git
Package: zsh-common
diff --git a/debian/gbp.conf b/debian/gbp.conf
index 505de96f8..5d7f7dd66 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -2,7 +2,7 @@
[DEFAULT]
upstream-branch = upstream
-debian-branch = debian-stretch
+debian-branch = debian
upstream-tag = zsh-%(version)s
debian-tag = debian/%(version)s
diff --git a/debian/patches/fix-aptitude-completion-for-0.7.5-807906.patch b/debian/patches/fix-aptitude-completion-for-0.7.5-807906.patch
deleted file mode 100644
index 6fcdd1edb..000000000
--- a/debian/patches/fix-aptitude-completion-for-0.7.5-807906.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-Description: Also parse --help output of aptitude 0.7.5 and later
-Author: Axel Beckert <abe@debian.org>
-Bug-Debian: https://bugs.debian.org/807906
-Forwarded: http://www.zsh.org/mla/workers/2015/msg03350.html
-
-Index: zsh/Completion/Debian/Command/_aptitude
-===================================================================
---- zsh.orig/Completion/Debian/Command/_aptitude 2015-09-08 23:39:06.026975805 +0200
-+++ zsh/Completion/Debian/Command/_aptitude 2015-12-26 19:26:14.681265798 +0100
-@@ -80,7 +80,7 @@
-
- case $state in
- cmds)
-- cmds=( ${${(M)${(f)"$(LC_ALL=C _call_program commands aptitude -h 2>/dev/null)"}:#* - *}/(#b) (*[^ ]) #- (*)/$match[1]:$match[2]:l})
-+ cmds=( ${${(M)${(f)"$(LC_ALL=C _call_program commands aptitude -h 2>/dev/null)"}:# [^- ][^ ]## *}/(#b) ([^ ]##) ##(- )#([^- ]*)/$match[1]:$match[3]:l})
-
- _describe -t commands 'aptitude command' cmds && ret=0
- ;;
diff --git a/debian/patches/fix-segfault-in-is_cond_binary_op.patch b/debian/patches/fix-segfault-in-is_cond_binary_op.patch
new file mode 100644
index 000000000..f03362f5f
--- /dev/null
+++ b/debian/patches/fix-segfault-in-is_cond_binary_op.patch
@@ -0,0 +1,18 @@
+Description: Fix segfault in is_cond_binary_op when compiling with -fPIE
+ The issue possibly also pops up under other circumstances.
+Author: Bart Schaefer <schaefer@brasslantern.com>
+Origin: http://www.zsh.org/mla/workers/2016/msg00394.html
+
+Index: zsh/Src/text.c
+===================================================================
+--- zsh.orig/Src/text.c 2016-01-24 17:19:53.947656591 +0100
++++ zsh/Src/text.c 2016-02-01 00:15:09.098327625 +0100
+@@ -47,7 +47,7 @@
+ */
+ static const char *cond_binary_ops[] = {
+ "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
+- "-ne", "-lt", "-gt", "-le", "-ge", "=~"
++ "-ne", "-lt", "-gt", "-le", "-ge", "=~", NULL
+ };
+
+ static char *tptr, *tbuf, *tlim, *tpending;
diff --git a/debian/patches/series b/debian/patches/series
index 7fa517010..d0f0c477b 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,2 @@
further-mitigate-test-suite-hangs.patch
-update-apt-completion-808317.patch
-fix-aptitude-completion-for-0.7.5-807906.patch
+fix-segfault-in-is_cond_binary_op.patch
diff --git a/debian/patches/update-apt-completion-808317.patch b/debian/patches/update-apt-completion-808317.patch
deleted file mode 100644
index a743a0c70..000000000
--- a/debian/patches/update-apt-completion-808317.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-Description: Add missing apt purge and autoremove subcommands
-Author: Felipe Sateler <fsateler@debian.org>
-Bug-Debian: https://bugs.debian.org/808317
-Origin: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=808317;att=1;filename=_apt.diff;msg=5
-Forwarded: http://www.zsh.org/mla/workers/2015/msg03348.html
-
---- a/Completion/Debian/Command/_apt 2015-12-03 20:44:53.000000000 -0300
-+++ b/Completion/Debian/Command/_apt 2015-12-18 12:36:49.326848831 -0300
-@@ -407,10 +407,12 @@
- /$'install\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" avail' \# \
- /$'[^\0/]#/'/ /$'[^\0/]#\0'/ ':release name::_apt_releases' \) \| \
- /$'remove\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" installed' \# \| \
-+ /$'purge\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" installed' \# \| \
- /$'upgrade\0'/ \| \
-+ /$'autoremove\0'/ \| \
- /$'full-upgrade\0'/ \| \
- /$'edit-sources\0'/ \| \
-- /"[]"/ ':argument-1::compadd "$expl_action[@]" list search show update install remove upgrade full-upgrade edit-sources'
-+ /"[]"/ ':argument-1::compadd "$expl_action[@]" list search show update install remove upgrade full-upgrade edit-sources autoremove purge'
-
- _apt-cmd () {
- local expl_action expl_packages