1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-01-01 05:16:05 +01:00
This commit is contained in:
Tanaka Akira 1999-05-12 04:49:46 +00:00
parent 53d36e795b
commit ea0ddb0fc6
39 changed files with 1870 additions and 858 deletions

View file

@ -1,4 +1,4 @@
#compdef -k complete-word \C-xc
#compdef -k complete-word \C-xC
# Function to correct a filename. Can be used as a completion widget,
# or as a function in its own right, in which case it will print the

View file

@ -3,10 +3,23 @@
# Simple completion front-end implementing spelling correction.
# The maximum number of errors is set quite high, and
# the numeric prefix can be used to specify a different value.
#
# If configurations keys with the prefix `correctword_' are
# given they override those starting with `correct_'.
local oca="$compconfig[correct_accept]"
compconfig[correct_accept]=6n
local oco="$compconfig[correct_original]"
local ocp="$compconfig[correct_prompt]"
local oci="$compconfig[correct_insert]"
compconfig[correct_accept]="${compconfig[correctword_accept]-6n}"
compconfig[correct_original]="${compconfig[correctword_original]-$oco}"
compconfig[correct_prompt]="${compconfig[correctword_prompt]-$ocp}"
compconfig[correct_insert]="${compconfig[correctword_insert]}"
_main_complete _correct
compconfig[correct_accept]=$oca
compconfig[correct_accept]="$oca"
compconfig[correct_original]="$oco"
compconfig[correct_prompt]="$ocp"
compconfig[correct_insert]="$oci"

View file

@ -42,14 +42,32 @@
# If we got the `-d'-flag, we will automatically dump the new state (at
# the end).
# `-f dir' is used to pass down the directory where this file was
# found. This is necessary if functionargzero is not set.
# If we were given an argument, this will be taken as the name of the
# file in which to store the dump.
if [[ "$1" = -d ]]; then
_i_autodump=1
shift
else
_i_autodump=0
_i_fdir=''
_i_dumpfile=''
_i_autodump=0
while [[ $1 = -[df] ]]; do
if [[ "$1" = -d ]]; then
_i_autodump=1
shift
if [[ -n "$1" && "$1" != -[df] ]]; then
_i_dumpfile="$1"
shift
fi
elif [[ "$1" = -f ]]; then
# Used by compinstall to pass down directory where compinit was found
shift
_i_fdir="$1"
shift
fi
done
# Get the directory if we don't have it already and we can
if [[ -z "$_i_fdir" && -o functionargzero && $0 = */* ]]; then
_i_fdir=${0:h}
fi
# The associative array containing the definitions for the commands.
@ -63,9 +81,19 @@ _patcomps=()
typeset -A compconfig
# Standard initialisation for `compconfig'.
(( $# )) && compconfig[dumpfile]="$1"
[[ -z "$compconfig[dumpfile]" ]] && compconfig[dumpfile]="$0.dump"
if [[ -n $_i_dumpfile ]]; then
# Explicitly supplied dumpfile.
compconfig[dumpfile]="$_i_dumpfile"
elif [[ -o functionargzero ]]; then
# We can deduce it from the name of this script
compconfig[dumpfile]="$0.dump"
elif [[ -n $_i_fdir ]]; then
# We were told what directory to use.
compconfig[dumpfile]="$_i_fdir/compinit.dump"
else
# Now we're stuck, but we'd better do something.
compconfig[dumpfile]="$HOME/.compinit.dump"
fi
compconfig[correct_accept]=2n
compconfig[correct_prompt]='correct to:'
@ -180,9 +208,15 @@ compdef() {
*)
# For commands store the function name in the `_comps'
# associative array, command names as keys.
for i; do
[[ -z "$new" || "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
done
if [[ -z "$new" ]]; then
for i; do
_comps[$i]="$func"
done
else
for i; do
[[ "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
done
fi
;;
esac
else
@ -265,8 +299,24 @@ compconf() {
# Now we automatically make the definition files autoloaded.
typeset -U _i_files
_i_files=( ${^~fpath}/_(|*[^~])(N:t) )
_i_initname=$0
_i_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
if [[ $#_i_files -lt 20 ]]; then
# Too few files: we need some more directories
# Assume that we need to add the compinit directory to fpath.
if [[ -n $_i_fdir ]]; then
if [[ $_i_fdir = */Core ]]; then
# Add all the Completion subdirectories
fpath=(${_i_fdir:h}/*(/) $fpath)
elif [[ -d $_i_fdir/Core ]]; then
# Likewise
fpath=(${_i_fdir}/*(/) $fpath)
else
fpath=($_i_fdir $fpath)
fi
_i_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
fi
fi
_i_done=''
# If we have a dump file, load it.
@ -286,38 +336,45 @@ if [[ -z "$_i_done" ]]; then
read -rA _i_line < $_i_file
_i_tag=$_i_line[1]
shift _i_line
if [[ $_i_tag = '#compdef' ]]; then
case $_i_tag in
(\#compdef)
if [[ $_i_line[1] = -[pk] ]]; then
compdef ${_i_line[1]}a "${_i_file:t}" "${(@)_i_line[2,-1]}"
else
compdef -na "${_i_file:t}" "${_i_line[@]}"
fi
elif [[ $_i_tag = '#autoload' ]]; then
;;
(\#autoload)
autoload ${_i_file:t}
fi
;;
esac
done
done
bindkey |
while read -rA _i_line; do
if [[ "$_i_line[2]" = complete-word ||
"$_i_line[2]" = delete-char-or-list ||
"$_i_line[2]" = expand-or-complete ||
"$_i_line[2]" = expand-or-complete-prefix ||
"$_i_line[2]" = list-choices ||
"$_i_line[2]" = menu-complete ||
"$_i_line[2]" = menu-expand-or-complete ||
"$_i_line[2]" = reverse-menu-complete ]]; then
case "$_i_line[2]" in
(complete-word) ;&
(delete-char-or-list) ;&
(expand-or-complete) ;&
(expand-or-complete-prefix) ;&
(list-choices) ;&
(menu-complete) ;&
(menu-expand-or-complete) ;&
(reverse-menu-complete)
zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
fi
;;
esac
done
unset _i_dir _i_line _i_file _i_tag
# If autodumping was requested, do it now.
(( _i_autodump )) && builtin . ${_i_initname:h}/compdump
if [[ -n ${_i_fdir} && $_i_autodump = 1 ]]; then
builtin . ${_i_fdir}/compdump
fi
fi
unset _i_files _i_initname _i_done _i_autodump
unset _i_files _i_initname _i_done _i_autodump _i_fdir _i_dumpfile

View file

@ -1,49 +1,129 @@
# This script is to be run by a user to setup the new function based
# This script is to be run by a user to set up the new function based
# completion system. The functions themselves are assumed to be already
# available in some directory; they should have been installed with the
# the shell (except we haven't written that yet).
#
# Run it as a script under zsh and answer the questions.
# You can run it as `zsh compinstall $FPATH' and it will be able to check
# your function path for the completion functions.
# Source this script (e.g. `. /path/compinstall') and answer the questions.
#
# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it),
# but you can make that unwritable and it will leave the lines in a
# temporary file instead.
#
# You can use this script to modify what compinstall previously
# added to ~/.zshrc.
# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it), but you
# can make that unwritable and it will leave the lines in a temporary file
# instead. It doesn't matter if .zshrc didn't exist before. If your
# .zshrc usually exits before the end, then you should take the code added
# by compinstall and put it (including the comment lines at the start and
# end) at the point you want it to be executed. If you run compinstall
# again it will find and replace those lines, so you can use this script to
# modify what compinstall previously added to ~/.zshrc.
#
# It is safe to abort with ^C any time you are being prompted for
# information; your .zshrc will not be altered.
#
# To do:
# - Maybe this should be sourced, then it can check the user's current
# setup better. But then there is a potentially horrendous option
# setting/resetting problem. (Maybe we need another way of doing that.)
# - Should probably offer to set different options for _approximate than
# for _complete if both are used.
# - Could add code for setting other completers and options.
# - Could add keys for context-sensitive help.
# - Probably should allow a set of directories to be added to $fpath,
# like Core, Base, etc.
# In case a startup script changed options
# Save the options. We will need to trap ^C to make sure they get
# restored properly.
typeset -A _ci_options
_ci_options=($(setopt kshoptionprint;setopt))
[[ -o kshoptionprint ]] || _ci_options[kshoptionprint]=off
[[ -o monitor ]] && _ci_options[monitor]=on
[[ -o zle ]] && _ci_options[zle]=on
emulate zsh
[[ -n $1 ]] && FPATH=$1
TRAPINT() {
unsetopt ${(k)_ci_options[(R)off]}
setopt ${(k)_ci_options[(R)on]}
for f in $fpath; do
if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then
fdir=$f
break
unset _ci_options _ci_f _ci_fdir _ci_files _ci_dumpfile _ci_lines
unset _ci_type _ci_completer _ci_accept _ci_cprompt _ci_startline
unset _ci_endline _ci_ifile _ci_tmpf _ci_defaults _ci_compconf _ci_warn
unset _ci_dtype _ci_existing _ci_line
if (( $1 )); then
print Aborted.
unfunction TRAPINT
return 1
fi
done
return 0
}
if [[ -z $fdir ]]; then
# Look for the defaults.
_ci_startline='# The following lines were added by compinstall'
_ci_endline='# End of lines added by compinstall'
_ci_ifile=${ZDOTDIR:-~}/.zshrc
_ci_lines=''
_ci_existing=''
typeset -A _ci_defaults
if [[ -f $_ci_ifile ]]; then
# This assumes the lines haven't been altered by the user too much
# after they were added.
_ci_compconf=0
sed -n "/^$_ci_startline/,/^$_ci_endline/p" $_ci_ifile |
while read -rA _ci_line; do
if (( $_ci_compconf )); then
# parse a compconf component as first argument
if [[ $_ci_line[-1] == \\ ]]; then
_ci_line=(${_ci_line[1,-2]})
else
_ci_compconf=0
fi
if [[ $_ci_line[1] = *=* ]]; then
_ci_f="${${_ci_line[*]}#*=}"
if [[ $_ci_f = \'*\' ]]; then
# strip quotes
_ci_f=${_ci_f[2,-2]//\'\\\'\'/\'}
fi
_ci_defaults[${_ci_line[1]%%\=*}]=$_ci_f
fi
_ci_existing="${_ci_existing} $_ci_line
"
elif [[ $_ci_line[1] = . && $_ci_line[2] = */compinit ]]; then
# parse the line sourcing compinit
[[ $_ci_line[3] = -f ]] && _ci_fdir=$_ci_line[4]
[[ $_ci_line[-2] = -d ]] && _ci_dumpfile=$_ci_line[-1]
elif [[ $_ci_line[1] = compconf ]]; then
# parse a compconf component as second argument (should be completer)
[[ $_ci_line[2] = completer=* ]] &&
_ci_completer=${_ci_line[2]#completer=}
[[ $_ci_line[-1] == \\ ]] && _ci_compconf=1
_ci_existing="${_ci_existing}$_ci_line
"
elif [[ $_ci_line[1] != \#* ]]; then
if [[ -z $_ci_warn ]]; then
_ci_warn=1
print "Warning: existing lines in compinstall setup not understood:"
fi
print - $_ci_line
_ci_existing="${_ci_existing}$_ci_line
"
fi
done
fi
# Find out where the completion functions are kept.
if [[ -z $_ci_fdir || ! -f $_ci_f/compinit || ! -f $_ci_f/compdump ]]; then
for _ci_f in $fpath; do
if [[ $_ci_f != . && -f $_ci_f/compinit && -f $_ci_f/compdump ]]; then
_ci_fdir=$_ci_f
break
fi
done
fi
if [[ -z $_ci_fdir || ! -d ${~_ci_fdir} ]]; then
print "Trying to find where the completion functions are..."
if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then
fdir=$0:h
if [[ $0 = */* && -o functionargzero &&
-f $0:h/compinit && -f $0:h/compdump ]]; then
_ci_fdir=$0:h
print "Using my directory, $_ci_fdir"
else
# more guesses?
print \
@ -51,22 +131,26 @@ if [[ -z $fdir ]]; then
installed. If they are not installed, you will need to find them in the
Completion/* directories of the zsh distribution and install them yourself,
or insult your system manager for incompetence."
vared -c fdir
while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit ||
! -f ${~fdir}/compdump ]]; do
vared -c _ci_fdir
while [[ ! -d ${~_ci_fdir} || ! -f ${~_ci_fdir}/compinit ||
! -f ${~_ci_fdir}/compdump ]]; do
print "I can't find them in that directory. Try again or abort."
vared fdir
vared _ci_fdir
done
fi
eval "fpath=($fdir \$fpath)"
fdir=${fdir/#$HOME/\~}
lines="fpath=($fdir \$fpath)\n"
else
print "Found completion functions in your fpath, will not alter it."
print "Keeping existing completion directiory $_ci_fdir"
fi
files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
if [[ $#files -lt 20 ]]; then
# Check if this is in fpath already, else put it there (with ~'s expanded).
_ci_f=${~_ci_fdir}
[[ -z ${fpath[(r)$_ci_f]} ]] && fpath=($_ci_f $fpath)
# Contract $HOME to ~ in the parameter to be used for writing.
_ci_fdir=${_ci_fdir/#$HOME/\~}
# Now check the fpath, ignoring the directory .
_ci_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
if [[ $#_ci_files -lt 20 ]]; then
print "
Hmmm, completion functions seem a bit thin on the ground. There should
be lots of files with names beginning with an underscore (_). You should
@ -75,12 +159,20 @@ look and see what's happened to these.
read
fi
if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump ||
-w ${~fdir}/compinit.dump ) ]]
# Set up the dumpfile
_ci_dtype=existing
if [[ -z $_ci_dumpfile ]]; then
_ci_dumpfile="${_ci_fdir}/compinit.dump"
_ci_dtype=standard
fi
if [[ -w ${~_ci_dumpfile:h} && ( ! -f ${~_ci_dumpfile} ||
-w ${~_ci_dumpfile} ) ]]
then
print "
Using standard dumpfile
${~fdir}/compinit.dump
Using $_ci_dtype dumpfile
${_ci_dumpfile}
to speed up initialisation.
[Hit return to continue]"
read
@ -88,23 +180,30 @@ else
print "
I will force completion to dump its status, which will speed up the shell's
start-up considerably. However, I can't write the file I'd like to, namely
$fdir/compinit.dump. Please edit a replacement."
dumpfile='~/.compinit.dump'
vared dumpfile
while ! touch ${~dumpfile} >& /dev/null; do
${_ci_dumpfile}. Please edit a replacement."
_ci_dumpfile='~/.compinit.dump'
vared _ci_dumpfile
while ! touch ${~_ci_dumpfile} >& /dev/null; do
print "Sorry, I can't write that either. Try again."
vared dumpfile
vared _ci_dumpfile
done
[[ -s $dumpfile ]] || rm -f $dumpfile
dumpfile=" $dumpfile"
[[ -s $_ci_dumpfile ]] || rm -f $_ci_dumpfile
fi
fdir=${fdir/#$HOME/\~}
lines="${lines}. $fdir/compinit -d$dumpfile\n"
_ci_lines="${_ci_lines}. $_ci_fdir/compinit -f $_ci_fdir -d"
[[ $_ci_dtype != standard ]] && _ci_lines="${_ci_lines} $_ci_dumpfile"
_ci_lines="${_ci_lines}
"
print "
Would you like to set some more advanced options? Otherwise, you
can re-run compinstall later to set these. [n]"
# The whole of the next part should be indented, but I can't be bothered.
if read -q; then
print "
In addition to completion, zsh can also perform correction of the
current word, or approximate completion, i.e. completion where the part of
the word typed so far can be corrected; or it can try correction, then
@ -112,105 +211,155 @@ approximate completion if that fails. Would you like:
0: Just ordinary completion
C: Correction
A: Approximate completion
B: Both?
Please type one of the keys above:"
while read -k type; do
print
case $type in
0*) completer=_complete
break
;;
[cC]*) completer=_complete:_correct
break
;;
[aA]*) completer=_complete:_approximate
break;
;;
[bB]*) completer=_complete:_correct:_approximate
break
;;
*) print Try again
;;
esac
done
B: Both"
if [[ -n $_ci_completer ]]; then
print " Default: use the current completer:\n$_ci_completer"
else
print "Please type one of the keys above."
fi
while read -k _ci_type; do
print
case $_ci_type in
0*) _ci_completer=_complete
break
;;
[cC]*) _ci_completer=_complete:_correct
break
;;
[aA]*) _ci_completer=_complete:_approximate
break;
;;
[bB]*) _ci_completer=_complete:_correct:_approximate
break
;;
*) [[ -n $_ci_completer ]] && break
print Try again
;;
esac
done
lines="${lines}compconf completer=$completer"
_ci_lines="${_ci_lines}compconf completer=$_ci_completer"
if [[ $completer = *(correct|approx)* ]]; then
print "
Correction and approximation will normally allow up to two errors,
and you will be able to use a numeric prefix (e.g. <Esc>4) to allow
more. The standard prompt is \`correct to:'. Do you want to change
any of this? [n]"
if read -q; then
print "Number of errors to accept normally (0 is OK):"
read accept
while [[ $accept != <-> ]]; do
read accept"?Please enter a number: "
done
print \
if [[ $_ci_completer = *(correct|approx)* ]]; then
_ci_accept=${_ci_defaults[correct_accept]}
_ci_cprompt=${_ci_defaults[correct_prompt]}
print "
Correction and approximation will allow up to ${${_ci_accept:-2}%%[^0-9]*} \
errors. "
case $_ci_accept in
*n*!*|*!*n) print "A numeric prefix, if not 1, will cause correction \
not to be done."
;;
*n*) print "A numeric prefix gives the maximum number of errors which \
will be accepted."
;;
*) print "The numeric prefix will not be used."
esac
print "The correction prompt is \`${_ci_cprompt:-correct to:}'.
Do you want to change any of this? [n]"
if read -q; then
print "Number of errors to accept normally (0 is OK):"
_ci_accept=${_ci_accept%%[^0-9]*}
vared _ci_accept
while [[ $_ci_accept != <-> ]]; do
print "Please enter a number:"
vared _ci_accept
done
print \
"How would you like the numeric prefix to be treated:
0: Not used by correction
U: Used to given the number of errors
U: The number gives the largest number of errors which will be
accepted when correcting
I: If present, and not 1, do not perform correction?
Please type one of the keys above:"
while read -k type; do
print
case $type in
0*) break
;;
[uU]*) accept="${accept}n"
break
;;
[Ii]*) accept="${accept}!n"
break
;;
*) print Try again
;;
esac
done
lines="$lines \\\\
correct_accept='$accept'"
print "
while read -k _ci_type; do
print
case $_ci_type in
0*) break
;;
[uU]*) _ci_accept="${_ci_accept}n"
break
;;
[Ii]*) _ci_accept="${_ci_accept}!n"
break
;;
*) print Try again
;;
esac
done
print "
Instead of the prompt \`correct to:', you can have no prompt, or a
prompt of your choosing which can display the number of errors found by
containing the string \`%e'. Do you wish to change the correction
prompt? [n]"
if read -q; then
cprompt=''
print "Edit a new prompt (may be empty):"
vared cprompt
lines="$lines \\\\
correct_prompt='${cprompt//\'/\'\\\'\'}'"
if read -q; then
print "Edit a new prompt (may be empty):"
vared _ci_cprompt
[[ -z $_ci_cprompt ]] && _ci_cprompt=':empty:'
fi
fi
if [[ -n $_ci_accept ]]; then
_ci_lines="$_ci_lines \\
correct_accept='$_ci_accept'"
unset '_ci_defaults[correct_accept]'
fi
if [[ -n $_ci_cprompt ]]; then
_ci_cprompt=${_ci_cprompt##:empty:}
_ci_lines="$_ci_lines \\
correct_prompt='${_ci_cprompt//\'/\'\\\'\'}'"
unset '_ci_defaults[correct_prompt]'
fi
fi
fi
lines="$lines\n"
_ci_warn=''
for _ci_f in ${(k)_ci_defaults}; do
if [[ -z $_ci_warn ]]; then
print "
(Keeping other existing configuration settings...)"
_ci_warn=1
fi
_ci_lines="$_ci_lines \\
${_ci_f}='${_ci_defaults[$_ci_f]//\'/\'\\\'\'}'"
done
_ci_lines="$_ci_lines
"
startline='# The following lines were added by compinstall'
endline='# End of lines added by compinstall'
ifile=${ZDOTDIR:-~}/.zshrc
[[ -f $ifile ]] || touch $ifile
tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
if [[ ! -w $ifile ]]; then
print "\nI can't write to $ifile. I will leave the lines to add in
\`$tmpf' and you must add them by hand."
print "\n$startline\n$lines\n$endline" >$tmpf
return 0
fi
if grep $endline $ifile >& /dev/null; then
print -- "$startline\n$lines$endline" >$tmpf
sed -e "/^$endline/r $tmpf
/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile &&
print "\nSuccesfully modified old compinstall lines in $ifile."
rm -f $tmpf ${tmpf}2
else
print "\n$startline\n$lines\n$endline" >>$ifile &&
print "\nSuccessfully appended lines to $ifile."
if [[ -n $_ci_existing ]]; then
print -nr "
I will retain the following lines from the existing completion setup:
$_ci_existing"
_ci_lines="$_ci_lines${_ci_existing}"
fi
fi # End of advanced options
[[ -f $_ci_ifile ]] || touch $_ci_ifile
_ci_tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
if [[ ! -w $_ci_ifile ]]; then
print "\nI can't write to $_ci_ifile. I will leave the lines to add in
\`$_ci_tmpf' and you must add them by hand."
print -r - "$_ci_startline
$_ci_lines$_ci_endline" >$_ci_tmpf
elif grep $_ci_endline $_ci_ifile >& /dev/null; then
print -r - "$_ci_startline
$_ci_lines$_ci_endline" >$_ci_tmpf
sed -e "/^$_ci_endline/r $_ci_tmpf
/^$_ci_startline/,/^$_ci_endline/d" $_ci_ifile >${_ci_tmpf}2 &&
mv ${_ci_tmpf}2 $_ci_ifile &&
print "\nSuccesfully modified old compinstall lines in $_ci_ifile."
rm -f $_ci_tmpf ${_ci_tmpf}2
else
print -r - "$_ci_startline
$_ci_lines$_ci_endline" >>$_ci_ifile &&
print "\nSuccessfully appended lines to $_ci_ifile."
fi
TRAPINT 0
return 0

View file

@ -27,5 +27,5 @@
# This must also serve as a shell script, so do not add spaces around the
# `=' signs.
VERSION=3.1.5-pws-17
VERSION_DATE='April 30, 1999'
VERSION=3.1.5-pws-18
VERSION_DATE='May 8, 1999'

View file

@ -318,10 +318,13 @@ cindex(file, history)
tt(fc -R) reads the history from the given file,
tt(fc -W) writes the history out to the given file,
and tt(fc -A) appends the history out to the given file.
If the tt(-I) option is added, only those
events that are new since last incremental append (write) to
the history file are appended (written).
In any case the file will have no more than tt($SAVEHIST)
If no filename is specified, the tt($HISTFILE) is assumed.
If the tt(-I) option is added to tt(-R), only those events that are
not already contained within the internal history list are added.
If the tt(-I) option is added to tt(-A) or tt(-W), only those
events that are new since last incremental append/write to
the history file are appended/written.
In any case, the created file will have no more than tt($SAVEHIST)
entries.
)
findex(fg)
@ -1169,30 +1172,26 @@ Equivalent to tt(whence -c).
findex(zmodload)
cindex(modules, loading)
cindex(loading modules)
xitem(tt(zmodload) [ tt(-iL) ] [ var(name) ... ])
xitem(tt(zmodload) tt(-u) [ tt(-i) ] var(name) ...)
xitem(tt(zmodload) tt(-d) [ tt(-L) ] [ var(name) [ var(dep) ... ] ])
xitem(tt(zmodload) tt(-du) var(name) [ var(dep) ... ])
xitem(tt(zmodload) tt(-a) [ tt(-iL) ] [ var(name) [ var(builtin) ... ] ])
xitem(tt(zmodload) tt(-au) [ tt(-i) ] var(builtin) ...)
xitem(tt(zmodload) tt(-c) [ tt(-iI) ] var(name) [ var(cond) ... ])
xitem(tt(zmodload) tt(-cu) [ tt(-iI) ] var(cond) ...)
xitem(tt(zmodload) tt(-c) [ tt(-IL) ])
xitem(tt(zmodload) tt(-p) [ tt(-i) ] var(name) [ var(parameter) ... ])
xitem(tt(zmodload) tt(-pu) [ tt(-i) ] var(parameter) ... ])
item(tt(zmodload) tt(-p) [ tt(-L) ])(
xitem(tt(zmodload) [ tt(-dL) ] [ ... ])
xitem(tt(zmodload) [ tt(-a) [ tt(-bcp) [ tt(-I) ] ] ] [ tt(-iL) ] ...)
item(tt(zmodload) tt(-u) [ tt(-abcdp) [ tt(-I) ] ] [ tt(-iL) ] ...)(
tt(zmodload) performs operations relating to zsh's loadable modules.
This feature is not available on all operating systems,
or on all installations on a particular operating system.
In the simplest case,
tt(zmodload) loads a binary module. The module must be in a file with a
name consisting of the specified var(name) followed by a standard suffix,
usually `tt(.so)'. If this can't be found, the var(name) is tried without
the suffix.
If the module to be loaded is already loaded and the tt(-i)
option is given, the duplicate module is ignored. Otherwise
tt(zmodload) prints an error message.
Without arguments all currently loaded binary modules are printed.
The tt(-L) option causes this list to be in the form of a series of
tt(zmodload) commands. Forms with arguments are:
startitem()
xitem(tt(zmodload) [ tt(-i) ] var(name) ... )
item(tt(zmodload) tt(-u) [ tt(-i) ] var(name) ...)(
In the simplest case, tt(zmodload) loads a binary module. The module must
be in a file with a name consisting of the specified var(name) followed by
a standard suffix, usually `tt(.so)'. If this can't be found, the
var(name) is tried without the suffix. If the module to be loaded is
already loaded and the tt(-i) option is given, the duplicate module is
ignored. Otherwise tt(zmodload) prints an error message.
The var(name)d module is searched for in the same way a command is, using
tt($module_path) instead of tt($path). If var(name) contains a `tt(/)',
@ -1209,55 +1208,66 @@ unloaded (or was never loaded).
Each module has a boot and a cleanup function. The module
will not be loaded if its boot function fails. Similarly a module
can only be unloaded if its cleanup function runs successfully.
)
xitem(tt(zmodload) tt(-d) [ tt(-L) ] [ var(name) ])
xitem(tt(zmodload) tt(-d) var(name) var(dep) ...)
item(tt(zmodload) tt(-ud) var(name) [ var(dep) ... ])(
The tt(-d) option can be used to specify module dependencies. The modules
named in the second and subsequent arguments will be loaded before the
module named in the first argument.
Without arguments all currently loaded binary modules are printed.
The tt(-L) option causes this list to be in the form of a series of
tt(zmodload) commands.
With tt(-d) and one argument, all dependencies for that module are listed.
With tt(-d) and no arguments, all module dependencies are listed. This
listing is by default in a Makefile-like format. The tt(-L) option
changes this format to a list of tt(zmodload -d) commands.
The tt(-d) option can be used to specify module dependencies.
This operation is idempotent regardless of the tt(-i) option.
The modules named in the second and subsequent arguments will be
loaded before the module named in the first argument.
If tt(-d) and tt(-u) are both used, dependencies are removed. If only one
argument is given, all dependencies for that module are removed.
)
xitem(tt(zmodload) tt(-ab) [ tt(-L) ])
xitem(tt(zmodload) tt(-ab) [ tt(-i) ] var(name) [ var(builtin) ... ])
item(tt(zmodload) tt(-ub) [ tt(-i) ] var(builtin) ...)(
The tt(-ab) option defines autoloaded builtins. It defines the specified
var(builtin)s. When any of those builtins is called, the module specified
in the first argument is loaded. If only the var(name) is given, one
builtin is defined, with the same name as the module. tt(-i) suppresses
the error if the builtin is already defined or autoloaded, regardless of
which module it came from.
With tt(-d) and one
argument, all dependencies for that module are listed. With tt(-d) and no
arguments, all module dependencies are listed.
This listing is by default in a Makefile-like format.
The tt(-L) option changes this format to a list of
tt(zmodload -d) commands.
With tt(-ab) and no arguments, all autoloaded builtins are listed, with the
module name (if different) shown in parentheses after the builtin name.
The tt(-L) option changes this format to a list of tt(zmodload -a)
commands.
If tt(-d) and tt(-u) are both used, dependencies are removed.
This operation is idempotent regardless of the tt(-i) option.
If only one argument is given, all dependencies for that module are removed.
The tt(-a) option defines autoloaded builtins. It defines the
specified var(builtin)s. When any of those builtins is called, the module
specified in the first argument is loaded. If only one argument is given,
one builtin is defined, with the same name as the module.
tt(-i) suppresses the error if the builtin is already defined or
autoloaded, regardless of which module it came from.
With tt(-a) and no arguments, all
autoloaded builtins are listed, with the module name (if different)
shown in parentheses after the builtin name. The tt(-L) option changes
this format to a list of tt(zmodload -a) commands.
If tt(-a) is used
together with the tt(-u) option it removes builtins defined with
tt(zmodload -a). This is only possible if the builtin is not yet
loaded. tt(-i) suppresses the error if the builtin is already
If tt(-b) is used together with the tt(-u) option, it removes builtins
previously defined with tt(-ab). This is only possible if the builtin is
not yet loaded. tt(-i) suppresses the error if the builtin is already
removed (or never existed).
The tt(-c) option is used to define autoloaded condition codes. The
)
xitem(tt(zmodload) tt(-ac) [ tt(-IL) ])
xitem(tt(zmodload) tt(-ac) [ tt(-iI) ] var(name) [ var(cond) ... ])
item(tt(zmodload) tt(-uc) [ tt(-iI) ] var(cond) ...)(
The tt(-ac) option is used to define autoloaded condition codes. The
var(cond) strings give the names of the conditions defined by the
module. The optional tt(-I) option is used to define infix condition
names. Without this option prefix condition names are defined.
Together with the tt(-u) option definitions for autoloaded conditions
are removed. If given no condition names all defined names are listed
(as a series of tt(zmodload) commands if the tt(-L) option is given).
If given no condition names, all defined names are listed (as a series of
tt(zmodload) commands if the tt(-L) option is given).
The tt(-p) option is like the tt(-c) option, but makes tt(zmodload)
work on autoloaded parameters instead of condition codes.
The tt(-uc) option removes definitions for autoloaded conditions.
)
xitem(tt(zmodload) tt(-ap) [ tt(-L) ])
xitem(tt(zmodload) tt(-ap) [ tt(-i) ] var(name) [ var(parameter) ... ])
item(tt(zmodload) tt(-up) [ tt(-i) ] var(parameter) ...)(
The tt(-p) option is like the tt(-b) and tt(-c) options, but makes
tt(zmodload) work on autoloaded parameters instead.
)
xitem(tt(zmodload) tt(-a) [ tt(-L) ])
xitem(tt(zmodload) tt(-a) [ tt(-i) ] var(name) [ var(builtin) ... ])
item(tt(zmodload) tt(-ua) [ tt(-i) ] var(builtin) ...)(
Equivalent to tt(-ab) and tt(-ub).
)
enditem()
)
enditem()

View file

@ -49,14 +49,42 @@ endmenu()
texinode(Initialisation)(Control Functions)()(Completion System)
sect(Initialisation)
The script tt(compinstall) can be run by a user to set up the completion
system for use. It will usually insert code into tt(.zshrc), although if
that is not writeable it will save it in another file and tell you that
file's locations. Note that it is up to you to make sure that the lines
added to tt(.zshrc) are actually run; you may, for example, need to move
them to an earlier place in the file if tt(.zshrc) usually returns early.
So long as you keep them all together (including the comment lines at the
start and finish), you can rerun tt(compinstall) and it will correctly
locate and modify these lines. Note, however, that any code you add to
this section by hand is likely to be lost if you rerun tt(compinstall).
You can run it as `tt(source )var(<path>)tt(/compinstall)' or
`tt(. )var(<path>)tt(/compinstall)', where var(<path>) is where the
completion functions are stored. It will ask you various questions about
how you would like completion set up. It is in two parts; the basic part
locates the completion files and decides where to put your personal
dumpfile, used to speed up initialisation after the first time. After
that, you will be asked if you wish to go on to the advanced set-up; if you
answer tt(n), you can rerun tt(compinstall) later without having to
re-enter any of the basic settings.
You can abort the installation any time you are being prompted for
information, and your tt(.zshrc) will not be altered at all.
subsect(Use of compinit)
This section describes the use of tt(compinit) to initialize completion for
the current session when run directly by the user; if you have run
tt(compinstall) it will be called automatically from your tt(.zshrc).
To initialise the system, the script tt(compinit) should be sourced with
`tt(source )var(<path>)tt(/compinit)' or
`tt(. )var(<path>)tt(/compinit)'. This will define a few utility functions,
arrange for all the necessary shell functions to be autoloaded, and will
then re-bind all keys that do completion to use the new system.
subsect(Arguments)
To speed up the running of tt(compinit), it can be made to produce a dumped
configuration which will be read in on future invocations. The easiest way
to do this is by adding the option tt(-d) whenever tt(compinit) is sourced.
@ -65,6 +93,15 @@ but with tt(.dump) appended to the end; alternatively, an explicit file
name can be given following the tt(-d). On the next call to tt(compinit
-d), the dumped file will be read instead.
The other option accepted by tt(compinit) is tt(-f var(dir)), which gives
the directory in which tt(compinit) resides. If you source tt(compinit) by
its full pathname, and the option tt(FUNCTION_ARGZERO) is set, as it is by
default unless tt(zsh) is emulating tt(sh) or tt(ksh), this is unnecessary
as tt(compinit) can deduce the directory for itself. It is used in two
ways: to find the program tt(compdump) used by the tt(-d) option, and to
check if the directory should be added to the function search path to find
the completion functions (see below).
If the number of completion files changes, tt(compinit) will recognise this
and produce a new dump file. However, if the name of a function or the
arguments in the first line of a tt(#compdef) funcion (as described below)
@ -80,8 +117,18 @@ subsect(Autoloaded files)
The convention for autoloaded functions used in completion is that they
start with an underscore; as already mentioned, the tt(fpath/FPATH)
parameter must contain the directory in which they are stored. When
tt(compinit) is sourced, it searches all such files accessible via
parameter must contain the directory in which they are stored. If
tt(compinit) does not find enough files beginning with an underscore (fewer
than twenty) in the search path, it will try to find more by adding its own
directory to the search path. If you keep all the completion files in this
directory, this means you never have to alter tt(fpath/FPATH) yourself.
Furthermore, if the directory in question ends in the path segment
tt(Core), or has a subdirectory named tt(Core), tt(compinit) will add all
subdirectories of the directory where tt(Core) is to the path: this allows
the functions to be in the same format as in the tt(zsh) source
distribution.
When tt(compinit) is sourced, it searches all such files accessible via
tt(fpath/FPATH) and reads the first line of each of them. This line should
contain one of the tags described below. Files whose first line does not
start with one of these tags are not considered to be part of the

View file

@ -717,18 +717,24 @@ If multiple nested tt(${...}) forms are present, substitution is
performed from the inside outwards. At each level, the substitution takes
account of whether the current value is a scalar or an array, whether the
whole substitution is in double quotes, and what flags are supplied to the
current level of substitution; the flags are not propagated up to enclosing
substitutions. The value passed back to an enclosing substitution is
always an array, which however will consist of one word if the value was
not itself an array. All the following steps take place where applicable
at all levels of substitution.
current level of substitution, just as if the nested substitution were the
outermost. The flags are not propagated up to enclosing
substitutions; the nested subsitution will return either a scalar or an
array as determined by the flags, possibly adjusted for quoting. All the
following steps take place where applicable at all levels of substitution.
Note that, unless the tt((P)) flag is present, the flags and any subscripts
apply directly to the value of the nested substitution; for example, the
expansion tt(${${foo}}) behaves exactly the same as tt(${foo}).
)
item(tt(2.) em(Parameter Subscripting))(
If the value is a raw parameter reference with a subscript, such as
tt(${)var(var)tt([3]}), the effect of subscripting is applied directly to
the parameter. If the parameter is an array, any second subscript,
indexing on the character in the word, may appear,
e.g. tt(${)var(var)tt([1][2]}).
the parameter. Subscripts are evaluated left to right; subsequent
subscripts apply to the scalar or array value yielded by the previous
subscript. Thus if tt(var) is an array, tt(${var[1][2]}) is the second
character of the first word, but tt(${var[2,4][2]}) is the entire third
word (the second word of the range of words two through four of the
original array). Any number of subscripts may appear.
)
item(tt(3.) em(Parameter Name Replacement))(
The effect of any tt((P)) flag, which treats the value so far as a
@ -746,6 +752,10 @@ item(tt(5.) em(Nested Subscripting))(
Any remaining subscript (i.e. of a nested substitution) is evaluated at
this point, based on whether the value is an array or a scalar; if it was
an array, a second subscript for the character in the word may also appear.
Note that tt(${foo[2,4][2]}) is thus equivalent to tt(${${foo[2,4]}[2]})
and also to tt("${${(@)foo[2,4]}[2]}") (the nested substitution returns an
array in both cases), but not to tt("${${foo[2,4]}[2]}") (the nested
substitution returns a scalar because of the quotes).
)
item(tt(6.) em(Modifiers))(
Any modifiers, as specified by a trailing tt(#), tt(%), tt(/)
@ -798,20 +808,17 @@ Suppose that tt($foo) contains the array tt(LPAR()bar baz)tt(RPAR()):
startitem()
item(tt("${(@)${foo}[1]}"))(
This produces the result tt(bar baz). First, the inner substitution
This produces the result tt(b). First, the inner substitution
tt("${foo}"), which has no array (tt(@)) flag, produces a single word
result. The outer substitution tt("${(@)...[1]}") acts on this result as
if it were a one word array, because of the array flag, so the result is
just that single word.
result tt("bar baz"). The outer substitution tt("${(@)...[1]}") detects
that this is a scalar, so that (despite the tt((@)) flag) the subscript
picks the first character.
)
item(tt("${${(@)foo}[1]}"))(
The produces the result tt(b). In this case, the inner substitution
The produces the result tt(bar). In this case, the inner substitution
tt("${(@)foo}") produces the array tt(LPAR()bar baz)tt(RPAR()). The outer
substitution tt("${...[1]}"), however, has no array flag, so that it joins
the array it has to a single word and indexes as if it were a string. Note
that this is not identical to the case tt("${foo[1]}"), since here the
expression tt(foo[1]) is recognised immediately as an index into an array,
so that the result in that case is tt(bar).
substitution tt("${...[1]}") detects that this is an array and picks the
first word. This is similar to the simple case tt("${foo[1]}").
)
enditem()

View file

@ -302,9 +302,10 @@ always produces named directory expansion.)
pindex(EXTENDED_HISTORY)
cindex(history, timestamping)
item(tt(EXTENDED_HISTORY))(
Save beginning and ending timestamps to the history file.
The format of these timestamps is
`tt(:)var(<beginning time>)tt(:)var(<ending time>)tt(:)var(<command>)'.
Save each command's beginning timestamp (in seconds since the epoch)
and the duration (in seconds) to the history file. The format of
this prefixed data is
`tt(:)var(<beginning time>)tt(:)var(<elapsed seconds>)tt(:)var(<command>)'.
)
pindex(FLOW_CONTROL)
cindex(flow control)
@ -405,6 +406,20 @@ item(tt(HIST_BEEP))(
Beep when an attempt is made to access a history entry which
isn't there.
)
pindex(HIST_EXPIRE_DUPS_FIRST)
cindex(history, expiring duplicates)
item(tt(HIST_EXPIRE_DUPS_FIRST))(
If the history needs to be trimmed to add a new line, setting this
option will cause the oldest duplicate history line to be lost before
losing a unique line from the internal history list.
)
pindex(HIST_IGNORE_ALL_DUPS)
cindex(history, ignoring all duplicates)
item(tt(HIST_IGNORE_ALL_DUPS) (tt(-h)))(
If a new command line being added to the history list duplicates an
older one, the older command is removed from the list (even if it is
not the previous event).
)
pindex(HIST_IGNORE_DUPS)
cindex(history, ignoring duplicates)
item(tt(HIST_IGNORE_DUPS) (tt(-h)))(
@ -426,6 +441,11 @@ item(tt(HIST_NO_STORE))(
Remove the tt(history) (tt(fc -l)) command from
the history when invoked.
)
pindex(HIST_SAVE_NO_DUPS)
item(tt(HIST_SAVE_NO_DUPS))(
When writing out the history file, older commands that duplicate
newer ones are omitted.
)
pindex(HIST_REDUCE_BLANKS)
item(tt(HIST_REDUCE_BLANKS))(
Remove superfluous blanks from each command line
@ -459,6 +479,15 @@ of tt(exit) or tt(logout) instead.
However, ten consecutive EOFs will cause the shell to exit anyway,
to avoid the shell hanging if its tty goes away.
)
pindex(INCREMENTAL_APPEND_HISTORY)
cindex(history, incremental appending to a file)
item(tt(INCREMENTAL_APPEND_HISTORY))(
This options works like APPEND_HISTORY except that new history lines
are added to the tt($HISTFILE) when they finish running, rather than
waiting until the shell is killed. The file is periodically trimmed
to the number of lines specified by tt($SAVEHIST), but can exceed this
value between trimmings.
)
pindex(INTERACTIVE)
item(tt(INTERACTIVE) (tt(-i), ksh: tt(-i)))(
This is an interactive shell. This option is set upon initialisation if
@ -798,6 +827,28 @@ This avoids the problem of reflexively answering `yes' to the query
when one didn't really mean it. The wait and query can always be
avoided by expanding the `tt(*)' in ZLE (with tab).
)
pindex(SHARE_HISTORY)
cindex(share history)
cindex(history, sharing)
item(tt(SHARE_HISTORY))(
This option both imports new commands from the history file, and also
causes your typed commands to be appended to the history file (like
specifiying tt(INCREMENTAL_APPEND_HISTORY)). The history lines are also
output with timestamps ala tt(EXTENDED_HISTORY) (which makes it easier to
find the spot where we left off reading the file after it gets re-written).
By default, history movement commands visit the imported lines as well as
the local lines, but you can toggle this on and off with the
set-local-history zle binding. It is also possible to create a zle
widget that will make some commands ignore imported commands, and some
include them.
If you find that you want more control over when commands
get imported, you may wish to turn tt(SHARE_HISTORY) off,
tt(INCREMENTAL_APPEND_HISTORY) on, and then manually import
commands whenever you need them using `fc -RI'.
)
pindex(SH_FILE_EXPANSION)
cindex(sh, expansion style)
cindex(expansion style, sh)

View file

@ -43,14 +43,14 @@ zstrtorlimt(const char *s, char **t, int base)
{
rlim_t ret = 0;
if (!base)
if (!base) {
if (*s != '0')
base = 10;
else if (*++s == 'x' || *s == 'X')
base = 16, s++;
else
base = 8;
}
if (base <= 10)
for (; *s >= '0' && *s < ('0' + base); s++)
ret = ret * base + *s - '0';

View file

@ -47,7 +47,7 @@ Cmlist cmatcher;
void (*makecompparamsptr) _((void));
/**/
void (*comp_setunsetptr) _((int, int));
void (*comp_setunsetptr) _((unsigned int, unsigned int));
/* pointers to functions required by compctl and defined by zle */
@ -147,6 +147,7 @@ createcompctltable(void)
compctltab->hash = hasher;
compctltab->emptytable = emptyhashtable;
compctltab->filltable = NULL;
compctltab->cmpnodes = strcmp;
compctltab->addnode = addhashnode;
compctltab->getnode = gethashnode2;
compctltab->getnode2 = gethashnode2;

View file

@ -91,6 +91,7 @@
"send-break", sendbreak, 0
"set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"spell-word", spellword, 0
"set-local-history", setlocalhistory, 0
"transpose-chars", transposechars, 0
"transpose-words", transposewords, 0
"undefined-key", undefinedkey, 0

View file

@ -47,27 +47,16 @@ int lastcol;
/**/
int histline;
/* the last line in the history (the current one), metafied */
/**/
char *curhistline;
#define ZLETEXT(X) ((X)->zle_text ? (X)->zle_text : (X)->text)
/**/
void
remember_edits(void)
{
if (histline == curhist) {
zsfree(curhistline);
curhistline = metafy((char *) line, ll, META_DUP);
}
else {
Histent ent = gethistent(histline);
if (metadiffer(ent->zle_text ? ent->zle_text : ent->text,
(char *) line, ll)) {
zsfree(ent->zle_text);
ent->zle_text = metafy((char *) line, ll, META_DUP);
}
Histent ent = quietgethist(histline);
if (metadiffer(ZLETEXT(ent), (char *) line, ll)) {
zsfree(ent->zle_text);
ent->zle_text = metafy((char *) line, ll, META_DUP);
}
}
@ -75,11 +64,11 @@ remember_edits(void)
void
forget_edits(void)
{
int i;
Histent he;
for (i = 0; i < histentct; i++) {
zsfree(histentarr[i].zle_text);
histentarr[i].zle_text = NULL;
for (he = hist_ring; he; he = up_histent(he)) {
zsfree(he->zle_text);
he->zle_text = NULL;
}
}
@ -87,16 +76,12 @@ forget_edits(void)
void
uphistory(void)
{
if (zmult < 0) {
zmult = -zmult;
downhistory();
zmult = -zmult;
} else if(!zle_goto_hist(histline - zmult) && isset(HISTBEEP))
if (!zle_goto_hist(histline, -zmult) && isset(HISTBEEP))
feep();
}
/**/
int
static int
upline(void)
{
int n = zmult;
@ -159,7 +144,6 @@ viuplineorhistory(void)
vifirstnonblank();
}
/**/
void
uplineorsearch(void)
@ -181,7 +165,7 @@ uplineorsearch(void)
}
/**/
int
static int
downline(void)
{
int n = zmult;
@ -268,26 +252,22 @@ downlineorsearch(void)
void
acceptlineanddownhistory(void)
{
char *s;
Histent he;
if (!(s = zle_get_event(histline + 1))) {
if (!(he = movehistent(quietgethist(histline), 1, HIST_FOREIGN))) {
feep();
return;
}
pushnode(bufstack, ztrdup(s));
pushnode(bufstack, ztrdup(ZLETEXT(he)));
done = 1;
stackhist = histline + 1;
stackhist = he->histnum;
}
/**/
void
downhistory(void)
{
if (zmult < 0) {
zmult = -zmult;
uphistory();
zmult = -zmult;
} else if(!zle_goto_hist(histline + zmult) && isset(HISTBEEP))
if (!zle_goto_hist(histline, zmult) && isset(HISTBEEP))
feep();
}
@ -298,7 +278,7 @@ static char *srch_str;
void
historysearchbackward(void)
{
int hl = histline;
Histent he;
int n = zmult;
char *s;
@ -308,7 +288,7 @@ historysearchbackward(void)
zmult = n;
return;
}
if (hl == curhist || hl != srch_hl || cs != srch_cs || mark != 0
if (histline == curhist || histline != srch_hl || cs != srch_cs || mark != 0
|| memcmp(srch_str, line, histpos) != 0) {
zfree(srch_str, histpos);
for (histpos = 0; histpos < ll && !iblank(line[histpos]); histpos++) ;
@ -317,28 +297,29 @@ historysearchbackward(void)
srch_str = zalloc(histpos);
memcpy(srch_str, line, histpos);
}
for (;;) {
hl--;
if (!(s = zle_get_event(hl))) {
feep();
return;
}
he = quietgethist(histline);
while ((he = movehistent(he, -1, hist_skip_flags))) {
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
continue;
s = ZLETEXT(he);
if (metadiffer(s, srch_str, histpos) < 0 &&
metadiffer(s, srch_str, ll)) {
if (--n <= 0)
break;
if (--n <= 0) {
zle_setline(he);
srch_hl = histline;
srch_cs = cs;
return;
}
}
}
zle_goto_hist(hl);
srch_hl = hl;
srch_cs = cs;
feep();
}
/**/
void
historysearchforward(void)
{
int hl = histline;
Histent he;
int n = zmult;
char *s;
@ -348,7 +329,7 @@ historysearchforward(void)
zmult = n;
return;
}
if (hl == curhist || hl != srch_hl || cs != srch_cs || mark != 0
if (histline == curhist || histline != srch_hl || cs != srch_cs || mark != 0
|| memcmp(srch_str, line, histpos) != 0) {
zfree(srch_str, histpos);
for (histpos = 0; histpos < ll && !iblank(line[histpos]); histpos++) ;
@ -357,20 +338,22 @@ historysearchforward(void)
srch_str = zalloc(histpos);
memcpy(srch_str, line, histpos);
}
for (;;) {
hl++;
if (!(s = zle_get_event(hl))) {
feep();
return;
he = quietgethist(histline);
while ((he = movehistent(he, 1, hist_skip_flags))) {
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
continue;
s = ZLETEXT(he);
if (metadiffer(s, srch_str, histpos) < (he->histnum == curhist) &&
metadiffer(s, srch_str, ll)) {
if (--n <= 0) {
zle_setline(he);
srch_hl = histline;
srch_cs = cs;
return;
}
}
if (metadiffer(s, srch_str, histpos) < (hl == curhist) &&
metadiffer(s, srch_str, ll))
if (--n <= 0)
break;
}
zle_goto_hist(hl);
srch_hl = hl;
srch_cs = cs;
feep();
}
/**/
@ -387,7 +370,7 @@ beginningofbufferorhistory(void)
void
beginningofhistory(void)
{
if (!zle_goto_hist(firsthist()) && isset(HISTBEEP))
if (!zle_goto_hist(firsthist(), 0) && isset(HISTBEEP))
feep();
}
@ -405,7 +388,7 @@ endofbufferorhistory(void)
void
endofhistory(void)
{
zle_goto_hist(curhist);
zle_goto_hist(curhist, 0);
}
/**/
@ -419,7 +402,7 @@ insertlastword(void)
/* multiple calls will now search back through the history, pem */
static char *lastinsert;
static int lasthist, lastpos;
int evhist = curhist - 1, save;
int evhist = addhistnum(curhist, -1, HIST_FOREIGN), save;
if (lastinsert) {
int lastlen = ztrlen(lastinsert);
@ -428,7 +411,7 @@ insertlastword(void)
if (lastpos <= pos &&
lastlen == pos - lastpos &&
memcmp(lastinsert, (char *)&line[lastpos], lastlen) == 0) {
evhist = --lasthist;
evhist = addhistnum(lasthist, -1, HIST_FOREIGN);
cs = lastpos;
foredel(pos - cs);
}
@ -464,41 +447,37 @@ insertlastword(void)
}
/**/
char *
qgetevent(int ev)
void
zle_setline(Histent he)
{
return ((ev == curhist) ? curhistline : quietgetevent(ev));
}
/**/
char *
zle_get_event(int ev)
{
Histent ent;
if (ev == curhist)
return curhistline;
if (! (ent = quietgethist(ev)))
return NULL;
if (ent->zle_text)
return ent->zle_text;
return ent->text;
}
/**/
static int
zle_goto_hist(int ev)
{
char *t;
remember_edits();
if(!(t = zle_get_event(ev)))
return 0;
mkundoent();
histline = ev;
setline(t);
histline = he->histnum;
setline(ZLETEXT(he));
setlastline();
clearlist = 1;
}
/**/
void
setlocalhistory(void)
{
if (zmod.flags & MOD_MULT) {
hist_skip_flags = zmult? HIST_FOREIGN : 0;
}
else {
hist_skip_flags ^= HIST_FOREIGN;
}
}
/**/
int
zle_goto_hist(int ev, int n)
{
Histent he = movehistent(quietgethist(ev), n, hist_skip_flags);
if (!he)
return 0;
zle_setline(he);
return 1;
}
@ -603,6 +582,7 @@ static struct isrch_spot {
static int max_spot = 0;
/**/
#ifdef MODULE
/**/
@ -612,6 +592,7 @@ free_isrch_spots(void)
zfree(isrch_spots, max_spot * sizeof(*isrch_spots));
}
/**/
#endif /* MODULE */
/**/
@ -665,13 +646,15 @@ doisearch(int dir)
char *okeymap = curkeymapname;
static char *previous_search = NULL;
static int previous_search_len = 0;
Histent he;
clearlist = 1;
strcpy(ibuf, ISEARCH_PROMPT);
memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3);
remember_edits();
s = zle_get_event(hl);
he = quietgethist(hl);
s = ZLETEXT(he);
selectkeymap("main", 1);
pos = metalen(s, cs);
for (;;) {
@ -705,15 +688,14 @@ doisearch(int dir)
if (!skip_line && ((sbuf[0] == '^') ?
(t = metadiffer(s, sbuf + 1, sbptr - 1) < sens ? s : NULL) :
(t = hstrnstr(s, pos, sbuf, sbptr, dir, sens)))) {
zle_goto_hist(hl);
zle_setline(he);
pos = t - s;
cs = ztrsub(t, s) + (dir == 1? sbptr - (sbuf[0]=='^') : 0);
nomatch = 0;
statusline = ibuf + NORM_PROMPT_POS;
break;
}
hl += dir;
if (!(s = zle_get_event(hl))) {
if (!(he = movehistent(he, dir, hist_skip_flags))) {
if (sbptr == (int)isrch_spots[top_spot-1].len
&& (isrch_spots[top_spot-1].flags & ISS_FAILING))
top_spot--;
@ -723,13 +705,17 @@ doisearch(int dir)
feep();
nomatch = 1;
}
s = last_line;
he = quietgethist(hl);
s = ZLETEXT(he);
skip_line = 0;
statusline = ibuf;
break;
}
hl = he->histnum;
s = ZLETEXT(he);
pos = dir == 1? 0 : strlen(s);
skip_line = !strcmp(last_line, s);
skip_line = isset(HISTFINDNODUPS)? !!(he->flags & HIST_DUP)
: !strcmp(last_line, s);
}
} else {
top_spot = 0;
@ -743,8 +729,9 @@ doisearch(int dir)
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
int i;
get_isrch_spot(0, &hl, &pos, &i, &sbptr, &dir, &nomatch);
s = zle_get_event(hl);
zle_goto_hist(hl);
he = quietgethist(hl);
zle_setline(he);
s = ZLETEXT(he);
cs = i;
break;
}
@ -769,10 +756,11 @@ doisearch(int dir)
statusline = ibuf;
skip_pos = 1;
}
s = zle_get_event(hl);
he = quietgethist(hl);
s = ZLETEXT(he);
if (nomatch || !sbptr || (sbptr == 1 && sbuf[0] == '^')) {
int i = cs;
zle_goto_hist(hl);
zle_setline(he);
cs = i;
}
memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3);
@ -874,42 +862,35 @@ doisearch(int dir)
void
acceptandinfernexthistory(void)
{
int t0;
char *s;
Histent he;
done = 1;
for (t0 = histline - 2;; t0--) {
if (!(s = qgetevent(t0)))
for (he = movehistent(quietgethist(histline), -2, HIST_FOREIGN);
he; he = movehistent(he, -1, HIST_FOREIGN)) {
if (!metadiffer(ZLETEXT(he), (char *) line, ll)) {
he = movehistent(he, 1, HIST_FOREIGN);
pushnode(bufstack, ztrdup(ZLETEXT(he)));
stackhist = he->histnum;
return;
if (!metadiffer(s, (char *) line, ll))
break;
}
}
if (!(s = qgetevent(t0 + 1)))
return;
pushnode(bufstack, ztrdup(s));
stackhist = t0 + 1;
}
/**/
void
infernexthistory(void)
{
int t0;
char *s;
Histent he;
for (t0 = histline - 2;; t0--) {
if (!(s = qgetevent(t0))) {
feep();
for (he = movehistent(quietgethist(histline), -2, HIST_FOREIGN);
he; he = movehistent(he, -1, HIST_FOREIGN)) {
if (!metadiffer(ZLETEXT(he), (char *) line, ll)) {
he = movehistent(he, 1, HIST_FOREIGN);
zle_setline(he);
return;
}
if (! metadiffer(s, (char *) line, ll))
break;
}
if (!(s = qgetevent(t0 + 1))) {
feep();
return;
}
zle_goto_hist(t0 + 1);
feep();
}
/**/
@ -925,7 +906,7 @@ vifetchhistory(void)
return;
}
}
if (!zle_goto_hist((zmod.flags & MOD_MULT) ? zmult : curhist) &&
if (!zle_goto_hist((zmod.flags & MOD_MULT) ? zmult : curhist, 0) &&
isset(HISTBEEP))
feep();
}
@ -1041,7 +1022,8 @@ vihistorysearchbackward(void)
void
virepeatsearch(void)
{
int hl = histline, t0;
Histent he;
int t0;
int n = zmult;
char *s;
@ -1054,23 +1036,21 @@ virepeatsearch(void)
visrchsense = -visrchsense;
}
t0 = strlen(visrchstr);
for (;;) {
hl += visrchsense;
if (!(s = zle_get_event(hl))) {
feep();
return;
he = quietgethist(histline);
while ((he = movehistent(he, visrchsense, hist_skip_flags))) {
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
continue;
s = ZLETEXT(he);
if (metadiffer(s, (char *) line, ll)
&& (*visrchstr == '^'? strncmp(s, visrchstr + 1, t0 - 1) == 0
: hstrnstr(s, 0, visrchstr, t0, 1, 1) != 0)) {
if (--n <= 0) {
zle_setline(he);
return;
}
}
if (!metadiffer(s, (char *) line, ll))
continue;
if (*visrchstr == '^') {
if (strncmp(s, visrchstr + 1, t0 - 1) != 0)
continue;
} else if (!hstrnstr(s, 0, visrchstr, t0, 1, 1))
continue;
if (--n <= 0)
break;
}
zle_goto_hist(hl);
feep();
}
/**/
@ -1090,8 +1070,8 @@ virevrepeatsearch(void)
void
historybeginningsearchbackward(void)
{
Histent he;
int cpos = cs; /* save cursor position */
int hl = histline;
int n = zmult;
char *s;
@ -1101,20 +1081,21 @@ historybeginningsearchbackward(void)
zmult = n;
return;
}
for (;;) {
hl--;
if (!(s = zle_get_event(hl))) {
feep();
return;
}
he = quietgethist(histline);
while ((he = movehistent(he, -1, hist_skip_flags))) {
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
continue;
s = ZLETEXT(he);
if (metadiffer(s, (char *)line, cs) < 0 &&
metadiffer(s, (char *)line, ll))
if (--n <= 0)
break;
metadiffer(s, (char *)line, ll)) {
if (--n <= 0) {
zle_setline(he);
cs = cpos;
return;
}
}
}
zle_goto_hist(hl);
cs = cpos;
feep();
}
/* Extra function added by A.R. Iano-Fletcher. */
@ -1124,8 +1105,8 @@ historybeginningsearchbackward(void)
void
historybeginningsearchforward(void)
{
Histent he;
int cpos = cs; /* save cursor position */
int hl = histline;
int n = zmult;
char *s;
@ -1135,18 +1116,19 @@ historybeginningsearchforward(void)
zmult = n;
return;
}
for (;;) {
hl++;
if (!(s = zle_get_event(hl))) {
feep();
return;
he = quietgethist(histline);
while ((he = movehistent(he, 1, hist_skip_flags))) {
if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
continue;
s = ZLETEXT(he);
if (metadiffer(s, (char *)line, cs) < (he->histnum == curhist) &&
metadiffer(s, (char *)line, ll)) {
if (--n <= 0) {
zle_setline(he);
cs = cpos;
return;
}
}
if (metadiffer(s, (char *)line, cs) < (hl == curhist) &&
metadiffer(s, (char *)line, ll))
if (--n <= 0)
break;
}
zle_goto_hist(hl);
cs = cpos;
feep();
}

View file

@ -130,6 +130,7 @@ createkeymapnamtab(void)
keymapnamtab->hash = hasher;
keymapnamtab->emptytable = emptyhashtable;
keymapnamtab->filltable = NULL;
keymapnamtab->cmpnodes = strcmp;
keymapnamtab->addnode = addhashnode;
keymapnamtab->getnode = gethashnode2;
keymapnamtab->getnode2 = gethashnode2;
@ -172,6 +173,7 @@ newkeytab(char *kmname)
ht->hash = hasher;
ht->emptytable = emptyhashtable;
ht->filltable = NULL;
ht->cmpnodes = strcmp;
ht->addnode = addhashnode;
ht->getnode = gethashnode2;
ht->getnode2 = gethashnode2;

View file

@ -111,6 +111,10 @@ int prefixflag;
/**/
int feepflag;
#ifdef FIONREAD
static int delayzsetterm;
#endif
/* set up terminal */
/**/
@ -119,12 +123,30 @@ zsetterm(void)
{
struct ttyinfo ti;
#if defined(CLOBBERS_TYPEAHEAD) && defined(FIONREAD)
#if defined(FIONREAD)
int val;
ioctl(SHTTY, FIONREAD, (char *)&val);
if (val)
if (val) {
/*
* Problems can occur on some systems when switching from
* canonical to non-canonical input. The former is usually
* set while running programmes, but the latter is necessary
* for zle. If there is input in canonical mode, then we
* need to read it without setting up the terminal. Furthermore,
* while that input gets processed there may be more input
* being typed (i.e. further typeahead). This means that
* we can't set up the terminal for zle *at all* until
* we are sure there is no more typeahead to come. So
* if there is typeahead, we set the flag delayzsetterm.
* Then getkey() performs another FIONREAD call; if that is
* 0, we have finally used up all the typeahead, and it is
* safe to alter the terminal, which we do at that point.
*/
delayzsetterm = 1;
return;
} else
delayzsetterm = 0;
#endif
/* sanitize the tty */
@ -298,7 +320,19 @@ getkey(int keytmout)
if (kungetct)
ret = STOUC(kungetbuf[--kungetct]);
else {
if (keytmout) {
#ifdef FIONREAD
if (delayzsetterm) {
int val;
ioctl(SHTTY, FIONREAD, (char *)&val);
if (!val)
zsetterm();
}
#endif
if (keytmout
#ifdef FIONREAD
&& ! delayzsetterm
#endif
) {
if (keytimeout > 500)
exp100ths = 500;
else if (keytimeout > 0)
@ -461,7 +495,6 @@ zleread(char *lp, char *rp, int flags)
undoing = 1;
line = (unsigned char *)zalloc((linesz = 256) + 2);
virangeflag = lastcmd = done = cs = ll = mark = 0;
curhistline = NULL;
vichgflag = 0;
viinsbegin = 0;
statusline = NULL;
@ -542,7 +575,6 @@ zleread(char *lp, char *rp, int flags)
zleactive = no_restore_tty = 0;
alarm(0);
} LASTALLOC;
zsfree(curhistline);
freeundo();
if (eofsent) {
free(line);

View file

@ -476,17 +476,10 @@ vigotomark(void)
feep();
return;
}
if (curhist != vimarkline[ch]) {
char *s;
remember_edits();
if (!(s = qgetevent(vimarkline[ch]))) {
vimarkline[ch] = 0;
feep();
return;
}
histline = vimarkline[ch];
setline(s);
if (curhist != vimarkline[ch] && !zle_goto_hist(vimarkline[ch], 0)) {
vimarkline[ch] = 0;
feep();
return;
}
cs = vimarkcs[ch];
if (cs > ll)

View file

@ -64,6 +64,7 @@ createthingytab(void)
thingytab->hash = hasher;
thingytab->emptytable = emptythingytab;
thingytab->filltable = NULL;
thingytab->cmpnodes = strcmp;
thingytab->addnode = addhashnode;
thingytab->getnode = gethashnode;
thingytab->getnode2 = gethashnode2;
@ -356,7 +357,7 @@ bin_zle(char *name, char **args, char *ops, int func)
/* check number of arguments */
for(n = 0; args[n]; n++) ;
if(!op->o && n != 1) {
if(!op->o && n != 1 && n != 2) {
zerrnam(name, "wrong number of arguments", NULL, 0);
return 1;
}
@ -515,17 +516,31 @@ static int
bin_zle_call(char *name, char **args, char *ops, char func)
{
Thingy t;
struct modifier modsave;
if(!zleactive || incompctlfunc || incompfunc) {
zerrnam(name, "widgets can only be called when ZLE is active",
NULL, 0);
return 1;
}
if (args[1]) {
modsave = zmod;
if (isdigit(*args[1])) {
zmod.mult = atoi(args[1]);
zmod.flags |= MOD_MULT;
}
else {
zmod.mult = 1;
zmod.flags &= ~MOD_MULT;
}
}
t = rthingy(args[0]);
PERMALLOC {
execzlefunc(t);
} LASTALLOC;
unrefthingy(t);
if (args[1])
zmod = modsave;
return 0;
}

View file

@ -578,6 +578,10 @@ static char *varname;
static int insubscr;
/* Parameter pointer for completing keys of an assoc array. */
static Param keypm;
/* 1 if we are completing in a quoted string (or inside `...`) */
/**/
@ -1364,9 +1368,15 @@ get_comp_string(void)
zsfree(varname);
varname = ztrdup(tt);
*s = sav;
if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb)
s = NULL, inwhat = IN_MATH, insubscr = 1;
else if (*s == '=' && cs > wb + (s - tt)) {
if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb) {
s = NULL;
inwhat = IN_MATH;
if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
(keypm->flags & PM_HASHED))
insubscr = 2;
else
insubscr = 1;
} else if (*s == '=' && cs > wb + (s - tt)) {
s++;
wb += s - tt;
t0 = STRING;
@ -1424,11 +1434,15 @@ get_comp_string(void)
zsfree(varname);
varname = ztrdup(nb);
*ne = sav;
if ((keypm = (Param) paramtab->getnode(paramtab,
varname)) &&
(keypm->flags & PM_HASHED))
insubscr = 2;
}
}
}
if (inwhat == IN_MATH) {
if (compfunc) {
if (compfunc || insubscr == 2) {
int lev;
char *p;
@ -1472,7 +1486,11 @@ get_comp_string(void)
zsfree(varname);
varname = ztrdup((char *) line + i + 1);
line[wb - 1] = sav;
insubscr = 1;
if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
(keypm->flags & PM_HASHED))
insubscr = 2;
else
insubscr = 1;
}
}
/* This variable will hold the current word in quoted form. */
@ -3524,7 +3542,7 @@ int
addmatches(Cadata dat, char **argv)
{
char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
char **aign = NULL, **dparr;
char **aign = NULL, **dparr = NULL;
int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
int oisalt = 0, isalt, isexact, doadd;
Cline lc = NULL;
@ -4360,7 +4378,7 @@ callcompfunc(char *s, char *fn)
PERMALLOC {
q = compwords = (char **)
zalloc((clwnum - aadd + 1) * sizeof(char *));
zalloc((clwnum + 1) * sizeof(char *));
for (p = clwords + aadd; *p; p++, q++) {
tmp = dupstring(*p);
untokenize(tmp);
@ -4829,13 +4847,22 @@ makecomplistglobal(char *os, int incmd, int lst, int flags)
char *s;
ccont = CC_CCCONT;
cc_dummy.suffix = NULL;
if (linwhat == IN_ENV) {
/* Default completion for parameter values. */
cc = &cc_default;
keypm = NULL;
} else if (linwhat == IN_MATH) {
/* Parameter names inside mathematical expression. */
cc_dummy.mask = CC_PARAMS;
if (insubscr == 2) {
/* Inside subscript of assoc array, complete keys. */
cc_dummy.mask = 0;
cc_dummy.suffix = "]";
} else {
/* Other math environment, complete paramete names. */
keypm = NULL;
cc_dummy.mask = CC_PARAMS;
}
cc = &cc_dummy;
cc_dummy.refc = 10000;
} else if (linwhat == IN_COND) {
@ -4851,13 +4878,16 @@ makecomplistglobal(char *os, int incmd, int lst, int flags)
(CC_FILES | CC_PARAMS);
cc = &cc_dummy;
cc_dummy.refc = 10000;
} else if (linredir)
keypm = NULL;
} else if (linredir) {
/* In redirections use default completion. */
cc = &cc_default;
else
keypm = NULL;
} else {
/* Otherwise get the matches for the command. */
keypm = NULL;
return makecomplistcmd(os, incmd, flags);
}
if (cc) {
/* First, use the -T compctl. */
if (!(flags & CFN_FIRST)) {
@ -5917,7 +5947,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
Comp compc = NULL;
char *e, *h, hpatsav;
Histent he;
int i = curhist - 1, n = cc->hnum;
int i = addhistnum(curhist,-1,HIST_FOREIGN), n = cc->hnum;
/* Parse the pattern, if it isn't the null string. */
if (*(cc->hpat)) {
@ -5971,7 +6001,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
if ((t = cc->mask & (CC_ALREG | CC_ALGLOB)))
/* Add the two types of aliases. */
dumphashtable(aliastab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
if (keypm && cc == &cc_dummy) {
/* Add the keys of the parameter in keypm. */
scanhashtable(keypm->gets.hfn(keypm), 0, 0, PM_UNSET, addhnmatch, 0);
keypm = NULL;
cc_dummy.suffix = NULL;
}
if (!errflag && cc->ylist) {
/* generate the user-defined display list: if anything fails, *
* we silently allow the normal completion list to be used. */

View file

@ -572,10 +572,8 @@ undo(void)
static void
unapplychange(struct change *ch)
{
if(ch->hist != histline) {
remember_edits();
setline(zle_get_event(histline = ch->hist));
}
if(ch->hist != histline)
zle_setline(quietgethist(ch->hist));
cs = ch->off;
if(ch->ins)
foredel(ztrlen(ch->ins));
@ -613,10 +611,8 @@ redo(void)
static void
applychange(struct change *ch)
{
if(ch->hist != histline) {
remember_edits();
setline(zle_get_event(histline = ch->hist));
}
if(ch->hist != histline)
zle_setline(quietgethist(ch->hist));
cs = ch->off;
if(ch->del)
foredel(ztrlen(ch->del));

View file

@ -120,7 +120,7 @@ static struct builtin builtins[] =
BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
#ifdef DYNAMIC
BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicIp", NULL),
BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ILabcdipu", NULL),
#endif
};
@ -142,6 +142,7 @@ createbuiltintable(void)
builtintab->hash = hasher;
builtintab->emptytable = NULL;
builtintab->filltable = NULL;
builtintab->cmpnodes = strcmp;
builtintab->addnode = addhashnode;
builtintab->getnode = gethashnode;
builtintab->getnode2 = gethashnode2;
@ -1146,19 +1147,17 @@ bin_fc(char *nam, char **argv, char *ops, int func)
}
if (ops['R']) {
/* read history from a file */
readhistfile(*argv ? *argv : getsparam("HISTFILE"), 1);
readhistfile(*argv, 1, ops['I'] ? HFILE_SKIPOLD : 0);
return 0;
}
if (ops['W']) {
/* write history to a file */
savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1,
(ops['I'] ? 2 : 0));
savehistfile(*argv, 1, ops['I'] ? HFILE_SKIPOLD : 0);
return 0;
}
if (ops['A']) {
/* append history to a file */
savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1,
(ops['I'] ? 3 : 1));
savehistfile(*argv, 1, HFILE_APPEND | (ops['I'] ? HFILE_SKIPOLD : 0));
return 0;
}
if (!(ops['l'] && unset(HISTNOSTORE)))
@ -1200,9 +1199,9 @@ bin_fc(char *nam, char **argv, char *ops, int func)
}
/* default values of first and last, and range checking */
if (first == -1)
first = (ops['l']) ? curhist - 16 : curhist - 1;
first = ops['l']? addhistnum(curhist,-16,0) : addhistnum(curhist,-1,0);
if (last == -1)
last = (ops['l']) ? curhist - 1 : first;
last = ops['l']? addhistnum(curhist,-1,0) : first;
if (first < firsthist())
first = firsthist();
if (last == -1)
@ -1267,7 +1266,7 @@ fcgetcomm(char *s)
* numbers indicate reversed numbering. */
if ((cmd = atoi(s))) {
if (cmd < 0)
cmd = curhist + cmd;
cmd = addhistnum(curhist,cmd,HIST_FOREIGN);
if (cmd >= curhist) {
zwarnnam("fc", "bad history number: %d", 0, cmd);
return -1;
@ -1331,7 +1330,7 @@ static int
fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment *subs, Comp com)
{
int fclistdone = 0;
char *s, *hs;
char *s;
Histent ent;
/* reverse range if required */
@ -1344,28 +1343,31 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment
if (!subs)
fclistdone = 1;
for (;;) {
hs = quietgetevent(first);
if (!hs) {
ent = gethistent(first, first < last? GETHIST_DOWNWARD : GETHIST_UPWARD);
if (!ent || ent->histnum < first || ent->histnum > last) {
if (first == last)
zwarnnam("fc", "no such event: %d", NULL, first);
return 1;
}
s = dupstring(hs);
else
zwarnnam("fc", "no events in that range", NULL, 0);
return 1;
}
for (;;) {
s = dupstring(ent->text);
/* this if does the pattern matching, if required */
if (!com || domatch(s, com, 0)) {
/* perform substitution */
fclistdone |= fcsubs(&s, subs);
/* do numbering */
if (n)
fprintf(f, "%5d ", first);
ent = NULL;
if (n) {
fprintf(f, "%5d%c ", ent->histnum,
ent->flags & HIST_FOREIGN? '*' : ' ');
}
/* output actual time (and possibly date) of execution of the
command, if required */
if (d) {
struct tm *ltm;
if (!ent)
ent = gethistent(first);
ltm = localtime(&ent->stim);
if (d >= 2) {
if (d >= 8) {
@ -1387,8 +1389,6 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment
/* display the time taken by the command, if required */
if (D) {
long diff;
if (!ent)
ent = gethistent(first);
diff = (ent->ftim) ? ent->ftim - ent->stim : 0;
fprintf(f, "%ld:%02ld ", diff / 60, diff % 60);
}
@ -1401,12 +1401,14 @@ fclist(FILE *f, int n, int r, int D, int d, int first, int last, struct asgment
fprintf(f, "%s\n", s);
}
/* move on to the next history line, or quit the loop */
if (first == last)
break;
else if (first > last)
first--;
else
first++;
if (first < last) {
if (!(ent = down_histent(ent)) || ent->histnum > last)
break;
}
else {
if (!(ent = up_histent(ent)) || ent->histnum < last)
break;
}
}
/* final processing */
@ -1768,7 +1770,8 @@ bin_typeset(char *name, char **argv, char *ops, int func)
for (i = 0; i < paramtab->hsize; i++) {
for (pm = (Param) paramtab->nodes[i]; pm;
pm = (Param) pm->next) {
if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED))
if (((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) ||
(pm->flags & PM_UNSET))
continue;
if (domatch(pm->nam, com, 0))
addlinknode(pmlist, pm);
@ -2523,10 +2526,7 @@ bin_print(char *name, char **args, char *ops, int func)
char **pargs = args;
PERMALLOC {
ent = gethistent(++curhist);
zsfree(ent->text);
if (ent->nwords)
zfree(ent->words, ent->nwords*2*sizeof(short));
ent = prepnexthistent(++curhist);
while (*pargs++)
nwords++;
if ((ent->nwords = nwords)) {
@ -2543,6 +2543,7 @@ bin_print(char *name, char **args, char *ops, int func)
ent->text = zjoin(args, ' ');
ent->stim = ent->ftim = time(NULL);
ent->flags = 0;
addhistnode(histtab, ent->text, ent);
} LASTALLOC;
return 0;
}
@ -2952,7 +2953,7 @@ zexit(int val, int from_signal)
killrunjobs(from_signal);
if (isset(RCS) && interact) {
if (!nohistsave)
savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
savehistfile(NULL, 1, HFILE_USE_OPTIONS);
if (islogin && !subsh) {
sourcehome(".zlogout");
#ifdef GLOBAL_ZLOGOUT

View file

@ -1862,7 +1862,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
/* If we are exec'ing a command, and we are not in a subshell, *
* then check if we should save the history file. */
if (isset(RCS) && interact && !nohistsave)
savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
savehistfile(NULL, 1, HFILE_USE_OPTIONS);
exit(lastval);
}
@ -1874,7 +1874,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
/* If we are exec'ing a command, and we are not *
* in a subshell, then save the history file. */
if (!subsh && isset(RCS) && interact && !nohistsave)
savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
savehistfile(NULL, 1, HFILE_USE_OPTIONS);
}
if (type == SIMPLE) {
if (cmd->vars) {
@ -2232,7 +2232,7 @@ getoutput(char *cmd, int qt)
zclose(pipes[1]);
retval = readoutput(pipes[0], qt);
fdtable[pipes[0]] = 0;
child_suspend(0); /* unblocks */
waitforpid(pid); /* unblocks */
lastval = cmdoutval;
return retval;
}

View file

@ -83,7 +83,7 @@ hasher(char *str)
unsigned hashval = 0;
while (*str)
hashval += (hashval << 5) + ((unsigned) *str++);
hashval += (hashval << 5) + *(unsigned char *)str++;
return hashval;
}
@ -138,7 +138,7 @@ deletehashtable(HashTable ht)
}
/* Add a node to a hash table. *
* nam is the key to use in hashing. dat is a pointer *
* nam is the key to use in hashing. nodeptr points *
* to the node to add. If there is already a node in *
* the table with the same key, it is first freed, and *
* then the new node is added. If the number of nodes *
@ -148,6 +148,17 @@ deletehashtable(HashTable ht)
/**/
void
addhashnode(HashTable ht, char *nam, void *nodeptr)
{
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
if (oldnode)
ht->freenode(oldnode);
}
/* Add a node to a hash table, returning the old node on replacment. */
/**/
HashNode
addhashnode2(HashTable ht, char *nam, void *nodeptr)
{
unsigned hashval;
HashNode hn, hp, hq;
@ -164,11 +175,11 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
ht->nodes[hashval] = hn;
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
expandhashtable(ht);
return;
return NULL;
}
/* else check if the first node contains the same key */
if (!strcmp(hp->nam, hn->nam)) {
if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
ht->nodes[hashval] = hn;
replacing:
hn->next = hp->next;
@ -182,15 +193,14 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
} else if(ht->scan->u.u == hp)
ht->scan->u.u = hn;
}
ht->freenode(hp);
return;
return hp;
}
/* else run through the list and check all the keys */
hq = hp;
hp = hp->next;
for (; hp; hq = hp, hp = hp->next) {
if (!strcmp(hp->nam, hn->nam)) {
if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
hq->next = hn;
goto replacing;
}
@ -201,6 +211,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
ht->nodes[hashval] = hn;
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
expandhashtable(ht);
return NULL;
}
/* Get an enabled entry in a hash table. *
@ -217,7 +228,7 @@ gethashnode(HashTable ht, char *nam)
hashval = ht->hash(nam) % ht->hsize;
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
if (!strcmp(hp->nam, nam)) {
if (ht->cmpnodes(hp->nam, nam) == 0) {
if (hp->flags & DISABLED)
return NULL;
else
@ -241,7 +252,7 @@ gethashnode2(HashTable ht, char *nam)
hashval = ht->hash(nam) % ht->hsize;
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
if (!strcmp(hp->nam, nam))
if (ht->cmpnodes(hp->nam, nam) == 0)
return hp;
}
return NULL;
@ -267,7 +278,7 @@ removehashnode(HashTable ht, char *nam)
return NULL;
/* else check if the key in the first one matches */
if (!strcmp(hp->nam, nam)) {
if (ht->cmpnodes(hp->nam, nam) == 0) {
ht->nodes[hashval] = hp->next;
gotit:
ht->ct--;
@ -288,7 +299,7 @@ removehashnode(HashTable ht, char *nam)
hq = hp;
hp = hp->next;
for (; hp; hq = hp, hp = hp->next) {
if (!strcmp(hp->nam, nam)) {
if (ht->cmpnodes(hp->nam, nam) == 0) {
hq->next = hp->next;
goto gotit;
}
@ -316,7 +327,7 @@ enablehashnode(HashNode hn, int flags)
hn->flags &= ~DISABLED;
}
/* Compare two hash table entries */
/* Compare two hash table entries by name */
/**/
static int
@ -498,6 +509,7 @@ emptyhashtable(HashTable ht)
resizehashtable(ht, ht->hsize);
}
/**/
#ifdef ZSH_HASH_DEBUG
/* Print info about hash table */
@ -550,6 +562,7 @@ bin_hashinfo(char *nam, char **args, char *ops, int func)
return 0;
}
/**/
#endif /* ZSH_HASH_DEBUG */
/********************************/
@ -577,6 +590,7 @@ createcmdnamtable(void)
cmdnamtab->hash = hasher;
cmdnamtab->emptytable = emptycmdnamtable;
cmdnamtab->filltable = fillcmdnamtable;
cmdnamtab->cmpnodes = strcmp;
cmdnamtab->addnode = addhashnode;
cmdnamtab->getnode = gethashnode2;
cmdnamtab->getnode2 = gethashnode2;
@ -747,6 +761,7 @@ createshfunctable(void)
shfunctab->hash = hasher;
shfunctab->emptytable = NULL;
shfunctab->filltable = NULL;
shfunctab->cmpnodes = strcmp;
shfunctab->addnode = addhashnode;
shfunctab->getnode = gethashnode;
shfunctab->getnode2 = gethashnode2;
@ -920,6 +935,7 @@ createreswdtable(void)
reswdtab->hash = hasher;
reswdtab->emptytable = NULL;
reswdtab->filltable = NULL;
reswdtab->cmpnodes = strcmp;
reswdtab->addnode = addhashnode;
reswdtab->getnode = gethashnode;
reswdtab->getnode2 = gethashnode2;
@ -980,6 +996,7 @@ createaliastable(void)
aliastab->hash = hasher;
aliastab->emptytable = NULL;
aliastab->filltable = NULL;
aliastab->cmpnodes = strcmp;
aliastab->addnode = addhashnode;
aliastab->getnode = gethashnode;
aliastab->getnode2 = gethashnode2;
@ -1109,6 +1126,7 @@ createnameddirtable(void)
nameddirtab->hash = hasher;
nameddirtab->emptytable = emptynameddirtable;
nameddirtab->filltable = fillnameddirtable;
nameddirtab->cmpnodes = strcmp;
nameddirtab->addnode = addnameddirnode;
nameddirtab->getnode = gethashnode;
nameddirtab->getnode2 = gethashnode2;
@ -1219,3 +1237,137 @@ printnameddirnode(HashNode hn, int printflags)
quotedzputs(nd->dir, stdout);
putchar('\n');
}
/*************************************/
/* History Line Hash Table Functions */
/*************************************/
/**/
void
createhisttable(void)
{
histtab = newhashtable(599, "histtab", NULL);
histtab->hash = histhasher;
histtab->emptytable = emptyhisttable;
histtab->filltable = NULL;
histtab->cmpnodes = histstrcmp;
histtab->addnode = addhistnode;
histtab->getnode = gethashnode2;
histtab->getnode2 = gethashnode2;
histtab->removenode = removehashnode;
histtab->disablenode = NULL;
histtab->enablenode = NULL;
histtab->freenode = freehistnode;
histtab->printnode = NULL;
}
/**/
unsigned
histhasher(char *str)
{
unsigned hashval = 0;
while (inblank(*str)) str++;
while (*str) {
if (inblank(*str)) {
do str++; while (inblank(*str));
if (*str)
hashval += (hashval << 5) + ' ';
}
else
hashval += (hashval << 5) + *(unsigned char *)str++;
}
return hashval;
}
/**/
void
emptyhisttable(HashTable ht)
{
emptyhashtable(ht);
if (hist_ring)
histremovedups();
}
/* Compare two strings with normalized white-space */
/**/
int
histstrcmp(const char *str1, const char *str2)
{
while (inblank(*str1)) str1++;
while (inblank(*str2)) str2++;
while (*str1 && *str2) {
if (inblank(*str1)) {
if (!inblank(*str2))
break;
do str1++; while (inblank(*str1));
do str2++; while (inblank(*str2));
}
else {
if (*str1 != *str2)
break;
str1++;
str2++;
}
}
return *str1 - *str2;
}
/**/
void
addhistnode(HashTable ht, char *nam, void *nodeptr)
{
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
Histent he = (Histent)nodeptr;
if (oldnode && oldnode != nodeptr) {
if (he->flags & HIST_MAKEUNIQUE
|| (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
he->flags |= HIST_DUP;
addhashnode(ht, oldnode->nam, oldnode); /* Remove the new dup */
}
else {
oldnode->flags |= HIST_DUP;
if (hist_ignore_all_dups)
freehistnode(oldnode); /* Remove the old dup */
}
}
else
he->flags &= ~HIST_MAKEUNIQUE;
}
/**/
void
freehistnode(HashNode nodeptr)
{
freehistdata((Histent)nodeptr, 1);
zfree(nodeptr, sizeof (struct histent));
}
/**/
void
freehistdata(Histent he, int unlink)
{
if (!he)
return;
if (!(he->flags & HIST_DUP))
removehashnode(histtab, he->text);
zsfree(he->text);
if (he->nwords)
zfree(he->words, he->nwords*2*sizeof(short));
if (unlink) {
if (!--histlinect)
hist_ring = NULL;
else {
if (he == hist_ring)
hist_ring = hist_ring->up;
he->up->down = he->down;
he->down->up = he->up;
}
}
}

View file

@ -56,23 +56,29 @@ int excs, exlast;
* Note on curhist: with history inactive, this points to the
* last line actually added to the history list. With history active,
* the line does not get added to the list until hend(), if at all.
* However, curhist is incremented to reflect the current line anyway.
* Thus if the line is not added to the list, curhist must be
* However, curhist is incremented to reflect the current line anyway
* and a temporary history entry is inserted while the user is editing.
* If the resulting line was not added to the list, curhist is
* decremented in hend().
*/
/**/
int curhist;
/* number of history entries */
/**/
int histentct;
/* array of history entries */
struct histent curline;
/* current line count of allocated history entries */
/**/
Histent histentarr;
int histlinect;
/* The history lines are kept in a hash, and also doubly-linked in a ring */
/**/
HashTable histtab;
/**/
Histent hist_ring;
/* capacity of history lists */
@ -90,6 +96,17 @@ int histdone;
/**/
int histactive;
/* Current setting of the associated option, but sometimes also includes
* the setting of the HIST_SAVE_NO_DUPS option. */
/**/
int hist_ignore_all_dups;
/* What flags (if any) we should skip when moving through the history */
/**/
int hist_skip_flags;
/* Bits of histactive variable */
#define HA_ACTIVE (1<<0) /* History mechanism is active */
#define HA_NOSTORE (1<<1) /* Don't store the line when finished */
@ -395,7 +412,7 @@ histsubchar(int c)
if (!*buf) {
if (c != '%') {
if (isset(CSHJUNKIEHISTORY))
ev = curhist - 1;
ev = addhistnum(curhist,-1,HIST_FOREIGN);
else
ev = defev;
if (c == ':' && evset == -1)
@ -410,10 +427,10 @@ histsubchar(int c)
evset = 0;
}
} else if ((t0 = atoi(buf))) {
ev = (t0 < 0) ? curhist + t0 : t0;
ev = (t0 < 0) ? addhistnum(curhist,t0,HIST_FOREIGN) : t0;
evset = 1;
} else if ((unsigned)*buf == bangchar) {
ev = curhist - 1;
ev = addhistnum(curhist,-1,HIST_FOREIGN);
evset = 1;
} else if (*buf == '#') {
ev = curhist;
@ -650,8 +667,6 @@ strinend(void)
void
hbegin(void)
{
Histent curhistent;
isfirstln = isfirstch = 1;
errflag = histdone = spaceflag = 0;
stophist = (!interact || unset(BANGHIST) || unset(SHINSTDIN)) << 1;
@ -661,43 +676,23 @@ hbegin(void)
if (histactive & HA_JUNKED)
curhist--;
curhistent = gethistent(curhist);
if (!curhistent->ftim)
curhistent->ftim = time(NULL);
histactive = HA_ACTIVE;
if (hist_ring && !hist_ring->ftim)
hist_ring->ftim = time(NULL);
if (interact && isset(SHINSTDIN) && !strin) {
histactive = HA_ACTIVE;
attachtty(mypgrp);
defev = curhist;
curhist++;
if (!hist_ring)
hist_ring = curline.up = curline.down = &curline;
else {
curline.up = hist_ring;
curline.down = hist_ring->down;
hist_ring->down = hist_ring->down->up = &curline;
hist_ring = &curline;
}
curline.histnum = ++curhist;
defev = addhistnum(curhist, -1, HIST_FOREIGN);
} else
histactive |= HA_NOINC;
}
/* compare current line with history entry using only text in words */
/**/
static int
histcmp(Histent he)
{
int kword, lword;
int nwords = chwordpos/2;
/* If the history entry came from a file, the words were not
* divided by the lexer so we have to resort to strcmp.
*/
if (he->flags & HIST_READ)
return strcmp(he->text, chline);
if (nwords != he->nwords)
return 1;
for (kword = 0; kword < 2*nwords; kword += 2)
if ((lword = chwords[kword+1]-chwords[kword])
!= he->words[kword+1]-he->words[kword] ||
memcmp(he->text+he->words[kword], chline+chwords[kword], lword))
return 1;
return 0;
histactive = HA_ACTIVE | HA_NOINC;
}
/**/
@ -726,6 +721,140 @@ histreduceblanks(void)
chline[pos] = '\0';
}
/**/
void
histremovedups(void)
{
Histent he, next;
for (he = hist_ring; he; he = next) {
next = up_histent(he);
if (he->flags & HIST_DUP)
freehistnode((HashNode)he);
}
}
/**/
int
addhistnum(int hl, int n, int xflags)
{
int dir = n < 0? -1 : n > 0? 1 : 0;
Histent he = gethistent(hl, dir);
if (!he)
return 0;
if (he->histnum != hl)
n -= dir;
if (n)
he = movehistent(he, n, xflags);
if (!he)
return dir < 0? firsthist() : curhist;
return he->histnum;
}
/**/
Histent
movehistent(Histent he, int n, int xflags)
{
while (n < 0) {
if (!(he = up_histent(he)))
return NULL;
if (!(he->flags & xflags))
n++;
}
while (n > 0) {
if (!(he = down_histent(he)))
return NULL;
if (!(he->flags & xflags))
n--;
}
return he;
}
/**/
Histent
up_histent(Histent he)
{
return he->up == hist_ring? NULL : he->up;
}
/**/
Histent
down_histent(Histent he)
{
return he == hist_ring? NULL : he->down;
}
/**/
Histent
gethistent(int ev, int nearmatch)
{
Histent he;
if (!hist_ring)
return NULL;
if (ev - hist_ring->down->histnum < hist_ring->histnum - ev) {
for (he = hist_ring->down; he->histnum <= ev; he = he->down) {
if (he->histnum == ev)
return he;
}
if (nearmatch < 0)
return up_histent(he);
if (nearmatch > 0)
return he;
}
else {
for (he = hist_ring; he->histnum >= ev; he = he->up) {
if (he->histnum == ev)
return he;
}
if (nearmatch < 0)
return he;
if (nearmatch > 0)
return down_histent(he);
}
return NULL;
}
/**/
Histent
prepnexthistent(int histnum)
{
Histent he;
if (histlinect < histsiz) {
he = (Histent)zcalloc(sizeof *he);
if (!hist_ring)
hist_ring = he->up = he->down = he;
else {
he->up = hist_ring;
he->down = hist_ring->down;
hist_ring->down = he->down->up = he;
hist_ring = he;
}
histlinect++;
}
else {
he = hist_ring->down;
if (isset(HISTEXPIREDUPSFIRST) && !(he->flags & HIST_DUP)) {
do {
he = he->down;
} while (he != hist_ring->down && !(he->flags & HIST_DUP)) ;
if (he != hist_ring->down) {
he->up->down = he->down;
he->down->up = he->up;
he->up = hist_ring;
he->down = hist_ring->down;
hist_ring->down = he->down->up = he;
}
}
freehistdata(hist_ring = he, 0);
}
hist_ring->histnum = histnum;
return hist_ring;
}
/* say we're done using the history mechanism */
/**/
@ -733,19 +862,35 @@ int
hend(void)
{
int flag, save = 1;
char *hf = getsparam("HISTFILE");
DPUTS(!chline, "BUG: chline is NULL in hend()");
if (histdone & HISTFLAG_SETTY)
settyinfo(&shttyinfo);
if (!(histactive & HA_NOINC)) {
curline.up->down = curline.down;
curline.down->up = curline.up;
if (hist_ring == &curline) {
if (!histlinect)
hist_ring = NULL;
else
hist_ring = curline.up;
}
curhist--;
}
if (histactive & (HA_NOSTORE|HA_NOINC)) {
zfree(chline, hlinesz);
zfree(chwords, chwordlen*sizeof(short));
chline = NULL;
if (!(histactive & HA_NOINC))
curhist--;
histactive = 0;
return 1;
}
if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS)
&& (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0)
histremovedups();
/* For history sharing, lock history file once for both read and write */
if (isset(SHAREHISTORY) && lockhistfile(hf, 0))
readhistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
flag = histdone;
histdone = 0;
if (hptr < chline + 1)
@ -781,8 +926,10 @@ hend(void)
}
if (save) {
Histent he;
int keepflags = 0;
int keepflags;
for (he = hist_ring; he && he->flags & hist_skip_flags;
he = up_histent(he)) ;
#ifdef DEBUG
/* debugging only */
if (chwordpos%2) {
@ -796,23 +943,21 @@ hend(void)
/* strip superfluous blanks, if desired */
if (isset(HISTREDUCEBLANKS))
histreduceblanks();
if (isset(HISTIGNOREDUPS) && (he = gethistent(curhist - 1))
&& he->text && !histcmp(he)) {
if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && he
&& histstrcmp(chline, he->text) == 0) {
/* This history entry compares the same as the previous.
* In case minor changes were made, we overwrite the
* previous one with the current one. This also gets
* the timestamp right. However, keep the old flags.
* previous one with the current one. This also gets the
* timestamp right. Perhaps, preserve the HIST_OLD flag.
*/
keepflags = he->flags;
curhist--;
keepflags = he->flags & HIST_OLD; /* Avoid re-saving */
freehistdata(he, 0);
} else {
keepflags = 0;
he = prepnexthistent(++curhist);
}
he = gethistent(curhist);
zsfree(he->text);
he->text = ztrdup(chline);
if (he->nwords)
zfree(he->words, he->nwords*2*sizeof(short));
he->stim = time(NULL);
he->ftim = 0L;
he->flags = keepflags;
@ -821,12 +966,15 @@ hend(void)
he->words = (short *)zalloc(chwordpos * sizeof(short));
memcpy(he->words, chwords, chwordpos * sizeof(short));
}
} else
curhist--;
addhistnode(histtab, he->text, he);
}
zfree(chline, hlinesz);
zfree(chwords, chwordlen*sizeof(short));
chline = NULL;
histactive = 0;
if (isset(SHAREHISTORY) || isset(INCREMENTALAPPENDHISTORY))
savehistfile(hf, 1, HFILE_USE_OPTIONS | HFILE_FAST);
unlockhistfile(hf); /* It's OK to call this even if we aren't locked */
return !(flag & HISTFLAG_NOEXEC || errflag);
}
@ -838,10 +986,7 @@ remhist(void)
{
if (!(histactive & HA_ACTIVE)) {
if (!(histactive & HA_JUNKED)) {
/* make sure this doesn't show up when we do firsthist() */
Histent he = gethistent(curhist);
zsfree(he->text);
he->text = NULL;
freehistnode((HashNode)hist_ring);
histactive |= HA_JUNKED;
/* curhist-- is delayed until the next hbegin() */
}
@ -1026,18 +1171,21 @@ getargspec(int argc, int marg, int evset)
static int
hconsearch(char *str, int *marg)
{
int t0, t1 = 0;
int t1 = 0;
char *s;
Histent he;
for (t0 = curhist - 1; (he = quietgethist(t0)); t0--)
for (he = up_histent(hist_ring); he; he = up_histent(he)) {
if (he->flags & HIST_FOREIGN)
continue;
if ((s = strstr(he->text, str))) {
int pos = s - he->text;
while (t1 < he->nwords && he->words[2*t1] <= pos)
t1++;
*marg = t1 - 1;
return t0;
return he->histnum;
}
}
return -1;
}
@ -1047,12 +1195,15 @@ hconsearch(char *str, int *marg)
int
hcomsearch(char *str)
{
int t0;
char *hs;
Histent he;
int len = strlen(str);
for (t0 = curhist - 1; (hs = quietgetevent(t0)); t0--)
if (!strncmp(hs, str, strlen(str)))
return t0;
for (he = up_histent(hist_ring); he; he = up_histent(he)) {
if (he->flags & HIST_FOREIGN)
continue;
if (strncmp(he->text, str, len) == 0)
return he->histnum;
}
return -1;
}
@ -1206,33 +1357,15 @@ convamps(char *out, char *in, int inlen)
}
/**/
struct histent *
Histent
quietgethist(int ev)
{
static struct histent storehist;
if (ev < firsthist() || ev > curhist)
return NULL;
if (ev == curhist && (histactive & HA_ACTIVE)) {
/* The current history line has not been stored. Build it up
* from other variables.
*/
storehist.text = chline;
storehist.nwords = chwordpos/2;
storehist.words = chwords;
return &storehist;
} else
return gethistent(ev);
}
/**/
char *
quietgetevent(int ev)
{
Histent ent = quietgethist(ev);
return ent ? ent->text : NULL;
curline.text = chline;
curline.nwords = chwordpos/2;
curline.words = chwords;
}
return gethistent(ev, GETHIST_EXACT);
}
/**/
@ -1362,10 +1495,9 @@ quotebreak(char **tr)
return 0;
}
#if 0
/* read an arbitrary amount of data into a buffer until stop is found */
/**/
#if 0 /**/
char *
hdynread(int stop)
{
@ -1424,61 +1556,80 @@ hdynread2(int stop)
void
inithist(void)
{
histentct = histsiz;
histentarr = (Histent) zcalloc(histentct * sizeof *histentarr);
createhisttable();
}
/**/
void
resizehistents(void)
{
int newentct, t0, t1, firstlex;
Histent newarr;
newentct = histsiz;
newarr = (Histent) zcalloc(newentct * sizeof *newarr);
firstlex = curhist - histsiz + 1;
t0 = firsthist();
if (t0 < curhist - newentct)
t0 = curhist - newentct;
t1 = t0 % newentct;
for (; t0 <= curhist; t0++) {
newarr[t1] = *gethistent(t0);
if (t0 < firstlex) {
zsfree(newarr[t1].text);
newarr[t1].text = NULL;
}
t1++;
if (t1 == newentct)
t1 = 0;
}
free(histentarr);
histentarr = newarr;
histentct = newentct;
while (histlinect > histsiz)
freehistnode((HashNode)hist_ring->down);
}
/* Remember the last line in the history file so we can find it again. */
static struct {
char *text;
time_t stim, mtim;
off_t fpos, fsiz;
int next_write_ev;
} lasthist;
static int histfile_linect;
/**/
void
readhistfile(char *s, int err)
readhistfile(char *fn, int err, int readflags)
{
char *buf;
char *buf, *start = NULL;
FILE *in;
Histent ent;
time_t tim = time(NULL);
Histent he;
time_t stim, ftim, tim = time(NULL);
off_t fpos;
short *wordlist;
struct stat sb;
int nwordpos, nwordlist, bufsiz;
int searching, newflags;
if (!s)
if (!fn && !(fn = getsparam("HISTFILE")))
return;
if ((in = fopen(unmeta(s), "r"))) {
if (readflags & HFILE_FAST) {
if (stat(fn, &sb) < 0
|| (lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
|| !lockhistfile(fn, 0))
return;
lasthist.fsiz = sb.st_size;
lasthist.mtim = sb.st_mtime;
}
else if (!lockhistfile(fn, 1))
return;
if ((in = fopen(unmeta(fn), "r"))) {
nwordlist = 16;
wordlist = (short *)zalloc(nwordlist*sizeof(short));
bufsiz = 1024;
buf = zalloc(bufsiz);
while (fgets(buf, bufsiz, in)) {
if (readflags & HFILE_FAST && lasthist.text) {
if (lasthist.fpos < lasthist.fsiz) {
fseek(in, lasthist.fpos, 0);
searching = 1;
}
else {
histfile_linect = 0;
searching = -1;
}
} else
searching = 0;
newflags = HIST_OLD | HIST_READ;
if (readflags & HFILE_FAST)
newflags |= HIST_FOREIGN;
if (readflags & HFILE_SKIPOLD
|| (hist_ignore_all_dups && newflags & hist_skip_flags))
newflags |= HIST_MAKEUNIQUE;
while (fpos = ftell(in), fgets(buf, bufsiz, in)) {
int l = strlen(buf);
char *pt, *start;
char *pt;
while (l) {
while (buf[l - 1] != '\n') {
@ -1488,114 +1639,184 @@ readhistfile(char *s, int err)
l++;
break;
}
l = strlen(buf);
l += strlen(buf+l);
}
buf[l - 1] = '\0';
if (l > 1 && buf[l - 2] == '\\') {
buf[l - 2] = '\n';
fgets(buf + l - 1, bufsiz - (l - 1), in);
l = strlen(buf);
buf[--l - 1] = '\n';
fgets(buf + l, bufsiz - l, in);
l += strlen(buf+l);
} else
break;
}
ent = gethistent(++curhist);
pt = buf;
if (*pt == ':') {
pt++;
ent->stim = zstrtol(pt, NULL, 0);
stim = zstrtol(pt, NULL, 0);
for (; *pt != ':' && *pt; pt++);
if (*pt) {
pt++;
ent->ftim = zstrtol(pt, NULL, 0);
ftim = zstrtol(pt, NULL, 0);
for (; *pt != ';' && *pt; pt++);
if (*pt)
pt++;
} else {
ent->ftim = tim;
}
if (ent->stim == 0)
ent->stim = tim;
if (ent->ftim == 0)
ent->ftim = tim;
} else
ftim = stim;
} else {
ent->ftim = ent->stim = tim;
if (*pt == '\\' && pt[1] == ':')
pt++;
stim = ftim = 0;
}
zsfree(ent->text);
ent->text = ztrdup(pt);
ent->flags = HIST_OLD|HIST_READ;
if (ent->nwords)
zfree(ent->words, ent->nwords*2*sizeof(short));
if (searching) {
if (searching > 0) {
if (stim == lasthist.stim
&& histstrcmp(pt, lasthist.text) == 0)
searching = 0;
else {
fseek(in, 0, 0);
histfile_linect = 0;
searching = -1;
}
continue;
}
else if (stim < lasthist.stim) {
histfile_linect++;
continue;
}
searching = 0;
}
if (readflags & HFILE_USE_OPTIONS) {
histfile_linect++;
lasthist.fpos = fpos;
lasthist.stim = stim;
}
he = prepnexthistent(++curhist);
he->text = ztrdup(pt);
he->flags = newflags;
if ((he->stim = stim) == 0)
he->stim = he->ftim = tim;
else if (ftim < stim)
he->ftim = stim + ftim;
else
he->ftim = ftim;
/* Divide up the words. We don't know how it lexes,
so just look for spaces.
so just look for white-space.
*/
nwordpos = 0;
start = pt;
do {
while (*pt == ' ')
while (inblank(*pt))
pt++;
if (*pt) {
if (nwordpos >= nwordlist)
wordlist = (short *) realloc(wordlist,
(nwordlist += 16)*sizeof(short));
wordlist[nwordpos++] = pt - start;
while (*pt && *pt != ' ')
while (*pt && !inblank(*pt))
pt++;
wordlist[nwordpos++] = pt - start;
}
} while (*pt);
ent->nwords = nwordpos/2;
if (ent->nwords) {
ent->words = (short *)zalloc(nwordpos*sizeof(short));
memcpy(ent->words, wordlist, nwordpos*sizeof(short));
he->nwords = nwordpos/2;
if (he->nwords) {
he->words = (short *)zalloc(nwordpos*sizeof(short));
memcpy(he->words, wordlist, nwordpos*sizeof(short));
} else
ent->words = (short *)NULL;
he->words = (short *)NULL;
addhistnode(histtab, he->text, he);
if (hist_ring != he)
curhist--; /* We discarded a foreign duplicate */
}
if (start && readflags & HFILE_USE_OPTIONS) {
zsfree(lasthist.text);
lasthist.text = ztrdup(start);
}
fclose(in);
zfree(wordlist, nwordlist*sizeof(short));
zfree(buf, bufsiz);
fclose(in);
} else if (err)
zerr("can't read history file", s, 0);
zerr("can't read history file", fn, 0);
unlockhistfile(fn);
}
/**/
void
savehistfile(char *s, int err, int app)
savehistfile(char *fn, int err, int writeflags)
{
char *t;
char *t, *start = NULL;
FILE *out;
int ev;
Histent ent;
Histent he;
int xcurhist = curhist - !!(histactive & HA_ACTIVE);
int savehist = getiparam("SAVEHIST");
int extended_history = isset(EXTENDEDHISTORY);
if (!s || !interact || savehist <= 0)
if (!interact || savehist <= 0 || !hist_ring
|| (!fn && !(fn = getsparam("HISTFILE"))))
return;
ev = curhist - savehist + 1;
if (ev < firsthist())
ev = firsthist();
if (app & 1)
out = fdopen(open(unmeta(s),
O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600), "a");
else
out = fdopen(open(unmeta(s),
O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600), "w");
if (writeflags & HFILE_FAST) {
he = gethistent(lasthist.next_write_ev, GETHIST_DOWNWARD);
while (he && he->flags & HIST_OLD) {
lasthist.next_write_ev = he->histnum + 1;
he = down_histent(he);
}
if (!he || !lockhistfile(fn, 0))
return;
if (histfile_linect > savehist + savehist / 5)
writeflags &= ~HFILE_FAST;
}
else {
if (!lockhistfile(fn, 1))
return;
he = hist_ring->down;
}
if (writeflags & HFILE_USE_OPTIONS) {
if (isset(APPENDHISTORY) || isset(INCREMENTALAPPENDHISTORY)
|| isset(SHAREHISTORY))
writeflags |= HFILE_APPEND | HFILE_SKIPOLD;
else
histfile_linect = 0;
if (isset(HISTSAVENODUPS))
writeflags |= HFILE_SKIPDUPS;
if (isset(SHAREHISTORY))
extended_history = 1;
}
if (writeflags & HFILE_APPEND) {
out = fdopen(open(unmeta(fn),
O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600), "a");
}
else {
out = fdopen(open(unmeta(fn),
O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600), "w");
}
if (out) {
for (; ev <= curhist - !!(histactive & HA_ACTIVE); ev++) {
ent = gethistent(ev);
if (app & 2) {
if (ent->flags & HIST_OLD)
for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
if ((writeflags & HFILE_SKIPDUPS && he->flags & HIST_DUP)
|| (writeflags & HFILE_SKIPFOREIGN && he->flags & HIST_FOREIGN))
continue;
if (writeflags & HFILE_SKIPOLD) {
if (he->flags & HIST_OLD)
continue;
ent->flags |= HIST_OLD;
he->flags |= HIST_OLD;
if (writeflags & HFILE_USE_OPTIONS)
lasthist.next_write_ev = he->histnum + 1;
}
t = ent->text;
if (isset(EXTENDEDHISTORY)) {
fprintf(out, ": %ld:%ld;",
(long)ent->stim,
(long)ent->ftim);
if (writeflags & HFILE_USE_OPTIONS) {
lasthist.fpos = ftell(out);
lasthist.stim = he->stim;
histfile_linect++;
}
t = start = he->text;
if (extended_history) {
fprintf(out, ": %ld:%ld;", (long)he->stim,
he->ftim? (long)(he->ftim - he->stim) : 0L);
} else if (*t == ':')
fputc('\\', out);
@ -1606,69 +1827,109 @@ savehistfile(char *s, int err, int app)
}
fputc('\n', out);
}
if (start && writeflags & HFILE_USE_OPTIONS) {
struct stat sb;
fflush(out);
if (fstat(fileno(out), &sb) == 0) {
lasthist.fsiz = sb.st_size;
lasthist.mtim = sb.st_mtime;
}
zsfree(lasthist.text);
lasthist.text = ztrdup(start);
}
fclose(out);
if (app & 2 && (out = fopen(unmeta(s), "r"))) {
char **store, buf[1024], **ptr;
int i, l, histnum = 0;
if ((writeflags & (HFILE_SKIPOLD | HFILE_FAST)) == HFILE_SKIPOLD) {
HashTable remember_histtab = histtab;
Histent remember_hist_ring = hist_ring;
int remember_histlinect = histlinect;
int remember_curhist = curhist;
store = (char **)zcalloc((savehist + 1) * sizeof *store);
while (fgets(buf, sizeof(buf), out)) {
char *t;
hist_ring = NULL;
curhist = histlinect = 0;
histsiz = savehist;
createhisttable(); /* sets histtab */
if (store[i = histnum % savehist])
free(store[i]);
store[i] = ztrdup(buf);
l = strlen(buf);
if (l > 1) {
t = store[i] + l;
while ((t[-1] != '\n' ||
(t[-1] == '\n' && t[-2] == '\\')) &&
fgets(buf, sizeof(buf), out)) {
l += strlen(buf);
store[i] = zrealloc(store[i], l + 1);
t = store[i] + l;
strcat(store[i], buf);
}
}
histnum++;
}
fclose(out);
if ((out = fdopen(open(unmeta(s),
O_WRONLY | O_TRUNC | O_NOCTTY, 0600), "w"))) {
if (histnum < savehist)
for (i = 0; i < histnum; i++)
fprintf(out, "%s", store[i]);
else
for (i = histnum; i < histnum + savehist; i++)
fprintf(out, "%s", store[i % savehist]);
fclose(out);
}
for (ptr = store; *ptr; ptr++)
zsfree(*ptr);
free(store);
hist_ignore_all_dups |= isset(HISTSAVENODUPS);
readhistfile(fn, err, 0);
hist_ignore_all_dups = isset(HISTIGNOREALLDUPS);
savehistfile(fn, err, 0);
deletehashtable(histtab);
curhist = remember_curhist;
histlinect = remember_histlinect;
hist_ring = remember_hist_ring;
histtab = remember_histtab;
}
} else if (err)
zerr("can't write history file %s", s, 0);
zerr("can't write history file %s", fn, 0);
unlockhistfile(fn);
}
static int lockhistct;
/**/
int
firsthist(void)
lockhistfile(char *fn, int keep_trying)
{
int ev;
Histent ent;
int ct = lockhistct;
ev = curhist - histentct + 1;
if (ev < 1)
ev = 1;
do {
ent = gethistent(ev);
if (ent->text)
break;
ev++;
if (!fn && !(fn = getsparam("HISTFILE")))
return 0;
if (!lockhistct++) {
struct stat sb;
int fd, len = strlen(fn);
char *tmpfile, *lockfile;
tmpfile = zalloc(len + 10 + 1);
sprintf(tmpfile, "%s.%ld", fn, mypid);
if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_EXCL, 0644)) >= 0) {
write(fd, "0\n", 2);
close(fd);
lockfile = zalloc(len + 5 + 1);
sprintf(lockfile, "%s.LOCK", fn);
while (link(tmpfile, lockfile) < 0) {
if (stat(lockfile, &sb) < 0) {
if (errno == ENOENT)
continue;
}
else if (keep_trying) {
if (time(NULL) - sb.st_mtime < 10)
sleep(1);
else
unlink(lockfile);
continue;
}
lockhistct--;
break;
}
free(lockfile);
}
unlink(tmpfile);
free(tmpfile);
}
while (ev < curhist);
return ev;
return ct != lockhistct;
}
/* Unlock the history file if this corresponds to the last nested lock
* request. If we don't have the file locked, just return.
*/
/**/
void
unlockhistfile(char *fn)
{
if (!fn && !(fn = getsparam("HISTFILE")))
return;
if (--lockhistct) {
if (lockhistct < 0)
lockhistct = 0;
}
else {
char *lockfile = zalloc(strlen(fn) + 5 + 1);
sprintf(lockfile, "%s.LOCK", fn);
unlink(lockfile);
free(lockfile);
}
}

View file

@ -110,15 +110,14 @@ loop(int toplevel, int justonce)
List prelist;
if (toplevel && (prelist = getshfunc("preexec")) != &dummy_list) {
Histent he = gethistent(curhist);
LinkList args;
int osc = sfcontext;
PERMALLOC {
args = newlinklist();
addlinknode(args, "preexec");
if (he && he->text)
addlinknode(args, he->text);
if (hist_ring)
addlinknode(args, hist_ring->text);
} LASTALLOC;
sfcontext = SFC_HOOK;
doshfunc("preexec", prelist, args, 0, 1);
@ -642,11 +641,13 @@ setupvals(void)
wrappers = NULL;
#ifdef TIOCGWINSZ
adjustwinsize();
adjustwinsize(0);
#else
/* Using zero below sets the defaults from termcap */
setiparam("COLUMNS", 0);
setiparam("LINES", 0);
/* columns and lines are normally zero, unless something different *
* was inhereted from the environment. If either of them are zero *
* the setiparam calls below set them to the defaults from termcap */
setiparam("COLUMNS", columns);
setiparam("LINES", lines);
#endif
#ifdef HAVE_GETRLIMIT
@ -828,7 +829,7 @@ init_misc(void)
}
if (interact && isset(RCS))
readhistfile(getsparam("HISTFILE"), 0);
readhistfile(NULL, 0, HFILE_USE_OPTIONS);
}
/* source a file */

View file

@ -180,11 +180,14 @@ update_job(Job jn)
} else { /* job is done, so remember return value */
lastval2 = val;
/* If last process was run in the current shell, keep old status
* and let it handle its own traps
* and let it handle its own traps, but always allow the test
* for the pgrp.
*/
if (job == thisjob && !(jn->stat & STAT_CURSH)) {
lastval = val;
inforeground = 1;
if (jn->stat & STAT_CURSH)
inforeground = 1;
else if (job == thisjob) {
lastval = val;
inforeground = 2;
}
}
@ -198,8 +201,20 @@ update_job(Job jn)
/* is this job in the foreground of an interactive shell? */
if (mypgrp != pgrp && inforeground &&
(jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
attachtty(mypgrp);
adjustwinsize(); /* check window size and adjust if necessary */
if (list_pipe) {
/*
* Oh, dear, we're right in the middle of some confusion
* of shell jobs on the righthand side of a pipeline, so
* it's death to call attachtty() just yet. Mark the
* fact in the job, so that the attachtty() will be called
* when the job is finally deleted.
*/
jn->stat |= STAT_ATTACH;
} else {
attachtty(mypgrp);
/* check window size and adjust if necessary */
adjustwinsize(0);
}
}
}
@ -223,7 +238,7 @@ update_job(Job jn)
* process group from the shell, so the shell will not receive *
* terminal signals, therefore we we pretend that the shell got *
* the signal too. */
if (inforeground && isset(MONITOR) && WIFSIGNALED(status)) {
if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) {
int sig = WTERMSIG(status);
if (sig == SIGINT || sig == SIGQUIT) {
@ -609,6 +624,11 @@ deletejob(Job jn)
{
struct process *pn, *nx;
if (jn->stat & STAT_ATTACH) {
attachtty(mypgrp);
adjustwinsize(0);
}
pn = jn->procs;
jn->procs = NULL;
for (; pn; pn = nx) {

View file

@ -142,6 +142,7 @@ addwrapper(Module m, FuncWrap w)
return 0;
}
/**/
#ifdef DYNAMIC
/* $module_path ($MODULE_PATH) */
@ -238,6 +239,7 @@ deletewrapper(Module m, FuncWrap w)
return 1;
}
/**/
#ifdef AIXDYNAMIC
#include <sys/ldr.h>
@ -273,6 +275,7 @@ load_and_bind(const char *fn)
#define dlclose(X) unload(X)
#define dlerror() (dlerrstr[0])
/**/
#else
#ifdef HAVE_DLFCN_H
@ -289,6 +292,7 @@ load_and_bind(const char *fn)
# endif
#endif
/**/
#ifdef HPUXDYNAMIC
# define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
# define dlclose(handle) shl_unload((shl_t)(handle))
@ -309,6 +313,7 @@ hpux_dlsym(void *handle, char *name)
# ifndef HAVE_DLCLOSE
# define dlclose(X) ((X), 0)
# endif
/**/
#endif
#ifdef DLSYM_NEEDS_UNDERSCORE
@ -331,6 +336,7 @@ hpux_dlsym(void *handle, char *name)
# define STR_FINISH_S "finish_%s"
#endif /* !DLSYM_NEEDS_UNDERSCORE */
/**/
#endif /* !AIXDYNAMIC */
#ifndef RTLD_LAZY
@ -408,6 +414,7 @@ find_module(const char *name)
return NULL;
}
/**/
#ifdef AIXDYNAMIC
/**/
@ -438,6 +445,7 @@ finish_module(Module m)
return ((int (*)_((int,Module))) m->handle)(3, m);
}
/**/
#else
static Module_func
@ -523,6 +531,7 @@ finish_module(Module m)
return r;
}
/**/
#endif /* !AIXDYNAMIC */
/**/
@ -664,7 +673,7 @@ autoloadscan(HashNode hn, int printflags)
if(bn->flags & BINF_ADDED)
return;
if(printflags & PRINT_LIST) {
fputs("zmodload -a ", stdout);
fputs("zmodload -ab ", stdout);
if(bn->optstr[0] == '-')
fputs("-- ", stdout);
quotedzputs(bn->optstr, stdout);
@ -687,7 +696,12 @@ autoloadscan(HashNode hn, int printflags)
int
bin_zmodload(char *nam, char **args, char *ops, int func)
{
if(ops['d'] && ops['a']) {
if ((ops['b'] || ops['c'] || ops['p']) && !(ops['a'] || ops['u'])) {
zwarnnam(nam, "-b, -c, and -p must be combined with -a or -u",
NULL, 0);
return 1;
}
if (ops['d'] && ops['a']) {
zwarnnam(nam, "-d cannot be combined with -a", NULL, 0);
return 1;
}
@ -695,16 +709,20 @@ bin_zmodload(char *nam, char **args, char *ops, int func)
zwarnnam(nam, "what do you want to unload?", NULL, 0);
return 1;
}
if(ops['d'])
if (ops['d'])
return bin_zmodload_dep(nam, args, ops);
else if(ops['a'])
else if ((ops['a'] || ops['b']) && !(ops['c'] || ops['p']))
return bin_zmodload_auto(nam, args, ops);
else if (ops['c'] || ops['C'])
else if (ops['c'] && !(ops['b'] || ops['p']))
return bin_zmodload_cond(nam, args, ops);
else if (ops['p'])
else if (ops['p'] && !(ops['b'] || ops['c']))
return bin_zmodload_param(nam, args, ops);
else
else if (!(ops['a'] || ops['b'] || ops['c'] || ops['p']))
return bin_zmodload_load(nam, args, ops);
else
zwarnnam(nam, "use only one of -b, -c, or -p", NULL, 0);
return 1;
}
/**/
@ -865,7 +883,7 @@ bin_zmodload_cond(char *nam, char **args, char *ops)
for (p = condtab; p; p = p->next) {
if (p->module) {
if (ops['L']) {
fputs("zmodload -c", stdout);
fputs("zmodload -ac", stdout);
if (p->flags & CONDF_INFIX)
putchar('I');
printf(" %s %s\n", p->module, p->name);
@ -908,7 +926,7 @@ printautoparams(HashNode hn, int lon)
if (pm->flags & PM_AUTOLOAD) {
if (lon)
printf("zmodload -p %s %s\n", pm->u.str, pm->nam);
printf("zmodload -ap %s %s\n", pm->u.str, pm->nam);
else
printf("%s (%s)\n", pm->nam, pm->u.str);
}
@ -1097,6 +1115,7 @@ bin_zmodload_load(char *nam, char **args, char *ops)
}
}
/**/
#endif /* DYNAMIC */
/* The list of module-defined conditions. */
@ -1252,6 +1271,7 @@ deleteparamdefs(char const *nam, Paramdef d, int size)
return 1;
}
/**/
#ifdef DYNAMIC
/* This adds a definition for autoloading a module for a condition. */
@ -1342,4 +1362,5 @@ add_autoparam(char *nam, char *module)
pm->flags |= PM_AUTOLOAD;
}
/**/
#endif

View file

@ -124,15 +124,20 @@ static struct optname optns[] = {
{NULL, "hashlistall", OPT_ALL, HASHLISTALL},
{NULL, "histallowclobber", 0, HISTALLOWCLOBBER},
{NULL, "histbeep", OPT_ALL, HISTBEEP},
{NULL, "histexpiredupsfirst", 0, HISTEXPIREDUPSFIRST},
{NULL, "histfindnodups", 0, HISTFINDNODUPS},
{NULL, "histignorealldups", 0, HISTIGNOREALLDUPS},
{NULL, "histignoredups", 0, HISTIGNOREDUPS},
{NULL, "histignorespace", 0, HISTIGNORESPACE},
{NULL, "histnofunctions", 0, HISTNOFUNCTIONS},
{NULL, "histnostore", 0, HISTNOSTORE},
{NULL, "histreduceblanks", 0, HISTREDUCEBLANKS},
{NULL, "histsavenodups", 0, HISTSAVENODUPS},
{NULL, "histverify", 0, HISTVERIFY},
{NULL, "hup", OPT_EMULATE|OPT_ZSH, HUP},
{NULL, "ignorebraces", OPT_EMULATE|OPT_SH, IGNOREBRACES},
{NULL, "ignoreeof", 0, IGNOREEOF},
{NULL, "incrementalappendhistory",0, INCREMENTALAPPENDHISTORY},
{NULL, "interactive", OPT_SPECIAL, INTERACTIVE},
{NULL, "interactivecomments", OPT_EMULATE|OPT_BOURNE, INTERACTIVECOMMENTS},
{NULL, "ksharrays", OPT_EMULATE|OPT_BOURNE, KSHARRAYS},
@ -176,6 +181,7 @@ static struct optname optns[] = {
{NULL, "restricted", OPT_SPECIAL, RESTRICTED},
{NULL, "rmstarsilent", OPT_BOURNE, RMSTARSILENT},
{NULL, "rmstarwait", 0, RMSTARWAIT},
{NULL, "sharehistory", OPT_KSH, SHAREHISTORY},
{NULL, "shfileexpansion", OPT_EMULATE|OPT_BOURNE, SHFILEEXPANSION},
{NULL, "shglob", OPT_EMULATE|OPT_BOURNE, SHGLOB},
{NULL, "shinstdin", OPT_SPECIAL, SHINSTDIN},
@ -378,9 +384,9 @@ printoptionnode(HashNode hn, int set)
optno = -optno;
if (isset(KSHOPTIONPRINT)) {
if (defset(on))
printf("no%-20s%s\n", on->nam, isset(optno) ? "off" : "on");
printf("no%-19s %s\n", on->nam, isset(optno) ? "off" : "on");
else
printf("%-22s%s\n", on->nam, isset(optno) ? "on" : "off");
printf("%-21s %s\n", on->nam, isset(optno) ? "on" : "off");
} else if (set == (isset(optno) ^ defset(on))) {
if (set ^ isset(optno))
fputs("no", stdout);
@ -399,6 +405,7 @@ createoptiontable(void)
optiontab->hash = hasher;
optiontab->emptytable = NULL;
optiontab->filltable = NULL;
optiontab->cmpnodes = strcmp;
optiontab->addnode = addhashnode;
optiontab->getnode = gethashnode;
optiontab->getnode2 = gethashnode2;
@ -635,6 +642,8 @@ dosetopt(int optno, int value, int force)
}
} else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN ||
optno == SINGLECOMMAND)) {
if (opts[optno] == value)
return 0;
/* it is not permitted to change the value of these options */
return -1;
} else if(!force && optno == USEZLE && value) {

View file

@ -270,6 +270,7 @@ newparamtable(int size, char const *name)
ht->hash = hasher;
ht->emptytable = emptyhashtable;
ht->filltable = NULL;
ht->cmpnodes = strcmp;
ht->addnode = addhashnode;
ht->getnode = getparamnode;
ht->getnode2 = getparamnode;
@ -282,6 +283,7 @@ newparamtable(int size, char const *name)
return ht;
}
/**/
#ifdef DYNAMIC
/**/
static HashNode
@ -299,6 +301,7 @@ getparamnode(HashTable ht, char *nam)
}
return hn;
}
/**/
#endif /* DYNAMIC */
/* Copy a parameter hash table */
@ -1753,7 +1756,7 @@ unsetparam_pm(Param pm, int altflag, int exp)
* Some specials, such as those used in zle, still need removing
* from the parameter table; they have the PM_REMOVABLE flag.
*/
if ((locallevel && locallevel >= pm->level) ||
if ((pm->level && locallevel >= pm->level) ||
(pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
return;
@ -1963,23 +1966,11 @@ intvarsetfn(Param pm, long x)
void
zlevarsetfn(Param pm, long x)
{
if ((long *)pm->u.data == & columns) {
if(x <= 0)
x = tccolumns > 0 ? tccolumns : 80;
if (x > 2)
termflags &= ~TERM_NARROW;
else
termflags |= TERM_NARROW;
} else if ((long *)pm->u.data == & lines) {
if(x <= 0)
x = tclines > 0 ? tclines : 24;
if (x > 2)
termflags &= ~TERM_SHORT;
else
termflags |= TERM_SHORT;
}
long *p = (long *)pm->u.data;
*((long *)pm->u.data) = x;
*p = x;
if (p == &lines || p == &columns)
adjustwinsize(2 + (p == &columns));
}
/* Function to set value of generic special scalar *

View file

@ -129,10 +129,9 @@ intr(void)
install_handler(SIGINT);
}
#if 0
/* disable ^C interrupts */
/**/
#if 0 /**/
void
nointr(void)
{
@ -505,7 +504,7 @@ handler(int sig)
#ifdef SIGWINCH
case SIGWINCH:
adjustwinsize(); /* check window size and adjust */
adjustwinsize(1); /* check window size and adjust */
if (sigtrapped[SIGWINCH])
dotrap(SIGWINCH);
break;

View file

@ -245,35 +245,43 @@ singsub(char **s)
* the result is stored in *a. If `a' is zero a multiple word result is *
* joined using sep or the IFS parameter if sep is zero and the result *
* is returned in *s. The return value is true iff the expansion *
* resulted in an empty list */
* resulted in an empty list. *
* The mult_isarr variable is used by paramsubst() to tell if it yields *
* an array. */
static int mult_isarr;
/**/
static int
multsub(char **s, char ***a, int *isarr, char *sep)
{
LinkList foo;
int l;
int l, omi = mult_isarr;
char **r, **p;
mult_isarr = 0;
foo = newlinklist();
addlinknode(foo, *s);
prefork(foo, 0);
if (errflag) {
if (isarr)
*isarr = 0;
mult_isarr = omi;
return 0;
}
if ((l = countlinknodes(foo)) > 1 || a) {
if ((l = countlinknodes(foo))) {
p = r = ncalloc((l + 1) * sizeof(char*));
while (nonempty(foo))
*p++ = (char *)ugetnode(foo);
*p = NULL;
if (a) {
if (a && mult_isarr) {
*a = r;
*isarr = 1;
mult_isarr = omi;
return 0;
}
*s = sepjoin(r, NULL);
mult_isarr = omi;
return 0;
}
if (l)
@ -282,6 +290,7 @@ multsub(char **s, char ***a, int *isarr, char *sep)
*s = dupstring("");
if (isarr)
*isarr = 0;
mult_isarr = omi;
return !l;
}
@ -977,16 +986,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
skipparens(*s, *s == Inpar ? Outpar : Outbrace, &s);
sav = *s;
*s = 0;
if (multsub(&val, ((!aspar && (!quoted || nojoin)) ? &aval : NULL),
&isarr, NULL) &&
quoted) {
if (multsub(&val, (aspar ? NULL : &aval), &isarr, NULL) && quoted) {
isarr = -1;
aval = alloc(sizeof(char *));
aspar = 0;
} else if (aspar)
idbeg = val;
if (isarr)
isarr = -1;
copied = 1;
*s = sav;
v = (Value) NULL;
@ -1465,6 +1470,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
val = dupstring(buf);
isarr = 0;
}
mult_isarr = isarr;
if (isarr > 0 && !plan9 && (!aval || !aval[0])) {
val = dupstring("");
isarr = 0;
@ -1485,6 +1491,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
val = aval[0];
else
isarr = 2;
mult_isarr = isarr;
}
}
if (casmod) {

View file

@ -72,10 +72,9 @@ taddstr(char *s)
tptr += sl;
}
#if 0
/* add an integer to the text buffer */
/**/
#if 0 /**/
void
taddint(int x)
{

View file

@ -209,10 +209,9 @@ nicechar(int c)
return buf;
}
#if 0
/* Output a string's visible representation. */
/**/
#if 0 /**/
void
nicefputs(char *s, FILE *f)
{
@ -853,27 +852,64 @@ int resetneeded;
/**/
int winchanged;
#endif
/* check the size of the window and adjust if necessary */
/* check the size of the window and adjust if necessary. *
* The value of from: *
* 0: called from update_job or setupvals *
* 1: called from the SIGWINCH handler *
* 2: the user have just changed LINES manually *
* 3: the user have just changed COLUMNS manually */
/**/
void
adjustwinsize(void)
adjustwinsize(int from)
{
#ifdef TIOCGWINSZ
int oldcols = columns, oldrows = lines;
#ifdef TIOCGWINSZ
static int userlines, usercols;
if (SHTTY == -1)
return;
ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize);
setiparam("COLUMNS", shttyinfo.winsize.ws_col);
setiparam("LINES", shttyinfo.winsize.ws_row);
if (zleactive && (oldcols != columns || oldrows != lines)) {
if (from == 2)
userlines = lines > 0;
if (from == 3)
usercols = columns > 0;
if (!ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize)) {
if (!userlines || from == 1)
lines = shttyinfo.winsize.ws_row;
if (!usercols || from == 1)
columns = shttyinfo.winsize.ws_col;
}
#endif /* TIOCGWINSZ */
if (lines <= 0)
lines = tclines > 0 ? tclines : 24;
if (columns <= 0)
columns = tccolumns > 0 ? tccolumns : 80;
if (lines > 2)
termflags &= ~TERM_SHORT;
else
termflags |= TERM_SHORT;
if (columns > 2)
termflags &= ~TERM_NARROW;
else
termflags |= TERM_NARROW;
#ifdef TIOCGWINSZ
if (interact && from >= 2) {
shttyinfo.winsize.ws_row = lines;
shttyinfo.winsize.ws_col = columns;
ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize);
}
#endif
if (zleactive && (from >= 2 || oldcols != columns || oldrows != lines)) {
resetneeded = winchanged = 1;
zrefresh();
}
#endif /* TIOCGWINSZ */
}
/* Move a fd to a place >= 10 and mark the new fd in fdtable. If the fd *
@ -3343,10 +3379,9 @@ dquotedztrdup(char const *s)
return ret;
}
#if 0
/* Unmetafy and output a string, double quoting it in its entirety. */
/**/
#if 0 /**/
int
dquotedzputs(char const *s, FILE *stream)
{

View file

@ -4,6 +4,7 @@ addbuiltins
addconddefs
addedx
addhashnode
addhistnum
addparamdefs
addwrapper
arrvargetfn
@ -45,6 +46,7 @@ deleteparamdefs
deletewrapper
domatch
doshfunc
down_histent
dputs
dquotedztrdup
dummy_list
@ -97,6 +99,8 @@ hgetc
hgetline
histentarr
histentct
hist_ring
hist_skip_flags
holdintr
hptr
hrealloc
@ -132,6 +136,7 @@ metadiffer
metafy
metalen
mode_to_octal
movehistent
mypgrp
mypid
nameddirtab
@ -240,6 +245,7 @@ unmetafy
unsetparam
unsetparam_pm
untokenize
up_histent
uremnode
useheap
winchanged

View file

@ -294,7 +294,7 @@ struct linklist {
#define peekfirst(X) ((X)->first->dat)
#define pushnode(X,Y) insertlinknode(X,(LinkNode) X,Y)
#define incnode(X) (X = nextnode(X))
#define gethistent(X) (histentarr+((X)%histentct))
#define firsthist() (hist_ring? hist_ring->down->histnum : curhist)
/********************************/
@ -611,6 +611,7 @@ struct job {
#define STAT_CURSH (1<<9) /* last command is in current shell */
#define STAT_NOSTTY (1<<10) /* the tty settings are not inherited */
/* from this job when it exits. */
#define STAT_ATTACH (1<<11) /* delay reattaching shell to tty */
#define SP_RUNNING -1 /* fake status for jobs currently running */
@ -679,6 +680,7 @@ typedef void (*AddNodeFunc) _((HashTable, char *, void *));
typedef HashNode (*GetNodeFunc) _((HashTable, char *));
typedef HashNode (*RemoveNodeFunc) _((HashTable, char *));
typedef void (*FreeNodeFunc) _((HashNode));
typedef int (*CompareFunc) _((const char *, const char *));
/* type of function that is passed to *
* scanhashtable or scanmatchtable */
@ -698,6 +700,7 @@ struct hashtable {
HashFunc hash; /* pointer to hash function for this table */
TableFunc emptytable; /* pointer to function to empty table */
TableFunc filltable; /* pointer to function to fill table */
CompareFunc cmpnodes; /* pointer to function to compare two nodes */
AddNodeFunc addnode; /* pointer to function to add new node */
GetNodeFunc getnode; /* pointer to function to get an enabled node */
GetNodeFunc getnode2; /* pointer to function to get node */
@ -1015,18 +1018,30 @@ struct nameddir {
/* history entry */
struct histent {
HashNode hash_next; /* next in hash chain */
char *text; /* the history line itself */
int flags; /* Misc flags */
Histent up; /* previous line (moving upward) */
Histent down; /* next line (moving downward) */
char *zle_text; /* the edited history line */
time_t stim; /* command started time (datestamp) */
time_t ftim; /* command finished time */
short *words; /* Position of words in history */
/* line: as pairs of start, end */
int nwords; /* Number of words in history line */
int flags; /* Misc flags */
int histnum; /* A sequential history number */
};
#define HIST_OLD 0x00000001 /* Command is already written to disk*/
#define HIST_READ 0x00000002 /* Command was read back from disk*/
#define HIST_MAKEUNIQUE 0x00000001 /* Kill this new entry if not unique */
#define HIST_OLD 0x00000002 /* Command is already written to disk*/
#define HIST_READ 0x00000004 /* Command was read back from disk*/
#define HIST_DUP 0x00000008 /* Command duplicates a later line */
#define HIST_FOREIGN 0x00000010 /* Command came from another shell */
#define GETHIST_UPWARD (-1)
#define GETHIST_DOWNWARD 1
#define GETHIST_EXACT 0
/* Parts of the code where history expansion is disabled *
* should be within a pair of STOPHIST ... ALLOWHIST */
@ -1039,6 +1054,13 @@ struct histent {
#define HISTFLAG_RECALL 4
#define HISTFLAG_SETTY 8
#define HFILE_APPEND 0x0001
#define HFILE_SKIPOLD 0x0002
#define HFILE_SKIPDUPS 0x0004
#define HFILE_SKIPFOREIGN 0x0008
#define HFILE_FAST 0x0010
#define HFILE_USE_OPTIONS 0x8000
/******************************************/
/* Definitions for programable completion */
/******************************************/
@ -1120,15 +1142,20 @@ enum {
HASHLISTALL,
HISTALLOWCLOBBER,
HISTBEEP,
HISTEXPIREDUPSFIRST,
HISTFINDNODUPS,
HISTIGNOREALLDUPS,
HISTIGNOREDUPS,
HISTIGNORESPACE,
HISTNOFUNCTIONS,
HISTNOSTORE,
HISTREDUCEBLANKS,
HISTSAVENODUPS,
HISTVERIFY,
HUP,
IGNOREBRACES,
IGNOREEOF,
INCREMENTALAPPENDHISTORY,
INTERACTIVE,
INTERACTIVECOMMENTS,
KSHARRAYS,
@ -1172,6 +1199,7 @@ enum {
RESTRICTED,
RMSTARSILENT,
RMSTARWAIT,
SHAREHISTORY,
SHFILEEXPANSION,
SHGLOB,
SHINSTDIN,

View file

@ -302,7 +302,11 @@ then
echo
zmodload -d -L
echo
zmodload -a -L
zmodload -ab -L
echo
zmodload -ac -L
echo
zmodload -ap -L
echo
zmodload -L
else

View file

@ -189,9 +189,6 @@
/* Define to 1 if struct timezone is defined by a system header */
#undef HAVE_STRUCT_TIMEZONE
/* Define if your system's typeahead disappears from the shell editor. */
#undef CLOBBERS_TYPEAHEAD
/* Define to 1 if there is a prototype defined for brk() on your system */
#undef HAVE_BRK_PROTO

View file

@ -24,6 +24,47 @@ dnl Zsh Development Group have no obligation to provide maintenance,
dnl support, updates, enhancements, or modifications.
dnl
dnl
dnl Code from the configure system for bash 2.03 (not zsh copyright).
dnl If available, use support for large files unless the user specified
dnl one of the CPPFLAGS, LDFLAGS, or LIBS variables (<eggert@twinsun.com>
dnl via GNU patch 2.5)
dnl
AC_DEFUN(zsh_LARGE_FILE_SUPPORT,
[AC_MSG_CHECKING(whether large file support needs explicit enabling)
ac_getconfs=''
ac_result=yes
ac_set=''
ac_shellvars='CPPFLAGS LDFLAGS LIBS'
for ac_shellvar in $ac_shellvars; do
case $ac_shellvar in
CPPFLAGS) ac_lfsvar=LFS_CFLAGS ac_lfs64var=LFS64_CFLAGS ;;
*) ac_lfsvar=LFS_$ac_shellvar ac_lfs64var=LFS64_$ac_shellvar ;;
esac
eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar
(getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; }
ac_getconf=`getconf $ac_lfsvar`
ac_getconf64=`getconf $ac_lfs64var`
ac_getconfs=$ac_getconfs$ac_getconf\ $ac_getconf64
eval ac_test_$ac_shellvar="\$ac_getconf\ \$ac_getconf64"
done
case "$ac_result$ac_getconfs" in
yes) ac_result=no ;;
esac
case "$ac_result$ac_set" in
yes?*) test "x$ac_set" != "xLDFLAGS" -o "x$auto_ldflags" = x && {
ac_result="yes, but $ac_set is already set, so use its settings"
}
esac
AC_MSG_RESULT($ac_result)
case $ac_result in
yes)
for ac_shellvar in $ac_shellvars; do
eval $ac_shellvar=\$ac_test_$ac_shellvar
done ;;
esac
])
dnl
dnl zsh_SYS_DYNAMIC_BROKEN
dnl Check whether static/shared library linking is broken.

View file

@ -204,6 +204,10 @@ test -z "${LDFLAGS+set}" && LDFLAGS= auto_ldflags=1
AC_PROG_CC
dnl Check for large file support (Solaris).
dnl This needs to be done early to get the stuff into the flags.
zsh_LARGE_FILE_SUPPORT
dnl if the user hasn't specified CFLAGS, then
dnl if compiler is gcc, then use -O2 and some warning flags
dnl else use -O
@ -883,25 +887,6 @@ zsh_PATH_UTMP(wtmp)
zsh_PATH_UTMP(utmpx)
zsh_PATH_UTMP(wtmpx)
dnl ----------------
dnl TYPEAHEAD KLUDGE
dnl ----------------
dnl Some systems clobber typeahead when you go from canonical input
dnl processing to non-canonical, so we need a FIONREAD ioctl.
dnl I don't know how to check this with configure, so I am using the
dnl system names directly.
dnl The doubled square brackets are necessary because autoconf uses m4.
AC_CACHE_CHECK(if typeahead needs FIONREAD, zsh_cv_sys_clobbers_typeahead,
[case x-$host_vendor-$host_os in
x-*-ultrix* | x-*-dgux* | x-sni-sysv4* | x-*-irix*)
zsh_cv_sys_clobbers_typeahead=yes;;
*)
zsh_cv_sys_clobbers_typeahead=no;;
esac])
if test $zsh_cv_sys_clobbers_typeahead = yes; then
AC_DEFINE(CLOBBERS_TYPEAHEAD)
fi
dnl -------------------
dnl brk/sbrk PROTOTYPES
dnl -------------------

View file

@ -1012,7 +1012,71 @@ pws: 6165: globsubst'd foo='~/bin' depended on extendedglob being set
Sven: 6167: show unloaded parameters as undefined
Bart: 6171 as rewritten in 6174: old RedHat Linux doesn't have normall
Bart: 6171 as rewritten in 6174: old RedHat Linux doesn't have normal
definitions for poll.
pws: 6180: Completion/Core/compinstall
pws-18
Bart: 6188: compinit speedup
pws: 6193: [un]setopt shouldn't complain when setting an unsettable option
to the value it already has
Sven: 6194: complete assoc array arguments by default where necessary
Sven: 6195: _expand_word and _correct_word change.
Sven: 6197: off by one error parsing assignment in completion
pws: 6202: trivial _correct_filename change, ^Xc -> ^XC
pws: 6205: use FIONREAD wherever defined, read chars immediately into
buffer
Bart: 6213: race condition in $(...), use waitforpid() instead of
unblocking child (which shouldn't happen until later).
Tanaka Akira: 6219: initialize a variable in zle_tricky.c
Wayne: 6220: various compilation warnings
pws: 6224: alter 6205 to read chars only when necessary, but ensure
terminal is set appropriately.
pws: 6227: configuration for large file support (from bash aclocal.m4).
pws: 6235: unset -m shouldn't restore unset parameters; unsetting a global
should remove it from paramtab even inside a function.
Wayne: 6236: history changes to improve management of duplicate lines,
incremental history read/write, and sharing history
pws: 6237: window size code upgraded from 3.0.6-pre2, plus Bart's patch
4447.
pws: 6238: Wayne's share_history option set in ksh emulation
pws: 6239: need space after incrementalappendhistory for kshoptionprint
pws: 6240: a pipeline ending in a builtin didn't attach to the tty pgrp.
Wayne: 6241: history editing can use foreign history commands; history
appended in hend() instead of hbegin()
Sven: 6046: nested parameter expansions can return either arrays or
scalars.
pws: 6246: doc changes for 6046, plus subscripts done properly
Sven: 6249: fix for 6046 (problem showed up with $(...))
Wayne: 6255: more history: zle toggle between local/global history; `zle
widget' can now take a direct numeric argument; small tweaks
pws: 6257: rewrite 6240 for any old builtin structure after the pipeline
pws: 6258: yet another attempt at the same problem
pws: 6259: second version of compinstall