mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-23 04:30:24 +02:00
Updated from list as far as 10376
This commit is contained in:
parent
e025336f2f
commit
4852545255
31 changed files with 13782 additions and 5610 deletions
|
@ -1,4 +1,4 @@
|
||||||
# $Id: is-at-least,v 1.1 2000/02/11 19:46:46 akr Exp $ -*- shell-script -*-
|
# $Id: is-at-least,v 1.2 2000/04/01 20:49:47 pws Exp $ -*- shell-script -*-
|
||||||
#
|
#
|
||||||
# Test whether $ZSH_VERSION (or some value of your choice, if a second argument
|
# Test whether $ZSH_VERSION (or some value of your choice, if a second argument
|
||||||
# is provided) is greater than or equal to x.y.z-r (in argument one). In fact,
|
# is provided) is greater than or equal to x.y.z-r (in argument one). In fact,
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
# seperated by `--'. For example:
|
# seperated by `--'. For example:
|
||||||
#
|
#
|
||||||
# zrecompile -p \
|
# zrecompile -p \
|
||||||
# -r ~/.zshrc -- \
|
# -R ~/.zshrc -- \
|
||||||
# -m ~/.zcompdump -- \
|
# -M ~/.zcompdump -- \
|
||||||
# ~/zsh/comp.zwc ~/zsh/Completion/*/_* \
|
# ~/zsh/comp.zwc ~/zsh/Completion/*/_* \
|
||||||
#
|
#
|
||||||
# This makes ~/.zshrc be compiled into ~/.zshrc.zwc if that doesn't
|
# This makes ~/.zshrc be compiled into ~/.zshrc.zwc if that doesn't
|
||||||
|
@ -33,8 +33,7 @@
|
||||||
# that needed re-compilation could be compiled and non-zero if compilation
|
# that needed re-compilation could be compiled and non-zero if compilation
|
||||||
# for at least one of the files failed.
|
# for at least one of the files failed.
|
||||||
|
|
||||||
emulate -L zsh
|
setopt localoptions extendedglob
|
||||||
setopt extendedglob
|
|
||||||
|
|
||||||
local opt check quiet zwc files re file pre ret map tmp mesg pats
|
local opt check quiet zwc files re file pre ret map tmp mesg pats
|
||||||
|
|
||||||
|
@ -68,7 +67,7 @@ if [[ -n $pats ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
files=( ${files:#*(.zwc|~)} )
|
files=( ${files:#*(.zwc|~)} )
|
||||||
if [[ $files[1] = -[rm] ]]; then
|
if [[ $files[1] = -[RM] ]]; then
|
||||||
map=( $files[1] )
|
map=( $files[1] )
|
||||||
shift 1 files
|
shift 1 files
|
||||||
else
|
else
|
||||||
|
@ -146,10 +145,10 @@ for zwc; do
|
||||||
# See if the wordcode file will be mapped.
|
# See if the wordcode file will be mapped.
|
||||||
|
|
||||||
if [[ $files[1] = *\(mapped\)* ]]; then
|
if [[ $files[1] = *\(mapped\)* ]]; then
|
||||||
map=-m
|
map=-M
|
||||||
mesg='succeeded (old saved)'
|
mesg='succeeded (old saved)'
|
||||||
else
|
else
|
||||||
map=-r
|
map=-R
|
||||||
mesg=succeeded
|
mesg=succeeded
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ local tmpf=${TMPPREFIX}zfcm$$
|
||||||
|
|
||||||
if [[ $ZFTP_SYSTEM = UNIX* ]]; then
|
if [[ $ZFTP_SYSTEM = UNIX* ]]; then
|
||||||
# hoo, aren't we lucky: this makes things so much easier
|
# hoo, aren't we lucky: this makes things so much easier
|
||||||
setopt localoptions rcexpandparam
|
setopt rcexpandparam
|
||||||
local dir
|
local dir
|
||||||
if [[ $1 = ?*/* ]]; then
|
if [[ $1 = ?*/* ]]; then
|
||||||
dir=${1%/*}
|
dir=${1%/*}
|
||||||
|
@ -25,13 +25,15 @@ if [[ $ZFTP_SYSTEM = UNIX* ]]; then
|
||||||
# If we're using -F, we get away with using a directory
|
# If we're using -F, we get away with using a directory
|
||||||
# to list, but not a glob. Don't ask me why.
|
# to list, but not a glob. Don't ask me why.
|
||||||
# I hate having to rely on awk here.
|
# I hate having to rely on awk here.
|
||||||
zftp ls -F $dir >$tmpf
|
zftp ls -LF $dir >$tmpf
|
||||||
reply=($(awk '/\/$/ { print substr($1, 0, length($1)-1) }' $tmpf))
|
reply=($(awk '/\/$/ { print substr($1, 0, length($1)-1) }' $tmpf))
|
||||||
rm -f $tmpf
|
rm -f $tmpf
|
||||||
if [[ $dir = / ]]; then
|
[[ -n $dir && $dir != */ ]] && dir="$dir/"
|
||||||
reply=(${dir}$reply)
|
if [[ -n $WIDGET ]]; then
|
||||||
|
_all_labels directories expl 'remote directory'
|
||||||
|
compadd -S/ -q -P "$dir" - $reply
|
||||||
elif [[ -n $dir ]]; then
|
elif [[ -n $dir ]]; then
|
||||||
reply=($dir/$reply)
|
reply=(${dir}$reply)
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# I simply don't know what to do here.
|
# I simply don't know what to do here.
|
||||||
|
|
|
@ -10,18 +10,27 @@ fi
|
||||||
local tmpf=${TMPPREFIX}zfgm$$
|
local tmpf=${TMPPREFIX}zfgm$$
|
||||||
|
|
||||||
if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
|
if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
|
||||||
# On the first argument to ls, we usually get away with a glob.
|
if [[ -n $WIDGET ]]; then
|
||||||
zftp ls "$1*$2" >$tmpf
|
local dir=${1:h}
|
||||||
reply=($(<$tmpf))
|
[[ $dir = */ ]] || dir="$dir/"
|
||||||
rm -f $tmpf
|
zftp ls -LF $dir >$tmpf
|
||||||
else
|
local reply
|
||||||
if (( $#zftp_fcache == 0 )); then
|
reply=(${${${(f)"$(<$tmpf)"}##$dir}%\*})
|
||||||
# Always cache the current directory and use it
|
rm -f $tmpf
|
||||||
# even if the system is UNIX.
|
_all_labels files expl 'remote file' compadd -P $dir - $reply
|
||||||
zftp ls >$tmpf
|
else
|
||||||
zftp_fcache=($(<$tmpf))
|
# On the first argument to ls, we usually get away with a glob.
|
||||||
|
zftp ls "$1*$2" >$tmpf
|
||||||
|
reply=($(<$tmpf))
|
||||||
rm -f $tmpf
|
rm -f $tmpf
|
||||||
fi
|
fi
|
||||||
reply=($zftp_fcache);
|
else
|
||||||
|
local fcache_name
|
||||||
|
zffcache
|
||||||
|
if [[ -n $WIDGET ]]; then
|
||||||
|
_all_labels files expl 'remote file' compadd -F fignore - ${(P)fcache_name}
|
||||||
|
else
|
||||||
|
reply=(${(P)fcache_name});
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
# }
|
# }
|
||||||
|
|
|
@ -1,89 +1,124 @@
|
||||||
# incremental-complete-word() {
|
|
||||||
|
|
||||||
# Autoload this function, run `zle -N <func-name>' and bind <func-name>
|
# Autoload this function, run `zle -N <func-name>' and bind <func-name>
|
||||||
# to a key.
|
# to a key.
|
||||||
|
|
||||||
|
|
||||||
# This allows incremental completion of a word. After starting this
|
# This allows incremental completion of a word. After starting this
|
||||||
# command, a list of completion choices is shown after every character you
|
# command, a list of completion choices can be shown after every character
|
||||||
# type, which you can delete with ^h or DEL. RET will accept the
|
# you type, which you can delete with ^h or DEL. RET will accept the
|
||||||
# completion so far. You can hit TAB to do normal completion and ^g to
|
# completion so far. You can hit TAB to do normal completion, ^g to
|
||||||
# abort back to the state when you started.
|
# abort back to the state when you started, and ^d to list the matches.
|
||||||
#
|
#
|
||||||
# Completion keys:
|
# This works only with the new function based completion system.
|
||||||
# incremental_prompt Prompt to show in status line during icompletion;
|
|
||||||
# the sequence `%u' is replaced by the unambiguous
|
|
||||||
# part of all matches if there is any and it is
|
|
||||||
# different from the word on the line
|
|
||||||
# incremental_stop Pattern matching keys which will cause icompletion
|
|
||||||
# to stop and the key to be re-executed
|
|
||||||
# incremental_break Pattern matching keys which will cause icompletion
|
|
||||||
# to stop and the key to be discarded
|
|
||||||
# incremental_completer Set of completers, like the `completer' key
|
|
||||||
# incremental_list If set to a non-empty string, the matches will be
|
|
||||||
# listed on every key-press
|
|
||||||
|
|
||||||
emulate -L zsh
|
# The main widget function.
|
||||||
unsetopt autolist menucomplete automenu # doesn't work well
|
|
||||||
|
|
||||||
local key lbuf="$LBUFFER" rbuf="$RBUFFER" pmpt word lastl lastr wid twid
|
incremental-complete-word() {
|
||||||
|
#emulate -L zsh
|
||||||
|
unsetopt autolist menucomplete automenu # doesn't work well
|
||||||
|
|
||||||
[[ -n "$compconfig[incremental_completer]" ]] &&
|
local key lbuf="$LBUFFER" rbuf="$RBUFFER" pmpt pstr word
|
||||||
set ${(s.:.)compconfig[incremental_completer]}
|
local lastl lastr wid twid num post toolong
|
||||||
pmpt="${compconfig[incremental_prompt]-incremental completion...}"
|
local curcontext="${curcontext}" stop brk
|
||||||
|
|
||||||
if [[ -n "$compconfig[incremental_list]" ]]; then
|
[[ -z "$curcontext" ]] && curcontext=:::
|
||||||
wid=list-choices
|
curcontext="incremental:${curcontext#*:}"
|
||||||
else
|
|
||||||
wid=complete-word
|
|
||||||
fi
|
|
||||||
|
|
||||||
zle $wid "$@"
|
zstyle -s ":completion:${curcontext}" prompt pmpt ||
|
||||||
LBUFFER="$lbuf"
|
pmpt='incremental (%c): %u%s %l'
|
||||||
RBUFFER="$rbuf"
|
zstyle -s ":completion:${curcontext}" stop stop
|
||||||
if [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
|
zstyle -s ":completion:${curcontext}" break brk
|
||||||
word=''
|
|
||||||
else
|
|
||||||
word="${_lastcomp[unambiguous]}"
|
|
||||||
fi
|
|
||||||
zle -R "${pmpt//\\%u/$word}"
|
|
||||||
read -k key
|
|
||||||
|
|
||||||
while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' &&
|
if zstyle -t ":completion:${curcontext}" list; then
|
||||||
'#key' -ne '#\\C-g' ]]; do
|
wid=list-choices
|
||||||
twid=$wid
|
post=( icw-list-helper )
|
||||||
if [[ "$key" = ${~compconfig[incremental_stop]} ]]; then
|
|
||||||
zle -U "$key"
|
|
||||||
return
|
|
||||||
elif [[ "$key" = ${~compconfig[incremental_break]} ]]; then
|
|
||||||
return
|
|
||||||
elif [[ '#key' -eq '#\\C-h' || '#key' -eq '#\\C-?' ]]; then
|
|
||||||
[[ $#LBUFFER -gt $#l ]] && LBUFFER="$LBUFFER[1,-2]"
|
|
||||||
elif [[ '#key' -eq '#\\t' ]]; then
|
|
||||||
zle complete-word "$@"
|
|
||||||
lbuf="$LBUFFER"
|
|
||||||
rbuf="$RBUFFER"
|
|
||||||
elif [[ '#key' -eq '#\\C-d' ]]; then
|
|
||||||
twid=list-choices
|
|
||||||
else
|
else
|
||||||
LBUFFER="$LBUFFER$key"
|
wid=complete-word
|
||||||
|
post=()
|
||||||
fi
|
fi
|
||||||
lastl="$LBUFFER"
|
|
||||||
lastr="$RBUFFER"
|
|
||||||
zle $twid "$@"
|
|
||||||
LBUFFER="$lastl"
|
|
||||||
RBUFFER="$lastr"
|
|
||||||
if [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
|
|
||||||
word=''
|
|
||||||
else
|
|
||||||
word="${_lastcomp[unambiguous]}"
|
|
||||||
fi
|
|
||||||
zle -R "${pmpt//\\%u/$word}"
|
|
||||||
read -k key
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ '#key' -eq '#\\C-g' ]]; then
|
comppostfuncs=( "$post[@]" )
|
||||||
|
zle $wid "$@"
|
||||||
LBUFFER="$lbuf"
|
LBUFFER="$lbuf"
|
||||||
RBUFFER="$rbuf"
|
RBUFFER="$rbuf"
|
||||||
fi
|
num=$_lastcomp[nmatches]
|
||||||
zle -Rc
|
if (( ! num )); then
|
||||||
# }
|
word=''
|
||||||
|
state='-no match-'
|
||||||
|
elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
|
||||||
|
word=''
|
||||||
|
state='-no prefix-'
|
||||||
|
else
|
||||||
|
word="${_lastcomp[unambiguous]}"
|
||||||
|
state=''
|
||||||
|
fi
|
||||||
|
zformat -f pstr "$pmpt" "u:${word}" "s:$state" "n:$num" \
|
||||||
|
"l:$toolong" "c:${_lastcomp[completer][2,-1]}"
|
||||||
|
zle -R "$pstr"
|
||||||
|
read -k key
|
||||||
|
|
||||||
|
while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' &&
|
||||||
|
'#key' -ne '#\\C-g' ]]; do
|
||||||
|
twid=$wid
|
||||||
|
if [[ "$key" = ${~stop} ]]; then
|
||||||
|
zle -U "$key"
|
||||||
|
return
|
||||||
|
elif [[ "$key" = ${~brk} ]]; then
|
||||||
|
return
|
||||||
|
elif [[ '#key' -eq '#\\C-h' || '#key' -eq '#\\C-?' ]]; then
|
||||||
|
[[ $#LBUFFER -gt $#l ]] && LBUFFER="$LBUFFER[1,-2]"
|
||||||
|
elif [[ '#key' -eq '#\\t' ]]; then
|
||||||
|
zle complete-word "$@"
|
||||||
|
lbuf="$LBUFFER"
|
||||||
|
rbuf="$RBUFFER"
|
||||||
|
elif [[ '#key' -eq '#\\C-d' ]]; then
|
||||||
|
twid=list-choices
|
||||||
|
else
|
||||||
|
LBUFFER="$LBUFFER$key"
|
||||||
|
fi
|
||||||
|
lastl="$LBUFFER"
|
||||||
|
lastr="$RBUFFER"
|
||||||
|
[[ "$twid" = "$wid" ]] && comppostfuncs=( "$post[@]" )
|
||||||
|
toolong=''
|
||||||
|
zle $twid "$@"
|
||||||
|
LBUFFER="$lastl"
|
||||||
|
RBUFFER="$lastr"
|
||||||
|
num=$_lastcomp[nmatches]
|
||||||
|
if (( ! num )); then
|
||||||
|
word=''
|
||||||
|
state='-no match-'
|
||||||
|
elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
|
||||||
|
word=''
|
||||||
|
state='-no prefix-'
|
||||||
|
else
|
||||||
|
word="${_lastcomp[unambiguous]}"
|
||||||
|
state=''
|
||||||
|
fi
|
||||||
|
zformat -f pstr "$pmpt" "u:${word}" "s:$state" "n:$num" \
|
||||||
|
"l:$toolong" "c:${_lastcomp[completer][2,-1]}"
|
||||||
|
zle -R "$pstr"
|
||||||
|
read -k key
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ '#key' -eq '#\\C-g' ]]; then
|
||||||
|
LBUFFER="$lbuf"
|
||||||
|
RBUFFER="$rbuf"
|
||||||
|
fi
|
||||||
|
zle -Rc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper function used as a completion post-function used to make sure that
|
||||||
|
# the list of matches in only shown if it fits on the screen.
|
||||||
|
|
||||||
|
icw-list-helper() {
|
||||||
|
|
||||||
|
# +1 for the status line we will add...
|
||||||
|
|
||||||
|
if [[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]]; then
|
||||||
|
compstate[list]='list explanations'
|
||||||
|
[[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]] && compstate[list]=''
|
||||||
|
|
||||||
|
toolong='...'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
incremental-complete-word "$@"
|
||||||
|
|
|
@ -1,64 +1,141 @@
|
||||||
# This set of functions implements a sort of magic history searching.
|
# This set of functions implements a sort of magic history searching.
|
||||||
# After predict-on, typing characters causes the editor to look backward
|
# After predict-on, typing characters causes the editor to look backward
|
||||||
# in the history for the first line beginning with what you have typed
|
# in the history for the first line beginning with what you have typed so
|
||||||
# so far. After predict-off, editing returns to normal for the line found.
|
# far. After predict-off, editing returns to normal for the line found.
|
||||||
# In fact, you often don't even need to use predict-off, because if the
|
# In fact, you often don't even need to use predict-off, because if the
|
||||||
# line doesn't match something in the history, adding a key at the end
|
# line doesn't match something in the history, adding a key performs
|
||||||
# behaves as normal --- though editing in the middle is liable to delete
|
# standard completion --- though editing in the middle is liable to delete
|
||||||
# the rest of the line.
|
# the rest of the line.
|
||||||
#
|
#
|
||||||
|
# With the function based completion system (which is needed for this),
|
||||||
|
# you should be able to type TAB at almost any point to advance the cursor
|
||||||
|
# to the next "interesting" character position (usually the end of the
|
||||||
|
# current word, but sometimes somewhere in the middle of the word). And
|
||||||
|
# of course as soon as the entire line is what you want, you can accept
|
||||||
|
# with RETURN, without needing to move the cursor to the end first.
|
||||||
|
#
|
||||||
# To use it:
|
# To use it:
|
||||||
# autoload -U predict-on
|
# autoload -U predict-on
|
||||||
# zle -N predict-on
|
# zle -N predict-on
|
||||||
# zle -N predict-off
|
# zle -N predict-off
|
||||||
# bindkey '...' predict-on
|
# bindkey '...' predict-on
|
||||||
# bindkey '...' predict-off
|
# bindkey '...' predict-off
|
||||||
# Note that all the functions are defined when you first call type the
|
# Note that all functions are defined when you first type the predict-on
|
||||||
# predict-on key, which means typing the predict-off key before that gives
|
# key, which means typing the predict-off key before that gives a harmless
|
||||||
# a harmless error message.
|
# error message.
|
||||||
|
|
||||||
predict-on() {
|
predict-on() {
|
||||||
zle -N self-insert insert-and-predict
|
zle -N self-insert insert-and-predict
|
||||||
zle -N magic-space insert-and-predict
|
zle -N magic-space insert-and-predict
|
||||||
zle -N backward-delete-char delete-backward-and-predict
|
zle -N backward-delete-char delete-backward-and-predict
|
||||||
|
zle -N delete-char-or-list delete-no-predict
|
||||||
}
|
}
|
||||||
predict-off() {
|
predict-off() {
|
||||||
zle -A .self-insert self-insert
|
zle -A .self-insert self-insert
|
||||||
zle -A .magic-space magic-space
|
zle -A .magic-space magic-space
|
||||||
zle -A .backward-delete-char backward-delete-char
|
zle -A .backward-delete-char backward-delete-char
|
||||||
}
|
}
|
||||||
insert-and-predict () {
|
insert-and-predict () {
|
||||||
emulate -L zsh
|
setopt localoptions noshwordsplit noksharrays
|
||||||
if [[ ${RBUFFER[1]} = ${KEYS[-1]} ]]
|
if [[ $LBUFFER = *$'\012'* ]]
|
||||||
then
|
then
|
||||||
# same as what's typed, just move on
|
# Editing a multiline buffer, it's unlikely prediction is wanted
|
||||||
|
zle .$WIDGET "$@"
|
||||||
|
return
|
||||||
|
elif [[ ${RBUFFER[1]} = ${KEYS[-1]} ]]
|
||||||
|
then
|
||||||
|
# Same as what's typed, just move on
|
||||||
((++CURSOR))
|
((++CURSOR))
|
||||||
else
|
else
|
||||||
LBUFFER="$LBUFFER$KEYS"
|
LBUFFER="$LBUFFER$KEYS"
|
||||||
if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]]
|
if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]]
|
||||||
then
|
then
|
||||||
zle .history-beginning-search-backward || RBUFFER=""
|
if ! zle .history-beginning-search-backward
|
||||||
|
then
|
||||||
|
RBUFFER=""
|
||||||
|
if [[ ${KEYS[-1]} != ' ' ]]
|
||||||
|
then
|
||||||
|
unsetopt automenu recexact
|
||||||
|
integer curs=$CURSOR pos nchar=${#LBUFFER//[^${KEYS[-1]}]}
|
||||||
|
local -a +h comppostfuncs
|
||||||
|
local crs curcontext="${curcontext}"
|
||||||
|
|
||||||
|
[[ -z "$curcontext" ]] && curcontext=:::
|
||||||
|
curcontext="predict:${curcontext#*:}"
|
||||||
|
|
||||||
|
comppostfuncs=( predict-limit-list )
|
||||||
|
zle complete-word
|
||||||
|
# Decide where to leave the cursor. The dummy loop is used to
|
||||||
|
# get out of that `case'.
|
||||||
|
repeat 1
|
||||||
|
do
|
||||||
|
zstyle -s ":completion:${curcontext}:" cursor crs
|
||||||
|
case $crs in
|
||||||
|
(complete)
|
||||||
|
# At the place where the completion left it, if it is after
|
||||||
|
# the character typed.
|
||||||
|
[[ ${LBUFFER[-1]} = ${KEYS[-1]} ]] && break
|
||||||
|
;&
|
||||||
|
(key)
|
||||||
|
# Or maybe at the n'th occurrence of the character typed.
|
||||||
|
pos=${BUFFER[(in:nchar:)${KEYS[-1]}]}
|
||||||
|
if [[ pos -gt curs ]]
|
||||||
|
then
|
||||||
|
CURSOR=$pos
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
;&
|
||||||
|
(*)
|
||||||
|
# Or else at the previous position.
|
||||||
|
CURSOR=$curs
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
delete-backward-and-predict() {
|
delete-backward-and-predict() {
|
||||||
emulate -L zsh
|
|
||||||
if [[ -n "$LBUFFER" ]]
|
if [[ -n "$LBUFFER" ]]
|
||||||
then
|
then
|
||||||
|
setopt localoptions noshwordsplit noksharrays
|
||||||
|
if [[ $LBUFFER = *$'\012'* ]] then
|
||||||
|
# Editing a multiline buffer, it's unlikely prediction is wanted
|
||||||
|
zle .$WIDGET "$@"
|
||||||
# If the last widget was e.g. a motion, then probably the intent is
|
# If the last widget was e.g. a motion, then probably the intent is
|
||||||
# to actually edit the line, not change the search prefix.
|
# to actually edit the line, not change the search prefix.
|
||||||
if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]]
|
elif [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]]
|
||||||
then
|
then
|
||||||
((--CURSOR))
|
((--CURSOR))
|
||||||
zle .history-beginning-search-forward || RBUFFER=""
|
zle .history-beginning-search-forward || RBUFFER=""
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
# Depending on preference, you might call "predict-off" here,
|
# Depending on preference, you might call "predict-off" here.
|
||||||
# and also set up forward deletions to turn off prediction.
|
|
||||||
LBUFFER="$LBUFFER[1,-2]"
|
LBUFFER="$LBUFFER[1,-2]"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
delete-no-predict() {
|
||||||
|
[[ $WIDGET != delete-char-or-list || -n $RBUFFER ]] && predict-off
|
||||||
|
zle .$WIDGET "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# This is a helper function for autocompletion to prevent long lists
|
||||||
|
# of matches from forcing a "do you wish to see all ...?" prompt.
|
||||||
|
|
||||||
|
predict-limit-list() {
|
||||||
|
if (( compstate[list_lines]+BUFFERLINES > LINES ||
|
||||||
|
( compstate[list_max] != 0 &&
|
||||||
|
compstate[nmatches] > compstate[list_max] ) ))
|
||||||
|
then
|
||||||
|
compstate[list]=''
|
||||||
|
elif zstyle -t ":completion:predict::::" list always
|
||||||
|
then
|
||||||
|
compstate[list]='force list'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle zsh autoloading conventions
|
||||||
|
|
||||||
[[ -o kshautoload ]] || predict-on "$@"
|
[[ -o kshautoload ]] || predict-on "$@"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
||||||
#
|
#
|
||||||
# $Id: make-zsh-urls,v 1.1 1999/11/09 02:36:42 akr Exp $
|
# $Id: make-zsh-urls,v 1.2 2000/04/01 20:49:47 pws Exp $
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,13 @@
|
||||||
#include "zpty.mdh"
|
#include "zpty.mdh"
|
||||||
#include "zpty.pro"
|
#include "zpty.pro"
|
||||||
|
|
||||||
|
/* The number of bytes we normally read when given no pattern and the
|
||||||
|
* upper bound on the number of bytes we read (even if we are give a
|
||||||
|
* pattern). */
|
||||||
|
|
||||||
|
#define READ_LEN 1024
|
||||||
|
#define READ_MAX (1024 * 1024)
|
||||||
|
|
||||||
typedef struct ptycmd *Ptycmd;
|
typedef struct ptycmd *Ptycmd;
|
||||||
|
|
||||||
struct ptycmd {
|
struct ptycmd {
|
||||||
|
@ -158,7 +165,7 @@ get_pty(int *master, int *slave)
|
||||||
|
|
||||||
#else /* ! __osf__ */
|
#else /* ! __osf__ */
|
||||||
|
|
||||||
#if __SVR4
|
#if defined(__SVR4) || defined(sinix)
|
||||||
|
|
||||||
#include <sys/stropts.h>
|
#include <sys/stropts.h>
|
||||||
|
|
||||||
|
@ -167,11 +174,12 @@ get_pty(int *master, int *slave)
|
||||||
{
|
{
|
||||||
int mfd, sfd;
|
int mfd, sfd;
|
||||||
char *name;
|
char *name;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if ((mfd = open("/dev/ptmx", O_RDWR)) < 0)
|
if ((mfd = open("/dev/ptmx", O_RDWR)) < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!(name = ptsname(mfd)) || grantpt(mfd) || unlockpt(mfd)) {
|
if (grantpt(mfd) || unlockpt(mfd) || !(name = ptsname(mfd))) {
|
||||||
close(mfd);
|
close(mfd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -179,20 +187,31 @@ get_pty(int *master, int *slave)
|
||||||
close(mfd);
|
close(mfd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (ioctl(sfd, I_PUSH, "ptem") ||
|
if ((ret = ioctl(sfd, I_FIND, "ptem")) != 1)
|
||||||
ioctl(sfd, I_PUSH, "ldterm") ||
|
if (ret == -1 || ioctl(sfd, I_PUSH, "ptem") == -1) {
|
||||||
ioctl(sfd, I_PUSH, "ttcompat")) {
|
close(mfd);
|
||||||
close(mfd);
|
close(sfd);
|
||||||
close(sfd);
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
if ((ret = ioctl(sfd, I_FIND, "ldterm")) != 1)
|
||||||
|
if (ret == -1 || ioctl(sfd, I_PUSH, "ldterm") == -1) {
|
||||||
|
close(mfd);
|
||||||
|
close(sfd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((ret = ioctl(sfd, I_FIND, "ttcompat")) != 1)
|
||||||
|
if (ret == -1 || ioctl(sfd, I_PUSH, "ttcompat") == -1) {
|
||||||
|
close(mfd);
|
||||||
|
close(sfd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
*master = mfd;
|
*master = mfd;
|
||||||
*slave = sfd;
|
*slave = sfd;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* ! __SVR4 */
|
#else /* ! (defined(__SVR4) || defind(sinix)) */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_pty(int *master, int *slave)
|
get_pty(int *master, int *slave)
|
||||||
|
@ -242,17 +261,17 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
||||||
if (!(cmd = findcmd(*args, 1))) {
|
if (!(cmd = findcmd(*args, 1))) {
|
||||||
zerrnam(nam, "unknown command: %s", *args, 0);
|
zwarnnam(nam, "unknown command: %s", *args, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (get_pty(&master, &slave)) {
|
if (get_pty(&master, &slave)) {
|
||||||
zerrnam(nam, "can't open pseudo terminal", NULL, 0);
|
zwarnnam(nam, "can't open pseudo terminal", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ((pid = fork()) == -1) {
|
if ((pid = fork()) == -1) {
|
||||||
close(master);
|
close(master);
|
||||||
close(slave);
|
close(slave);
|
||||||
zerrnam(nam, "couldn't create pty command: %s", pname, 0);
|
zwarnnam(nam, "couldn't create pty command: %s", pname, 0);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!pid) {
|
} else if (!pid) {
|
||||||
if (!echo) {
|
if (!echo) {
|
||||||
|
@ -298,6 +317,8 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
|
||||||
|
|
||||||
close(slave);
|
close(slave);
|
||||||
|
|
||||||
|
setpgrp(0L, getpid());
|
||||||
|
|
||||||
execve(cmd, args, environ);
|
execve(cmd, args, environ);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -307,9 +328,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
|
||||||
p = (Ptycmd) zalloc(sizeof(*p));
|
p = (Ptycmd) zalloc(sizeof(*p));
|
||||||
|
|
||||||
p->name = ztrdup(pname);
|
p->name = ztrdup(pname);
|
||||||
PERMALLOC {
|
p->args = zarrdup(args);
|
||||||
p->args = arrdup(args);
|
|
||||||
} LASTALLOC;
|
|
||||||
p->fd = master;
|
p->fd = master;
|
||||||
p->pid = pid;
|
p->pid = pid;
|
||||||
p->echo = echo;
|
p->echo = echo;
|
||||||
|
@ -343,7 +362,9 @@ deleteptycmd(Ptycmd cmd)
|
||||||
zsfree(p->name);
|
zsfree(p->name);
|
||||||
freearray(p->args);
|
freearray(p->args);
|
||||||
|
|
||||||
kill(p->pid, SIGHUP);
|
/* We kill the process group the command put itself in. */
|
||||||
|
|
||||||
|
kill(-(p->pid), SIGHUP);
|
||||||
|
|
||||||
zclose(cmd->fd);
|
zclose(cmd->fd);
|
||||||
|
|
||||||
|
@ -375,7 +396,7 @@ checkptycmd(Ptycmd cmd)
|
||||||
static int
|
static int
|
||||||
ptyread(char *nam, Ptycmd cmd, char **args)
|
ptyread(char *nam, Ptycmd cmd, char **args)
|
||||||
{
|
{
|
||||||
int blen = 256, used = 0, ret;
|
int blen = 256, used = 0, ret = 1;
|
||||||
char *buf = (char *) zhalloc(blen + 1);
|
char *buf = (char *) zhalloc(blen + 1);
|
||||||
Patprog prog = NULL;
|
Patprog prog = NULL;
|
||||||
|
|
||||||
|
@ -383,57 +404,113 @@ ptyread(char *nam, Ptycmd cmd, char **args)
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
if (args[2]) {
|
if (args[2]) {
|
||||||
zerrnam(nam, "too many arguments", NULL, 0);
|
zwarnnam(nam, "too many arguments", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
p = dupstring(args[1]);
|
p = dupstring(args[1]);
|
||||||
tokenize(p);
|
tokenize(p);
|
||||||
remnulargs(p);
|
remnulargs(p);
|
||||||
if (!(prog = patcompile(p, PAT_STATIC, NULL))) {
|
if (!(prog = patcompile(p, PAT_STATIC, NULL))) {
|
||||||
zerrnam(nam, "bad pattern: %s", args[1], 0);
|
zwarnnam(nam, "bad pattern: %s", args[1], 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
while ((ret = read(cmd->fd, buf + used, 1)) == 1) {
|
if (!ret) {
|
||||||
|
checkptycmd(cmd);
|
||||||
|
if (cmd->fin)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((ret = read(cmd->fd, buf + used, 1)) == 1) {
|
||||||
if (++used == blen) {
|
if (++used == blen) {
|
||||||
buf = hrealloc(buf, blen, blen << 1);
|
buf = hrealloc(buf, blen, blen << 1);
|
||||||
blen <<= 1;
|
blen <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[used] = '\0';
|
buf[used] = '\0';
|
||||||
} while (prog && !pattry(prog, buf));
|
|
||||||
|
/**** Hm. If we leave the loop when ret < 0 the user would have
|
||||||
|
* to make sure that `zpty -r' is tried more than once if
|
||||||
|
* there will be some output and we only got the ret == -1
|
||||||
|
* because the output is not yet available.
|
||||||
|
* The same for the `write' below. */
|
||||||
|
|
||||||
|
if (ret < 0 && (cmd->block
|
||||||
|
#ifdef EWOULDBLOCK
|
||||||
|
|| errno != EWOULDBLOCK
|
||||||
|
#else
|
||||||
|
#ifdef EAGAIN
|
||||||
|
|| errno != EAGAIN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!prog && !ret)
|
||||||
|
break;
|
||||||
|
} while (!errflag &&
|
||||||
|
(prog ? (used < READ_MAX && (!ret || !pattry(prog, buf))) :
|
||||||
|
(used < READ_LEN)));
|
||||||
|
|
||||||
if (*args)
|
if (*args)
|
||||||
setsparam(*args, ztrdup(buf));
|
setsparam(*args, ztrdup(metafy(buf, used, META_HREALLOC)));
|
||||||
else
|
else {
|
||||||
printf("%s", buf);
|
fflush(stdout);
|
||||||
|
write(1, buf, used);
|
||||||
|
}
|
||||||
return !used;
|
return !used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ptywritestr(Ptycmd cmd, char *s, int len)
|
||||||
|
{
|
||||||
|
int written;
|
||||||
|
|
||||||
|
for (; len; len -= written, s += written) {
|
||||||
|
if ((written = write(cmd->fd, s, len)) < 0 &&
|
||||||
|
(cmd->block
|
||||||
|
#ifdef EWOULDBLOCK
|
||||||
|
|| errno != EWOULDBLOCK
|
||||||
|
#else
|
||||||
|
#ifdef EAGAIN
|
||||||
|
|| errno != EAGAIN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
))
|
||||||
|
return 1;
|
||||||
|
if (written < 0) {
|
||||||
|
checkptycmd(cmd);
|
||||||
|
if (cmd->fin)
|
||||||
|
break;
|
||||||
|
written = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ptywrite(Ptycmd cmd, char **args, int nonl)
|
ptywrite(Ptycmd cmd, char **args, int nonl)
|
||||||
{
|
{
|
||||||
if (*args) {
|
if (*args) {
|
||||||
char sp = ' ';
|
char sp = ' ';
|
||||||
|
|
||||||
while (*args) {
|
while (*args)
|
||||||
write(cmd->fd, *args, strlen(*args));
|
if (ptywritestr(cmd, *args, strlen(*args)) ||
|
||||||
|
(*++args && ptywritestr(cmd, &sp, 1)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (*++args)
|
|
||||||
write(cmd->fd, &sp, 1);
|
|
||||||
}
|
|
||||||
if (!nonl) {
|
if (!nonl) {
|
||||||
sp = '\n';
|
sp = '\n';
|
||||||
write(cmd->fd, &sp, 1);
|
if (ptywritestr(cmd, &sp, 1))
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int n;
|
int n;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
while ((n = read(0, buf, BUFSIZ)) > 0)
|
while ((n = read(0, buf, BUFSIZ)) > 0)
|
||||||
write(cmd->fd, buf, n);
|
if (ptywritestr(cmd, buf, n))
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -449,17 +526,17 @@ bin_zpty(char *nam, char **args, char *ops, int func)
|
||||||
ops['d'] || ops['L'])) ||
|
ops['d'] || ops['L'])) ||
|
||||||
(ops['d'] && (ops['b'] || ops['e'] || ops['L'])) ||
|
(ops['d'] && (ops['b'] || ops['e'] || ops['L'])) ||
|
||||||
(ops['L'] && (ops['b'] || ops['e']))) {
|
(ops['L'] && (ops['b'] || ops['e']))) {
|
||||||
zerrnam(nam, "illegal option combination", NULL, 0);
|
zwarnnam(nam, "illegal option combination", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (ops['r'] || ops['w']) {
|
if (ops['r'] || ops['w']) {
|
||||||
Ptycmd p;
|
Ptycmd p;
|
||||||
|
|
||||||
if (!*args) {
|
if (!*args) {
|
||||||
zerrnam(nam, "missing pty command name", NULL, 0);
|
zwarnnam(nam, "missing pty command name", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!(p = getptycmd(*args))) {
|
} else if (!(p = getptycmd(*args))) {
|
||||||
zerrnam(nam, "no such pty command: %s", *args, 0);
|
zwarnnam(nam, "no such pty command: %s", *args, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
checkptycmd(p);
|
checkptycmd(p);
|
||||||
|
@ -486,11 +563,11 @@ bin_zpty(char *nam, char **args, char *ops, int func)
|
||||||
return ret;
|
return ret;
|
||||||
} else if (*args) {
|
} else if (*args) {
|
||||||
if (!args[1]) {
|
if (!args[1]) {
|
||||||
zerrnam(nam, "missing command", NULL, 0);
|
zwarnnam(nam, "missing command", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (getptycmd(*args)) {
|
if (getptycmd(*args)) {
|
||||||
zerrnam(nam, "pty command name already used: %s", *args, 0);
|
zwarnnam(nam, "pty command name already used: %s", *args, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return newptycmd(nam, *args, args + 1, ops['e'], ops['b']);
|
return newptycmd(nam, *args, args + 1, ops['e'], ops['b']);
|
||||||
|
|
443
Src/Zle/comp.h
443
Src/Zle/comp.h
|
@ -27,111 +27,362 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#undef compctlread
|
typedef struct cmatcher *Cmatcher;
|
||||||
|
typedef struct cmlist *Cmlist;
|
||||||
|
typedef struct cpattern *Cpattern;
|
||||||
|
typedef struct menuinfo *Menuinfo;
|
||||||
|
typedef struct cexpl *Cexpl;
|
||||||
|
typedef struct cmgroup *Cmgroup;
|
||||||
|
typedef struct cmatch *Cmatch;
|
||||||
|
|
||||||
typedef struct compctlp *Compctlp;
|
/* This is for explantion strings. */
|
||||||
typedef struct compctl *Compctl;
|
|
||||||
typedef struct compcond *Compcond;
|
|
||||||
|
|
||||||
/* node for compctl hash table (compctltab) */
|
struct cexpl {
|
||||||
|
char *str; /* the string */
|
||||||
struct compctlp {
|
int count; /* the number of matches */
|
||||||
HashNode next; /* next in hash chain */
|
int fcount; /* number of matches with fignore ignored */
|
||||||
char *nam; /* command name */
|
|
||||||
int flags; /* CURRENTLY UNUSED */
|
|
||||||
Compctl cc; /* pointer to the compctl desc. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* compctl -x condition */
|
/* This describes a group of matches. */
|
||||||
|
|
||||||
struct compcond {
|
struct cmgroup {
|
||||||
Compcond and, or; /* the next or'ed/and'ed conditions */
|
char *name; /* the name of this group */
|
||||||
int type; /* the type (CCT_*) */
|
Cmgroup prev; /* previous on the list */
|
||||||
int n; /* the array length */
|
Cmgroup next; /* next one in list */
|
||||||
union { /* these structs hold the data used to */
|
int flags; /* see CGF_* below */
|
||||||
struct { /* test this condition */
|
int mcount; /* number of matches */
|
||||||
int *a, *b; /* CCT_POS, CCT_NUMWORDS */
|
Cmatch *matches; /* the matches */
|
||||||
}
|
int lcount; /* number of things to list here */
|
||||||
r;
|
int llcount; /* number of line-displays */
|
||||||
struct { /* CCT_CURSTR, CCT_CURPAT,... */
|
char **ylist; /* things to list */
|
||||||
int *p;
|
int ecount; /* number of explanation string */
|
||||||
char **s;
|
Cexpl *expls; /* explanation strings */
|
||||||
}
|
int ccount; /* number of compctls used */
|
||||||
s;
|
LinkList lexpls; /* list of explanation string while building */
|
||||||
struct { /* CCT_RANGESTR,... */
|
LinkList lmatches; /* list of matches */
|
||||||
char **a, **b;
|
LinkList lfmatches; /* list of matches without fignore */
|
||||||
}
|
LinkList lallccs; /* list of used compctls */
|
||||||
l;
|
int num; /* number of this group */
|
||||||
}
|
int nbrbeg; /* number of opened braces */
|
||||||
u;
|
int nbrend; /* number of closed braces */
|
||||||
|
/* The following is collected/used during listing. */
|
||||||
|
int dcount; /* number of matches to list in columns */
|
||||||
|
int cols; /* number of columns */
|
||||||
|
int lins; /* number of lines */
|
||||||
|
int width; /* column width */
|
||||||
|
int *widths; /* column widths for listpacked */
|
||||||
|
int totl; /* total length */
|
||||||
|
int shortest; /* length of shortest match */
|
||||||
|
Cmgroup perm; /* perm. alloced version of this group */
|
||||||
|
int new; /* new matches since last permalloc() */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CCT_UNUSED 0
|
|
||||||
#define CCT_POS 1
|
|
||||||
#define CCT_CURSTR 2
|
|
||||||
#define CCT_CURPAT 3
|
|
||||||
#define CCT_WORDSTR 4
|
|
||||||
#define CCT_WORDPAT 5
|
|
||||||
#define CCT_CURSUF 6
|
|
||||||
#define CCT_CURPRE 7
|
|
||||||
#define CCT_CURSUB 8
|
|
||||||
#define CCT_CURSUBC 9
|
|
||||||
#define CCT_NUMWORDS 10
|
|
||||||
#define CCT_RANGESTR 11
|
|
||||||
#define CCT_RANGEPAT 12
|
|
||||||
|
|
||||||
/* Contains the real description for compctls */
|
#define CGF_NOSORT 1 /* don't sort this group */
|
||||||
|
#define CGF_LINES 2 /* these are to be printed on different lines */
|
||||||
|
#define CGF_HASDL 4 /* has display strings printed on separate lines */
|
||||||
|
#define CGF_UNIQALL 8 /* remove all duplicates */
|
||||||
|
#define CGF_UNIQCON 16 /* remove consecutive duplicates */
|
||||||
|
#define CGF_PACKED 32 /* LIST_PACKED for this group */
|
||||||
|
#define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */
|
||||||
|
|
||||||
struct compctl {
|
/* This is the struct used to hold matches. */
|
||||||
int refc; /* reference count */
|
|
||||||
Compctl next; /* next compctl for -x */
|
struct cmatch {
|
||||||
unsigned long mask; /* mask of things to complete (CC_*) */
|
char *str; /* the match itself */
|
||||||
char *keyvar; /* for -k (variable) */
|
char *ipre; /* ignored prefix, has to be re-inserted */
|
||||||
char *glob; /* for -g (globbing) */
|
char *ripre; /* ignored prefix, unquoted */
|
||||||
char *str; /* for -s (expansion) */
|
char *isuf; /* ignored suffix */
|
||||||
char *func; /* for -K (function) */
|
char *ppre; /* the path prefix */
|
||||||
char *explain; /* for -X (explanation) */
|
char *psuf; /* the path suffix */
|
||||||
char *ylist; /* for -y (user-defined desc. for listing) */
|
char *prpre; /* path prefix for opendir */
|
||||||
char *prefix, *suffix; /* for -P and -S (prefix, suffix) */
|
char *pre; /* prefix string from -P */
|
||||||
char *subcmd; /* for -l (command name to use) */
|
char *suf; /* suffix string from -S */
|
||||||
char *withd; /* for -w (with directory */
|
char *disp; /* string to display (compadd -d) */
|
||||||
char *hpat; /* for -H (history pattern) */
|
char *autoq; /* closing quote to add automatically */
|
||||||
int hnum; /* for -H (number of events to search) */
|
int flags; /* see CMF_* below */
|
||||||
Compctl ext; /* for -x (first of the compctls after -x) */
|
int *brpl; /* places where to put the brace prefixes */
|
||||||
Compcond cond; /* for -x (condition for this compctl) */
|
int *brsl; /* ...and the suffixes */
|
||||||
Compctl xor; /* for + (next of the xor'ed compctls) */
|
char *rems; /* when to remove the suffix */
|
||||||
|
char *remf; /* shell function to call for suffix-removal */
|
||||||
|
int qipl; /* length of quote-prefix */
|
||||||
|
int qisl; /* length of quote-suffix */
|
||||||
|
int rnum; /* group relative number */
|
||||||
|
int gnum; /* global number */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* objects to complete */
|
#define CMF_FILE (1<< 0) /* this is a file */
|
||||||
#define CC_FILES (1<<0)
|
#define CMF_REMOVE (1<< 1) /* remove the suffix */
|
||||||
#define CC_COMMPATH (1<<1)
|
#define CMF_ISPAR (1<< 2) /* is paramter expansion */
|
||||||
#define CC_REMOVE (1<<2)
|
#define CMF_PARBR (1<< 3) /* paramter expansion with a brace */
|
||||||
#define CC_OPTIONS (1<<3)
|
#define CMF_PARNEST (1<< 4) /* nested paramter expansion */
|
||||||
#define CC_VARS (1<<4)
|
#define CMF_NOLIST (1<< 5) /* should not be listed */
|
||||||
#define CC_BINDINGS (1<<5)
|
#define CMF_DISPLINE (1<< 6) /* display strings one per line */
|
||||||
#define CC_ARRAYS (1<<6)
|
#define CMF_HIDE (1<< 7) /* temporarily hide this one */
|
||||||
#define CC_INTVARS (1<<7)
|
#define CMF_NOSPACE (1<< 8) /* don't add a space */
|
||||||
#define CC_SHFUNCS (1<<8)
|
#define CMF_PACKED (1<< 9) /* prefer LIST_PACKED */
|
||||||
#define CC_PARAMS (1<<9)
|
#define CMF_ROWS (1<<10) /* prefer LIST_ROWS_FIRST */
|
||||||
#define CC_ENVVARS (1<<10)
|
#define CMF_MULT (1<<11) /* string appears more than once */
|
||||||
#define CC_JOBS (1<<11)
|
#define CMF_FMULT (1<<12) /* first of multiple equal strings */
|
||||||
#define CC_RUNNING (1<<12)
|
|
||||||
#define CC_STOPPED (1<<13)
|
/* Stuff for completion matcher control. */
|
||||||
#define CC_BUILTINS (1<<14)
|
|
||||||
#define CC_ALREG (1<<15)
|
struct cmlist {
|
||||||
#define CC_ALGLOB (1<<16)
|
Cmlist next; /* next one in the list of global matchers */
|
||||||
#define CC_USERS (1<<17)
|
Cmatcher matcher; /* the matcher definition */
|
||||||
#define CC_DISCMDS (1<<18)
|
char *str; /* the string for it */
|
||||||
#define CC_EXCMDS (1<<19)
|
};
|
||||||
#define CC_SCALARS (1<<20)
|
|
||||||
#define CC_READONLYS (1<<21)
|
struct cmatcher {
|
||||||
#define CC_SPECIALS (1<<22)
|
int refc; /* reference counter */
|
||||||
#define CC_DELETE (1<<23)
|
Cmatcher next; /* next matcher */
|
||||||
#define CC_NAMED (1<<24)
|
int flags; /* see CMF_* below */
|
||||||
#define CC_QUOTEFLAG (1<<25)
|
Cpattern line; /* what matches on the line */
|
||||||
#define CC_EXTCMDS (1<<26)
|
int llen; /* length of line pattern */
|
||||||
#define CC_RESWDS (1<<27)
|
Cpattern word; /* what matches in the word */
|
||||||
#define CC_DIRS (1<<28)
|
int wlen; /* length of word pattern */
|
||||||
|
Cpattern left; /* left anchor */
|
||||||
|
int lalen; /* length of left anchor */
|
||||||
|
Cpattern right; /* right anchor */
|
||||||
|
int ralen; /* length of right anchor */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CMF_LINE 1
|
||||||
|
#define CMF_LEFT 2
|
||||||
|
#define CMF_RIGHT 4
|
||||||
|
|
||||||
|
struct cpattern {
|
||||||
|
Cpattern next; /* next sub-pattern */
|
||||||
|
unsigned char tab[256]; /* table of matched characters */
|
||||||
|
int equiv; /* if this is a {...} class */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is a special return value for parse_cmatcher(), *
|
||||||
|
* signalling an error. */
|
||||||
|
|
||||||
|
#define pcm_err ((Cmatcher) 1)
|
||||||
|
|
||||||
|
/* Information about what to put on the line as the unambiguous string.
|
||||||
|
* The code always keeps lists of these structs up to date while
|
||||||
|
* matches are added (in the aminfo structs below).
|
||||||
|
* The lists have two levels: in the first one we have one struct per
|
||||||
|
* word-part, where parts are separated by the anchors of `*' patterns.
|
||||||
|
* These structs have pointers (in the prefix and suffix fields) to
|
||||||
|
* lists of cline structs describing the strings before or after the
|
||||||
|
* the anchor. */
|
||||||
|
|
||||||
|
typedef struct cline *Cline;
|
||||||
|
typedef struct clsub Clsub;
|
||||||
|
|
||||||
|
struct cline {
|
||||||
|
Cline next;
|
||||||
|
int flags;
|
||||||
|
char *line;
|
||||||
|
int llen;
|
||||||
|
char *word;
|
||||||
|
int wlen;
|
||||||
|
char *orig;
|
||||||
|
int olen;
|
||||||
|
int slen;
|
||||||
|
Cline prefix, suffix;
|
||||||
|
int min, max;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CLF_MISS 1
|
||||||
|
#define CLF_DIFF 2
|
||||||
|
#define CLF_SUF 4
|
||||||
|
#define CLF_MID 8
|
||||||
|
#define CLF_NEW 16
|
||||||
|
#define CLF_LINE 32
|
||||||
|
#define CLF_JOIN 64
|
||||||
|
#define CLF_MATCHED 128
|
||||||
|
|
||||||
|
/* Information for ambiguous completions. One for fignore ignored and *
|
||||||
|
* one for normal completion. */
|
||||||
|
|
||||||
|
typedef struct aminfo *Aminfo;
|
||||||
|
|
||||||
|
struct aminfo {
|
||||||
|
Cmatch firstm; /* the first match */
|
||||||
|
int exact; /* if there was an exact match */
|
||||||
|
Cmatch exactm; /* the exact match (if any) */
|
||||||
|
int count; /* number of matches */
|
||||||
|
Cline line; /* unambiguous line string */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Information about menucompletion stuff. */
|
||||||
|
|
||||||
|
struct menuinfo {
|
||||||
|
Cmgroup group; /* position in the group list */
|
||||||
|
Cmatch *cur; /* match currently inserted */
|
||||||
|
int pos; /* begin on line */
|
||||||
|
int len; /* length of inserted string */
|
||||||
|
int end; /* end on the line */
|
||||||
|
int we; /* non-zero if the cursor was at the end */
|
||||||
|
int insc; /* length of suffix inserted */
|
||||||
|
int asked; /* we asked if the list should be shown */
|
||||||
|
char *prebr; /* prefix before a brace, if any */
|
||||||
|
char *postbr; /* suffix after a brace */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flags for compadd and addmatches(). */
|
||||||
|
|
||||||
|
#define CAF_QUOTE 1
|
||||||
|
#define CAF_NOSORT 2
|
||||||
|
#define CAF_MATCH 4
|
||||||
|
#define CAF_UNIQCON 8
|
||||||
|
#define CAF_UNIQALL 16
|
||||||
|
|
||||||
|
/* Data for compadd and addmatches() */
|
||||||
|
|
||||||
|
typedef struct cadata *Cadata;
|
||||||
|
|
||||||
|
struct cadata {
|
||||||
|
char *ipre; /* ignored prefix (-i) */
|
||||||
|
char *isuf; /* ignored suffix (-I) */
|
||||||
|
char *ppre; /* `path' prefix (-p) */
|
||||||
|
char *psuf; /* `path' suffix (-s) */
|
||||||
|
char *prpre; /* expanded `path' prefix (-W) */
|
||||||
|
char *pre; /* prefix to insert (-P) */
|
||||||
|
char *suf; /* suffix to insert (-S) */
|
||||||
|
char *group; /* name of the group (-[JV]) */
|
||||||
|
char *rems; /* remove suffix on chars... (-r) */
|
||||||
|
char *remf; /* function to remove suffix (-R) */
|
||||||
|
char *ign; /* ignored suffixes (-F) */
|
||||||
|
int flags; /* CMF_* flags (-[fqn]) */
|
||||||
|
int aflags; /* CAF_* flags (-[QUa]) */
|
||||||
|
Cmatcher match; /* match spec (parsed from -M) */
|
||||||
|
char *exp; /* explanation (-X) */
|
||||||
|
char *apar; /* array to store matches in (-A) */
|
||||||
|
char *opar; /* array to store originals in (-O) */
|
||||||
|
char *dpar; /* array to delete non-matches in (-D) */
|
||||||
|
char *disp; /* array with display lists (-d) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* List data. */
|
||||||
|
|
||||||
|
typedef struct cldata *Cldata;
|
||||||
|
|
||||||
|
struct cldata {
|
||||||
|
int columns; /* screen width */
|
||||||
|
int lines; /* screen height */
|
||||||
|
int menuacc; /* value of global menuacc */
|
||||||
|
int valid; /* no need to calculate anew */
|
||||||
|
int nlist; /* number of matches to list */
|
||||||
|
int nlines; /* number of lines needed */
|
||||||
|
int hidden; /* != 0 if there are hidden matches */
|
||||||
|
int onlyexpl; /* != 0 if only explanations to print */
|
||||||
|
int showall; /* != 0 if hidden matches should be shown */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int,
|
||||||
|
char *, struct stat *);
|
||||||
|
|
||||||
|
/* Flags for fromcomp. */
|
||||||
|
|
||||||
|
#define FC_LINE 1
|
||||||
|
#define FC_INWORD 2
|
||||||
|
|
||||||
|
/* Flags for special parameters. */
|
||||||
|
|
||||||
|
#define CPN_WORDS 0
|
||||||
|
#define CP_WORDS (1 << CPN_WORDS)
|
||||||
|
#define CPN_CURRENT 1
|
||||||
|
#define CP_CURRENT (1 << CPN_CURRENT)
|
||||||
|
#define CPN_PREFIX 2
|
||||||
|
#define CP_PREFIX (1 << CPN_PREFIX)
|
||||||
|
#define CPN_SUFFIX 3
|
||||||
|
#define CP_SUFFIX (1 << CPN_SUFFIX)
|
||||||
|
#define CPN_IPREFIX 4
|
||||||
|
#define CP_IPREFIX (1 << CPN_IPREFIX)
|
||||||
|
#define CPN_ISUFFIX 5
|
||||||
|
#define CP_ISUFFIX (1 << CPN_ISUFFIX)
|
||||||
|
#define CPN_QIPREFIX 6
|
||||||
|
#define CP_QIPREFIX (1 << CPN_QIPREFIX)
|
||||||
|
#define CPN_QISUFFIX 7
|
||||||
|
#define CP_QISUFFIX (1 << CPN_QISUFFIX)
|
||||||
|
#define CPN_COMPSTATE 8
|
||||||
|
#define CP_COMPSTATE (1 << CPN_COMPSTATE)
|
||||||
|
|
||||||
|
#define CP_REALPARAMS 9
|
||||||
|
#define CP_ALLREALS ((unsigned int) 0x1ff)
|
||||||
|
|
||||||
|
|
||||||
|
#define CPN_NMATCHES 0
|
||||||
|
#define CP_NMATCHES (1 << CPN_NMATCHES)
|
||||||
|
#define CPN_CONTEXT 1
|
||||||
|
#define CP_CONTEXT (1 << CPN_CONTEXT)
|
||||||
|
#define CPN_PARAMETER 2
|
||||||
|
#define CP_PARAMETER (1 << CPN_PARAMETER)
|
||||||
|
#define CPN_REDIRECT 3
|
||||||
|
#define CP_REDIRECT (1 << CPN_REDIRECT)
|
||||||
|
#define CPN_QUOTE 4
|
||||||
|
#define CP_QUOTE (1 << CPN_QUOTE)
|
||||||
|
#define CPN_QUOTING 5
|
||||||
|
#define CP_QUOTING (1 << CPN_QUOTING)
|
||||||
|
#define CPN_RESTORE 6
|
||||||
|
#define CP_RESTORE (1 << CPN_RESTORE)
|
||||||
|
#define CPN_LIST 7
|
||||||
|
#define CP_LIST (1 << CPN_LIST)
|
||||||
|
#define CPN_INSERT 8
|
||||||
|
#define CP_INSERT (1 << CPN_INSERT)
|
||||||
|
#define CPN_EXACT 9
|
||||||
|
#define CP_EXACT (1 << CPN_EXACT)
|
||||||
|
#define CPN_EXACTSTR 10
|
||||||
|
#define CP_EXACTSTR (1 << CPN_EXACTSTR)
|
||||||
|
#define CPN_PATMATCH 11
|
||||||
|
#define CP_PATMATCH (1 << CPN_PATMATCH)
|
||||||
|
#define CPN_PATINSERT 12
|
||||||
|
#define CP_PATINSERT (1 << CPN_PATINSERT)
|
||||||
|
#define CPN_UNAMBIG 13
|
||||||
|
#define CP_UNAMBIG (1 << CPN_UNAMBIG)
|
||||||
|
#define CPN_UNAMBIGC 14
|
||||||
|
#define CP_UNAMBIGC (1 << CPN_UNAMBIGC)
|
||||||
|
#define CPN_LISTMAX 15
|
||||||
|
#define CP_LISTMAX (1 << CPN_LISTMAX)
|
||||||
|
#define CPN_LASTPROMPT 16
|
||||||
|
#define CP_LASTPROMPT (1 << CPN_LASTPROMPT)
|
||||||
|
#define CPN_TOEND 17
|
||||||
|
#define CP_TOEND (1 << CPN_TOEND)
|
||||||
|
#define CPN_OLDLIST 18
|
||||||
|
#define CP_OLDLIST (1 << CPN_OLDLIST)
|
||||||
|
#define CPN_OLDINS 19
|
||||||
|
#define CP_OLDINS (1 << CPN_OLDINS)
|
||||||
|
#define CPN_VARED 20
|
||||||
|
#define CP_VARED (1 << CPN_VARED)
|
||||||
|
#define CPN_LISTLINES 21
|
||||||
|
#define CP_LISTLINES (1 << CPN_LISTLINES)
|
||||||
|
#define CPN_QUOTES 22
|
||||||
|
#define CP_QUOTES (1 << CPN_QUOTES)
|
||||||
|
#define CPN_IGNORED 23
|
||||||
|
#define CP_IGNORED (1 << CPN_IGNORED)
|
||||||
|
|
||||||
|
#define CP_KEYPARAMS 24
|
||||||
|
#define CP_ALLKEYS ((unsigned int) 0xffffff)
|
||||||
|
|
||||||
|
/* Hooks. */
|
||||||
|
|
||||||
|
#define INSERTMATCHHOOK (comphooks + 0)
|
||||||
|
#define MENUSTARTHOOK (comphooks + 1)
|
||||||
|
#define COMPCTLMAKEHOOK (comphooks + 2)
|
||||||
|
#define COMPCTLCLEANUPHOOK (comphooks + 3)
|
||||||
|
#define COMPLISTMATCHESHOOK (comphooks + 4)
|
||||||
|
|
||||||
|
/* compctl hook data struct */
|
||||||
|
|
||||||
|
struct ccmakedat {
|
||||||
|
char *str;
|
||||||
|
int incmd;
|
||||||
|
int lst;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Data given to offered hooks. */
|
||||||
|
|
||||||
|
typedef struct chdata *Chdata;
|
||||||
|
|
||||||
|
struct chdata {
|
||||||
|
Cmgroup matches; /* the matches generated */
|
||||||
|
int num; /* the number of matches */
|
||||||
|
Cmatch cur; /* current match or NULL */
|
||||||
|
};
|
||||||
|
|
||||||
#define CC_EXPANDEXPL (1<<30)
|
|
||||||
#define CC_RESERVED (1<<31)
|
|
||||||
|
|
1496
Src/Zle/compcore.c
1496
Src/Zle/compcore.c
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* complete.c - the complete module
|
* complete.c - the complete module, interface part
|
||||||
*
|
*
|
||||||
* This file is part of zsh, the Z shell.
|
* This file is part of zsh, the Z shell.
|
||||||
*
|
*
|
||||||
|
@ -29,12 +29,50 @@
|
||||||
|
|
||||||
#include "complete.mdh"
|
#include "complete.mdh"
|
||||||
#include "complete.pro"
|
#include "complete.pro"
|
||||||
#define GLOBAL_PROTOTYPES
|
|
||||||
#include "zle_tricky.pro"
|
/* global variables for shell parameters in new style completion */
|
||||||
#undef GLOBAL_PROTOTYPES
|
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export zlong compcurrent;
|
||||||
|
/**/
|
||||||
|
zlong complistmax,
|
||||||
|
complistlines,
|
||||||
|
compignored;
|
||||||
|
|
||||||
|
/**/
|
||||||
|
mod_export
|
||||||
|
char **compwords,
|
||||||
|
*compprefix,
|
||||||
|
*compsuffix,
|
||||||
|
*compisuffix,
|
||||||
|
*compqiprefix,
|
||||||
|
*compqisuffix,
|
||||||
|
*compquote,
|
||||||
|
*compqstack,
|
||||||
|
*comppatmatch,
|
||||||
|
*complastprompt;
|
||||||
|
/**/
|
||||||
|
char *compiprefix,
|
||||||
|
*compcontext,
|
||||||
|
*compparameter,
|
||||||
|
*compredirect,
|
||||||
|
*compquoting,
|
||||||
|
*comprestore,
|
||||||
|
*complist,
|
||||||
|
*compinsert,
|
||||||
|
*compexact,
|
||||||
|
*compexactstr,
|
||||||
|
*comppatinsert,
|
||||||
|
*comptoend,
|
||||||
|
*compoldlist,
|
||||||
|
*compoldins,
|
||||||
|
*compvared;
|
||||||
|
|
||||||
|
/**/
|
||||||
|
Param *comprpms, *compkpms;
|
||||||
|
|
||||||
|
/**/
|
||||||
|
mod_export void
|
||||||
freecmlist(Cmlist l)
|
freecmlist(Cmlist l)
|
||||||
{
|
{
|
||||||
Cmlist n;
|
Cmlist n;
|
||||||
|
@ -51,7 +89,7 @@ freecmlist(Cmlist l)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
freecmatcher(Cmatcher m)
|
freecmatcher(Cmatcher m)
|
||||||
{
|
{
|
||||||
Cmatcher n;
|
Cmatcher n;
|
||||||
|
@ -86,29 +124,10 @@ freecpattern(Cpattern p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy a list of completion matchers. */
|
|
||||||
|
|
||||||
static Cmlist
|
|
||||||
cpcmlist(Cmlist l)
|
|
||||||
{
|
|
||||||
Cmlist r = NULL, *p = &r, n;
|
|
||||||
|
|
||||||
while (l) {
|
|
||||||
*p = n = (Cmlist) zalloc(sizeof(struct cmlist));
|
|
||||||
n->next = NULL;
|
|
||||||
n->matcher = cpcmatcher(l->matcher);
|
|
||||||
n->str = ztrdup(l->str);
|
|
||||||
|
|
||||||
p = &(n->next);
|
|
||||||
l = l->next;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy a completion matcher list. */
|
/* Copy a completion matcher list. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
Cmatcher
|
mod_export Cmatcher
|
||||||
cpcmatcher(Cmatcher m)
|
cpcmatcher(Cmatcher m)
|
||||||
{
|
{
|
||||||
Cmatcher r = NULL, *p = &r, n;
|
Cmatcher r = NULL, *p = &r, n;
|
||||||
|
@ -155,37 +174,10 @@ cpcpattern(Cpattern o)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the global match specs. */
|
|
||||||
|
|
||||||
/**/
|
|
||||||
int
|
|
||||||
set_gmatcher(char *name, char **argv)
|
|
||||||
{
|
|
||||||
Cmlist l = NULL, *q = &l, n;
|
|
||||||
Cmatcher m;
|
|
||||||
|
|
||||||
while (*argv) {
|
|
||||||
if ((m = parse_cmatcher(name, *argv)) == pcm_err)
|
|
||||||
return 1;
|
|
||||||
*q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
|
|
||||||
n->next = NULL;
|
|
||||||
n->matcher = m;
|
|
||||||
n->str = *argv++;
|
|
||||||
|
|
||||||
q = &(n->next);
|
|
||||||
}
|
|
||||||
freecmlist(cmatcher);
|
|
||||||
PERMALLOC {
|
|
||||||
cmatcher = cpcmlist(l);
|
|
||||||
} LASTALLOC;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse a string for matcher control, containing multiple matchers. */
|
/* Parse a string for matcher control, containing multiple matchers. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
Cmatcher
|
mod_export Cmatcher
|
||||||
parse_cmatcher(char *name, char *s)
|
parse_cmatcher(char *name, char *s)
|
||||||
{
|
{
|
||||||
Cmatcher ret = NULL, r = NULL, n;
|
Cmatcher ret = NULL, r = NULL, n;
|
||||||
|
@ -262,8 +254,11 @@ parse_cmatcher(char *name, char *s)
|
||||||
return pcm_err;
|
return pcm_err;
|
||||||
}
|
}
|
||||||
word = NULL;
|
word = NULL;
|
||||||
wl = -1;
|
if (*++s == '*') {
|
||||||
s++;
|
s++;
|
||||||
|
wl = -2;
|
||||||
|
} else
|
||||||
|
wl = -1;
|
||||||
} else {
|
} else {
|
||||||
word = parse_pattern(name, &s, &wl, 0, &err);
|
word = parse_pattern(name, &s, &wl, 0, &err);
|
||||||
|
|
||||||
|
@ -389,17 +384,17 @@ static int
|
||||||
bin_compadd(char *name, char **argv, char *ops, int func)
|
bin_compadd(char *name, char **argv, char *ops, int func)
|
||||||
{
|
{
|
||||||
struct cadata dat;
|
struct cadata dat;
|
||||||
char *p, **sp, *e, *m = NULL;
|
char *p, **sp, *e, *m = NULL, *mstr = NULL;
|
||||||
int dm;
|
int dm;
|
||||||
Cmatcher match = NULL;
|
Cmatcher match = NULL;
|
||||||
|
|
||||||
if (incompfunc != 1) {
|
if (incompfunc != 1) {
|
||||||
zerrnam(name, "can only be called from completion function", NULL, 0);
|
zwarnnam(name, "can only be called from completion function", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre =
|
dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre =
|
||||||
dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp =
|
dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp =
|
||||||
dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = dat.ylist = NULL;
|
dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
|
||||||
dat.match = NULL;
|
dat.match = NULL;
|
||||||
dat.flags = 0;
|
dat.flags = 0;
|
||||||
dat.aflags = CAF_MATCH;
|
dat.aflags = CAF_MATCH;
|
||||||
|
@ -462,10 +457,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
||||||
if (!(dat.aflags & CAF_UNIQALL))
|
if (!(dat.aflags & CAF_UNIQALL))
|
||||||
dat.aflags |= CAF_UNIQCON;
|
dat.aflags |= CAF_UNIQCON;
|
||||||
break;
|
break;
|
||||||
case 'y':
|
|
||||||
sp = &(dat.ylist);
|
|
||||||
e = "string expected after -%c";
|
|
||||||
break;
|
|
||||||
case 'i':
|
case 'i':
|
||||||
sp = &(dat.ipre);
|
sp = &(dat.ipre);
|
||||||
e = "string expected after -%c";
|
e = "string expected after -%c";
|
||||||
|
@ -486,9 +477,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
||||||
sp = &(dat.prpre);
|
sp = &(dat.prpre);
|
||||||
e = "string expected after -%c";
|
e = "string expected after -%c";
|
||||||
break;
|
break;
|
||||||
case 'a':
|
|
||||||
dat.aflags |= CAF_ALT;
|
|
||||||
break;
|
|
||||||
case 'M':
|
case 'M':
|
||||||
sp = &m;
|
sp = &m;
|
||||||
e = "matching specification expected after -%c";
|
e = "matching specification expected after -%c";
|
||||||
|
@ -531,7 +519,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
||||||
argv++;
|
argv++;
|
||||||
goto ca_args;
|
goto ca_args;
|
||||||
default:
|
default:
|
||||||
zerrnam(name, "bad option: -%c", NULL, *p);
|
zwarnnam(name, "bad option: -%c", NULL, *p);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (sp) {
|
if (sp) {
|
||||||
|
@ -545,18 +533,29 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
||||||
*sp = *argv;
|
*sp = *argv;
|
||||||
p = "" - 1;
|
p = "" - 1;
|
||||||
} else {
|
} else {
|
||||||
zerrnam(name, e, NULL, *p);
|
zwarnnam(name, e, NULL, *p);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (dm && (match = parse_cmatcher(name, m)) == pcm_err) {
|
if (dm) {
|
||||||
match = NULL;
|
if (mstr)
|
||||||
return 1;
|
mstr = tricat(mstr, " ", m);
|
||||||
|
else
|
||||||
|
mstr = ztrdup(m);
|
||||||
|
m = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mstr && (match = parse_cmatcher(name, mstr)) == pcm_err) {
|
||||||
|
zsfree(mstr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
zsfree(mstr);
|
||||||
|
|
||||||
ca_args:
|
ca_args:
|
||||||
if (!*argv)
|
|
||||||
|
if (!*argv && !dat.group &&
|
||||||
|
!(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
dat.match = match = cpcmatcher(match);
|
dat.match = match = cpcmatcher(match);
|
||||||
|
@ -574,7 +573,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
||||||
#define CVT_SUFPAT 5
|
#define CVT_SUFPAT 5
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
ignore_prefix(int l)
|
ignore_prefix(int l)
|
||||||
{
|
{
|
||||||
if (l) {
|
if (l) {
|
||||||
|
@ -598,7 +597,7 @@ ignore_prefix(int l)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
ignore_suffix(int l)
|
ignore_suffix(int l)
|
||||||
{
|
{
|
||||||
if (l) {
|
if (l) {
|
||||||
|
@ -621,7 +620,7 @@ ignore_suffix(int l)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
restrict_range(int b, int e)
|
restrict_range(int b, int e)
|
||||||
{
|
{
|
||||||
int wl = arrlen(compwords) - 1;
|
int wl = arrlen(compwords) - 1;
|
||||||
|
@ -644,6 +643,7 @@ restrict_range(int b, int e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
static int
|
static int
|
||||||
do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
|
do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
|
||||||
{
|
{
|
||||||
|
@ -740,7 +740,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
|
||||||
char *p, sav;
|
char *p, sav;
|
||||||
|
|
||||||
if (!(l = strlen(compprefix)))
|
if (!(l = strlen(compprefix)))
|
||||||
return 0;
|
return ((na == 1 || na == -1) && pattry(pp, compprefix));
|
||||||
if (na < 0) {
|
if (na < 0) {
|
||||||
p = compprefix + l;
|
p = compprefix + l;
|
||||||
na = -na;
|
na = -na;
|
||||||
|
@ -766,7 +766,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
if (!(ol = l = strlen(compsuffix)))
|
if (!(ol = l = strlen(compsuffix)))
|
||||||
return 0;
|
return ((na == 1 || na == -1) && pattry(pp, compsuffix));
|
||||||
if (na < 0) {
|
if (na < 0) {
|
||||||
p = compsuffix;
|
p = compsuffix;
|
||||||
na = -na;
|
na = -na;
|
||||||
|
@ -798,11 +798,11 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
||||||
char *sa = NULL, *sb = NULL;
|
char *sa = NULL, *sb = NULL;
|
||||||
|
|
||||||
if (incompfunc != 1) {
|
if (incompfunc != 1) {
|
||||||
zerrnam(name, "can only be called from completion function", NULL, 0);
|
zwarnnam(name, "can only be called from completion function", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (argv[0][0] != '-') {
|
if (argv[0][0] != '-') {
|
||||||
zerrnam(name, "missing option", NULL, 0);
|
zwarnnam(name, "missing option", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
switch (argv[0][1]) {
|
switch (argv[0][1]) {
|
||||||
|
@ -814,7 +814,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
||||||
case 'S': test = CVT_SUFPAT; break;
|
case 'S': test = CVT_SUFPAT; break;
|
||||||
case 'q': return set_comp_sep();
|
case 'q': return set_comp_sep();
|
||||||
default:
|
default:
|
||||||
zerrnam(name, "bad option -%c", NULL, argv[0][1]);
|
zwarnnam(name, "bad option -%c", NULL, argv[0][1]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (argv[0][2]) {
|
if (argv[0][2]) {
|
||||||
|
@ -823,7 +823,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
||||||
na = 2;
|
na = 2;
|
||||||
} else {
|
} else {
|
||||||
if (!(sa = argv[1])) {
|
if (!(sa = argv[1])) {
|
||||||
zerrnam(name, "missing string for option -%c", NULL, argv[0][1]);
|
zwarnnam(name, "missing string for option -%c", NULL, argv[0][1]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
sb = argv[2];
|
sb = argv[2];
|
||||||
|
@ -831,7 +831,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
||||||
}
|
}
|
||||||
if (((test == CVT_PRENUM || test == CVT_SUFNUM) ? !!sb :
|
if (((test == CVT_PRENUM || test == CVT_SUFNUM) ? !!sb :
|
||||||
(sb && argv[na]))) {
|
(sb && argv[na]))) {
|
||||||
zerrnam(name, "too many arguments", NULL, 0);
|
zwarnnam(name, "too many arguments", NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
switch (test) {
|
switch (test) {
|
||||||
|
@ -841,11 +841,9 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
||||||
break;
|
break;
|
||||||
case CVT_RANGEPAT:
|
case CVT_RANGEPAT:
|
||||||
tokenize(sa);
|
tokenize(sa);
|
||||||
sa = rembslash(sa);
|
|
||||||
remnulargs(sa);
|
remnulargs(sa);
|
||||||
if (sb) {
|
if (sb) {
|
||||||
tokenize(sb);
|
tokenize(sb);
|
||||||
sb = rembslash(sb);
|
|
||||||
remnulargs(sb);
|
remnulargs(sb);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -861,7 +859,6 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
||||||
} else
|
} else
|
||||||
na = -1;
|
na = -1;
|
||||||
tokenize(sa);
|
tokenize(sa);
|
||||||
sa = rembslash(sa);
|
|
||||||
remnulargs(sa);
|
remnulargs(sa);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -892,9 +889,6 @@ static struct compparam comprparams[] = {
|
||||||
|
|
||||||
static struct compparam compkparams[] = {
|
static struct compparam compkparams[] = {
|
||||||
{ "nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_nmatches) },
|
{ "nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_nmatches) },
|
||||||
{ "matcher", PM_INTEGER, VAL(compmatcher), NULL, NULL },
|
|
||||||
{ "matcher_string", PM_SCALAR, VAL(compmatcherstr), NULL, NULL },
|
|
||||||
{ "total_matchers", PM_INTEGER, VAL(compmatchertot), NULL, NULL },
|
|
||||||
{ "context", PM_SCALAR, VAL(compcontext), NULL, NULL },
|
{ "context", PM_SCALAR, VAL(compcontext), NULL, NULL },
|
||||||
{ "parameter", PM_SCALAR, VAL(compparameter), NULL, NULL },
|
{ "parameter", PM_SCALAR, VAL(compparameter), NULL, NULL },
|
||||||
{ "redirect", PM_SCALAR, VAL(compredirect), NULL, NULL },
|
{ "redirect", PM_SCALAR, VAL(compredirect), NULL, NULL },
|
||||||
|
@ -902,7 +896,6 @@ static struct compparam compkparams[] = {
|
||||||
{ "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL, NULL },
|
{ "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL, NULL },
|
||||||
{ "restore", PM_SCALAR, VAL(comprestore), NULL, NULL },
|
{ "restore", PM_SCALAR, VAL(comprestore), NULL, NULL },
|
||||||
{ "list", PM_SCALAR, NULL, VAL(set_complist), VAL(get_complist) },
|
{ "list", PM_SCALAR, NULL, VAL(set_complist), VAL(get_complist) },
|
||||||
{ "force_list", PM_SCALAR, VAL(compforcelist), NULL, NULL },
|
|
||||||
{ "insert", PM_SCALAR, VAL(compinsert), NULL, NULL },
|
{ "insert", PM_SCALAR, VAL(compinsert), NULL, NULL },
|
||||||
{ "exact", PM_SCALAR, VAL(compexact), NULL, NULL },
|
{ "exact", PM_SCALAR, VAL(compexact), NULL, NULL },
|
||||||
{ "exact_string", PM_SCALAR, VAL(compexactstr), NULL, NULL },
|
{ "exact_string", PM_SCALAR, VAL(compexactstr), NULL, NULL },
|
||||||
|
@ -917,8 +910,9 @@ static struct compparam compkparams[] = {
|
||||||
{ "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
|
{ "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
|
||||||
{ "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL },
|
{ "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL },
|
||||||
{ "vared", PM_SCALAR, VAL(compvared), NULL, NULL },
|
{ "vared", PM_SCALAR, VAL(compvared), NULL, NULL },
|
||||||
{ "alternate_nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_anmatches) },
|
|
||||||
{ "list_lines", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_listlines) },
|
{ "list_lines", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_listlines) },
|
||||||
|
{ "all_quotes", PM_SCALAR | PM_READONLY, VAL(compqstack), NULL, NULL },
|
||||||
|
{ "ignored", PM_INTEGER | PM_READONLY, VAL(compignored), NULL, NULL },
|
||||||
{ NULL, 0, NULL, NULL, NULL }
|
{ NULL, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -976,7 +970,7 @@ makecompparams(void)
|
||||||
|
|
||||||
comprpms[CPN_COMPSTATE] = cpm;
|
comprpms[CPN_COMPSTATE] = cpm;
|
||||||
tht = paramtab;
|
tht = paramtab;
|
||||||
cpm->level = locallevel;
|
cpm->level = locallevel + 1;
|
||||||
cpm->gets.hfn = get_compstate;
|
cpm->gets.hfn = get_compstate;
|
||||||
cpm->sets.hfn = set_compstate;
|
cpm->sets.hfn = set_compstate;
|
||||||
cpm->unsetfn = compunsetfn;
|
cpm->unsetfn = compunsetfn;
|
||||||
|
@ -1029,14 +1023,7 @@ set_compstate(Param pm, HashTable ht)
|
||||||
static zlong
|
static zlong
|
||||||
get_nmatches(Param pm)
|
get_nmatches(Param pm)
|
||||||
{
|
{
|
||||||
return num_matches(1);
|
return (permmatches(0) ? 0 : nmatches);
|
||||||
}
|
|
||||||
|
|
||||||
/**/
|
|
||||||
static zlong
|
|
||||||
get_anmatches(Param pm)
|
|
||||||
{
|
|
||||||
return num_matches(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -1083,14 +1070,37 @@ static void
|
||||||
compunsetfn(Param pm, int exp)
|
compunsetfn(Param pm, int exp)
|
||||||
{
|
{
|
||||||
if (exp) {
|
if (exp) {
|
||||||
if (PM_TYPE(pm->flags) == PM_SCALAR) {
|
if (pm->u.data) {
|
||||||
zsfree(*((char **) pm->u.data));
|
if (PM_TYPE(pm->flags) == PM_SCALAR) {
|
||||||
*((char **) pm->u.data) = ztrdup("");
|
zsfree(*((char **) pm->u.data));
|
||||||
} else if (PM_TYPE(pm->flags) == PM_ARRAY) {
|
*((char **) pm->u.data) = ztrdup("");
|
||||||
freearray(*((char ***) pm->u.data));
|
} else if (PM_TYPE(pm->flags) == PM_ARRAY) {
|
||||||
*((char ***) pm->u.data) = zcalloc(sizeof(char *));
|
freearray(*((char ***) pm->u.data));
|
||||||
|
*((char ***) pm->u.data) = zcalloc(sizeof(char *));
|
||||||
|
} else if (PM_TYPE(pm->flags) == PM_HASHED) {
|
||||||
|
deleteparamtable(pm->u.hash);
|
||||||
|
pm->u.hash = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pm->flags |= PM_UNSET;
|
} else if (PM_TYPE(pm->flags) == PM_HASHED) {
|
||||||
|
Param *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
deletehashtable(pm->u.hash);
|
||||||
|
pm->u.hash = NULL;
|
||||||
|
|
||||||
|
for (p = compkpms, i = CP_KEYPARAMS; i--; p++)
|
||||||
|
*p = NULL;
|
||||||
|
}
|
||||||
|
if (!exp) {
|
||||||
|
Param *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (p = comprpms, i = CP_REALPARAMS; i; p++, i--)
|
||||||
|
if (*p == pm) {
|
||||||
|
*p = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,31 +1112,35 @@ comp_setunset(int rset, int runset, int kset, int kunset)
|
||||||
|
|
||||||
if (comprpms && (rset >= 0 || runset >= 0)) {
|
if (comprpms && (rset >= 0 || runset >= 0)) {
|
||||||
for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) {
|
for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) {
|
||||||
if (rset & 1)
|
if (*p) {
|
||||||
(*p)->flags &= ~PM_UNSET;
|
if (rset & 1)
|
||||||
if (runset & 1)
|
(*p)->flags &= ~PM_UNSET;
|
||||||
(*p)->flags |= PM_UNSET;
|
if (runset & 1)
|
||||||
|
(*p)->flags |= PM_UNSET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (comprpms && (kset >= 0 || kunset >= 0)) {
|
if (compkpms && (kset >= 0 || kunset >= 0)) {
|
||||||
for (p = compkpms; kset || kunset; kset >>= 1, kunset >>= 1, p++) {
|
for (p = compkpms; kset || kunset; kset >>= 1, kunset >>= 1, p++) {
|
||||||
if (kset & 1)
|
if (*p) {
|
||||||
(*p)->flags &= ~PM_UNSET;
|
if (kset & 1)
|
||||||
if (kunset & 1)
|
(*p)->flags &= ~PM_UNSET;
|
||||||
(*p)->flags |= PM_UNSET;
|
if (kunset & 1)
|
||||||
|
(*p)->flags |= PM_UNSET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static int
|
static int
|
||||||
comp_wrapper(List list, FuncWrap w, char *name)
|
comp_wrapper(Eprog prog, FuncWrap w, char *name)
|
||||||
{
|
{
|
||||||
if (incompfunc != 1)
|
if (incompfunc != 1)
|
||||||
return 1;
|
return 1;
|
||||||
else {
|
else {
|
||||||
char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
|
char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
|
||||||
char *oqipre, *oqisuf, *oq, *oqi;
|
char *oqipre, *oqisuf, *oq, *oqi, *oqs, *oaq;
|
||||||
zlong ocur;
|
zlong ocur;
|
||||||
unsigned int runset = 0, kunset = 0, m, sm;
|
unsigned int runset = 0, kunset = 0, m, sm;
|
||||||
Param *pp;
|
Param *pp;
|
||||||
|
@ -1142,52 +1156,65 @@ comp_wrapper(List list, FuncWrap w, char *name)
|
||||||
orest = comprestore;
|
orest = comprestore;
|
||||||
comprestore = ztrdup("auto");
|
comprestore = ztrdup("auto");
|
||||||
ocur = compcurrent;
|
ocur = compcurrent;
|
||||||
opre = dupstring(compprefix);
|
opre = ztrdup(compprefix);
|
||||||
osuf = dupstring(compsuffix);
|
osuf = ztrdup(compsuffix);
|
||||||
oipre = dupstring(compiprefix);
|
oipre = ztrdup(compiprefix);
|
||||||
oisuf = dupstring(compisuffix);
|
oisuf = ztrdup(compisuffix);
|
||||||
oqipre = dupstring(compqiprefix);
|
oqipre = ztrdup(compqiprefix);
|
||||||
oqisuf = dupstring(compqisuffix);
|
oqisuf = ztrdup(compqisuffix);
|
||||||
oq = dupstring(compquote);
|
oq = ztrdup(compquote);
|
||||||
oqi = dupstring(compquoting);
|
oqi = ztrdup(compquoting);
|
||||||
|
oqs = ztrdup(compqstack);
|
||||||
|
oaq = ztrdup(autoq);
|
||||||
|
owords = zarrdup(compwords);
|
||||||
|
|
||||||
HEAPALLOC {
|
runshfunc(prog, w, name);
|
||||||
owords = arrdup(compwords);
|
|
||||||
} LASTALLOC;
|
|
||||||
|
|
||||||
runshfunc(list, w, name);
|
|
||||||
|
|
||||||
if (comprestore && !strcmp(comprestore, "auto")) {
|
if (comprestore && !strcmp(comprestore, "auto")) {
|
||||||
compcurrent = ocur;
|
compcurrent = ocur;
|
||||||
zsfree(compprefix);
|
zsfree(compprefix);
|
||||||
compprefix = ztrdup(opre);
|
compprefix = opre;
|
||||||
zsfree(compsuffix);
|
zsfree(compsuffix);
|
||||||
compsuffix = ztrdup(osuf);
|
compsuffix = osuf;
|
||||||
zsfree(compiprefix);
|
zsfree(compiprefix);
|
||||||
compiprefix = ztrdup(oipre);
|
compiprefix = oipre;
|
||||||
zsfree(compisuffix);
|
zsfree(compisuffix);
|
||||||
compisuffix = ztrdup(oisuf);
|
compisuffix = oisuf;
|
||||||
zsfree(compqiprefix);
|
zsfree(compqiprefix);
|
||||||
compqiprefix = ztrdup(oqipre);
|
compqiprefix = oqipre;
|
||||||
zsfree(compqisuffix);
|
zsfree(compqisuffix);
|
||||||
compqisuffix = ztrdup(oqisuf);
|
compqisuffix = oqisuf;
|
||||||
zsfree(compquote);
|
zsfree(compquote);
|
||||||
compquote = ztrdup(oq);
|
compquote = oq;
|
||||||
zsfree(compquoting);
|
zsfree(compquoting);
|
||||||
compquoting = ztrdup(oqi);
|
compquoting = oqi;
|
||||||
|
zsfree(compqstack);
|
||||||
|
compqstack = oqs;
|
||||||
|
zsfree(autoq);
|
||||||
|
autoq = oaq;
|
||||||
freearray(compwords);
|
freearray(compwords);
|
||||||
PERMALLOC {
|
compwords = owords;
|
||||||
compwords = arrdup(owords);
|
|
||||||
} LASTALLOC;
|
|
||||||
comp_setunset(CP_COMPSTATE |
|
comp_setunset(CP_COMPSTATE |
|
||||||
(~runset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
|
(~runset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
|
||||||
CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX |
|
CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX |
|
||||||
CP_QIPREFIX | CP_QISUFFIX)),
|
CP_QIPREFIX | CP_QISUFFIX)),
|
||||||
(runset & CP_ALLREALS),
|
(runset & CP_ALLREALS),
|
||||||
(~kunset & CP_RESTORE), (kunset & CP_ALLKEYS));
|
(~kunset & CP_RESTORE), (kunset & CP_ALLKEYS));
|
||||||
} else
|
} else {
|
||||||
comp_setunset(CP_COMPSTATE, 0, (~kunset & CP_RESTORE),
|
comp_setunset(CP_COMPSTATE, 0, (~kunset & CP_RESTORE),
|
||||||
(kunset & CP_RESTORE));
|
(kunset & CP_RESTORE));
|
||||||
|
zsfree(opre);
|
||||||
|
zsfree(osuf);
|
||||||
|
zsfree(oipre);
|
||||||
|
zsfree(oisuf);
|
||||||
|
zsfree(oqipre);
|
||||||
|
zsfree(oqisuf);
|
||||||
|
zsfree(oq);
|
||||||
|
zsfree(oqi);
|
||||||
|
zsfree(oqs);
|
||||||
|
zsfree(oaq);
|
||||||
|
freearray(owords);
|
||||||
|
}
|
||||||
zsfree(comprestore);
|
zsfree(comprestore);
|
||||||
comprestore = orest;
|
comprestore = orest;
|
||||||
|
|
||||||
|
@ -1228,42 +1255,6 @@ cond_range(char **a, int id)
|
||||||
(id ? cond_str(a, 1, 1) : NULL), 0);
|
(id ? cond_str(a, 1, 1) : NULL), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
|
||||||
static void
|
|
||||||
cmsetfn(Param pm, char **v)
|
|
||||||
{
|
|
||||||
set_gmatcher(pm->nam, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**/
|
|
||||||
static char **
|
|
||||||
cmgetfn(Param pm)
|
|
||||||
{
|
|
||||||
int num;
|
|
||||||
Cmlist p;
|
|
||||||
char **ret, **q;
|
|
||||||
|
|
||||||
for (num = 0, p = cmatcher; p; p = p->next, num++);
|
|
||||||
|
|
||||||
ret = (char **) zhalloc((num + 1) * sizeof(char *));
|
|
||||||
|
|
||||||
for (q = ret, p = cmatcher; p; p = p->next, q++)
|
|
||||||
*q = dupstring(p->str);
|
|
||||||
*q = NULL;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**/
|
|
||||||
static void
|
|
||||||
cmunsetfn(Param pm, int exp)
|
|
||||||
{
|
|
||||||
char *dummy[1];
|
|
||||||
|
|
||||||
dummy[0] = NULL;
|
|
||||||
set_gmatcher(pm->nam, dummy);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct builtin bintab[] = {
|
static struct builtin bintab[] = {
|
||||||
BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL),
|
BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL),
|
||||||
BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL),
|
BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL),
|
||||||
|
@ -1280,53 +1271,108 @@ static struct funcwrap wrapper[] = {
|
||||||
WRAPDEF(comp_wrapper),
|
WRAPDEF(comp_wrapper),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct paramdef patab[] = {
|
/* The order of the entries in this table has to match the *HOOK
|
||||||
PARAMDEF("compmatchers", PM_ARRAY|PM_SPECIAL, NULL, cmsetfn, cmgetfn, cmunsetfn)
|
* macros in comp.h */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
struct hookdef comphooks[] = {
|
||||||
|
HOOKDEF("insert_match", NULL, HOOKF_ALL),
|
||||||
|
HOOKDEF("menu_start", NULL, HOOKF_ALL),
|
||||||
|
HOOKDEF("compctl_make", NULL, 0),
|
||||||
|
HOOKDEF("compctl_cleanup", NULL, 0),
|
||||||
|
HOOKDEF("comp_list_matches", ilistmatches, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
setup_complete(Module m)
|
setup_(Module m)
|
||||||
{
|
{
|
||||||
makecompparamsptr = makecompparams;
|
hasperm = 0;
|
||||||
comp_setunsetptr = comp_setunset;
|
|
||||||
|
comprpms = compkpms = NULL;
|
||||||
|
compwords = NULL;
|
||||||
|
compprefix = compsuffix = compiprefix = compisuffix =
|
||||||
|
compqiprefix = compqisuffix =
|
||||||
|
compcontext = compparameter = compredirect = compquote =
|
||||||
|
compquoting = comprestore = complist = compinsert =
|
||||||
|
compexact = compexactstr = comppatmatch = comppatinsert =
|
||||||
|
complastprompt = comptoend = compoldlist = compoldins =
|
||||||
|
compvared = compqstack = NULL;
|
||||||
|
|
||||||
|
hascompmod = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
boot_complete(Module m)
|
boot_(Module m)
|
||||||
{
|
{
|
||||||
|
addhookfunc("complete", (Hookfn) do_completion);
|
||||||
|
addhookfunc("before_complete", (Hookfn) before_complete);
|
||||||
|
addhookfunc("after_complete", (Hookfn) after_complete);
|
||||||
|
addhookfunc("accept_completion", (Hookfn) accept_last);
|
||||||
|
addhookfunc("reverse_menu", (Hookfn) reverse_menu);
|
||||||
|
addhookfunc("list_matches", (Hookfn) list_matches);
|
||||||
|
addhookfunc("invalidate_list", (Hookfn) invalidate_list);
|
||||||
|
addhookdefs(m->nam, comphooks, sizeof(comphooks)/sizeof(*comphooks));
|
||||||
if (!(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
|
if (!(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
|
||||||
addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
|
addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
|
||||||
addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) |
|
|
||||||
!addwrapper(m, wrapper)))
|
!addwrapper(m, wrapper)))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MODULE
|
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
cleanup_complete(Module m)
|
cleanup_(Module m)
|
||||||
{
|
{
|
||||||
|
deletehookfunc("complete", (Hookfn) do_completion);
|
||||||
|
deletehookfunc("before_complete", (Hookfn) before_complete);
|
||||||
|
deletehookfunc("after_complete", (Hookfn) after_complete);
|
||||||
|
deletehookfunc("accept_completion", (Hookfn) accept_last);
|
||||||
|
deletehookfunc("reverse_menu", (Hookfn) reverse_menu);
|
||||||
|
deletehookfunc("list_matches", (Hookfn) list_matches);
|
||||||
|
deletehookfunc("invalidate_list", (Hookfn) invalidate_list);
|
||||||
|
deletehookdefs(m->nam, comphooks, sizeof(comphooks)/sizeof(*comphooks));
|
||||||
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
|
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
|
||||||
deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
|
deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
|
||||||
deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab));
|
|
||||||
deletewrapper(m, wrapper);
|
deletewrapper(m, wrapper);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
finish_complete(Module m)
|
finish_(Module m)
|
||||||
{
|
{
|
||||||
makecompparamsptr = NULL;
|
if (compwords)
|
||||||
comp_setunsetptr = NULL;
|
freearray(compwords);
|
||||||
|
zsfree(compprefix);
|
||||||
|
zsfree(compsuffix);
|
||||||
|
zsfree(compiprefix);
|
||||||
|
zsfree(compisuffix);
|
||||||
|
zsfree(compqiprefix);
|
||||||
|
zsfree(compqisuffix);
|
||||||
|
zsfree(compcontext);
|
||||||
|
zsfree(compparameter);
|
||||||
|
zsfree(compredirect);
|
||||||
|
zsfree(compquote);
|
||||||
|
zsfree(compqstack);
|
||||||
|
zsfree(compquoting);
|
||||||
|
zsfree(comprestore);
|
||||||
|
zsfree(complist);
|
||||||
|
zsfree(compinsert);
|
||||||
|
zsfree(compexact);
|
||||||
|
zsfree(compexactstr);
|
||||||
|
zsfree(comppatmatch);
|
||||||
|
zsfree(comppatinsert);
|
||||||
|
zsfree(complastprompt);
|
||||||
|
zsfree(comptoend);
|
||||||
|
zsfree(compoldlist);
|
||||||
|
zsfree(compoldins);
|
||||||
|
zsfree(compvared);
|
||||||
|
|
||||||
|
hascompmod = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -28,15 +28,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "complete.mdh"
|
#include "complete.mdh"
|
||||||
#define GLOBAL_PROTOTYPES
|
|
||||||
#include "zle_tricky.pro"
|
|
||||||
#undef GLOBAL_PROTOTYPES
|
|
||||||
#include "compmatch.pro"
|
#include "compmatch.pro"
|
||||||
|
|
||||||
/* Convenience macro for calling bslashquote() (formerly quotename()). */
|
|
||||||
|
|
||||||
#define quotename(s, e) bslashquote(s, e, instring)
|
|
||||||
|
|
||||||
/* This compares two cpattern lists and returns non-zero if they are
|
/* This compares two cpattern lists and returns non-zero if they are
|
||||||
* equal. */
|
* equal. */
|
||||||
|
|
||||||
|
@ -75,14 +68,14 @@ cmp_cmatchers(Cmatcher a, Cmatcher b)
|
||||||
/* Add the given matchers to the bmatcher list. */
|
/* Add the given matchers to the bmatcher list. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
add_bmatchers(Cmatcher m)
|
add_bmatchers(Cmatcher m)
|
||||||
{
|
{
|
||||||
Cmlist old = bmatchers, *q = &bmatchers, n;
|
Cmlist old = bmatchers, *q = &bmatchers, n;
|
||||||
|
|
||||||
for (; m; m = m->next) {
|
for (; m; m = m->next) {
|
||||||
if ((!m->flags && m->wlen > 0 && m->llen > 0) ||
|
if ((!m->flags && m->wlen > 0 && m->llen > 0) ||
|
||||||
(m->flags == CMF_RIGHT && m->wlen == -1 && !m->llen)) {
|
(m->flags == CMF_RIGHT && m->wlen < 0 && !m->llen)) {
|
||||||
*q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
|
*q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
|
||||||
n->matcher = m;
|
n->matcher = m;
|
||||||
q = &(n->next);
|
q = &(n->next);
|
||||||
|
@ -95,7 +88,7 @@ add_bmatchers(Cmatcher m)
|
||||||
* ensure that the bmatchers list contains no matchers not in mstack. */
|
* ensure that the bmatchers list contains no matchers not in mstack. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
update_bmatchers(void)
|
update_bmatchers(void)
|
||||||
{
|
{
|
||||||
Cmlist p = bmatchers, q = NULL, ms;
|
Cmlist p = bmatchers, q = NULL, ms;
|
||||||
|
@ -141,6 +134,7 @@ get_cline(char *l, int ll, char *w, int wl, char *o, int ol, int fl)
|
||||||
r->slen = 0;
|
r->slen = 0;
|
||||||
r->flags = fl;
|
r->flags = fl;
|
||||||
r->prefix = r->suffix = NULL;
|
r->prefix = r->suffix = NULL;
|
||||||
|
r->min = r->max = 0;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,7 +437,7 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
|
||||||
int sfx, int test, int part)
|
int sfx, int test, int part)
|
||||||
{
|
{
|
||||||
int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw;
|
int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw;
|
||||||
int il = 0, iw = 0, t, ind, add, he = 0, bpc, obc = bc;
|
int il = 0, iw = 0, t, ind, add, he = 0, bpc, obc = bc, bslash;
|
||||||
VARARR(unsigned char, ea, ll + 1);
|
VARARR(unsigned char, ea, ll + 1);
|
||||||
char *ow;
|
char *ow;
|
||||||
Cmlist ms;
|
Cmlist ms;
|
||||||
|
@ -553,7 +547,7 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
|
||||||
} else
|
} else
|
||||||
t = match_str(l + llen + moff, tp + moff,
|
t = match_str(l + llen + moff, tp + moff,
|
||||||
NULL, 0, NULL, 0, 1, part);
|
NULL, 0, NULL, 0, 1, part);
|
||||||
if (t || !both)
|
if (t || (mp->wlen == -1 && !both))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -743,12 +737,15 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
|
||||||
if (mp)
|
if (mp)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (l[ind] == w[ind]) {
|
bslash = 0;
|
||||||
|
if (l[ind] == w[ind] ||
|
||||||
|
(bslash = (lw > 1 && w[ind] == '\\' &&
|
||||||
|
(ind ? (w[0] == l[0]) : (w[1] == l[0]))))) {
|
||||||
/* No matcher could be used, but the strings have the same
|
/* No matcher could be used, but the strings have the same
|
||||||
* character here, skip over it. */
|
* character here, skip over it. */
|
||||||
l += add; w += add;
|
l += add; w += (bslash ? (add + add ) : add);
|
||||||
il++; iw++;
|
il++; iw += 1 + bslash;
|
||||||
ll--; lw--;
|
ll--; lw -= 1 + bslash;
|
||||||
bc++;
|
bc++;
|
||||||
if (!test)
|
if (!test)
|
||||||
while (bp && bc >= (useqbr ? bp->qpos : bp->pos)) {
|
while (bp && bc >= (useqbr ? bp->qpos : bp->pos)) {
|
||||||
|
@ -839,7 +836,7 @@ match_parts(char *l, char *w, int n, int part)
|
||||||
* and the suffix don't match the word w. */
|
* and the suffix don't match the word w. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
char *
|
mod_export char *
|
||||||
comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
|
comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
|
||||||
Brinfo *bpl, int bcp, Brinfo *bsl, int bcs, int *exact)
|
Brinfo *bpl, int bcp, Brinfo *bsl, int bcs, int *exact)
|
||||||
{
|
{
|
||||||
|
@ -853,9 +850,8 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
|
||||||
if (!pattry(cp, r))
|
if (!pattry(cp, r))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
r = (qu ? quotename(r, NULL) : dupstring(r));
|
r = (qu == 2 ? tildequote(r, 0) : multiquote(r, !qu));
|
||||||
if (qu == 2 && r[0] == '\\' && r[1] == '~')
|
|
||||||
chuck(r);
|
|
||||||
/* We still break it into parts here, trying to build a sensible
|
/* We still break it into parts here, trying to build a sensible
|
||||||
* cline list for these matches, too. */
|
* cline list for these matches, too. */
|
||||||
w = dupstring(w);
|
w = dupstring(w);
|
||||||
|
@ -866,10 +862,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
|
||||||
Cline pli, plil;
|
Cline pli, plil;
|
||||||
int mpl, rpl, wl;
|
int mpl, rpl, wl;
|
||||||
|
|
||||||
w = (qu ? quotename(w, NULL) : dupstring(w));
|
w = (qu == 2 ? tildequote(w, 0) : multiquote(w, !qu));
|
||||||
if (qu == 2 && w[0] == '\\' && w[1] == '~')
|
|
||||||
chuck(w);
|
|
||||||
|
|
||||||
wl = strlen(w);
|
wl = strlen(w);
|
||||||
|
|
||||||
/* Always try to match the prefix. */
|
/* Always try to match the prefix. */
|
||||||
|
@ -1016,7 +1009,7 @@ bld_parts(char *str, int len, int plen, Cline *lp)
|
||||||
while (len) {
|
while (len) {
|
||||||
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
|
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
|
||||||
mp = ms->matcher;
|
mp = ms->matcher;
|
||||||
if (mp->flags == CMF_RIGHT && mp->wlen == -1 &&
|
if (mp && mp->flags == CMF_RIGHT && mp->wlen < 0 &&
|
||||||
!mp->llen && len >= mp->ralen && mp->ralen &&
|
!mp->llen && len >= mp->ralen && mp->ralen &&
|
||||||
pattern_match(mp->right, str, NULL, NULL)) {
|
pattern_match(mp->right, str, NULL, NULL)) {
|
||||||
int olen = str - p, llen;
|
int olen = str - p, llen;
|
||||||
|
@ -1136,7 +1129,7 @@ bld_line(Cpattern pat, char *line, char *lp,
|
||||||
t = 0;
|
t = 0;
|
||||||
for (ms = bmatchers; ms && !t; ms = ms->next) {
|
for (ms = bmatchers; ms && !t; ms = ms->next) {
|
||||||
mp = ms->matcher;
|
mp = ms->matcher;
|
||||||
if (!mp->flags && mp->wlen <= wlen && mp->llen <= l &&
|
if (mp && !mp->flags && mp->wlen <= wlen && mp->llen <= l &&
|
||||||
pattern_match(mp->line, (sfx ? line - mp->llen : line),
|
pattern_match(mp->line, (sfx ? line - mp->llen : line),
|
||||||
NULL, ea) &&
|
NULL, ea) &&
|
||||||
pattern_match(mp->word, (sfx ? word - mp->wlen : word),
|
pattern_match(mp->word, (sfx ? word - mp->wlen : word),
|
||||||
|
@ -1186,7 +1179,7 @@ join_strs(int la, char *sa, int lb, char *sb)
|
||||||
/* Different characters, try the matchers. */
|
/* Different characters, try the matchers. */
|
||||||
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
|
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
|
||||||
mp = ms->matcher;
|
mp = ms->matcher;
|
||||||
if (!mp->flags && mp->wlen > 0 && mp->llen > 0 &&
|
if (mp && !mp->flags && mp->wlen > 0 && mp->llen > 0 &&
|
||||||
mp->wlen <= la && mp->wlen <= lb) {
|
mp->wlen <= la && mp->wlen <= lb) {
|
||||||
/* The pattern has no anchors and the word
|
/* The pattern has no anchors and the word
|
||||||
* pattern fits, try it. */
|
* pattern fits, try it. */
|
||||||
|
@ -1373,7 +1366,7 @@ join_sub(Cmdata md, char *str, int len, int *mlen, int sfx, int join)
|
||||||
/* We use only those patterns that match a non-empty
|
/* We use only those patterns that match a non-empty
|
||||||
* string in both the line and the word and that have
|
* string in both the line and the word and that have
|
||||||
* no anchors. */
|
* no anchors. */
|
||||||
if (!mp->flags && mp->wlen > 0 && mp->llen > 0) {
|
if (mp && !mp->flags && mp->wlen > 0 && mp->llen > 0) {
|
||||||
/* We first test, if the old string matches already the
|
/* We first test, if the old string matches already the
|
||||||
* new one. */
|
* new one. */
|
||||||
if (mp->llen <= ol && mp->wlen <= nl &&
|
if (mp->llen <= ol && mp->wlen <= nl &&
|
||||||
|
@ -1684,7 +1677,7 @@ join_mid(Cline o, Cline n)
|
||||||
* didn't. */
|
* didn't. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static void
|
static int
|
||||||
sub_join(Cline a, Cline b, Cline e, int anew)
|
sub_join(Cline a, Cline b, Cline e, int anew)
|
||||||
{
|
{
|
||||||
if (!e->suffix && a->prefix) {
|
if (!e->suffix && a->prefix) {
|
||||||
|
@ -1707,31 +1700,28 @@ sub_join(Cline a, Cline b, Cline e, int anew)
|
||||||
*p = e->prefix;
|
*p = e->prefix;
|
||||||
ca = a->prefix;
|
ca = a->prefix;
|
||||||
|
|
||||||
while (n != op) {
|
while (n) {
|
||||||
e->prefix = cp_cline(n, 0);
|
e->prefix = cp_cline(n, 0);
|
||||||
a->prefix = cp_cline(ca, 0);
|
a->prefix = cp_cline(ca, 0);
|
||||||
|
|
||||||
if (anew) {
|
if (anew) {
|
||||||
join_psfx(e, a, NULL, NULL, 0);
|
join_psfx(e, a, NULL, NULL, 0);
|
||||||
if (e->prefix) {
|
if (e->prefix)
|
||||||
e->min += min;
|
return max - min;
|
||||||
e->max += max;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
join_psfx(e, a, NULL, NULL, 0);
|
join_psfx(a, e, NULL, NULL, 0);
|
||||||
if (a->prefix) {
|
if (a->prefix)
|
||||||
a->min += min;
|
return max - min;
|
||||||
a->max += max;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
min -= n->min;
|
min -= n->min;
|
||||||
max -= n->max;
|
|
||||||
|
|
||||||
|
if (n == op)
|
||||||
|
break;
|
||||||
n = n->next;
|
n = n->next;
|
||||||
}
|
}
|
||||||
|
return max - min;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This simplifies the cline list given as the first argument so that
|
/* This simplifies the cline list given as the first argument so that
|
||||||
|
@ -1748,7 +1738,8 @@ join_clines(Cline o, Cline n)
|
||||||
if (!o)
|
if (!o)
|
||||||
return n;
|
return n;
|
||||||
else {
|
else {
|
||||||
Cline oo = o, nn = n, po = NULL, pn = NULL;
|
Cline oo = o, nn = n, po = NULL, pn = NULL, x;
|
||||||
|
int diff;
|
||||||
|
|
||||||
/* Walk through the lists. */
|
/* Walk through the lists. */
|
||||||
while (o && n) {
|
while (o && n) {
|
||||||
|
@ -1760,7 +1751,7 @@ join_clines(Cline o, Cline n)
|
||||||
|
|
||||||
for (t = o; (tn = t->next) && (tn->flags & CLF_NEW); t = tn);
|
for (t = o; (tn = t->next) && (tn->flags & CLF_NEW); t = tn);
|
||||||
if (tn && cmp_anchors(tn, n, 0)) {
|
if (tn && cmp_anchors(tn, n, 0)) {
|
||||||
sub_join(n, o, tn, 1);
|
diff = sub_join(n, o, tn, 1);
|
||||||
|
|
||||||
if (po)
|
if (po)
|
||||||
po->next = tn;
|
po->next = tn;
|
||||||
|
@ -1768,8 +1759,15 @@ join_clines(Cline o, Cline n)
|
||||||
oo = tn;
|
oo = tn;
|
||||||
t->next = NULL;
|
t->next = NULL;
|
||||||
free_cline(o);
|
free_cline(o);
|
||||||
|
x = o;
|
||||||
o = tn;
|
o = tn;
|
||||||
o->flags |= CLF_MISS;
|
if (po && cmp_anchors(x, po, 0)) {
|
||||||
|
po->flags |= CLF_MISS;
|
||||||
|
po->max += diff;
|
||||||
|
} else {
|
||||||
|
o->flags |= CLF_MISS;
|
||||||
|
o->max += diff;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1778,10 +1776,16 @@ join_clines(Cline o, Cline n)
|
||||||
|
|
||||||
for (t = n; (tn = t->next) && (tn->flags & CLF_NEW); t = tn);
|
for (t = n; (tn = t->next) && (tn->flags & CLF_NEW); t = tn);
|
||||||
if (tn && cmp_anchors(o, tn, 0)) {
|
if (tn && cmp_anchors(o, tn, 0)) {
|
||||||
sub_join(o, n, tn, 0);
|
diff = sub_join(o, n, tn, 0);
|
||||||
|
|
||||||
|
if (po && cmp_anchors(n, pn, 0)) {
|
||||||
|
po->flags |= CLF_MISS;
|
||||||
|
po->max += diff;
|
||||||
|
} else {
|
||||||
|
o->flags |= CLF_MISS;
|
||||||
|
o->max += diff;
|
||||||
|
}
|
||||||
n = tn;
|
n = tn;
|
||||||
o->flags |= CLF_MISS;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1809,6 +1813,7 @@ join_clines(Cline o, Cline n)
|
||||||
t = tn);
|
t = tn);
|
||||||
if (tn && cmp_anchors(tn, n, 1)) {
|
if (tn && cmp_anchors(tn, n, 1)) {
|
||||||
sub_join(n, o, tn, 1);
|
sub_join(n, o, tn, 1);
|
||||||
|
|
||||||
if (po)
|
if (po)
|
||||||
po->next = tn;
|
po->next = tn;
|
||||||
else
|
else
|
||||||
|
@ -1837,24 +1842,41 @@ join_clines(Cline o, Cline n)
|
||||||
for (t = n; (tn = t->next) && !cmp_anchors(o, tn, 1); t = tn);
|
for (t = n; (tn = t->next) && !cmp_anchors(o, tn, 1); t = tn);
|
||||||
|
|
||||||
if (tn) {
|
if (tn) {
|
||||||
sub_join(o, n, tn, 0);
|
diff = sub_join(o, n, tn, 0);
|
||||||
|
|
||||||
|
if (po && cmp_anchors(n, pn, 0)) {
|
||||||
|
po->flags |= CLF_MISS;
|
||||||
|
po->max += diff;
|
||||||
|
} else {
|
||||||
|
o->flags |= CLF_MISS;
|
||||||
|
o->max += diff;
|
||||||
|
}
|
||||||
n = tn;
|
n = tn;
|
||||||
o->flags |= CLF_MISS;
|
po = o;
|
||||||
|
o = o->next;
|
||||||
|
pn = n;
|
||||||
|
n = n->next;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
for (t = o; (tn = t->next) && !cmp_anchors(n, tn, 1);
|
for (t = o; (tn = t->next) && !cmp_anchors(n, tn, 1);
|
||||||
t = tn);
|
t = tn);
|
||||||
|
|
||||||
if (tn) {
|
if (tn) {
|
||||||
sub_join(n, o, tn, 1);
|
diff = sub_join(n, o, tn, 1);
|
||||||
|
|
||||||
if (po)
|
if (po)
|
||||||
po->next = tn;
|
po->next = tn;
|
||||||
else
|
else
|
||||||
oo = tn;
|
oo = tn;
|
||||||
|
x = o;
|
||||||
o = tn;
|
o = tn;
|
||||||
o->flags |= CLF_MISS;
|
if (po && cmp_anchors(x, po, 0)) {
|
||||||
|
po->flags |= CLF_MISS;
|
||||||
|
po->max += diff;
|
||||||
|
} else {
|
||||||
|
o->flags |= CLF_MISS;
|
||||||
|
o->max += diff;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (o->flags & CLF_SUF)
|
if (o->flags & CLF_SUF)
|
||||||
|
|
|
@ -28,16 +28,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "complete.mdh"
|
#include "complete.mdh"
|
||||||
#define GLOBAL_PROTOTYPES
|
|
||||||
#include "zle_tricky.pro"
|
|
||||||
#undef GLOBAL_PROTOTYPES
|
|
||||||
#include "compresult.pro"
|
#include "compresult.pro"
|
||||||
|
|
||||||
/* Convenience macro for calling bslashquote() (formerly quotename()). *
|
|
||||||
* This uses the instring variable above. */
|
|
||||||
|
|
||||||
#define quotename(s, e) bslashquote(s, e, instring)
|
|
||||||
|
|
||||||
#define inststr(X) inststrlen((X),1,-1)
|
#define inststr(X) inststrlen((X),1,-1)
|
||||||
|
|
||||||
/* This cuts the cline list before the stuff that isn't worth
|
/* This cuts the cline list before the stuff that isn't worth
|
||||||
|
@ -72,7 +64,8 @@ cut_cline(Cline l)
|
||||||
q = p;
|
q = p;
|
||||||
}
|
}
|
||||||
if (!e && q && !q->orig && !q->olen && (q->flags & CLF_MISS) &&
|
if (!e && q && !q->orig && !q->olen && (q->flags & CLF_MISS) &&
|
||||||
!(q->flags & CLF_MATCHED) && (q->word ? q->wlen : q->llen) < 3) {
|
(!(q->flags & CLF_MATCHED) || (!q->prefix && !q->suffix)) &&
|
||||||
|
(q->word ? q->wlen : q->llen) < 3) {
|
||||||
q->word = q->line = NULL;
|
q->word = q->line = NULL;
|
||||||
q->wlen = q->llen = 0;
|
q->wlen = q->llen = 0;
|
||||||
}
|
}
|
||||||
|
@ -143,8 +136,9 @@ cline_str(Cline l, int ins, int *csp)
|
||||||
|
|
||||||
l = cut_cline(l);
|
l = cut_cline(l);
|
||||||
|
|
||||||
pmm = smm = dm = 0;
|
pmm = smm = dm = pcs = scs = 0;
|
||||||
pm = pmax = sm = smax = d = mid = cbr = -1;
|
pm = pmax = sm = smax = d = mid = cbr = -1;
|
||||||
|
brp = brs = NULL;
|
||||||
|
|
||||||
/* Get the information about the brace beginning and end we have
|
/* Get the information about the brace beginning and end we have
|
||||||
* to re-insert. */
|
* to re-insert. */
|
||||||
|
@ -594,7 +588,7 @@ do_ambiguous(void)
|
||||||
/* If we have to insert the first match, call do_single(). This is *
|
/* If we have to insert the first match, call do_single(). This is *
|
||||||
* how REC_EXACT takes effect. We effectively turn the ambiguous *
|
* how REC_EXACT takes effect. We effectively turn the ambiguous *
|
||||||
* completion into an unambiguous one. */
|
* completion into an unambiguous one. */
|
||||||
if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) {
|
if (ainfo && ainfo->exact == 1 && !(fromcomp & FC_LINE)) {
|
||||||
minfo.cur = NULL;
|
minfo.cur = NULL;
|
||||||
do_single(ainfo->exactm);
|
do_single(ainfo->exactm);
|
||||||
invalidatelist();
|
invalidatelist();
|
||||||
|
@ -616,6 +610,7 @@ do_ambiguous(void)
|
||||||
do_ambig_menu();
|
do_ambig_menu();
|
||||||
} else if (ainfo) {
|
} else if (ainfo) {
|
||||||
int atend = (cs == we), la, eq, tcs;
|
int atend = (cs == we), la, eq, tcs;
|
||||||
|
VARARR(char, old, we - wb);
|
||||||
|
|
||||||
minfo.cur = NULL;
|
minfo.cur = NULL;
|
||||||
minfo.asked = 0;
|
minfo.asked = 0;
|
||||||
|
@ -623,11 +618,24 @@ do_ambiguous(void)
|
||||||
fixsuffix();
|
fixsuffix();
|
||||||
|
|
||||||
/* First remove the old string from the line. */
|
/* First remove the old string from the line. */
|
||||||
|
tcs = cs;
|
||||||
cs = wb;
|
cs = wb;
|
||||||
|
memcpy(old, (char *) line + wb, we - wb);
|
||||||
foredel(we - wb);
|
foredel(we - wb);
|
||||||
|
|
||||||
/* Now get the unambiguous string and insert it into the line. */
|
/* Now get the unambiguous string and insert it into the line. */
|
||||||
cline_str(ainfo->line, 1, NULL);
|
cline_str(ainfo->line, 1, NULL);
|
||||||
|
|
||||||
|
/* Sometimes the different match specs used may result in a cline
|
||||||
|
* that gives an empty string. If that happened, we re-insert the
|
||||||
|
* old string. Unless there were matches added with -U, that is. */
|
||||||
|
if (!(lastend - wb) && !hasunmatched) {
|
||||||
|
cs = wb;
|
||||||
|
foredel(lastend - wb);
|
||||||
|
inststrlen(old, 0, we - wb);
|
||||||
|
lastend = we;
|
||||||
|
cs = tcs;
|
||||||
|
}
|
||||||
if (eparq) {
|
if (eparq) {
|
||||||
tcs = cs;
|
tcs = cs;
|
||||||
cs = lastend;
|
cs = lastend;
|
||||||
|
@ -677,7 +685,7 @@ do_ambiguous(void)
|
||||||
if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
|
if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
|
||||||
((!showinglist && (!listshown || !oldlist)) ||
|
((!showinglist && (!listshown || !oldlist)) ||
|
||||||
(usemenu == 3 && !oldlist)) &&
|
(usemenu == 3 && !oldlist)) &&
|
||||||
(smatches >= 2 || (compforcelist && *compforcelist)))
|
(smatches >= 2 || forcelist))
|
||||||
showinglist = -2;
|
showinglist = -2;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -690,7 +698,7 @@ do_ambiguous(void)
|
||||||
* (l)stat(). */
|
* (l)stat(). */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
mod_export int
|
||||||
ztat(char *nam, struct stat *buf, int ls)
|
ztat(char *nam, struct stat *buf, int ls)
|
||||||
{
|
{
|
||||||
char b[PATH_MAX], *p;
|
char b[PATH_MAX], *p;
|
||||||
|
@ -708,7 +716,7 @@ ztat(char *nam, struct stat *buf, int ls)
|
||||||
/* Insert a single match in the command line. */
|
/* Insert a single match in the command line. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
do_single(Cmatch m)
|
do_single(Cmatch m)
|
||||||
{
|
{
|
||||||
int l, sr = 0, scs;
|
int l, sr = 0, scs;
|
||||||
|
@ -726,7 +734,8 @@ do_single(Cmatch m)
|
||||||
/* We are currently not in a menu-completion, *
|
/* We are currently not in a menu-completion, *
|
||||||
* so set the position variables. */
|
* so set the position variables. */
|
||||||
minfo.pos = wb;
|
minfo.pos = wb;
|
||||||
minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp));
|
minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp) ||
|
||||||
|
(!movetoend && cs == we));
|
||||||
minfo.end = we;
|
minfo.end = we;
|
||||||
}
|
}
|
||||||
/* If we are already in a menu-completion or if we have done a *
|
/* If we are already in a menu-completion or if we have done a *
|
||||||
|
@ -792,19 +801,40 @@ do_single(Cmatch m)
|
||||||
else {
|
else {
|
||||||
/* Build the path name. */
|
/* Build the path name. */
|
||||||
if (partest && !*psuf && !(m->flags & CMF_PARNEST)) {
|
if (partest && !*psuf && !(m->flags & CMF_PARNEST)) {
|
||||||
int ne = noerrs;
|
int ne = noerrs, tryit = 1;
|
||||||
|
|
||||||
p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ?
|
p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ?
|
||||||
parpre : m->ripre) +
|
parpre : m->ripre) +
|
||||||
strlen(str) + 2);
|
strlen(str) + 2);
|
||||||
sprintf(p, "%s%s%c",
|
sprintf(p, "%s%s%c",
|
||||||
((m->flags & CMF_ISPAR) ? parpre : m->ripre), str,
|
((m->flags & CMF_ISPAR) ? parpre : m->ripre), str,
|
||||||
((m->flags & CMF_PARBR) ? Outbrace : '\0'));
|
((m->flags & CMF_PARBR) ? '}' : '\0'));
|
||||||
noerrs = 1;
|
if (*p == '$') {
|
||||||
parsestr(p);
|
char *n;
|
||||||
singsub(&p);
|
Param pm;
|
||||||
errflag = 0;
|
|
||||||
noerrs = ne;
|
if (p[1] == '{') {
|
||||||
|
char *e;
|
||||||
|
|
||||||
|
n = dupstring(p + 2);
|
||||||
|
e = n + strlen(n) - 1;
|
||||||
|
|
||||||
|
if (*e == '}')
|
||||||
|
*e = '\0';
|
||||||
|
} else
|
||||||
|
n = p + 1;
|
||||||
|
|
||||||
|
if ((pm = (Param) paramtab->getnode(paramtab, n)) &&
|
||||||
|
PM_TYPE(pm->flags) != PM_SCALAR)
|
||||||
|
tryit = 0;
|
||||||
|
}
|
||||||
|
if (tryit) {
|
||||||
|
noerrs = 1;
|
||||||
|
parsestr(p);
|
||||||
|
singsub(&p);
|
||||||
|
errflag = 0;
|
||||||
|
noerrs = ne;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
p = (char *) zhalloc(strlen(prpre) + strlen(str) +
|
p = (char *) zhalloc(strlen(prpre) + strlen(str) +
|
||||||
strlen(psuf) + 3);
|
strlen(psuf) + 3);
|
||||||
|
@ -857,11 +887,13 @@ do_single(Cmatch m)
|
||||||
/* If we didn't add a suffix, add a space, unless we are *
|
/* If we didn't add a suffix, add a space, unless we are *
|
||||||
* doing menu completion or we are completing files and *
|
* doing menu completion or we are completing files and *
|
||||||
* the string doesn't name an existing file. */
|
* the string doesn't name an existing file. */
|
||||||
if (m->autoq && (!m->isuf || m->isuf[0] != m->autoq)) {
|
if (m->autoq && (!m->isuf || !strpfx(m->autoq, m->isuf))) {
|
||||||
inststrlen(&(m->autoq), 1, 1);
|
int al = strlen(m->autoq);
|
||||||
minfo.insc++;
|
inststrlen(m->autoq, 1, al);
|
||||||
|
minfo.insc += al;
|
||||||
}
|
}
|
||||||
if (!menucmp && (usemenu != 3 || insspace)) {
|
if (!menucmp && !(m->flags & CMF_NOSPACE) &&
|
||||||
|
(usemenu != 3 || insspace)) {
|
||||||
inststrlen(" ", 1, 1);
|
inststrlen(" ", 1, 1);
|
||||||
minfo.insc++;
|
minfo.insc++;
|
||||||
if (minfo.we)
|
if (minfo.we)
|
||||||
|
@ -897,7 +929,7 @@ do_single(Cmatch m)
|
||||||
* insert the next completion. */
|
* insert the next completion. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
do_menucmp(int lst)
|
do_menucmp(int lst)
|
||||||
{
|
{
|
||||||
/* Just list the matches if the list was requested. */
|
/* Just list the matches if the list was requested. */
|
||||||
|
@ -906,44 +938,40 @@ do_menucmp(int lst)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Otherwise go to the next match in the array... */
|
/* Otherwise go to the next match in the array... */
|
||||||
HEAPALLOC {
|
do {
|
||||||
do {
|
if (!*++(minfo.cur)) {
|
||||||
if (!*++(minfo.cur)) {
|
do {
|
||||||
do {
|
if (!(minfo.group = (minfo.group)->next))
|
||||||
if (!(minfo.group = (minfo.group)->next))
|
minfo.group = amatches;
|
||||||
minfo.group = amatches;
|
} while (!(minfo.group)->mcount);
|
||||||
} while (!(minfo.group)->mcount);
|
minfo.cur = minfo.group->matches;
|
||||||
minfo.cur = minfo.group->matches;
|
}
|
||||||
}
|
} while (menuacc &&
|
||||||
} while (menuacc &&
|
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
||||||
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
/* ... and insert it into the command line. */
|
||||||
/* ... and insert it into the command line. */
|
metafy_line();
|
||||||
metafy_line();
|
do_single(*(minfo.cur));
|
||||||
do_single(*(minfo.cur));
|
unmetafy_line();
|
||||||
unmetafy_line();
|
|
||||||
} LASTALLOC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
reverse_menu(Hookdef dummy, void *dummy2)
|
reverse_menu(Hookdef dummy, void *dummy2)
|
||||||
{
|
{
|
||||||
HEAPALLOC {
|
do {
|
||||||
do {
|
if (minfo.cur == (minfo.group)->matches) {
|
||||||
if (minfo.cur == (minfo.group)->matches) {
|
do {
|
||||||
do {
|
if (!(minfo.group = (minfo.group)->prev))
|
||||||
if (!(minfo.group = (minfo.group)->prev))
|
minfo.group = lmatches;
|
||||||
minfo.group = lmatches;
|
} while (!(minfo.group)->mcount);
|
||||||
} while (!(minfo.group)->mcount);
|
minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
|
||||||
minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
|
} else
|
||||||
} else
|
minfo.cur--;
|
||||||
minfo.cur--;
|
} while (menuacc &&
|
||||||
} while (menuacc &&
|
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
||||||
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
metafy_line();
|
||||||
metafy_line();
|
do_single(*(minfo.cur));
|
||||||
do_single(*(minfo.cur));
|
unmetafy_line();
|
||||||
unmetafy_line();
|
|
||||||
} LASTALLOC;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -953,7 +981,7 @@ reverse_menu(Hookdef dummy, void *dummy2)
|
||||||
* accept several selections from the list of matches. */
|
* accept several selections from the list of matches. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
mod_export int
|
||||||
accept_last(void)
|
accept_last(void)
|
||||||
{
|
{
|
||||||
if (!menuacc) {
|
if (!menuacc) {
|
||||||
|
@ -1042,7 +1070,7 @@ do_ambig_menu(void)
|
||||||
} else {
|
} else {
|
||||||
if (oldlist) {
|
if (oldlist) {
|
||||||
if (oldins && minfo.cur)
|
if (oldins && minfo.cur)
|
||||||
acceptlast();
|
accept_last();
|
||||||
} else
|
} else
|
||||||
minfo.cur = NULL;
|
minfo.cur = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1074,24 +1102,6 @@ do_ambig_menu(void)
|
||||||
minfo.cur = mc;
|
minfo.cur = mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the real number of matches. */
|
|
||||||
|
|
||||||
/**/
|
|
||||||
zlong
|
|
||||||
num_matches(int normal)
|
|
||||||
{
|
|
||||||
int alt;
|
|
||||||
|
|
||||||
PERMALLOC {
|
|
||||||
alt = permmatches(0);
|
|
||||||
} LASTALLOC;
|
|
||||||
|
|
||||||
if (normal)
|
|
||||||
return (alt ? 0 : nmatches);
|
|
||||||
else
|
|
||||||
return (alt ? nmatches : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the number of screen lines needed for the list. */
|
/* Return the number of screen lines needed for the list. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -1100,14 +1110,12 @@ list_lines(void)
|
||||||
{
|
{
|
||||||
Cmgroup oam;
|
Cmgroup oam;
|
||||||
|
|
||||||
PERMALLOC {
|
permmatches(0);
|
||||||
permmatches(0);
|
|
||||||
} LASTALLOC;
|
|
||||||
|
|
||||||
oam = amatches;
|
oam = amatches;
|
||||||
amatches = pmatches;
|
amatches = pmatches;
|
||||||
listdat.valid = 0;
|
listdat.valid = 0;
|
||||||
calclist();
|
calclist(0);
|
||||||
listdat.valid = 0;
|
listdat.valid = 0;
|
||||||
amatches = oam;
|
amatches = oam;
|
||||||
|
|
||||||
|
@ -1124,132 +1132,25 @@ comp_list(char *v)
|
||||||
onlyexpl = (v && strstr(v, "expl"));
|
onlyexpl = (v && strstr(v, "expl"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is used to print the explanation string. *
|
|
||||||
* It returns the number of lines printed. */
|
|
||||||
|
|
||||||
/**/
|
|
||||||
int
|
|
||||||
printfmt(char *fmt, int n, int dopr, int doesc)
|
|
||||||
{
|
|
||||||
char *p = fmt, nc[DIGBUFSIZE];
|
|
||||||
int l = 0, cc = 0, b = 0, s = 0, u = 0, m;
|
|
||||||
|
|
||||||
for (; *p; p++) {
|
|
||||||
/* Handle the `%' stuff (%% == %, %n == <number of matches>). */
|
|
||||||
if (doesc && *p == '%') {
|
|
||||||
if (*++p) {
|
|
||||||
m = 0;
|
|
||||||
switch (*p) {
|
|
||||||
case '%':
|
|
||||||
if (dopr)
|
|
||||||
putc('%', shout);
|
|
||||||
cc++;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
sprintf(nc, "%d", n);
|
|
||||||
if (dopr)
|
|
||||||
fprintf(shout, nc);
|
|
||||||
cc += strlen(nc);
|
|
||||||
break;
|
|
||||||
case 'B':
|
|
||||||
b = 1;
|
|
||||||
if (dopr)
|
|
||||||
tcout(TCBOLDFACEBEG);
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
b = 0; m = 1;
|
|
||||||
if (dopr)
|
|
||||||
tcout(TCALLATTRSOFF);
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
s = 1;
|
|
||||||
if (dopr)
|
|
||||||
tcout(TCSTANDOUTBEG);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
s = 0; m = 1;
|
|
||||||
if (dopr)
|
|
||||||
tcout(TCSTANDOUTEND);
|
|
||||||
break;
|
|
||||||
case 'U':
|
|
||||||
u = 1;
|
|
||||||
if (dopr)
|
|
||||||
tcout(TCUNDERLINEBEG);
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
u = 0; m = 1;
|
|
||||||
if (dopr)
|
|
||||||
tcout(TCUNDERLINEEND);
|
|
||||||
break;
|
|
||||||
case '{':
|
|
||||||
for (p++; *p && (*p != '%' || p[1] != '}'); p++, cc++)
|
|
||||||
if (dopr)
|
|
||||||
putc(*p, shout);
|
|
||||||
if (*p)
|
|
||||||
p++;
|
|
||||||
else
|
|
||||||
p--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (dopr && m) {
|
|
||||||
if (b)
|
|
||||||
tcout(TCBOLDFACEBEG);
|
|
||||||
if (s)
|
|
||||||
tcout(TCSTANDOUTBEG);
|
|
||||||
if (u)
|
|
||||||
tcout(TCUNDERLINEBEG);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cc++;
|
|
||||||
if (*p == '\n') {
|
|
||||||
if (dopr) {
|
|
||||||
if (tccan(TCCLEAREOL))
|
|
||||||
tcout(TCCLEAREOL);
|
|
||||||
else {
|
|
||||||
int s = columns - 1 - (cc % columns);
|
|
||||||
|
|
||||||
while (s-- > 0)
|
|
||||||
putc(' ', shout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l += 1 + (cc / columns);
|
|
||||||
cc = 0;
|
|
||||||
}
|
|
||||||
if (dopr)
|
|
||||||
putc(*p, shout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dopr) {
|
|
||||||
if (tccan(TCCLEAREOL))
|
|
||||||
tcout(TCCLEAREOL);
|
|
||||||
else {
|
|
||||||
int s = columns - 1 - (cc % columns);
|
|
||||||
|
|
||||||
while (s-- > 0)
|
|
||||||
putc(' ', shout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return l + (cc / columns);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This skips over matches that are not to be listed. */
|
/* This skips over matches that are not to be listed. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
Cmatch *
|
Cmatch *
|
||||||
skipnolist(Cmatch *p)
|
skipnolist(Cmatch *p, int showall)
|
||||||
{
|
{
|
||||||
while (*p && (((*p)->flags & (CMF_NOLIST | CMF_HIDE)) ||
|
int mask = (showall ? 0 : (CMF_NOLIST | CMF_MULT)) | CMF_HIDE;
|
||||||
((*p)->disp && ((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
|
|
||||||
|
while (*p && (((*p)->flags & mask) ||
|
||||||
|
((*p)->disp &&
|
||||||
|
((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
calclist(void)
|
calclist(int showall)
|
||||||
{
|
{
|
||||||
Cmgroup g;
|
Cmgroup g;
|
||||||
Cmatch *p, m;
|
Cmatch *p, m;
|
||||||
|
@ -1259,7 +1160,7 @@ calclist(void)
|
||||||
VARARR(int, mlens, nmatches + 1);
|
VARARR(int, mlens, nmatches + 1);
|
||||||
|
|
||||||
if (listdat.valid && onlyexpl == listdat.onlyexpl &&
|
if (listdat.valid && onlyexpl == listdat.onlyexpl &&
|
||||||
menuacc == listdat.menuacc &&
|
menuacc == listdat.menuacc && showall == listdat.showall &&
|
||||||
lines == listdat.lines && columns == listdat.columns)
|
lines == listdat.lines && columns == listdat.columns)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1267,6 +1168,8 @@ calclist(void)
|
||||||
char **pp = g->ylist;
|
char **pp = g->ylist;
|
||||||
int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
|
int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
|
||||||
|
|
||||||
|
g->flags |= CGF_PACKED | CGF_ROWS;
|
||||||
|
|
||||||
if (!onlyexpl && pp) {
|
if (!onlyexpl && pp) {
|
||||||
/* We have an ylist, lets see, if it contains newlines. */
|
/* We have an ylist, lets see, if it contains newlines. */
|
||||||
hidden = 1;
|
hidden = 1;
|
||||||
|
@ -1283,8 +1186,8 @@ calclist(void)
|
||||||
while ((sptr = *pp)) {
|
while ((sptr = *pp)) {
|
||||||
while (sptr && *sptr) {
|
while (sptr && *sptr) {
|
||||||
nlines += (nlptr = strchr(sptr, '\n'))
|
nlines += (nlptr = strchr(sptr, '\n'))
|
||||||
? 1 + (nlptr-sptr)/columns
|
? 1 + (nlptr-sptr) / columns
|
||||||
: strlen(sptr)/columns;
|
: strlen(sptr) / columns;
|
||||||
sptr = nlptr ? nlptr+1 : NULL;
|
sptr = nlptr ? nlptr+1 : NULL;
|
||||||
}
|
}
|
||||||
nlines++;
|
nlines++;
|
||||||
|
@ -1327,7 +1230,11 @@ calclist(void)
|
||||||
mlens[m->gnum] = l;
|
mlens[m->gnum] = l;
|
||||||
}
|
}
|
||||||
nlist++;
|
nlist++;
|
||||||
} else if (!(m->flags & CMF_NOLIST)) {
|
if (!(m->flags & CMF_PACKED))
|
||||||
|
g->flags &= ~CGF_PACKED;
|
||||||
|
if (!(m->flags & CMF_ROWS))
|
||||||
|
g->flags &= ~CGF_ROWS;
|
||||||
|
} else if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) {
|
||||||
l = niceztrlen(m->str);
|
l = niceztrlen(m->str);
|
||||||
ndisp++;
|
ndisp++;
|
||||||
if (l > glong)
|
if (l > glong)
|
||||||
|
@ -1337,6 +1244,10 @@ calclist(void)
|
||||||
totl += l;
|
totl += l;
|
||||||
mlens[m->gnum] = l;
|
mlens[m->gnum] = l;
|
||||||
nlist++;
|
nlist++;
|
||||||
|
if (!(m->flags & CMF_PACKED))
|
||||||
|
g->flags &= ~CGF_PACKED;
|
||||||
|
if (!(m->flags & CMF_ROWS))
|
||||||
|
g->flags &= ~CGF_ROWS;
|
||||||
} else
|
} else
|
||||||
hidden = 1;
|
hidden = 1;
|
||||||
}
|
}
|
||||||
|
@ -1361,9 +1272,11 @@ calclist(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!onlyexpl) {
|
if (!onlyexpl) {
|
||||||
|
char **pp;
|
||||||
|
int *ws, tlines, tline, tcols, maxlen, nth, width, glines;
|
||||||
|
|
||||||
for (g = amatches; g; g = g->next) {
|
for (g = amatches; g; g = g->next) {
|
||||||
char **pp;
|
glines = 0;
|
||||||
int glines = 0;
|
|
||||||
|
|
||||||
zfree(g->widths, 0);
|
zfree(g->widths, 0);
|
||||||
g->widths = NULL;
|
g->widths = NULL;
|
||||||
|
@ -1396,20 +1309,19 @@ calclist(void)
|
||||||
if (m->disp) {
|
if (m->disp) {
|
||||||
if (!(m->flags & CMF_DISPLINE))
|
if (!(m->flags & CMF_DISPLINE))
|
||||||
glines += 1 + (mlens[m->gnum] / columns);
|
glines += 1 + (mlens[m->gnum] / columns);
|
||||||
} else if (!(m->flags & CMF_NOLIST))
|
} else if (showall ||
|
||||||
glines += 1 + ((1 + mlens[m->gnum]) / columns);
|
!(m->flags & (CMF_NOLIST | CMF_MULT)))
|
||||||
|
glines += 1 + ((mlens[m->gnum]) / columns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g->lins = glines;
|
g->lins = glines;
|
||||||
nlines += glines;
|
nlines += glines;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!onlyexpl && isset(LISTPACKED)) {
|
|
||||||
char **pp;
|
|
||||||
int *ws, tlines, tline, tcols, maxlen, nth, width;
|
|
||||||
|
|
||||||
for (g = amatches; g; g = g->next) {
|
for (g = amatches; g; g = g->next) {
|
||||||
|
if (!(g->flags & CGF_PACKED))
|
||||||
|
continue;
|
||||||
|
|
||||||
ws = g->widths = (int *) zalloc(columns * sizeof(int));
|
ws = g->widths = (int *) zalloc(columns * sizeof(int));
|
||||||
memset(ws, 0, columns * sizeof(int));
|
memset(ws, 0, columns * sizeof(int));
|
||||||
tlines = g->lins;
|
tlines = g->lins;
|
||||||
|
@ -1424,11 +1336,13 @@ calclist(void)
|
||||||
for (i = 0; *pp; i++, pp++)
|
for (i = 0; *pp; i++, pp++)
|
||||||
ylens[i] = strlen(*pp) + add;
|
ylens[i] = strlen(*pp) + add;
|
||||||
|
|
||||||
if (isset(LISTROWSFIRST)) {
|
if (g->flags & CGF_ROWS) {
|
||||||
int count, tcol, first, maxlines = 0, llines;
|
int count, tcol, first, maxlines = 0, llines;
|
||||||
|
int beg = columns / g->shortest, end = g->cols;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
tcols = (beg + end) >> 1;
|
||||||
|
|
||||||
for (tcols = columns / g->shortest; tcols > g->cols;
|
|
||||||
tcols--) {
|
|
||||||
for (nth = first = maxlen = width = maxlines =
|
for (nth = first = maxlen = width = maxlines =
|
||||||
llines = tcol = 0,
|
llines = tcol = 0,
|
||||||
count = g->dcount;
|
count = g->dcount;
|
||||||
|
@ -1452,17 +1366,33 @@ calclist(void)
|
||||||
ws[tcol++] = maxlen;
|
ws[tcol++] = maxlen;
|
||||||
width += maxlen;
|
width += maxlen;
|
||||||
}
|
}
|
||||||
if (!count && width < columns)
|
if (!count && width < columns &&
|
||||||
|
(tcols <= 0 || beg == end))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (beg == end) {
|
||||||
|
beg--;
|
||||||
|
end--;
|
||||||
|
} else if (width < columns) {
|
||||||
|
if ((end = tcols) == beg - 1)
|
||||||
|
end++;
|
||||||
|
} else {
|
||||||
|
if ((beg = tcols) - 1 == end)
|
||||||
|
end++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tcols > g->cols)
|
if (tcols > g->cols)
|
||||||
tlines = maxlines;
|
tlines = maxlines;
|
||||||
} else {
|
} else {
|
||||||
for (tlines = ((g->totl + columns) / columns);
|
int beg = ((g->totl + columns) / columns);
|
||||||
tlines < g->lins; tlines++) {
|
int end = g->lins;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
tlines = (beg + end) >> 1;
|
||||||
|
|
||||||
for (pp = g->ylist, nth = tline = width =
|
for (pp = g->ylist, nth = tline = width =
|
||||||
maxlen = tcols = 0;
|
maxlen = tcols = 0;
|
||||||
*pp; nth++, pp++) {
|
*pp; pp++) {
|
||||||
if (ylens[nth] > maxlen)
|
if (ylens[nth] > maxlen)
|
||||||
maxlen = ylens[nth];
|
maxlen = ylens[nth];
|
||||||
if (++tline == tlines) {
|
if (++tline == tlines) {
|
||||||
|
@ -1471,24 +1401,41 @@ calclist(void)
|
||||||
ws[tcols++] = maxlen;
|
ws[tcols++] = maxlen;
|
||||||
maxlen = tline = 0;
|
maxlen = tline = 0;
|
||||||
}
|
}
|
||||||
|
nth++;
|
||||||
}
|
}
|
||||||
if (tline) {
|
if (tline) {
|
||||||
ws[tcols++] = maxlen;
|
ws[tcols++] = maxlen;
|
||||||
width += maxlen;
|
width += maxlen;
|
||||||
}
|
}
|
||||||
if (nth == yl && width < columns)
|
if (nth == yl && width < columns &&
|
||||||
|
(beg == end || tlines >= g->lins))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (beg == end) {
|
||||||
|
beg++;
|
||||||
|
end++;
|
||||||
|
} else if (width < columns) {
|
||||||
|
if ((end = tlines) == beg + 1)
|
||||||
|
end--;
|
||||||
|
} else {
|
||||||
|
if ((beg = tlines) + 1 == end)
|
||||||
|
end--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (tlines > g->lins)
|
||||||
|
tlines = g->lins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (g->width) {
|
} else if (g->width) {
|
||||||
if (isset(LISTROWSFIRST)) {
|
if (g->flags & CGF_ROWS) {
|
||||||
int addlen, count, tcol, maxlines = 0, llines, i;
|
int addlen, count, tcol, maxlines = 0, llines, i;
|
||||||
|
int beg = columns / g->shortest, end = g->cols;
|
||||||
Cmatch *first;
|
Cmatch *first;
|
||||||
|
|
||||||
for (tcols = columns / g->shortest; tcols > g->cols;
|
while (1) {
|
||||||
tcols--) {
|
tcols = (beg + end) >> 1;
|
||||||
p = first = skipnolist(g->matches);
|
|
||||||
|
p = first = skipnolist(g->matches, showall);
|
||||||
for (maxlen = width = maxlines = llines = tcol = 0,
|
for (maxlen = width = maxlines = llines = tcol = 0,
|
||||||
count = g->dcount;
|
count = g->dcount;
|
||||||
count > 0; count--) {
|
count > 0; count--) {
|
||||||
|
@ -1497,7 +1444,7 @@ calclist(void)
|
||||||
if (addlen > maxlen)
|
if (addlen > maxlen)
|
||||||
maxlen = addlen;
|
maxlen = addlen;
|
||||||
for (i = tcols; i && *p; i--)
|
for (i = tcols; i && *p; i--)
|
||||||
p = skipnolist(p + 1);
|
p = skipnolist(p + 1, showall);
|
||||||
|
|
||||||
llines++;
|
llines++;
|
||||||
if (!*p) {
|
if (!*p) {
|
||||||
|
@ -1510,29 +1457,46 @@ calclist(void)
|
||||||
ws[tcol++] = maxlen;
|
ws[tcol++] = maxlen;
|
||||||
maxlen = 0;
|
maxlen = 0;
|
||||||
|
|
||||||
p = first = skipnolist(first + 1);
|
p = first = skipnolist(first + 1, showall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tlines) {
|
if (tlines) {
|
||||||
ws[tcol++] = maxlen;
|
ws[tcol++] = maxlen;
|
||||||
width += maxlen;
|
width += maxlen;
|
||||||
}
|
}
|
||||||
if (!count && width < columns)
|
if (!count && width < columns &&
|
||||||
|
(tcols <= 0 || beg == end))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (beg == end) {
|
||||||
|
beg--;
|
||||||
|
end--;
|
||||||
|
} else if (width < columns) {
|
||||||
|
if ((end = tcols) == beg - 1)
|
||||||
|
end++;
|
||||||
|
} else {
|
||||||
|
if ((beg = tcols) - 1 == end)
|
||||||
|
end++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tcols > g->cols)
|
if (tcols > g->cols)
|
||||||
tlines = maxlines;
|
tlines = maxlines;
|
||||||
} else {
|
} else {
|
||||||
int addlen;
|
int addlen;
|
||||||
|
int smask = ((showall ? 0 : (CMF_NOLIST | CMF_MULT)) |
|
||||||
|
CMF_HIDE);
|
||||||
|
int beg = ((g->totl + columns) / columns);
|
||||||
|
int end = g->lins;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
tlines = (beg + end) >> 1;
|
||||||
|
|
||||||
for (tlines = ((g->totl + columns) / columns);
|
|
||||||
tlines < g->lins; tlines++) {
|
|
||||||
for (p = g->matches, nth = tline = width =
|
for (p = g->matches, nth = tline = width =
|
||||||
maxlen = tcols = 0;
|
maxlen = tcols = 0;
|
||||||
(m = *p); p++, nth++) {
|
(m = *p); p++) {
|
||||||
if (!(m->flags &
|
if (!(m->flags &
|
||||||
(m->disp ? (CMF_DISPLINE | CMF_HIDE) :
|
(m->disp ? (CMF_DISPLINE | CMF_HIDE) :
|
||||||
(CMF_NOLIST | CMF_HIDE)))) {
|
smask))) {
|
||||||
addlen = mlens[m->gnum] + add;
|
addlen = mlens[m->gnum] + add;
|
||||||
if (addlen > maxlen)
|
if (addlen > maxlen)
|
||||||
maxlen = addlen;
|
maxlen = addlen;
|
||||||
|
@ -1542,15 +1506,30 @@ calclist(void)
|
||||||
ws[tcols++] = maxlen;
|
ws[tcols++] = maxlen;
|
||||||
maxlen = tline = 0;
|
maxlen = tline = 0;
|
||||||
}
|
}
|
||||||
|
nth++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tline) {
|
if (tline) {
|
||||||
ws[tcols++] = maxlen;
|
ws[tcols++] = maxlen;
|
||||||
width += maxlen;
|
width += maxlen;
|
||||||
}
|
}
|
||||||
if (nth == g->dcount && width < columns)
|
if (nth == g->dcount && width < columns &&
|
||||||
|
(beg == end || tlines >= g->lins))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (beg == end) {
|
||||||
|
beg++;
|
||||||
|
end++;
|
||||||
|
} else if (width < columns) {
|
||||||
|
if ((end = tlines) == beg + 1)
|
||||||
|
end--;
|
||||||
|
} else {
|
||||||
|
if ((beg = tlines) + 1 == end)
|
||||||
|
end--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (tlines > g->lins)
|
||||||
|
tlines = g->lins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tlines == g->lins) {
|
if (tlines == g->lins) {
|
||||||
|
@ -1584,21 +1563,23 @@ calclist(void)
|
||||||
listdat.onlyexpl = onlyexpl;
|
listdat.onlyexpl = onlyexpl;
|
||||||
listdat.columns = columns;
|
listdat.columns = columns;
|
||||||
listdat.lines = lines;
|
listdat.lines = lines;
|
||||||
|
listdat.showall = showall;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int asklist(void)
|
mod_export int asklist(void)
|
||||||
{
|
{
|
||||||
/* Set the cursor below the prompt. */
|
/* Set the cursor below the prompt. */
|
||||||
trashzle();
|
trashzle();
|
||||||
showinglist = listshown = 0;
|
showinglist = listshown = 0;
|
||||||
|
|
||||||
clearflag = (isset(USEZLE) && !termflags &&
|
clearflag = (isset(USEZLE) && !termflags && dolastprompt);
|
||||||
complastprompt && *complastprompt);
|
lastlistlen = 0;
|
||||||
|
|
||||||
/* Maybe we have to ask if the user wants to see the list. */
|
/* Maybe we have to ask if the user wants to see the list. */
|
||||||
if ((!minfo.cur || !minfo.asked) &&
|
if ((!minfo.cur || !minfo.asked) &&
|
||||||
((complistmax && listdat.nlist > complistmax) ||
|
((complistmax > 0 && listdat.nlist >= complistmax) ||
|
||||||
|
(complistmax < 0 && listdat.nlines <= -complistmax) ||
|
||||||
(!complistmax && listdat.nlines >= lines))) {
|
(!complistmax && listdat.nlines >= lines))) {
|
||||||
int qup;
|
int qup;
|
||||||
zsetterm();
|
zsetterm();
|
||||||
|
@ -1614,8 +1595,7 @@ int asklist(void)
|
||||||
tcmultout(TCUP, TCMULTUP, nlnct);
|
tcmultout(TCUP, TCMULTUP, nlnct);
|
||||||
} else
|
} else
|
||||||
putc('\n', shout);
|
putc('\n', shout);
|
||||||
if (minfo.cur)
|
minfo.asked = 2;
|
||||||
minfo.asked = 2;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (clearflag) {
|
if (clearflag) {
|
||||||
|
@ -1626,15 +1606,14 @@ int asklist(void)
|
||||||
} else
|
} else
|
||||||
putc('\n', shout);
|
putc('\n', shout);
|
||||||
settyinfo(&shttyinfo);
|
settyinfo(&shttyinfo);
|
||||||
if (minfo.cur)
|
minfo.asked = 1;
|
||||||
minfo.asked = 1;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return (minfo.asked ? minfo.asked - 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
mod_export int
|
||||||
printlist(int over, CLPrintFunc printm)
|
printlist(int over, CLPrintFunc printm, int showall)
|
||||||
{
|
{
|
||||||
Cmgroup g;
|
Cmgroup g;
|
||||||
Cmatch *p, m;
|
Cmatch *p, m;
|
||||||
|
@ -1715,7 +1694,7 @@ printlist(int over, CLPrintFunc printm)
|
||||||
while (a--)
|
while (a--)
|
||||||
putc(' ', shout);
|
putc(' ', shout);
|
||||||
}
|
}
|
||||||
pq += (isset(LISTROWSFIRST) ? 1 : nc);
|
pq += ((g->flags & CGF_ROWS) ? 1 : nc);
|
||||||
mc++;
|
mc++;
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
|
@ -1728,10 +1707,11 @@ printlist(int over, CLPrintFunc printm)
|
||||||
tcout(TCCLEAREOD);
|
tcout(TCCLEAREOD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pp += (isset(LISTROWSFIRST) ? g->cols : 1);
|
pp += ((g->flags & CGF_ROWS) ? g->cols : 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!listdat.onlyexpl && g->lcount) {
|
} else if (!listdat.onlyexpl &&
|
||||||
|
(g->lcount || (showall && g->mcount))) {
|
||||||
int n = g->dcount, nl, nc, i, j, wid;
|
int n = g->dcount, nl, nc, i, j, wid;
|
||||||
Cmatch *q;
|
Cmatch *q;
|
||||||
|
|
||||||
|
@ -1765,7 +1745,7 @@ printlist(int over, CLPrintFunc printm)
|
||||||
tcout(TCCLEAREOD);
|
tcout(TCCLEAREOD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (p = skipnolist(g->matches); n && nl--;) {
|
for (p = skipnolist(g->matches, showall); n && nl--;) {
|
||||||
i = g->cols;
|
i = g->cols;
|
||||||
mc = 0;
|
mc = 0;
|
||||||
q = p;
|
q = p;
|
||||||
|
@ -1794,14 +1774,16 @@ printlist(int over, CLPrintFunc printm)
|
||||||
printed++;
|
printed++;
|
||||||
|
|
||||||
if (--n)
|
if (--n)
|
||||||
for (j = (isset(LISTROWSFIRST) ? 1 : nc); j && *q; j--)
|
for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
|
||||||
q = skipnolist(q + 1);
|
j && *q; j--)
|
||||||
|
q = skipnolist(q + 1, showall);
|
||||||
mc++;
|
mc++;
|
||||||
}
|
}
|
||||||
while (i-- > 0)
|
while (i-- > 0) {
|
||||||
printm(g, NULL, mc++, ml, (!i),
|
printm(g, NULL, mc, ml, (!i),
|
||||||
(g->widths ? g->widths[mc] : g->width), NULL, NULL);
|
(g->widths ? g->widths[mc] : g->width), NULL, NULL);
|
||||||
|
mc++;
|
||||||
|
}
|
||||||
if (n) {
|
if (n) {
|
||||||
putc('\n', shout);
|
putc('\n', shout);
|
||||||
ml++;
|
ml++;
|
||||||
|
@ -1811,25 +1793,30 @@ printlist(int over, CLPrintFunc printm)
|
||||||
tcout(TCCLEAREOD);
|
tcout(TCCLEAREOD);
|
||||||
}
|
}
|
||||||
if (nl)
|
if (nl)
|
||||||
for (j = (isset(LISTROWSFIRST) ? g->cols : 1); j && *p; j--)
|
for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
|
||||||
p = skipnolist(p + 1);
|
j && *p; j--)
|
||||||
|
p = skipnolist(p + 1, showall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (g->lcount)
|
if (g->lcount || (showall && g->mcount))
|
||||||
pnl = 1;
|
pnl = 1;
|
||||||
g = g->next;
|
g = g->next;
|
||||||
}
|
}
|
||||||
|
lastlistlen = 0;
|
||||||
if (clearflag) {
|
if (clearflag) {
|
||||||
/* Move the cursor up to the prompt, if always_last_prompt *
|
/* Move the cursor up to the prompt, if always_last_prompt *
|
||||||
* is set and all that... */
|
* is set and all that... */
|
||||||
if ((ml = listdat.nlines + nlnct - 1) < lines) {
|
if ((ml = listdat.nlines + nlnct - 1) < lines) {
|
||||||
tcmultout(TCUP, TCMULTUP, ml);
|
tcmultout(TCUP, TCMULTUP, ml);
|
||||||
showinglist = -1;
|
showinglist = -1;
|
||||||
|
|
||||||
|
lastlistlen = listdat.nlines;
|
||||||
} else
|
} else
|
||||||
clearflag = 0, putc('\n', shout);
|
clearflag = 0, putc('\n', shout);
|
||||||
} else
|
} else
|
||||||
putc('\n', shout);
|
putc('\n', shout);
|
||||||
|
|
||||||
listshown = (clearflag ? 1 : -1);
|
listshown = (clearflag ? 1 : -1);
|
||||||
|
|
||||||
return printed;
|
return printed;
|
||||||
|
@ -1858,9 +1845,8 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
|
||||||
nicezputs(m->str, shout);
|
nicezputs(m->str, shout);
|
||||||
len = niceztrlen(m->str);
|
len = niceztrlen(m->str);
|
||||||
|
|
||||||
if (isset(LISTTYPES)) {
|
if (isset(LISTTYPES) && buf) {
|
||||||
if (buf)
|
putc(file_type(buf->st_mode), shout);
|
||||||
putc(file_type(buf->st_mode), shout);
|
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1876,7 +1862,7 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
|
||||||
int
|
int
|
||||||
ilistmatches(Hookdef dummy, Chdata dat)
|
ilistmatches(Hookdef dummy, Chdata dat)
|
||||||
{
|
{
|
||||||
calclist();
|
calclist(0);
|
||||||
|
|
||||||
if (!listdat.nlines) {
|
if (!listdat.nlines) {
|
||||||
showinglist = listshown = 0;
|
showinglist = listshown = 0;
|
||||||
|
@ -1885,7 +1871,7 @@ ilistmatches(Hookdef dummy, Chdata dat)
|
||||||
if (asklist())
|
if (asklist())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
printlist(0, iprintm);
|
printlist(0, iprintm, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1897,6 +1883,7 @@ int
|
||||||
list_matches(Hookdef dummy, void *dummy2)
|
list_matches(Hookdef dummy, void *dummy2)
|
||||||
{
|
{
|
||||||
struct chdata dat;
|
struct chdata dat;
|
||||||
|
int ret;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
|
@ -1909,18 +1896,20 @@ list_matches(Hookdef dummy, void *dummy2)
|
||||||
dat.matches = amatches;
|
dat.matches = amatches;
|
||||||
dat.num = nmatches;
|
dat.num = nmatches;
|
||||||
dat.cur = NULL;
|
dat.cur = NULL;
|
||||||
return runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
|
ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invalidate the completion list. */
|
/* Invalidate the completion list. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
mod_export int
|
||||||
invalidate_list(void)
|
invalidate_list(void)
|
||||||
{
|
{
|
||||||
if (showinglist == -2)
|
|
||||||
listmatches();
|
|
||||||
if (validlist) {
|
if (validlist) {
|
||||||
|
if (showinglist == -2)
|
||||||
|
zrefresh();
|
||||||
freematches(lastmatches);
|
freematches(lastmatches);
|
||||||
lastmatches = NULL;
|
lastmatches = NULL;
|
||||||
hasoldlist = 0;
|
hasoldlist = 0;
|
||||||
|
|
1498
Src/Zle/computil.c
1498
Src/Zle/computil.c
File diff suppressed because it is too large
Load diff
|
@ -19,20 +19,21 @@
|
||||||
"backward-kill-line", backwardkillline, ZLE_KILL | ZLE_KEEPSUFFIX
|
"backward-kill-line", backwardkillline, ZLE_KILL | ZLE_KEEPSUFFIX
|
||||||
"backward-kill-word", backwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX
|
"backward-kill-word", backwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX
|
||||||
"backward-word", backwardword, 0
|
"backward-word", backwardword, 0
|
||||||
|
"beep", handlefeep, 0
|
||||||
"beginning-of-buffer-or-history", beginningofbufferorhistory, 0
|
"beginning-of-buffer-or-history", beginningofbufferorhistory, 0
|
||||||
"beginning-of-history", beginningofhistory, 0
|
"beginning-of-history", beginningofhistory, 0
|
||||||
"beginning-of-line", beginningofline, 0
|
"beginning-of-line", beginningofline, 0
|
||||||
"beginning-of-line-hist", beginningoflinehist, 0
|
"beginning-of-line-hist", beginningoflinehist, 0
|
||||||
"capitalize-word", capitalizeword, 0
|
"capitalize-word", capitalizeword, 0
|
||||||
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
|
||||||
"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||||
"copy-prev-word", copyprevword, 0
|
"copy-prev-word", copyprevword, ZLE_KEEPSUFFIX
|
||||||
"copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX
|
"copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX
|
||||||
"delete-char", deletechar, ZLE_KEEPSUFFIX
|
"delete-char", deletechar, ZLE_KEEPSUFFIX
|
||||||
"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||||
"delete-word", deleteword, ZLE_KEEPSUFFIX
|
"delete-word", deleteword, ZLE_KEEPSUFFIX
|
||||||
"describe-key-briefly", describekeybriefly, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"describe-key-briefly", describekeybriefly, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"digit-argument", digitargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"digit-argument", digitargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
|
||||||
"down-case-word", downcaseword, 0
|
"down-case-word", downcaseword, 0
|
||||||
"down-history", downhistory, 0
|
"down-history", downhistory, 0
|
||||||
"down-line-or-history", downlineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
|
"down-line-or-history", downlineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
|
||||||
|
@ -43,13 +44,14 @@
|
||||||
"end-of-history", endofhistory, 0
|
"end-of-history", endofhistory, 0
|
||||||
"end-of-line", endofline, 0
|
"end-of-line", endofline, 0
|
||||||
"end-of-line-hist", endoflinehist, 0
|
"end-of-line-hist", endoflinehist, 0
|
||||||
|
"end-of-list", endoflist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"exchange-point-and-mark", exchangepointandmark, 0
|
"exchange-point-and-mark", exchangepointandmark, 0
|
||||||
"execute-last-named-cmd", NULL, 0
|
"execute-last-named-cmd", NULL, 0
|
||||||
"execute-named-cmd", NULL, 0
|
"execute-named-cmd", NULL, 0
|
||||||
"expand-cmd-path", expandcmdpath, 0
|
"expand-cmd-path", expandcmdpath, 0
|
||||||
"expand-history", expandhistory, 0
|
"expand-history", expandhistory, 0
|
||||||
"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||||
"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||||
"expand-word", expandword, 0
|
"expand-word", expandword, 0
|
||||||
"forward-char", forwardchar, 0
|
"forward-char", forwardchar, 0
|
||||||
"forward-word", forwardword, 0
|
"forward-word", forwardword, 0
|
||||||
|
@ -68,12 +70,12 @@
|
||||||
"kill-region", killregion, ZLE_KILL | ZLE_KEEPSUFFIX
|
"kill-region", killregion, ZLE_KILL | ZLE_KEEPSUFFIX
|
||||||
"kill-whole-line", killwholeline, ZLE_KILL | ZLE_KEEPSUFFIX
|
"kill-whole-line", killwholeline, ZLE_KILL | ZLE_KEEPSUFFIX
|
||||||
"kill-word", killword, ZLE_KILL | ZLE_KEEPSUFFIX
|
"kill-word", killword, ZLE_KILL | ZLE_KEEPSUFFIX
|
||||||
"list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_ISCOMP
|
||||||
"list-expand", listexpand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"list-expand", listexpand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"magic-space", magicspace, 0
|
"magic-space", magicspace, 0
|
||||||
"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||||
"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||||
"neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
|
||||||
"overwrite-mode", overwritemode, 0
|
"overwrite-mode", overwritemode, 0
|
||||||
"pound-insert", poundinsert, 0
|
"pound-insert", poundinsert, 0
|
||||||
"push-input", pushinput, 0
|
"push-input", pushinput, 0
|
||||||
|
@ -83,19 +85,20 @@
|
||||||
"quote-line", quoteline, 0
|
"quote-line", quoteline, 0
|
||||||
"quote-region", quoteregion, 0
|
"quote-region", quoteregion, 0
|
||||||
"redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"redo", redo, 0
|
"redo", redo, ZLE_KEEPSUFFIX
|
||||||
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||||
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||||
"self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||||
"send-break", sendbreak, 0
|
"send-break", sendbreak, 0
|
||||||
"set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"spell-word", spellword, 0
|
"spell-word", spellword, 0
|
||||||
|
"set-local-history", setlocalhistory, 0
|
||||||
"transpose-chars", transposechars, 0
|
"transpose-chars", transposechars, 0
|
||||||
"transpose-words", transposewords, 0
|
"transpose-words", transposewords, 0
|
||||||
"undefined-key", undefinedkey, 0
|
"undefined-key", undefinedkey, 0
|
||||||
"undo", undo, 0
|
"undo", undo, ZLE_KEEPSUFFIX
|
||||||
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
|
||||||
"up-case-word", upcaseword, 0
|
"up-case-word", upcaseword, 0
|
||||||
"up-history", uphistory, 0
|
"up-history", uphistory, 0
|
||||||
"up-line-or-history", uplineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
|
"up-line-or-history", uplineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
|
||||||
|
@ -145,8 +148,8 @@
|
||||||
"vi-open-line-below", viopenlinebelow, 0
|
"vi-open-line-below", viopenlinebelow, 0
|
||||||
"vi-oper-swap-case", vioperswapcase, 0
|
"vi-oper-swap-case", vioperswapcase, 0
|
||||||
"vi-pound-insert", vipoundinsert, 0
|
"vi-pound-insert", vipoundinsert, 0
|
||||||
"vi-put-after", viputafter, ZLE_YANK
|
"vi-put-after", viputafter, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||||
"vi-put-before", viputbefore, ZLE_YANK
|
"vi-put-before", viputbefore, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||||
"vi-quoted-insert", viquotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
"vi-quoted-insert", viquotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||||
"vi-repeat-change", virepeatchange, 0
|
"vi-repeat-change", virepeatchange, 0
|
||||||
"vi-repeat-find", virepeatfind, 0
|
"vi-repeat-find", virepeatfind, 0
|
||||||
|
@ -159,7 +162,7 @@
|
||||||
"vi-set-mark", visetmark, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"vi-set-mark", visetmark, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"vi-substitute", visubstitute, 0
|
"vi-substitute", visubstitute, 0
|
||||||
"vi-swap-case", viswapcase, 0
|
"vi-swap-case", viswapcase, 0
|
||||||
"vi-undo-change", viundochange, 0
|
"vi-undo-change", viundochange, ZLE_KEEPSUFFIX
|
||||||
"vi-unindent", viunindent, 0
|
"vi-unindent", viunindent, 0
|
||||||
"vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE
|
"vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE
|
||||||
"vi-yank", viyank, 0
|
"vi-yank", viyank, 0
|
||||||
|
@ -168,5 +171,5 @@
|
||||||
"what-cursor-position", whatcursorposition, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"what-cursor-position", whatcursorposition, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"where-is", whereis, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"where-is", whereis, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"which-command", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
"which-command", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||||
"yank", yank, ZLE_YANK
|
"yank", yank, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||||
"yank-pop", yankpop, ZLE_YANK
|
"yank-pop", yankpop, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct cutbuffer vibuf[35];
|
||||||
/**/
|
/**/
|
||||||
char *lastline;
|
char *lastline;
|
||||||
/**/
|
/**/
|
||||||
int lastlinesz, lastll;
|
int lastlinesz, lastll, lastcs;
|
||||||
|
|
||||||
/* size of line buffer */
|
/* size of line buffer */
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ sizeline(int sz)
|
||||||
/* insert space for ct chars at cursor position */
|
/* insert space for ct chars at cursor position */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
spaceinline(int ct)
|
spaceinline(int ct)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -105,7 +105,7 @@ shiftchars(int to, int cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
backkill(int ct, int dir)
|
backkill(int ct, int dir)
|
||||||
{
|
{
|
||||||
int i = (cs -= ct);
|
int i = (cs -= ct);
|
||||||
|
@ -115,7 +115,7 @@ backkill(int ct, int dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
forekill(int ct, int dir)
|
forekill(int ct, int dir)
|
||||||
{
|
{
|
||||||
int i = cs;
|
int i = cs;
|
||||||
|
@ -191,14 +191,14 @@ cut(int i, int ct, int dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
backdel(int ct)
|
backdel(int ct)
|
||||||
{
|
{
|
||||||
shiftchars(cs -= ct, ct);
|
shiftchars(cs -= ct, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
foredel(int ct)
|
foredel(int ct)
|
||||||
{
|
{
|
||||||
shiftchars(cs, ct);
|
shiftchars(cs, ct);
|
||||||
|
@ -283,7 +283,7 @@ hstrnstr(char *haystack, int pos, char *needle, int len, int dir, int sens)
|
||||||
* characters are read. Case is folded. */
|
* characters are read. Case is folded. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
mod_export int
|
||||||
getzlequery(void)
|
getzlequery(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
@ -409,19 +409,11 @@ showmsg(char const *msg)
|
||||||
/* handle the error flag */
|
/* handle the error flag */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
int
|
||||||
feep(void)
|
handlefeep(char **args)
|
||||||
{
|
{
|
||||||
feepflag = 1;
|
zbeep();
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
/**/
|
|
||||||
void
|
|
||||||
handlefeep(void)
|
|
||||||
{
|
|
||||||
if(feepflag)
|
|
||||||
beep();
|
|
||||||
feepflag = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************/
|
/***************/
|
||||||
|
@ -446,6 +438,7 @@ initundo(void)
|
||||||
curchange->del = curchange->ins = NULL;
|
curchange->del = curchange->ins = NULL;
|
||||||
lastline = zalloc(lastlinesz = linesz);
|
lastline = zalloc(lastlinesz = linesz);
|
||||||
memcpy(lastline, line, lastll = ll);
|
memcpy(lastline, line, lastll = ll);
|
||||||
|
lastcs = cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -519,6 +512,8 @@ mkundoent(void)
|
||||||
ch->next = NULL;
|
ch->next = NULL;
|
||||||
ch->hist = histline;
|
ch->hist = histline;
|
||||||
ch->off = pre;
|
ch->off = pre;
|
||||||
|
ch->old_cs = lastcs;
|
||||||
|
ch->new_cs = cs;
|
||||||
if(suf + pre == lastll)
|
if(suf + pre == lastll)
|
||||||
ch->del = NULL;
|
ch->del = NULL;
|
||||||
else
|
else
|
||||||
|
@ -549,32 +544,36 @@ setlastline(void)
|
||||||
if(lastlinesz != linesz)
|
if(lastlinesz != linesz)
|
||||||
lastline = realloc(lastline, lastlinesz = linesz);
|
lastline = realloc(lastline, lastlinesz = linesz);
|
||||||
memcpy(lastline, line, lastll = ll);
|
memcpy(lastline, line, lastll = ll);
|
||||||
|
lastcs = cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move backwards through the change list */
|
/* move backwards through the change list */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
int
|
||||||
undo(void)
|
undo(char **args)
|
||||||
{
|
{
|
||||||
handleundo();
|
handleundo();
|
||||||
do {
|
do {
|
||||||
if(!curchange->prev) {
|
if(!curchange->prev)
|
||||||
feep();
|
return 1;
|
||||||
return;
|
if (unapplychange(curchange->prev))
|
||||||
}
|
curchange = curchange->prev;
|
||||||
unapplychange(curchange = curchange->prev);
|
else
|
||||||
|
break;
|
||||||
} while(curchange->flags & CH_PREV);
|
} while(curchange->flags & CH_PREV);
|
||||||
setlastline();
|
setlastline();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static void
|
static int
|
||||||
unapplychange(struct change *ch)
|
unapplychange(struct change *ch)
|
||||||
{
|
{
|
||||||
if(ch->hist != histline) {
|
if(ch->hist != histline) {
|
||||||
remember_edits();
|
zle_setline(quietgethist(ch->hist));
|
||||||
setline(zle_get_event(histline = ch->hist));
|
cs = ch->new_cs;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
cs = ch->off;
|
cs = ch->off;
|
||||||
if(ch->ins)
|
if(ch->ins)
|
||||||
|
@ -589,33 +588,37 @@ unapplychange(struct change *ch)
|
||||||
else
|
else
|
||||||
line[cs++] = STOUC(*c);
|
line[cs++] = STOUC(*c);
|
||||||
}
|
}
|
||||||
|
cs = ch->old_cs;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move forwards through the change list */
|
/* move forwards through the change list */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
int
|
||||||
redo(void)
|
redo(char **args)
|
||||||
{
|
{
|
||||||
handleundo();
|
handleundo();
|
||||||
do {
|
do {
|
||||||
if(!curchange->next) {
|
if(!curchange->next)
|
||||||
feep();
|
return 1;
|
||||||
return;
|
if (applychange(curchange))
|
||||||
}
|
curchange = curchange->next;
|
||||||
applychange(curchange);
|
else
|
||||||
curchange = curchange->next;
|
break;
|
||||||
} while(curchange->prev->flags & CH_NEXT);
|
} while(curchange->prev->flags & CH_NEXT);
|
||||||
setlastline();
|
setlastline();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static void
|
static int
|
||||||
applychange(struct change *ch)
|
applychange(struct change *ch)
|
||||||
{
|
{
|
||||||
if(ch->hist != histline) {
|
if(ch->hist != histline) {
|
||||||
remember_edits();
|
zle_setline(quietgethist(ch->hist));
|
||||||
setline(zle_get_event(histline = ch->hist));
|
cs = ch->old_cs;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
cs = ch->off;
|
cs = ch->off;
|
||||||
if(ch->del)
|
if(ch->del)
|
||||||
|
@ -630,13 +633,15 @@ applychange(struct change *ch)
|
||||||
else
|
else
|
||||||
line[cs++] = STOUC(*c);
|
line[cs++] = STOUC(*c);
|
||||||
}
|
}
|
||||||
|
cs = ch->new_cs;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vi undo: toggle between the end of the undo list and the preceding point */
|
/* vi undo: toggle between the end of the undo list and the preceding point */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
int
|
||||||
viundochange(void)
|
viundochange(char **args)
|
||||||
{
|
{
|
||||||
handleundo();
|
handleundo();
|
||||||
if(curchange->next) {
|
if(curchange->next) {
|
||||||
|
@ -645,6 +650,7 @@ viundochange(void)
|
||||||
curchange = curchange->next;
|
curchange = curchange->next;
|
||||||
} while(curchange->next);
|
} while(curchange->next);
|
||||||
setlastline();
|
setlastline();
|
||||||
|
return 0;
|
||||||
} else
|
} else
|
||||||
undo();
|
return undo(args);
|
||||||
}
|
}
|
||||||
|
|
1506
Src/builtin.c
1506
Src/builtin.c
File diff suppressed because it is too large
Load diff
326
Src/cond.c
326
Src/cond.c
|
@ -30,125 +30,277 @@
|
||||||
#include "zsh.mdh"
|
#include "zsh.mdh"
|
||||||
#include "cond.pro"
|
#include "cond.pro"
|
||||||
|
|
||||||
|
int tracingcond;
|
||||||
|
|
||||||
|
static char *condstr[COND_MOD] = {
|
||||||
|
"!", "&&", "||", "==", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
|
||||||
|
"-ne", "-lt", "-gt", "-le", "-ge"
|
||||||
|
};
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
evalcond(Cond c)
|
evalcond(Estate state)
|
||||||
{
|
{
|
||||||
struct stat *st;
|
struct stat *st;
|
||||||
|
char *left, *right;
|
||||||
|
Wordcode pcode;
|
||||||
|
wordcode code;
|
||||||
|
int ctype, htok = 0;
|
||||||
|
|
||||||
switch (c->type) {
|
rec:
|
||||||
|
|
||||||
|
left = right = NULL;
|
||||||
|
pcode = state->pc++;
|
||||||
|
code = *pcode;
|
||||||
|
ctype = WC_COND_TYPE(code);
|
||||||
|
|
||||||
|
switch (ctype) {
|
||||||
case COND_NOT:
|
case COND_NOT:
|
||||||
return !evalcond(c->left);
|
if (tracingcond)
|
||||||
|
fprintf(xtrerr, " %s", condstr[ctype]);
|
||||||
|
return !evalcond(state);
|
||||||
case COND_AND:
|
case COND_AND:
|
||||||
return evalcond(c->left) && evalcond(c->right);
|
if (evalcond(state)) {
|
||||||
|
if (tracingcond)
|
||||||
|
fprintf(xtrerr, " %s", condstr[ctype]);
|
||||||
|
goto rec;
|
||||||
|
} else {
|
||||||
|
state->pc = pcode + (WC_COND_SKIP(code) + 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case COND_OR:
|
case COND_OR:
|
||||||
return evalcond(c->left) || evalcond(c->right);
|
if (!evalcond(state)) {
|
||||||
|
if (tracingcond)
|
||||||
|
fprintf(xtrerr, " %s", condstr[ctype]);
|
||||||
|
goto rec;
|
||||||
|
} else {
|
||||||
|
state->pc = pcode + (WC_COND_SKIP(code) + 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case COND_MOD:
|
||||||
|
case COND_MODI:
|
||||||
|
{
|
||||||
|
Conddef cd;
|
||||||
|
char *name = ecgetstr(state, EC_NODUP, NULL), **strs;
|
||||||
|
int l = WC_COND_SKIP(code);
|
||||||
|
|
||||||
|
if (ctype == COND_MOD)
|
||||||
|
strs = ecgetarr(state, l, EC_DUP, NULL);
|
||||||
|
else {
|
||||||
|
char *sbuf[3];
|
||||||
|
|
||||||
|
sbuf[0] = ecgetstr(state, EC_NODUP, NULL);
|
||||||
|
sbuf[1] = ecgetstr(state, EC_NODUP, NULL);
|
||||||
|
sbuf[2] = NULL;
|
||||||
|
|
||||||
|
strs = arrdup(sbuf);
|
||||||
|
l = 2;
|
||||||
|
}
|
||||||
|
if ((cd = getconddef((ctype == COND_MODI), name + 1, 1))) {
|
||||||
|
if (ctype == COND_MOD &&
|
||||||
|
(l < cd->min || (cd->max >= 0 && l > cd->max))) {
|
||||||
|
zerr("unrecognized condition: `%s'", name, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (tracingcond)
|
||||||
|
tracemodcond(name, strs, ctype == COND_MODI);
|
||||||
|
return cd->handler(strs, cd->condid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char *s = strs[0];
|
||||||
|
|
||||||
|
strs[0] = dupstring(name);
|
||||||
|
name = s;
|
||||||
|
|
||||||
|
if (name && name[0] == '-' &&
|
||||||
|
(cd = getconddef(0, name + 1, 1))) {
|
||||||
|
if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
|
||||||
|
zerr("unrecognized condition: `%s'", name, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (tracingcond)
|
||||||
|
tracemodcond(name, strs, ctype == COND_MODI);
|
||||||
|
return cd->handler(strs, cd->condid);
|
||||||
|
} else
|
||||||
|
zerr("unrecognized condition: `%s'", name, 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
singsub((char **)&c->left);
|
left = ecgetstr(state, EC_DUPTOK, &htok);
|
||||||
untokenize(c->left);
|
if (htok) {
|
||||||
if (c->right) {
|
singsub(&left);
|
||||||
singsub((char **)&c->right);
|
untokenize(left);
|
||||||
if (c->type != COND_STREQ && c->type != COND_STRNEQ)
|
|
||||||
untokenize(c->right);
|
|
||||||
}
|
}
|
||||||
switch (c->type) {
|
if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) {
|
||||||
|
right = ecgetstr(state, EC_DUPTOK, &htok);
|
||||||
|
if (htok) {
|
||||||
|
singsub(&right);
|
||||||
|
untokenize(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tracingcond) {
|
||||||
|
if (ctype < COND_MOD) {
|
||||||
|
char *rt = (char *) right;
|
||||||
|
if (ctype == COND_STREQ || ctype == COND_STRNEQ) {
|
||||||
|
rt = dupstring(ecrawstr(state->prog, state->pc, NULL));
|
||||||
|
singsub(&rt);
|
||||||
|
untokenize(rt);
|
||||||
|
}
|
||||||
|
fprintf(xtrerr, " %s %s %s", left, condstr[ctype], rt);
|
||||||
|
} else
|
||||||
|
fprintf(xtrerr, " -%c %s", ctype, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctype >= COND_EQ && ctype <= COND_GE) {
|
||||||
|
mnumber mn1, mn2;
|
||||||
|
mn1 = matheval(left);
|
||||||
|
mn2 = matheval(right);
|
||||||
|
|
||||||
|
if (((mn1.type|mn2.type) & (MN_INTEGER|MN_FLOAT)) ==
|
||||||
|
(MN_INTEGER|MN_FLOAT)) {
|
||||||
|
/* promote to float */
|
||||||
|
if (mn1.type & MN_INTEGER) {
|
||||||
|
mn1.type = MN_FLOAT;
|
||||||
|
mn1.u.d = (double)mn1.u.l;
|
||||||
|
}
|
||||||
|
if (mn2.type & MN_INTEGER) {
|
||||||
|
mn2.type = MN_FLOAT;
|
||||||
|
mn2.u.d = (double)mn2.u.l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(ctype) {
|
||||||
|
case COND_EQ:
|
||||||
|
return (mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) :
|
||||||
|
(mn1.u.l == mn2.u.l);
|
||||||
|
case COND_NE:
|
||||||
|
return (mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) :
|
||||||
|
(mn1.u.l != mn2.u.l);
|
||||||
|
case COND_LT:
|
||||||
|
return (mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) :
|
||||||
|
(mn1.u.l < mn2.u.l);
|
||||||
|
case COND_GT:
|
||||||
|
return (mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) :
|
||||||
|
(mn1.u.l > mn2.u.l);
|
||||||
|
case COND_LE:
|
||||||
|
return (mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) :
|
||||||
|
(mn1.u.l <= mn2.u.l);
|
||||||
|
case COND_GE:
|
||||||
|
return (mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) :
|
||||||
|
(mn1.u.l >= mn2.u.l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctype) {
|
||||||
case COND_STREQ:
|
case COND_STREQ:
|
||||||
return matchpat(c->left, c->right);
|
|
||||||
case COND_STRNEQ:
|
case COND_STRNEQ:
|
||||||
return !matchpat(c->left, c->right);
|
{
|
||||||
|
int test, npat = state->pc[1];
|
||||||
|
Patprog pprog = state->prog->pats[npat];
|
||||||
|
|
||||||
|
if (pprog == dummy_patprog1 || pprog == dummy_patprog2) {
|
||||||
|
char *opat;
|
||||||
|
int save;
|
||||||
|
|
||||||
|
right = opat = dupstring(ecrawstr(state->prog, state->pc,
|
||||||
|
&htok));
|
||||||
|
if (htok)
|
||||||
|
singsub(&right);
|
||||||
|
save = (!(state->prog->flags & EF_HEAP) &&
|
||||||
|
!strcmp(opat, right) && pprog != dummy_patprog2);
|
||||||
|
|
||||||
|
if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC),
|
||||||
|
NULL)))
|
||||||
|
zerr("bad pattern: %s", right, 0);
|
||||||
|
else if (save)
|
||||||
|
state->prog->pats[npat] = pprog;
|
||||||
|
}
|
||||||
|
state->pc += 2;
|
||||||
|
test = (pprog && pattry(pprog, left));
|
||||||
|
|
||||||
|
return (ctype == COND_STREQ ? test : !test);
|
||||||
|
}
|
||||||
case COND_STRLT:
|
case COND_STRLT:
|
||||||
return strcmp(c->left, c->right) < 0;
|
return strcmp(left, right) < 0;
|
||||||
case COND_STRGTR:
|
case COND_STRGTR:
|
||||||
return strcmp(c->left, c->right) > 0;
|
return strcmp(left, right) > 0;
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'a':
|
case 'a':
|
||||||
return (doaccess(c->left, F_OK));
|
return (doaccess(left, F_OK));
|
||||||
case 'b':
|
case 'b':
|
||||||
return (S_ISBLK(dostat(c->left)));
|
return (S_ISBLK(dostat(left)));
|
||||||
case 'c':
|
case 'c':
|
||||||
return (S_ISCHR(dostat(c->left)));
|
return (S_ISCHR(dostat(left)));
|
||||||
case 'd':
|
case 'd':
|
||||||
return (S_ISDIR(dostat(c->left)));
|
return (S_ISDIR(dostat(left)));
|
||||||
case 'f':
|
case 'f':
|
||||||
return (S_ISREG(dostat(c->left)));
|
return (S_ISREG(dostat(left)));
|
||||||
case 'g':
|
case 'g':
|
||||||
return (!!(dostat(c->left) & S_ISGID));
|
return (!!(dostat(left) & S_ISGID));
|
||||||
case 'k':
|
case 'k':
|
||||||
return (!!(dostat(c->left) & S_ISVTX));
|
return (!!(dostat(left) & S_ISVTX));
|
||||||
case 'n':
|
case 'n':
|
||||||
return (!!strlen(c->left));
|
return (!!strlen(left));
|
||||||
case 'o':
|
case 'o':
|
||||||
return (optison(c->left));
|
return (optison(left));
|
||||||
case 'p':
|
case 'p':
|
||||||
return (S_ISFIFO(dostat(c->left)));
|
return (S_ISFIFO(dostat(left)));
|
||||||
case 'r':
|
case 'r':
|
||||||
return (doaccess(c->left, R_OK));
|
return (doaccess(left, R_OK));
|
||||||
case 's':
|
case 's':
|
||||||
return ((st = getstat(c->left)) && !!(st->st_size));
|
return ((st = getstat(left)) && !!(st->st_size));
|
||||||
case 'S':
|
case 'S':
|
||||||
return (S_ISSOCK(dostat(c->left)));
|
return (S_ISSOCK(dostat(left)));
|
||||||
case 'u':
|
case 'u':
|
||||||
return (!!(dostat(c->left) & S_ISUID));
|
return (!!(dostat(left) & S_ISUID));
|
||||||
case 'w':
|
case 'w':
|
||||||
return (doaccess(c->left, W_OK));
|
return (doaccess(left, W_OK));
|
||||||
case 'x':
|
case 'x':
|
||||||
if (privasserted()) {
|
if (privasserted()) {
|
||||||
mode_t mode = dostat(c->left);
|
mode_t mode = dostat(left);
|
||||||
return (mode & S_IXUGO) || S_ISDIR(mode);
|
return (mode & S_IXUGO) || S_ISDIR(mode);
|
||||||
}
|
}
|
||||||
return doaccess(c->left, X_OK);
|
return doaccess(left, X_OK);
|
||||||
case 'z':
|
case 'z':
|
||||||
return (!strlen(c->left));
|
return (!strlen(left));
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'L':
|
case 'L':
|
||||||
return (S_ISLNK(dolstat(c->left)));
|
return (S_ISLNK(dolstat(left)));
|
||||||
case 'O':
|
case 'O':
|
||||||
return ((st = getstat(c->left)) && st->st_uid == geteuid());
|
return ((st = getstat(left)) && st->st_uid == geteuid());
|
||||||
case 'G':
|
case 'G':
|
||||||
return ((st = getstat(c->left)) && st->st_gid == getegid());
|
return ((st = getstat(left)) && st->st_gid == getegid());
|
||||||
case 'N':
|
case 'N':
|
||||||
return ((st = getstat(c->left)) && st->st_atime <= st->st_mtime);
|
return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
|
||||||
case 't':
|
case 't':
|
||||||
return isatty(matheval(c->left));
|
return isatty(mathevali(left));
|
||||||
case COND_EQ:
|
|
||||||
return matheval(c->left) == matheval(c->right);
|
|
||||||
case COND_NE:
|
|
||||||
return matheval(c->left) != matheval(c->right);
|
|
||||||
case COND_LT:
|
|
||||||
return matheval(c->left) < matheval(c->right);
|
|
||||||
case COND_GT:
|
|
||||||
return matheval(c->left) > matheval(c->right);
|
|
||||||
case COND_LE:
|
|
||||||
return matheval(c->left) <= matheval(c->right);
|
|
||||||
case COND_GE:
|
|
||||||
return matheval(c->left) >= matheval(c->right);
|
|
||||||
case COND_NT:
|
case COND_NT:
|
||||||
case COND_OT:
|
case COND_OT:
|
||||||
{
|
{
|
||||||
time_t a;
|
time_t a;
|
||||||
|
|
||||||
if (!(st = getstat(c->left)))
|
if (!(st = getstat(left)))
|
||||||
return 0;
|
return 0;
|
||||||
a = st->st_mtime;
|
a = st->st_mtime;
|
||||||
if (!(st = getstat(c->right)))
|
if (!(st = getstat(right)))
|
||||||
return 0;
|
return 0;
|
||||||
return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
|
return (ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
|
||||||
}
|
}
|
||||||
case COND_EF:
|
case COND_EF:
|
||||||
{
|
{
|
||||||
dev_t d;
|
dev_t d;
|
||||||
ino_t i;
|
ino_t i;
|
||||||
|
|
||||||
if (!(st = getstat(c->left)))
|
if (!(st = getstat(left)))
|
||||||
return 0;
|
return 0;
|
||||||
d = st->st_dev;
|
d = st->st_dev;
|
||||||
i = st->st_ino;
|
i = st->st_ino;
|
||||||
if (!(st = getstat(c->right)))
|
if (!(st = getstat(right)))
|
||||||
return 0;
|
return 0;
|
||||||
return d == st->st_dev && i == st->st_ino;
|
return d == st->st_dev && i == st->st_ino;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
zerr("bad cond structure", NULL, 0);
|
zerr("bad cond code", NULL, 0);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -158,6 +310,10 @@ evalcond(Cond c)
|
||||||
static int
|
static int
|
||||||
doaccess(char *s, int c)
|
doaccess(char *s, int c)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_FACCESSX
|
||||||
|
if (!strncmp(s, "/dev/fd/", 8))
|
||||||
|
return !faccessx(atoi(s + 8), c, ACC_SELF);
|
||||||
|
#endif
|
||||||
return !access(unmeta(s), c);
|
return !access(unmeta(s), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,3 +380,59 @@ optison(char *s)
|
||||||
else
|
else
|
||||||
return isset(i);
|
return isset(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
mod_export char *
|
||||||
|
cond_str(char **args, int num, int raw)
|
||||||
|
{
|
||||||
|
char *s = args[num];
|
||||||
|
|
||||||
|
if (has_token(s)) {
|
||||||
|
singsub(&s);
|
||||||
|
if (!raw)
|
||||||
|
untokenize(s);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
mod_export zlong
|
||||||
|
cond_val(char **args, int num)
|
||||||
|
{
|
||||||
|
char *s = args[num];
|
||||||
|
|
||||||
|
if (has_token(s)) {
|
||||||
|
singsub(&s);
|
||||||
|
untokenize(s);
|
||||||
|
}
|
||||||
|
return mathevali(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
mod_export int
|
||||||
|
cond_match(char **args, int num, char *str)
|
||||||
|
{
|
||||||
|
char *s = args[num];
|
||||||
|
|
||||||
|
singsub(&s);
|
||||||
|
|
||||||
|
return matchpat(str, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static void
|
||||||
|
tracemodcond(char *name, char **args, int inf)
|
||||||
|
{
|
||||||
|
char **aptr;
|
||||||
|
|
||||||
|
args = arrdup(args);
|
||||||
|
for (aptr = args; *aptr; aptr++)
|
||||||
|
untokenize(*aptr);
|
||||||
|
if (inf) {
|
||||||
|
fprintf(xtrerr, " %s %s %s", args[0], name, args[1]);
|
||||||
|
} else {
|
||||||
|
fprintf(xtrerr, " %s", name);
|
||||||
|
while (*args)
|
||||||
|
fprintf(xtrerr, " %s", *args++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1868
Src/exec.c
1868
Src/exec.c
File diff suppressed because it is too large
Load diff
506
Src/hashtable.c
506
Src/hashtable.c
|
@ -77,13 +77,13 @@ static HashTable firstht, lastht;
|
||||||
/* Generic hash function */
|
/* Generic hash function */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
unsigned
|
mod_export unsigned
|
||||||
hasher(char *str)
|
hasher(char *str)
|
||||||
{
|
{
|
||||||
unsigned hashval = 0;
|
unsigned hashval = 0, c;
|
||||||
|
|
||||||
while (*str)
|
while ((c = *((unsigned char *) str++)))
|
||||||
hashval += (hashval << 5) + ((unsigned) *str++);
|
hashval += (hashval << 5) + c;
|
||||||
|
|
||||||
return hashval;
|
return hashval;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ hasher(char *str)
|
||||||
/* Get a new hash table */
|
/* Get a new hash table */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashTable
|
mod_export HashTable
|
||||||
newhashtable(int size, char const *name, PrintTableStats printinfo)
|
newhashtable(int size, char const *name, PrintTableStats printinfo)
|
||||||
{
|
{
|
||||||
HashTable ht;
|
HashTable ht;
|
||||||
|
@ -112,6 +112,7 @@ newhashtable(int size, char const *name, PrintTableStats printinfo)
|
||||||
ht->hsize = size;
|
ht->hsize = size;
|
||||||
ht->ct = 0;
|
ht->ct = 0;
|
||||||
ht->scan = NULL;
|
ht->scan = NULL;
|
||||||
|
ht->scantab = NULL;
|
||||||
return ht;
|
return ht;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +120,7 @@ newhashtable(int size, char const *name, PrintTableStats printinfo)
|
||||||
* existing pointers to the hash table are invalid. */
|
* existing pointers to the hash table are invalid. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
deletehashtable(HashTable ht)
|
deletehashtable(HashTable ht)
|
||||||
{
|
{
|
||||||
ht->emptytable(ht);
|
ht->emptytable(ht);
|
||||||
|
@ -132,13 +133,14 @@ deletehashtable(HashTable ht)
|
||||||
ht->last->next = ht->next;
|
ht->last->next = ht->next;
|
||||||
else
|
else
|
||||||
firstht = ht->next;
|
firstht = ht->next;
|
||||||
|
zsfree(ht->tablename);
|
||||||
#endif /* ZSH_HASH_DEBUG */
|
#endif /* ZSH_HASH_DEBUG */
|
||||||
zfree(ht->nodes, ht->hsize * sizeof(HashNode));
|
zfree(ht->nodes, ht->hsize * sizeof(HashNode));
|
||||||
zfree(ht, sizeof(*ht));
|
zfree(ht, sizeof(*ht));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a node to a hash table. *
|
/* 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 *
|
* to the node to add. If there is already a node in *
|
||||||
* the table with the same key, it is first freed, and *
|
* the table with the same key, it is first freed, and *
|
||||||
* then the new node is added. If the number of nodes *
|
* then the new node is added. If the number of nodes *
|
||||||
|
@ -146,8 +148,19 @@ deletehashtable(HashTable ht)
|
||||||
* the table is then expanded. */
|
* the table is then expanded. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
addhashnode(HashTable ht, char *nam, void *nodeptr)
|
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;
|
unsigned hashval;
|
||||||
HashNode hn, hp, hq;
|
HashNode hn, hp, hq;
|
||||||
|
@ -164,15 +177,15 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
||||||
ht->nodes[hashval] = hn;
|
ht->nodes[hashval] = hn;
|
||||||
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
|
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
|
||||||
expandhashtable(ht);
|
expandhashtable(ht);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* else check if the first node contains the same key */
|
/* 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;
|
ht->nodes[hashval] = hn;
|
||||||
replacing:
|
replacing:
|
||||||
hn->next = hp->next;
|
hn->next = hp->next;
|
||||||
if(ht->scan)
|
if(ht->scan) {
|
||||||
if(ht->scan->sorted) {
|
if(ht->scan->sorted) {
|
||||||
HashNode *tab = ht->scan->u.s.tab;
|
HashNode *tab = ht->scan->u.s.tab;
|
||||||
int i;
|
int i;
|
||||||
|
@ -181,15 +194,15 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
||||||
tab[i] = hn;
|
tab[i] = hn;
|
||||||
} else if(ht->scan->u.u == hp)
|
} else if(ht->scan->u.u == hp)
|
||||||
ht->scan->u.u = hn;
|
ht->scan->u.u = hn;
|
||||||
ht->freenode(hp);
|
}
|
||||||
return;
|
return hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* else run through the list and check all the keys */
|
/* else run through the list and check all the keys */
|
||||||
hq = hp;
|
hq = hp;
|
||||||
hp = hp->next;
|
hp = hp->next;
|
||||||
for (; hp; 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;
|
hq->next = hn;
|
||||||
goto replacing;
|
goto replacing;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +213,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
||||||
ht->nodes[hashval] = hn;
|
ht->nodes[hashval] = hn;
|
||||||
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
|
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
|
||||||
expandhashtable(ht);
|
expandhashtable(ht);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get an enabled entry in a hash table. *
|
/* Get an enabled entry in a hash table. *
|
||||||
|
@ -208,7 +222,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
||||||
* or isn't found, it returns NULL */
|
* or isn't found, it returns NULL */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashNode
|
mod_export HashNode
|
||||||
gethashnode(HashTable ht, char *nam)
|
gethashnode(HashTable ht, char *nam)
|
||||||
{
|
{
|
||||||
unsigned hashval;
|
unsigned hashval;
|
||||||
|
@ -216,7 +230,7 @@ gethashnode(HashTable ht, char *nam)
|
||||||
|
|
||||||
hashval = ht->hash(nam) % ht->hsize;
|
hashval = ht->hash(nam) % ht->hsize;
|
||||||
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
|
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)
|
if (hp->flags & DISABLED)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
|
@ -232,7 +246,7 @@ gethashnode(HashTable ht, char *nam)
|
||||||
* it returns NULL. */
|
* it returns NULL. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashNode
|
mod_export HashNode
|
||||||
gethashnode2(HashTable ht, char *nam)
|
gethashnode2(HashTable ht, char *nam)
|
||||||
{
|
{
|
||||||
unsigned hashval;
|
unsigned hashval;
|
||||||
|
@ -240,7 +254,7 @@ gethashnode2(HashTable ht, char *nam)
|
||||||
|
|
||||||
hashval = ht->hash(nam) % ht->hsize;
|
hashval = ht->hash(nam) % ht->hsize;
|
||||||
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
|
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
|
||||||
if (!strcmp(hp->nam, nam))
|
if (ht->cmpnodes(hp->nam, nam) == 0)
|
||||||
return hp;
|
return hp;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -252,7 +266,7 @@ gethashnode2(HashTable ht, char *nam)
|
||||||
* is no such node, then it returns NULL */
|
* is no such node, then it returns NULL */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashNode
|
mod_export HashNode
|
||||||
removehashnode(HashTable ht, char *nam)
|
removehashnode(HashTable ht, char *nam)
|
||||||
{
|
{
|
||||||
unsigned hashval;
|
unsigned hashval;
|
||||||
|
@ -266,11 +280,11 @@ removehashnode(HashTable ht, char *nam)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* else check if the key in the first one matches */
|
/* 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;
|
ht->nodes[hashval] = hp->next;
|
||||||
gotit:
|
gotit:
|
||||||
ht->ct--;
|
ht->ct--;
|
||||||
if(ht->scan)
|
if(ht->scan) {
|
||||||
if(ht->scan->sorted) {
|
if(ht->scan->sorted) {
|
||||||
HashNode *tab = ht->scan->u.s.tab;
|
HashNode *tab = ht->scan->u.s.tab;
|
||||||
int i;
|
int i;
|
||||||
|
@ -279,6 +293,7 @@ removehashnode(HashTable ht, char *nam)
|
||||||
tab[i] = NULL;
|
tab[i] = NULL;
|
||||||
} else if(ht->scan->u.u == hp)
|
} else if(ht->scan->u.u == hp)
|
||||||
ht->scan->u.u = hp->next;
|
ht->scan->u.u = hp->next;
|
||||||
|
}
|
||||||
return hp;
|
return hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +301,7 @@ removehashnode(HashTable ht, char *nam)
|
||||||
hq = hp;
|
hq = hp;
|
||||||
hp = hp->next;
|
hp = hp->next;
|
||||||
for (; hp; 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;
|
hq->next = hp->next;
|
||||||
goto gotit;
|
goto gotit;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +329,7 @@ enablehashnode(HashNode hn, int flags)
|
||||||
hn->flags &= ~DISABLED;
|
hn->flags &= ~DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compare two hash table entries */
|
/* Compare two hash table entries by name */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static int
|
static int
|
||||||
|
@ -343,11 +358,15 @@ hnamcmp(const void *ap, const void *bp)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfunc, int scanflags)
|
scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfunc, int scanflags)
|
||||||
{
|
{
|
||||||
struct scanstatus st;
|
struct scanstatus st;
|
||||||
|
|
||||||
|
if (ht->scantab) {
|
||||||
|
ht->scantab(ht, scanfunc, scanflags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (sorted) {
|
if (sorted) {
|
||||||
int i, ct = ht->ct;
|
int i, ct = ht->ct;
|
||||||
VARARR(HashNode, hnsorttab, ct);
|
VARARR(HashNode, hnsorttab, ct);
|
||||||
|
@ -399,7 +418,7 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
scanmatchtable(HashTable ht, Comp com, int flags1, int flags2, ScanFunc scanfunc, int scanflags)
|
scanmatchtable(HashTable ht, Patprog pprog, int flags1, int flags2, ScanFunc scanfunc, int scanflags)
|
||||||
{
|
{
|
||||||
int i, hsize = ht->hsize;
|
int i, hsize = ht->hsize;
|
||||||
HashNode *nodes = ht->nodes;
|
HashNode *nodes = ht->nodes;
|
||||||
|
@ -414,9 +433,10 @@ scanmatchtable(HashTable ht, Comp com, int flags1, int flags2, ScanFunc scanfunc
|
||||||
HashNode hn = st.u.u;
|
HashNode hn = st.u.u;
|
||||||
st.u.u = st.u.u->next;
|
st.u.u = st.u.u->next;
|
||||||
if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2) &&
|
if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2) &&
|
||||||
domatch(hn->nam, com, 0))
|
pattry(pprog, hn->nam)) {
|
||||||
scanfunc(hn, scanflags);
|
scanfunc(hn, scanflags);
|
||||||
match++;
|
match++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ht->scan = NULL;
|
ht->scan = NULL;
|
||||||
|
@ -489,12 +509,13 @@ resizehashtable(HashTable ht, int newsize)
|
||||||
/* Generic method to empty a hash table */
|
/* Generic method to empty a hash table */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
emptyhashtable(HashTable ht)
|
emptyhashtable(HashTable ht)
|
||||||
{
|
{
|
||||||
resizehashtable(ht, ht->hsize);
|
resizehashtable(ht, ht->hsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
#ifdef ZSH_HASH_DEBUG
|
#ifdef ZSH_HASH_DEBUG
|
||||||
|
|
||||||
/* Print info about hash table */
|
/* Print info about hash table */
|
||||||
|
@ -547,6 +568,7 @@ bin_hashinfo(char *nam, char **args, char *ops, int func)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
#endif /* ZSH_HASH_DEBUG */
|
#endif /* ZSH_HASH_DEBUG */
|
||||||
|
|
||||||
/********************************/
|
/********************************/
|
||||||
|
@ -556,12 +578,12 @@ bin_hashinfo(char *nam, char **args, char *ops, int func)
|
||||||
/* hash table containing external commands */
|
/* hash table containing external commands */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashTable cmdnamtab;
|
mod_export HashTable cmdnamtab;
|
||||||
|
|
||||||
/* how far we've hashed the PATH so far */
|
/* how far we've hashed the PATH so far */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
char **pathchecked;
|
mod_export char **pathchecked;
|
||||||
|
|
||||||
/* Create a new command hash table */
|
/* Create a new command hash table */
|
||||||
|
|
||||||
|
@ -574,6 +596,7 @@ createcmdnamtable(void)
|
||||||
cmdnamtab->hash = hasher;
|
cmdnamtab->hash = hasher;
|
||||||
cmdnamtab->emptytable = emptycmdnamtable;
|
cmdnamtab->emptytable = emptycmdnamtable;
|
||||||
cmdnamtab->filltable = fillcmdnamtable;
|
cmdnamtab->filltable = fillcmdnamtable;
|
||||||
|
cmdnamtab->cmpnodes = strcmp;
|
||||||
cmdnamtab->addnode = addhashnode;
|
cmdnamtab->addnode = addhashnode;
|
||||||
cmdnamtab->getnode = gethashnode2;
|
cmdnamtab->getnode = gethashnode2;
|
||||||
cmdnamtab->getnode2 = gethashnode2;
|
cmdnamtab->getnode2 = gethashnode2;
|
||||||
|
@ -604,6 +627,9 @@ hashdir(char **dirp)
|
||||||
Cmdnam cn;
|
Cmdnam cn;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
char *fn;
|
char *fn;
|
||||||
|
#ifdef _WIN32
|
||||||
|
char *exe;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp))))
|
if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp))))
|
||||||
return;
|
return;
|
||||||
|
@ -615,6 +641,23 @@ hashdir(char **dirp)
|
||||||
cn->u.name = dirp;
|
cn->u.name = dirp;
|
||||||
cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
|
cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
|
||||||
}
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Hash foo.exe as foo, since when no real foo exists, foo.exe
|
||||||
|
will get executed by DOS automatically. This quiets
|
||||||
|
spurious corrections when CORRECT or CORRECT_ALL is set. */
|
||||||
|
if ((exe = strrchr(fn, '.')) &&
|
||||||
|
(exe[1] == 'E' || exe[1] == 'e') &&
|
||||||
|
(exe[2] == 'X' || exe[2] == 'x') &&
|
||||||
|
(exe[3] == 'E' || exe[3] == 'e') && exe[4] == 0) {
|
||||||
|
*exe = 0;
|
||||||
|
if (!cmdnamtab->getnode(cmdnamtab, fn)) {
|
||||||
|
cn = (Cmdnam) zcalloc(sizeof *cn);
|
||||||
|
cn->flags = 0;
|
||||||
|
cn->u.name = dirp;
|
||||||
|
cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* _WIN32 */
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
@ -713,7 +756,7 @@ printcmdnamnode(HashNode hn, int printflags)
|
||||||
/* hash table containing the shell functions */
|
/* hash table containing the shell functions */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashTable shfunctab;
|
mod_export HashTable shfunctab;
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
void
|
||||||
|
@ -724,6 +767,7 @@ createshfunctable(void)
|
||||||
shfunctab->hash = hasher;
|
shfunctab->hash = hasher;
|
||||||
shfunctab->emptytable = NULL;
|
shfunctab->emptytable = NULL;
|
||||||
shfunctab->filltable = NULL;
|
shfunctab->filltable = NULL;
|
||||||
|
shfunctab->cmpnodes = strcmp;
|
||||||
shfunctab->addnode = addhashnode;
|
shfunctab->addnode = addhashnode;
|
||||||
shfunctab->getnode = gethashnode;
|
shfunctab->getnode = gethashnode;
|
||||||
shfunctab->getnode2 = gethashnode2;
|
shfunctab->getnode2 = gethashnode2;
|
||||||
|
@ -798,7 +842,7 @@ freeshfuncnode(HashNode hn)
|
||||||
|
|
||||||
zsfree(shf->nam);
|
zsfree(shf->nam);
|
||||||
if (shf->funcdef)
|
if (shf->funcdef)
|
||||||
freestruct(shf->funcdef);
|
freeeprog(shf->funcdef);
|
||||||
zfree(shf, sizeof(struct shfunc));
|
zfree(shf, sizeof(struct shfunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -828,21 +872,34 @@ printshfuncnode(HashNode hn, int printflags)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->flags & PM_UNDEFINED)
|
if (f->flags & PM_UNDEFINED)
|
||||||
printf("undefined ");
|
t = tricat("builtin autoload -X",
|
||||||
if (f->flags & PM_TAGGED)
|
((f->flags & PM_UNALIASED)? "U" : ""),
|
||||||
printf("traced ");
|
((f->flags & PM_TAGGED)? "t" : ""));
|
||||||
if ((f->flags & PM_UNDEFINED) || !f->funcdef) {
|
else {
|
||||||
nicezputs(f->nam, stdout);
|
if (!f->funcdef)
|
||||||
printf(" () { }\n");
|
t = 0;
|
||||||
return;
|
else
|
||||||
|
t = getpermtext(f->funcdef, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
t = getpermtext((void *) dupstruct((void *) f->funcdef));
|
|
||||||
quotedzputs(f->nam, stdout);
|
quotedzputs(f->nam, stdout);
|
||||||
printf(" () {\n\t");
|
if (t) {
|
||||||
zputs(t, stdout);
|
printf(" () {\n\t");
|
||||||
printf("\n}\n");
|
if (f->flags & PM_UNDEFINED)
|
||||||
zsfree(t);
|
printf("%c undefined\n\t", hashchar);
|
||||||
|
if (f->flags & PM_TAGGED)
|
||||||
|
printf("%c traced\n\t", hashchar);
|
||||||
|
zputs(t, stdout);
|
||||||
|
if (f->funcdef && (f->funcdef->flags & EF_RUN)) {
|
||||||
|
printf("\n\t");
|
||||||
|
quotedzputs(f->nam, stdout);
|
||||||
|
printf(" \"$@\"");
|
||||||
|
}
|
||||||
|
printf("\n}\n");
|
||||||
|
zsfree(t);
|
||||||
|
} else {
|
||||||
|
printf(" () { }\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************/
|
/**************************************/
|
||||||
|
@ -882,7 +939,7 @@ static struct reswd reswds[] = {
|
||||||
/* hash table containing the reserved words */
|
/* hash table containing the reserved words */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashTable reswdtab;
|
mod_export HashTable reswdtab;
|
||||||
|
|
||||||
/* Build the hash table containing zsh's reserved words. */
|
/* Build the hash table containing zsh's reserved words. */
|
||||||
|
|
||||||
|
@ -897,6 +954,7 @@ createreswdtable(void)
|
||||||
reswdtab->hash = hasher;
|
reswdtab->hash = hasher;
|
||||||
reswdtab->emptytable = NULL;
|
reswdtab->emptytable = NULL;
|
||||||
reswdtab->filltable = NULL;
|
reswdtab->filltable = NULL;
|
||||||
|
reswdtab->cmpnodes = strcmp;
|
||||||
reswdtab->addnode = addhashnode;
|
reswdtab->addnode = addhashnode;
|
||||||
reswdtab->getnode = gethashnode;
|
reswdtab->getnode = gethashnode;
|
||||||
reswdtab->getnode2 = gethashnode2;
|
reswdtab->getnode2 = gethashnode2;
|
||||||
|
@ -944,7 +1002,7 @@ printreswdnode(HashNode hn, int printflags)
|
||||||
/* hash table containing the aliases */
|
/* hash table containing the aliases */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashTable aliastab;
|
mod_export HashTable aliastab;
|
||||||
|
|
||||||
/* Create new hash table for aliases */
|
/* Create new hash table for aliases */
|
||||||
|
|
||||||
|
@ -957,6 +1015,7 @@ createaliastable(void)
|
||||||
aliastab->hash = hasher;
|
aliastab->hash = hasher;
|
||||||
aliastab->emptytable = NULL;
|
aliastab->emptytable = NULL;
|
||||||
aliastab->filltable = NULL;
|
aliastab->filltable = NULL;
|
||||||
|
aliastab->cmpnodes = strcmp;
|
||||||
aliastab->addnode = addhashnode;
|
aliastab->addnode = addhashnode;
|
||||||
aliastab->getnode = gethashnode;
|
aliastab->getnode = gethashnode;
|
||||||
aliastab->getnode2 = gethashnode2;
|
aliastab->getnode2 = gethashnode2;
|
||||||
|
@ -974,7 +1033,7 @@ createaliastable(void)
|
||||||
/* Create a new alias node */
|
/* Create a new alias node */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
Alias
|
mod_export Alias
|
||||||
createaliasnode(char *txt, int flags)
|
createaliasnode(char *txt, int flags)
|
||||||
{
|
{
|
||||||
Alias al;
|
Alias al;
|
||||||
|
@ -1061,101 +1120,25 @@ printaliasnode(HashNode hn, int printflags)
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************/
|
|
||||||
/* Parameter Hash Table Functions */
|
|
||||||
/**********************************/
|
|
||||||
|
|
||||||
/**/
|
|
||||||
void
|
|
||||||
freeparamnode(HashNode hn)
|
|
||||||
{
|
|
||||||
Param pm = (Param) hn;
|
|
||||||
|
|
||||||
zsfree(pm->nam);
|
|
||||||
zfree(pm, sizeof(struct param));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print a parameter */
|
|
||||||
|
|
||||||
/**/
|
|
||||||
void
|
|
||||||
printparamnode(HashNode hn, int printflags)
|
|
||||||
{
|
|
||||||
Param p = (Param) hn;
|
|
||||||
char *t, **u;
|
|
||||||
|
|
||||||
if (p->flags & PM_UNSET)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Print the attributes of the parameter */
|
|
||||||
if (printflags & PRINT_TYPE) {
|
|
||||||
if (p->flags & PM_INTEGER)
|
|
||||||
printf("integer ");
|
|
||||||
if (p->flags & PM_ARRAY)
|
|
||||||
printf("array ");
|
|
||||||
if (p->flags & PM_LEFT)
|
|
||||||
printf("left justified %d ", p->ct);
|
|
||||||
if (p->flags & PM_RIGHT_B)
|
|
||||||
printf("right justified %d ", p->ct);
|
|
||||||
if (p->flags & PM_RIGHT_Z)
|
|
||||||
printf("zero filled %d ", p->ct);
|
|
||||||
if (p->flags & PM_LOWER)
|
|
||||||
printf("lowercase ");
|
|
||||||
if (p->flags & PM_UPPER)
|
|
||||||
printf("uppercase ");
|
|
||||||
if (p->flags & PM_READONLY)
|
|
||||||
printf("readonly ");
|
|
||||||
if (p->flags & PM_TAGGED)
|
|
||||||
printf("tagged ");
|
|
||||||
if (p->flags & PM_EXPORTED)
|
|
||||||
printf("exported ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (printflags & PRINT_NAMEONLY) {
|
|
||||||
zputs(p->nam, stdout);
|
|
||||||
putchar('\n');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* How the value is displayed depends *
|
|
||||||
* on the type of the parameter */
|
|
||||||
quotedzputs(p->nam, stdout);
|
|
||||||
putchar('=');
|
|
||||||
switch (PM_TYPE(p->flags)) {
|
|
||||||
case PM_SCALAR:
|
|
||||||
/* string: simple output */
|
|
||||||
if (p->gets.cfn && (t = p->gets.cfn(p)))
|
|
||||||
quotedzputs(t, stdout);
|
|
||||||
putchar('\n');
|
|
||||||
break;
|
|
||||||
case PM_INTEGER:
|
|
||||||
/* integer */
|
|
||||||
printf("%ld\n", p->gets.ifn(p));
|
|
||||||
break;
|
|
||||||
case PM_ARRAY:
|
|
||||||
/* array */
|
|
||||||
putchar('(');
|
|
||||||
u = p->gets.afn(p);
|
|
||||||
if(*u) {
|
|
||||||
quotedzputs(*u++, stdout);
|
|
||||||
while (*u) {
|
|
||||||
putchar(' ');
|
|
||||||
quotedzputs(*u++, stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf(")\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************/
|
/****************************************/
|
||||||
/* Named Directory Hash Table Functions */
|
/* Named Directory Hash Table Functions */
|
||||||
/****************************************/
|
/****************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_NIS_PLUS
|
||||||
|
# include <rpcsvc/nis.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_NIS
|
||||||
|
# include <rpc/types.h>
|
||||||
|
# include <rpc/rpc.h>
|
||||||
|
# include <rpcsvc/ypclnt.h>
|
||||||
|
# include <rpcsvc/yp_prot.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* hash table containing named directories */
|
/* hash table containing named directories */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
HashTable nameddirtab;
|
mod_export HashTable nameddirtab;
|
||||||
|
|
||||||
/* != 0 if all the usernames have already been *
|
/* != 0 if all the usernames have already been *
|
||||||
* added to the named directory hash table. */
|
* added to the named directory hash table. */
|
||||||
|
@ -1173,6 +1156,7 @@ createnameddirtable(void)
|
||||||
nameddirtab->hash = hasher;
|
nameddirtab->hash = hasher;
|
||||||
nameddirtab->emptytable = emptynameddirtable;
|
nameddirtab->emptytable = emptynameddirtable;
|
||||||
nameddirtab->filltable = fillnameddirtable;
|
nameddirtab->filltable = fillnameddirtable;
|
||||||
|
nameddirtab->cmpnodes = strcmp;
|
||||||
nameddirtab->addnode = addnameddirnode;
|
nameddirtab->addnode = addnameddirnode;
|
||||||
nameddirtab->getnode = gethashnode;
|
nameddirtab->getnode = gethashnode;
|
||||||
nameddirtab->getnode2 = gethashnode2;
|
nameddirtab->getnode2 = gethashnode2;
|
||||||
|
@ -1200,12 +1184,122 @@ emptynameddirtable(HashTable ht)
|
||||||
/* Add all the usernames in the password file/database *
|
/* Add all the usernames in the password file/database *
|
||||||
* to the named directories table. */
|
* to the named directories table. */
|
||||||
|
|
||||||
|
#ifdef HAVE_NIS_PLUS
|
||||||
|
static int
|
||||||
|
add_userdir(nis_name table, nis_object *object, void *userdata)
|
||||||
|
{
|
||||||
|
if (object->zo_data.objdata_u.en_data.en_cols.en_cols >= 6) {
|
||||||
|
static char name[40], dir[PATH_MAX + 1];
|
||||||
|
register entry_col *ec =
|
||||||
|
object->zo_data.objdata_u.en_data.en_cols.en_cols_val;
|
||||||
|
register int nl = minimum(ec[0].ec_value.ec_value_len, 39);
|
||||||
|
register int dl = minimum(ec[5].ec_value.ec_value_len, PATH_MAX);
|
||||||
|
|
||||||
|
memcpy(name, ec[0].ec_value.ec_value_val, nl);
|
||||||
|
name[nl] = '\0';
|
||||||
|
memcpy(dir, ec[5].ec_value.ec_value_val, dl);
|
||||||
|
dir[dl] = '\0';
|
||||||
|
|
||||||
|
adduserdir(name, dir, ND_USERNAME, 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_NIS
|
||||||
|
static int
|
||||||
|
add_userdir(int status, char *key, int keylen, char *val, int vallen, char *dummy)
|
||||||
|
{
|
||||||
|
char *p, *d, *de;
|
||||||
|
|
||||||
|
if (status != YP_TRUE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (vallen > keylen && *(p = val + keylen) == ':') {
|
||||||
|
*p++ = '\0';
|
||||||
|
if ((de = strrchr(p, ':'))) {
|
||||||
|
*de = '\0';
|
||||||
|
if ((d = strrchr(p, ':'))) {
|
||||||
|
if (*++d && val[0])
|
||||||
|
adduserdir(val, d, ND_USERNAME, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
# endif /* HAVE_NIS */
|
||||||
|
#endif /* HAVE_NIS_PLUS */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static void
|
static void
|
||||||
fillnameddirtable(HashTable ht)
|
fillnameddirtable(HashTable ht)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_GETPWENT
|
|
||||||
if (!allusersadded) {
|
if (!allusersadded) {
|
||||||
|
#if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS)
|
||||||
|
FILE *pwf;
|
||||||
|
char buf[BUFSIZ], *p, *d, *de;
|
||||||
|
int skipping, oldct = nameddirtab->ct, usepwf = 1;
|
||||||
|
|
||||||
|
# ifndef HAVE_NIS_PLUS
|
||||||
|
char domain[YPMAXDOMAIN];
|
||||||
|
struct ypall_callback cb;
|
||||||
|
|
||||||
|
/* Get potential matches from NIS and cull those without local accounts */
|
||||||
|
if (getdomainname(domain, YPMAXDOMAIN) == 0) {
|
||||||
|
cb.foreach = (int (*)()) add_userdir;
|
||||||
|
cb.data = NULL;
|
||||||
|
yp_all(domain, PASSWD_MAP, &cb);
|
||||||
|
}
|
||||||
|
# else /* HAVE_NIS_PLUS */
|
||||||
|
/* Maybe we should turn this string into a #define'd constant...? */
|
||||||
|
|
||||||
|
nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH,
|
||||||
|
add_userdir, 0);
|
||||||
|
# endif
|
||||||
|
if (nameddirtab->ct == oldct) {
|
||||||
|
/* Using NIS or NIS+ didn't add any user directories. This seems
|
||||||
|
* fishy, so we fall back to using getpwent(). If we don't have
|
||||||
|
* that, we only use the passwd file. */
|
||||||
|
#ifdef HAVE_GETPWENT
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
setpwent();
|
||||||
|
|
||||||
|
/* loop through the password file/database *
|
||||||
|
* and add all entries returned. */
|
||||||
|
while ((pw = getpwent()) && !errflag)
|
||||||
|
adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1);
|
||||||
|
|
||||||
|
endpwent();
|
||||||
|
usepwf = 0;
|
||||||
|
#endif /* HAVE_GETPWENT */
|
||||||
|
}
|
||||||
|
if (usepwf) {
|
||||||
|
/* Don't forget the non-NIS matches from the flat passwd file */
|
||||||
|
if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) {
|
||||||
|
skipping = 0;
|
||||||
|
while (fgets(buf, BUFSIZ, pwf) != NULL) {
|
||||||
|
if (strchr(buf, '\n') != NULL) {
|
||||||
|
if (!skipping) {
|
||||||
|
if ((p = strchr(buf, ':')) != NULL) {
|
||||||
|
*p++ = '\0';
|
||||||
|
if ((de = strrchr(p, ':'))) {
|
||||||
|
*de = '\0';
|
||||||
|
if ((d = strrchr(p, ':'))) {
|
||||||
|
if (*++d && buf[0])
|
||||||
|
adduserdir(buf, d, ND_USERNAME, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
skipping = 0;
|
||||||
|
} else
|
||||||
|
skipping = 1;
|
||||||
|
}
|
||||||
|
fclose(pwf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else /* no NIS or NIS_PLUS */
|
||||||
|
#ifdef HAVE_GETPWENT
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
|
|
||||||
setpwent();
|
setpwent();
|
||||||
|
@ -1213,13 +1307,13 @@ fillnameddirtable(HashTable ht)
|
||||||
/* loop through the password file/database *
|
/* loop through the password file/database *
|
||||||
* and add all entries returned. */
|
* and add all entries returned. */
|
||||||
while ((pw = getpwent()) && !errflag)
|
while ((pw = getpwent()) && !errflag)
|
||||||
adduserdir(ztrdup(pw->pw_name), pw->pw_dir, ND_USERNAME, 1);
|
adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1);
|
||||||
|
|
||||||
endpwent();
|
endpwent();
|
||||||
|
#endif /* HAVE_GETPWENT */
|
||||||
|
#endif
|
||||||
allusersadded = 1;
|
allusersadded = 1;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
#endif /* HAVE_GETPWENT */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add an entry to the named directory hash *
|
/* Add an entry to the named directory hash *
|
||||||
|
@ -1283,3 +1377,137 @@ printnameddirnode(HashNode hn, int printflags)
|
||||||
quotedzputs(nd->dir, stdout);
|
quotedzputs(nd->dir, stdout);
|
||||||
putchar('\n');
|
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 != (HashNode)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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
347
Src/jobs.c
347
Src/jobs.c
|
@ -33,12 +33,12 @@
|
||||||
/* the process group of the shell */
|
/* the process group of the shell */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
pid_t mypgrp;
|
mod_export pid_t mypgrp;
|
||||||
|
|
||||||
/* the job we are working on */
|
/* the job we are working on */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int thisjob;
|
mod_export int thisjob;
|
||||||
|
|
||||||
/* the current job (+) */
|
/* the current job (+) */
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ int prevjob;
|
||||||
/* the job table */
|
/* the job table */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
struct job jobtab[MAXJOB];
|
mod_export struct job jobtab[MAXJOB];
|
||||||
|
|
||||||
/* shell timings */
|
/* shell timings */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -64,13 +64,18 @@ struct tms shtms;
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int ttyfrozen;
|
int ttyfrozen;
|
||||||
|
|
||||||
/* empty job structure for quick clearing of jobtab entries */
|
|
||||||
|
|
||||||
static struct job zero; /* static variables are initialized to zero */
|
/* Previous values of errflag and breaks if the signal handler had to
|
||||||
|
* change them. And a flag saying if it did that. */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
int prev_errflag, prev_breaks, errbrk_saved;
|
||||||
|
|
||||||
static struct timeval dtimeval, now;
|
static struct timeval dtimeval, now;
|
||||||
|
|
||||||
|
/**/
|
||||||
|
int numpipestats, pipestats[MAX_PIPESTATS];
|
||||||
|
|
||||||
/* Diff two timevals for elapsed-time computations */
|
/* Diff two timevals for elapsed-time computations */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -96,9 +101,13 @@ makerunning(Job jn)
|
||||||
|
|
||||||
jn->stat &= ~STAT_STOPPED;
|
jn->stat &= ~STAT_STOPPED;
|
||||||
for (pn = jn->procs; pn; pn = pn->next)
|
for (pn = jn->procs; pn; pn = pn->next)
|
||||||
|
#if 0
|
||||||
if (WIFSTOPPED(pn->status) &&
|
if (WIFSTOPPED(pn->status) &&
|
||||||
(!(jn->stat & STAT_SUPERJOB) || pn->next))
|
(!(jn->stat & STAT_SUPERJOB) || pn->next))
|
||||||
pn->status = SP_RUNNING;
|
pn->status = SP_RUNNING;
|
||||||
|
#endif
|
||||||
|
if (WIFSTOPPED(pn->status))
|
||||||
|
pn->status = SP_RUNNING;
|
||||||
|
|
||||||
if (jn->stat & STAT_SUPERJOB)
|
if (jn->stat & STAT_SUPERJOB)
|
||||||
makerunning(jobtab + jn->other);
|
makerunning(jobtab + jn->other);
|
||||||
|
@ -125,6 +134,86 @@ findproc(pid_t pid, Job *jptr, Process *pptr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find the super-job of a sub-job. */
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
super_job(int sub)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < MAXJOB; i++)
|
||||||
|
if ((jobtab[i].stat & STAT_SUPERJOB) &&
|
||||||
|
jobtab[i].other == sub &&
|
||||||
|
jobtab[i].gleader)
|
||||||
|
return i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
static int
|
||||||
|
handle_sub(int job, int fg)
|
||||||
|
{
|
||||||
|
Job jn = jobtab + job, sj = jobtab + jn->other;
|
||||||
|
|
||||||
|
if ((sj->stat & STAT_DONE) || !sj->procs) {
|
||||||
|
struct process *p;
|
||||||
|
|
||||||
|
for (p = sj->procs; p; p = p->next)
|
||||||
|
if (WIFSIGNALED(p->status)) {
|
||||||
|
if (jn->gleader != mypgrp && jn->procs->next)
|
||||||
|
killpg(jn->gleader, WTERMSIG(p->status));
|
||||||
|
else
|
||||||
|
kill(jn->procs->pid, WTERMSIG(p->status));
|
||||||
|
kill(sj->other, SIGCONT);
|
||||||
|
kill(sj->other, WTERMSIG(p->status));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!p) {
|
||||||
|
int cp;
|
||||||
|
|
||||||
|
jn->stat &= ~STAT_SUPERJOB;
|
||||||
|
jn->stat |= STAT_WASSUPER;
|
||||||
|
|
||||||
|
if ((cp = ((WIFEXITED(jn->procs->status) ||
|
||||||
|
WIFSIGNALED(jn->procs->status)) &&
|
||||||
|
killpg(jn->gleader, 0) == -1))) {
|
||||||
|
Process p;
|
||||||
|
for (p = jn->procs; p->next; p = p->next);
|
||||||
|
jn->gleader = p->pid;
|
||||||
|
}
|
||||||
|
/* This deleted the job too early if the parent
|
||||||
|
shell waited for a command in a list that will
|
||||||
|
be executed by the sub-shell (e.g.: if we have
|
||||||
|
`ls|if true;then sleep 20;cat;fi' and ^Z the
|
||||||
|
sleep, the rest will be executed by a sub-shell,
|
||||||
|
but the parent shell gets notified for the
|
||||||
|
sleep.
|
||||||
|
deletejob(sj); */
|
||||||
|
/* If this super-job contains only the sub-shell,
|
||||||
|
we have to attach the tty to its process group
|
||||||
|
now. */
|
||||||
|
if ((fg || thisjob == job) &&
|
||||||
|
(!jn->procs->next || cp || jn->procs->pid != jn->gleader))
|
||||||
|
attachtty(jn->gleader);
|
||||||
|
kill(sj->other, SIGCONT);
|
||||||
|
}
|
||||||
|
curjob = jn - jobtab;
|
||||||
|
} else if (sj->stat & STAT_STOPPED) {
|
||||||
|
struct process *p;
|
||||||
|
|
||||||
|
jn->stat |= STAT_STOPPED;
|
||||||
|
for (p = jn->procs; p; p = p->next)
|
||||||
|
if (p->status == SP_RUNNING ||
|
||||||
|
(!WIFEXITED(p->status) && !WIFSIGNALED(p->status)))
|
||||||
|
p->status = sj->procs->status;
|
||||||
|
curjob = jn - jobtab;
|
||||||
|
printjob(jn, !!isset(LONGLISTJOBS), 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update status of process that we have just WAIT'ed for */
|
/* Update status of process that we have just WAIT'ed for */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -175,16 +264,31 @@ update_job(Job jn)
|
||||||
jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
|
jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
|
||||||
gettyinfo(jn->ty);
|
gettyinfo(jn->ty);
|
||||||
}
|
}
|
||||||
if (jn->stat & STAT_STOPPED)
|
if (jn->stat & STAT_STOPPED) {
|
||||||
|
if (jn->stat & STAT_SUBJOB) {
|
||||||
|
/* If we have `cat foo|while read a; grep $a bar;done'
|
||||||
|
* and have hit ^Z, the sub-job is stopped, but the
|
||||||
|
* super-job may still be running, waiting to be stopped
|
||||||
|
* or to exit. So we have to send it a SIGTSTP. */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((i = super_job(job)))
|
||||||
|
killpg(jobtab[i].gleader, SIGTSTP);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else { /* job is done, so remember return value */
|
}
|
||||||
|
}
|
||||||
|
{ /* job is done or stopped, remember return value */
|
||||||
lastval2 = val;
|
lastval2 = val;
|
||||||
/* If last process was run in the current shell, keep old status
|
/* 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)) {
|
if (jn->stat & STAT_CURSH)
|
||||||
lastval = val;
|
inforeground = 1;
|
||||||
inforeground = 1;
|
else if (job == thisjob) {
|
||||||
|
lastval = val;
|
||||||
|
inforeground = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,15 +302,72 @@ update_job(Job jn)
|
||||||
/* is this job in the foreground of an interactive shell? */
|
/* is this job in the foreground of an interactive shell? */
|
||||||
if (mypgrp != pgrp && inforeground &&
|
if (mypgrp != pgrp && inforeground &&
|
||||||
(jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
|
(jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
|
||||||
attachtty(mypgrp);
|
if (list_pipe) {
|
||||||
adjustwinsize(); /* check window size and adjust if necessary */
|
if (somestopped || (pgrp > 1 && kill(-pgrp, 0) == -1)) {
|
||||||
|
attachtty(mypgrp);
|
||||||
|
/* check window size and adjust if necessary */
|
||||||
|
adjustwinsize(0);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
/* If we have `foo|while true; (( x++ )); done', and hit
|
||||||
|
* ^C, we have to stop the loop, too. */
|
||||||
|
if ((val & 0200) && inforeground == 1) {
|
||||||
|
if (!errbrk_saved) {
|
||||||
|
errbrk_saved = 1;
|
||||||
|
prev_breaks = breaks;
|
||||||
|
prev_errflag = errflag;
|
||||||
|
}
|
||||||
|
breaks = loops;
|
||||||
|
errflag = 1;
|
||||||
|
inerrflush();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
attachtty(mypgrp);
|
||||||
|
/* check window size and adjust if necessary */
|
||||||
|
adjustwinsize(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (list_pipe && (val & 0200) && inforeground == 1) {
|
||||||
|
if (!errbrk_saved) {
|
||||||
|
errbrk_saved = 1;
|
||||||
|
prev_breaks = breaks;
|
||||||
|
prev_errflag = errflag;
|
||||||
|
}
|
||||||
|
breaks = loops;
|
||||||
|
errflag = 1;
|
||||||
|
inerrflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (somestopped && jn->stat & STAT_SUPERJOB)
|
if (somestopped && jn->stat & STAT_SUPERJOB)
|
||||||
return;
|
return;
|
||||||
jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
|
jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
|
||||||
STAT_CHANGED | STAT_DONE;
|
STAT_CHANGED | STAT_DONE;
|
||||||
|
if (job == thisjob && (jn->stat & STAT_DONE)) {
|
||||||
|
int i;
|
||||||
|
Process p;
|
||||||
|
|
||||||
|
for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++)
|
||||||
|
pipestats[i] = ((WIFSIGNALED(p->status)) ?
|
||||||
|
0200 | WTERMSIG(p->status) :
|
||||||
|
WEXITSTATUS(p->status));
|
||||||
|
if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS)
|
||||||
|
pipestats[i++] = lastval;
|
||||||
|
numpipestats = i;
|
||||||
|
}
|
||||||
|
if (!inforeground &&
|
||||||
|
(jn->stat & (STAT_SUBJOB | STAT_DONE)) == (STAT_SUBJOB | STAT_DONE)) {
|
||||||
|
int su;
|
||||||
|
|
||||||
|
if ((su = super_job(jn - jobtab)))
|
||||||
|
handle_sub(su, 0);
|
||||||
|
}
|
||||||
if ((jn->stat & (STAT_DONE | STAT_STOPPED)) == STAT_STOPPED) {
|
if ((jn->stat & (STAT_DONE | STAT_STOPPED)) == STAT_STOPPED) {
|
||||||
prevjob = curjob;
|
prevjob = curjob;
|
||||||
curjob = job;
|
curjob = job;
|
||||||
|
@ -214,7 +375,7 @@ update_job(Job jn)
|
||||||
if ((isset(NOTIFY) || job == thisjob) && (jn->stat & STAT_LOCKED)) {
|
if ((isset(NOTIFY) || job == thisjob) && (jn->stat & STAT_LOCKED)) {
|
||||||
printjob(jn, !!isset(LONGLISTJOBS), 0);
|
printjob(jn, !!isset(LONGLISTJOBS), 0);
|
||||||
if (zleactive)
|
if (zleactive)
|
||||||
refresh();
|
zrefresh();
|
||||||
}
|
}
|
||||||
if (sigtrapped[SIGCHLD] && job != thisjob)
|
if (sigtrapped[SIGCHLD] && job != thisjob)
|
||||||
dotrap(SIGCHLD);
|
dotrap(SIGCHLD);
|
||||||
|
@ -223,7 +384,7 @@ update_job(Job jn)
|
||||||
* process group from the shell, so the shell will not receive *
|
* process group from the shell, so the shell will not receive *
|
||||||
* terminal signals, therefore we we pretend that the shell got *
|
* terminal signals, therefore we we pretend that the shell got *
|
||||||
* the signal too. */
|
* the signal too. */
|
||||||
if (inforeground && isset(MONITOR) && WIFSIGNALED(status)) {
|
if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) {
|
||||||
int sig = WTERMSIG(status);
|
int sig = WTERMSIG(status);
|
||||||
|
|
||||||
if (sig == SIGINT || sig == SIGQUIT) {
|
if (sig == SIGINT || sig == SIGQUIT) {
|
||||||
|
@ -256,13 +417,14 @@ setprevjob(void)
|
||||||
|
|
||||||
for (i = MAXJOB - 1; i; i--)
|
for (i = MAXJOB - 1; i; i--)
|
||||||
if ((jobtab[i].stat & STAT_INUSE) && (jobtab[i].stat & STAT_STOPPED) &&
|
if ((jobtab[i].stat & STAT_INUSE) && (jobtab[i].stat & STAT_STOPPED) &&
|
||||||
i != curjob && i != thisjob) {
|
!(jobtab[i].stat & STAT_SUBJOB) && i != curjob && i != thisjob) {
|
||||||
prevjob = i;
|
prevjob = i;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = MAXJOB - 1; i; i--)
|
for (i = MAXJOB - 1; i; i--)
|
||||||
if ((jobtab[i].stat & STAT_INUSE) && i != curjob && i != thisjob) {
|
if ((jobtab[i].stat & STAT_INUSE) && !(jobtab[i].stat & STAT_SUBJOB) &&
|
||||||
|
i != curjob && i != thisjob) {
|
||||||
prevjob = i;
|
prevjob = i;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -409,6 +571,7 @@ dumptime(Job jn)
|
||||||
static int
|
static int
|
||||||
should_report_time(Job j)
|
should_report_time(Job j)
|
||||||
{
|
{
|
||||||
|
struct value vbuf;
|
||||||
Value v;
|
Value v;
|
||||||
char *s = "REPORTTIME";
|
char *s = "REPORTTIME";
|
||||||
int reporttime;
|
int reporttime;
|
||||||
|
@ -417,9 +580,10 @@ should_report_time(Job j)
|
||||||
if (j->stat & STAT_TIMED)
|
if (j->stat & STAT_TIMED)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!(v = getvalue(&s, 0)) || (reporttime = getintvalue(v)) < 0)
|
if (!(v = getvalue(&vbuf, &s, 0)) ||
|
||||||
|
(reporttime = getintvalue(v)) < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
/* can this ever happen? */
|
/* can this ever happen? */
|
||||||
if (!j->procs)
|
if (!j->procs)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -462,10 +626,10 @@ printjob(Job jn, int lng, int synch)
|
||||||
if (jn->stat & STAT_SUPERJOB &&
|
if (jn->stat & STAT_SUPERJOB &&
|
||||||
jn->procs->status == SP_RUNNING && !pn->next)
|
jn->procs->status == SP_RUNNING && !pn->next)
|
||||||
pn->status = SP_RUNNING;
|
pn->status = SP_RUNNING;
|
||||||
if (pn->status != SP_RUNNING)
|
if (pn->status != SP_RUNNING) {
|
||||||
if (WIFSIGNALED(pn->status)) {
|
if (WIFSIGNALED(pn->status)) {
|
||||||
sig = WTERMSIG(pn->status);
|
sig = WTERMSIG(pn->status);
|
||||||
llen = strlen(sigmsg[sig]);
|
llen = strlen(sigmsg(sig));
|
||||||
if (WCOREDUMP(pn->status))
|
if (WCOREDUMP(pn->status))
|
||||||
llen += 14;
|
llen += 14;
|
||||||
if (llen > len)
|
if (llen > len)
|
||||||
|
@ -476,13 +640,14 @@ printjob(Job jn, int lng, int synch)
|
||||||
doputnl = 1;
|
doputnl = 1;
|
||||||
} else if (WIFSTOPPED(pn->status)) {
|
} else if (WIFSTOPPED(pn->status)) {
|
||||||
sig = WSTOPSIG(pn->status);
|
sig = WSTOPSIG(pn->status);
|
||||||
if ((int)strlen(sigmsg[sig]) > len)
|
if ((int)strlen(sigmsg(sig)) > len)
|
||||||
len = strlen(sigmsg[sig]);
|
len = strlen(sigmsg(sig));
|
||||||
if (job == thisjob && sig == SIGTSTP)
|
if (job == thisjob && sig == SIGTSTP)
|
||||||
doputnl = 1;
|
doputnl = 1;
|
||||||
} else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
|
} else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
|
||||||
WEXITSTATUS(pn->status))
|
WEXITSTATUS(pn->status))
|
||||||
sflag = 1;
|
sflag = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print if necessary */
|
/* print if necessary */
|
||||||
|
@ -508,7 +673,7 @@ printjob(Job jn, int lng, int synch)
|
||||||
break;
|
break;
|
||||||
len2 += strlen(qn->text) + 2;
|
len2 += strlen(qn->text) + 2;
|
||||||
}
|
}
|
||||||
if (job != thisjob)
|
if (job != thisjob) {
|
||||||
if (fline)
|
if (fline)
|
||||||
fprintf(fout, "[%ld] %c ",
|
fprintf(fout, "[%ld] %c ",
|
||||||
(long)(jn - jobtab),
|
(long)(jn - jobtab),
|
||||||
|
@ -516,7 +681,7 @@ printjob(Job jn, int lng, int synch)
|
||||||
: (job == prevjob) ? '-' : ' ');
|
: (job == prevjob) ? '-' : ' ');
|
||||||
else
|
else
|
||||||
fprintf(fout, (job > 9) ? " " : " ");
|
fprintf(fout, (job > 9) ? " " : " ");
|
||||||
else
|
} else
|
||||||
fprintf(fout, "zsh: ");
|
fprintf(fout, "zsh: ");
|
||||||
if (lng & 1)
|
if (lng & 1)
|
||||||
fprintf(fout, "%ld ", (long) pn->pid);
|
fprintf(fout, "%ld ", (long) pn->pid);
|
||||||
|
@ -531,25 +696,26 @@ printjob(Job jn, int lng, int synch)
|
||||||
lng &= ~3;
|
lng &= ~3;
|
||||||
} else
|
} else
|
||||||
fprintf(fout, "%*s", skip, "");
|
fprintf(fout, "%*s", skip, "");
|
||||||
if (pn->status == SP_RUNNING)
|
if (pn->status == SP_RUNNING) {
|
||||||
if (!conted)
|
if (!conted)
|
||||||
fprintf(fout, "running%*s", len - 7 + 2, "");
|
fprintf(fout, "running%*s", len - 7 + 2, "");
|
||||||
else
|
else
|
||||||
fprintf(fout, "continued%*s", len - 9 + 2, "");
|
fprintf(fout, "continued%*s", len - 9 + 2, "");
|
||||||
else if (WIFEXITED(pn->status))
|
}
|
||||||
|
else if (WIFEXITED(pn->status)) {
|
||||||
if (WEXITSTATUS(pn->status))
|
if (WEXITSTATUS(pn->status))
|
||||||
fprintf(fout, "exit %-4d%*s", WEXITSTATUS(pn->status),
|
fprintf(fout, "exit %-4d%*s", WEXITSTATUS(pn->status),
|
||||||
len - 9 + 2, "");
|
len - 9 + 2, "");
|
||||||
else
|
else
|
||||||
fprintf(fout, "done%*s", len - 4 + 2, "");
|
fprintf(fout, "done%*s", len - 4 + 2, "");
|
||||||
else if (WIFSTOPPED(pn->status))
|
} else if (WIFSTOPPED(pn->status))
|
||||||
fprintf(fout, "%-*s", len + 2, sigmsg[WSTOPSIG(pn->status)]);
|
fprintf(fout, "%-*s", len + 2, sigmsg(WSTOPSIG(pn->status)));
|
||||||
else if (WCOREDUMP(pn->status))
|
else if (WCOREDUMP(pn->status))
|
||||||
fprintf(fout, "%s (core dumped)%*s",
|
fprintf(fout, "%s (core dumped)%*s",
|
||||||
sigmsg[WTERMSIG(pn->status)],
|
sigmsg(WTERMSIG(pn->status)),
|
||||||
(int)(len - 14 + 2 - strlen(sigmsg[WTERMSIG(pn->status)])), "");
|
(int)(len - 14 + 2 - strlen(sigmsg(WTERMSIG(pn->status)))), "");
|
||||||
else
|
else
|
||||||
fprintf(fout, "%-*s", len + 2, sigmsg[WTERMSIG(pn->status)]);
|
fprintf(fout, "%-*s", len + 2, sigmsg(WTERMSIG(pn->status)));
|
||||||
for (; pn != qn; pn = pn->next)
|
for (; pn != qn; pn = pn->next)
|
||||||
fprintf(fout, (pn->next) ? "%s | " : "%s", pn->text);
|
fprintf(fout, (pn->next) ? "%s | " : "%s", pn->text);
|
||||||
putc('\n', fout);
|
putc('\n', fout);
|
||||||
|
@ -565,7 +731,8 @@ printjob(Job jn, int lng, int synch)
|
||||||
* the directory where the job is running, otherwise the current directory
|
* the directory where the job is running, otherwise the current directory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((lng & 4) || (interact && job == thisjob && strcmp(jn->pwd, pwd))) {
|
if ((lng & 4) || (interact && job == thisjob &&
|
||||||
|
jn->pwd && strcmp(jn->pwd, pwd))) {
|
||||||
fprintf(shout, "(pwd %s: ", (lng & 4) ? "" : "now");
|
fprintf(shout, "(pwd %s: ", (lng & 4) ? "" : "now");
|
||||||
fprintdir((lng & 4) ? jn->pwd : pwd, shout);
|
fprintdir((lng & 4) ? jn->pwd : pwd, shout);
|
||||||
fprintf(shout, ")\n");
|
fprintf(shout, ")\n");
|
||||||
|
@ -607,20 +774,31 @@ deletejob(Job jn)
|
||||||
{
|
{
|
||||||
struct process *pn, *nx;
|
struct process *pn, *nx;
|
||||||
|
|
||||||
|
if (jn->stat & STAT_ATTACH) {
|
||||||
|
attachtty(mypgrp);
|
||||||
|
adjustwinsize(0);
|
||||||
|
}
|
||||||
|
|
||||||
pn = jn->procs;
|
pn = jn->procs;
|
||||||
jn->procs = NULL;
|
jn->procs = NULL;
|
||||||
for (; pn; pn = nx) {
|
for (; pn; pn = nx) {
|
||||||
nx = pn->next;
|
nx = pn->next;
|
||||||
zfree(pn, sizeof(struct process));
|
zfree(pn, sizeof(struct process));
|
||||||
}
|
}
|
||||||
zsfree(jn->pwd);
|
|
||||||
|
|
||||||
deletefilelist(jn->filelist);
|
deletefilelist(jn->filelist);
|
||||||
|
|
||||||
if (jn->ty)
|
if (jn->ty)
|
||||||
zfree(jn->ty, sizeof(struct ttyinfo));
|
zfree(jn->ty, sizeof(struct ttyinfo));
|
||||||
|
if (jn->pwd)
|
||||||
*jn = zero;
|
zsfree(jn->pwd);
|
||||||
|
jn->pwd = NULL;
|
||||||
|
if (jn->stat & STAT_WASSUPER)
|
||||||
|
deletejob(jobtab + jn->other);
|
||||||
|
jn->gleader = jn->other = 0;
|
||||||
|
jn->stat = jn->stty_in_env = 0;
|
||||||
|
jn->procs = NULL;
|
||||||
|
jn->filelist = NULL;
|
||||||
|
jn->ty = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add a process to the current job */
|
/* add a process to the current job */
|
||||||
|
@ -729,40 +907,20 @@ waitjob(int job, int sig)
|
||||||
what this might be. --oberon
|
what this might be. --oberon
|
||||||
|
|
||||||
errflag = 0; */
|
errflag = 0; */
|
||||||
if (jn->stat & STAT_SUPERJOB) {
|
if (subsh) {
|
||||||
Job sj = jobtab + jn->other;
|
killjb(jn, SIGCONT);
|
||||||
if (sj->stat & STAT_DONE) {
|
jn->stat &= ~STAT_STOPPED;
|
||||||
struct process *p;
|
|
||||||
|
|
||||||
for (p = sj->procs; p; p = p->next)
|
|
||||||
if (WIFSIGNALED(p->status)) {
|
|
||||||
killpg(jn->gleader, WTERMSIG(p->status));
|
|
||||||
kill(sj->other, SIGCONT);
|
|
||||||
kill(sj->other, WTERMSIG(p->status));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!p) {
|
|
||||||
jn->stat &= ~STAT_SUPERJOB;
|
|
||||||
kill(sj->other, SIGCONT);
|
|
||||||
deletejob(sj);
|
|
||||||
}
|
|
||||||
curjob = jn - jobtab;
|
|
||||||
}
|
|
||||||
else if (sj->stat & STAT_STOPPED) {
|
|
||||||
struct process *p;
|
|
||||||
|
|
||||||
jn->stat |= STAT_STOPPED;
|
|
||||||
for (p = jn->procs; p; p = p->next)
|
|
||||||
p->status = sj->procs->status;
|
|
||||||
curjob = jn - jobtab;
|
|
||||||
printjob(jn, !!isset(LONGLISTJOBS), 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (jn->stat & STAT_SUPERJOB)
|
||||||
|
if (handle_sub(jn - jobtab, 1))
|
||||||
|
break;
|
||||||
child_block();
|
child_block();
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
deletejob(jn);
|
deletejob(jn);
|
||||||
|
pipestats[0] = lastval;
|
||||||
|
numpipestats = 1;
|
||||||
|
}
|
||||||
child_unblock();
|
child_unblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,24 +930,29 @@ waitjob(int job, int sig)
|
||||||
void
|
void
|
||||||
waitjobs(void)
|
waitjobs(void)
|
||||||
{
|
{
|
||||||
waitjob(thisjob, 0);
|
Job jn = jobtab + thisjob;
|
||||||
|
|
||||||
|
if (jn->procs)
|
||||||
|
waitjob(thisjob, 0);
|
||||||
|
else {
|
||||||
|
deletejob(jn);
|
||||||
|
pipestats[0] = lastval;
|
||||||
|
numpipestats = 1;
|
||||||
|
}
|
||||||
thisjob = -1;
|
thisjob = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear job table when entering subshells */
|
/* clear job table when entering subshells */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
mod_export void
|
||||||
clearjobtab(void)
|
clearjobtab(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 1; i < MAXJOB; i++) {
|
for (i = 1; i < MAXJOB; i++)
|
||||||
if (jobtab[i].pwd)
|
|
||||||
zsfree(jobtab[i].pwd);
|
|
||||||
if (jobtab[i].ty)
|
if (jobtab[i].ty)
|
||||||
zfree(jobtab[i].ty, sizeof(struct ttyinfo));
|
zfree(jobtab[i].ty, sizeof(struct ttyinfo));
|
||||||
}
|
|
||||||
|
|
||||||
memset(jobtab, 0, sizeof(jobtab)); /* zero out table */
|
memset(jobtab, 0, sizeof(jobtab)); /* zero out table */
|
||||||
}
|
}
|
||||||
|
@ -805,7 +968,8 @@ initjob(void)
|
||||||
for (i = 1; i < MAXJOB; i++)
|
for (i = 1; i < MAXJOB; i++)
|
||||||
if (!jobtab[i].stat) {
|
if (!jobtab[i].stat) {
|
||||||
jobtab[i].stat = STAT_INUSE;
|
jobtab[i].stat = STAT_INUSE;
|
||||||
jobtab[i].pwd = ztrdup(pwd);
|
if (jobtab[i].pwd)
|
||||||
|
zsfree(jobtab[i].pwd);
|
||||||
jobtab[i].gleader = 0;
|
jobtab[i].gleader = 0;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -814,6 +978,21 @@ initjob(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**/
|
||||||
|
void
|
||||||
|
setjobpwd(void)
|
||||||
|
{
|
||||||
|
int i, l;
|
||||||
|
|
||||||
|
for (i = 1; i < MAXJOB; i++)
|
||||||
|
if (jobtab[i].stat && !jobtab[i].pwd) {
|
||||||
|
if ((l = strlen(pwd)) >= PATH_MAX)
|
||||||
|
jobtab[i].pwd = ztrdup(pwd + l - PATH_MAX);
|
||||||
|
else
|
||||||
|
jobtab[i].pwd = ztrdup(pwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* print pids for & */
|
/* print pids for & */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
@ -1071,7 +1250,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
|
||||||
/* If you immediately type "exit" after "jobs", this *
|
/* If you immediately type "exit" after "jobs", this *
|
||||||
* will prevent zexit from complaining about stopped jobs */
|
* will prevent zexit from complaining about stopped jobs */
|
||||||
stopmsg = 2;
|
stopmsg = 2;
|
||||||
if (!*argv)
|
if (!*argv) {
|
||||||
/* This block handles all of the default cases (no arguments). bg,
|
/* This block handles all of the default cases (no arguments). bg,
|
||||||
fg and disown act on the current job, and jobs and wait act on all the
|
fg and disown act on the current job, and jobs and wait act on all the
|
||||||
jobs. */
|
jobs. */
|
||||||
|
@ -1100,6 +1279,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
|
||||||
waitjob(job, SIGINT);
|
waitjob(job, SIGINT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Defaults have been handled. We now have an argument or two, or three...
|
/* Defaults have been handled. We now have an argument or two, or three...
|
||||||
In the default case for bg, fg and disown, the argument will be provided by
|
In the default case for bg, fg and disown, the argument will be provided by
|
||||||
|
@ -1157,7 +1337,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
|
||||||
/* for bg and fg -- show the job we are operating on */
|
/* for bg and fg -- show the job we are operating on */
|
||||||
printjob(jobtab + job, (stopped) ? -1 : 0, 1);
|
printjob(jobtab + job, (stopped) ? -1 : 0, 1);
|
||||||
if (func != BIN_BG) { /* fg or wait */
|
if (func != BIN_BG) { /* fg or wait */
|
||||||
if (strcmp(jobtab[job].pwd, pwd)) {
|
if (jobtab[job].pwd && strcmp(jobtab[job].pwd, pwd)) {
|
||||||
fprintf(shout, "(pwd : ");
|
fprintf(shout, "(pwd : ");
|
||||||
fprintdir(jobtab[job].pwd, shout);
|
fprintdir(jobtab[job].pwd, shout);
|
||||||
fprintf(shout, ")\n");
|
fprintf(shout, ")\n");
|
||||||
|
@ -1165,7 +1345,14 @@ bin_fg(char *name, char **argv, char *ops, int func)
|
||||||
fflush(shout);
|
fflush(shout);
|
||||||
if (func != BIN_WAIT) { /* fg */
|
if (func != BIN_WAIT) { /* fg */
|
||||||
thisjob = job;
|
thisjob = job;
|
||||||
attachtty(jobtab[job].gleader);
|
if ((jobtab[job].stat & STAT_SUPERJOB) &&
|
||||||
|
((!jobtab[job].procs->next ||
|
||||||
|
(jobtab[job].stat & STAT_SUBLEADER) ||
|
||||||
|
killpg(jobtab[job].gleader, 0) == -1)) &&
|
||||||
|
jobtab[jobtab[job].other].gleader)
|
||||||
|
attachtty(jobtab[jobtab[job].other].gleader);
|
||||||
|
else
|
||||||
|
attachtty(jobtab[job].gleader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stopped) {
|
if (stopped) {
|
||||||
|
|
380
Src/loop.c
380
Src/loop.c
|
@ -43,47 +43,79 @@ int contflag;
|
||||||
/* # of break levels */
|
/* # of break levels */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int breaks;
|
mod_export int breaks;
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
execfor(Cmd cmd)
|
execfor(Estate state, int do_exec)
|
||||||
{
|
{
|
||||||
List list;
|
Wordcode end, loop;
|
||||||
Forcmd node;
|
wordcode code = state->pc[-1];
|
||||||
char *str;
|
int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0;
|
||||||
int val;
|
char *name, *str, *cond = NULL, *advance = NULL;
|
||||||
LinkList args;
|
zlong val = 0;
|
||||||
|
LinkList args = NULL;
|
||||||
|
|
||||||
node = cmd->u.forcmd;
|
name = ecgetstr(state, EC_NODUP, NULL);
|
||||||
args = cmd->args;
|
end = state->pc + WC_FOR_SKIP(code);
|
||||||
if (node->condition) {
|
|
||||||
str = node->name;
|
if (iscond) {
|
||||||
|
str = dupstring(name);
|
||||||
singsub(&str);
|
singsub(&str);
|
||||||
|
if (isset(XTRACE)) {
|
||||||
|
char *str2 = dupstring(str);
|
||||||
|
untokenize(str2);
|
||||||
|
printprompt4();
|
||||||
|
fprintf(xtrerr, "%s\n", str2);
|
||||||
|
fflush(xtrerr);
|
||||||
|
}
|
||||||
if (!errflag)
|
if (!errflag)
|
||||||
matheval(str);
|
matheval(str);
|
||||||
if (errflag)
|
if (errflag) {
|
||||||
|
state->pc = end;
|
||||||
return lastval = errflag;
|
return lastval = errflag;
|
||||||
} else if (!node->inflag) {
|
}
|
||||||
|
cond = ecgetstr(state, EC_NODUP, &ctok);
|
||||||
|
advance = ecgetstr(state, EC_NODUP, &atok);
|
||||||
|
} else if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
|
||||||
|
int htok = 0;
|
||||||
|
|
||||||
|
if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
|
||||||
|
state->pc = end;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (htok)
|
||||||
|
execsubst(args);
|
||||||
|
} else {
|
||||||
char **x;
|
char **x;
|
||||||
|
|
||||||
args = newlinklist();
|
args = newlinklist();
|
||||||
for (x = pparams; *x; x++)
|
for (x = pparams; *x; x++)
|
||||||
addlinknode(args, ztrdup(*x));
|
addlinknode(args, dupstring(*x));
|
||||||
}
|
}
|
||||||
lastval = 0;
|
lastval = 0;
|
||||||
loops++;
|
loops++;
|
||||||
pushheap();
|
pushheap();
|
||||||
|
cmdpush(CS_FOR);
|
||||||
|
loop = state->pc;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (node->condition) {
|
if (iscond) {
|
||||||
str = dupstring(node->condition);
|
if (ctok) {
|
||||||
singsub(&str);
|
str = dupstring(cond);
|
||||||
|
singsub(&str);
|
||||||
|
} else
|
||||||
|
str = cond;
|
||||||
if (!errflag) {
|
if (!errflag) {
|
||||||
while (iblank(*str))
|
while (iblank(*str))
|
||||||
str++;
|
str++;
|
||||||
if (*str)
|
if (*str) {
|
||||||
val = matheval(str);
|
if (isset(XTRACE)) {
|
||||||
else
|
printprompt4();
|
||||||
|
fprintf(xtrerr, "%s\n", str);
|
||||||
|
fflush(xtrerr);
|
||||||
|
}
|
||||||
|
val = mathevali(str);
|
||||||
|
} else
|
||||||
val = 1;
|
val = 1;
|
||||||
}
|
}
|
||||||
if (errflag) {
|
if (errflag) {
|
||||||
|
@ -95,22 +127,36 @@ execfor(Cmd cmd)
|
||||||
if (!val)
|
if (!val)
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
str = (char *) ugetnode(args);
|
if (!args || !(str = (char *) ugetnode(args)))
|
||||||
if (!str)
|
|
||||||
break;
|
break;
|
||||||
setsparam(node->name, ztrdup(str));
|
if (isset(XTRACE)) {
|
||||||
|
printprompt4();
|
||||||
|
fprintf(xtrerr, "%s=%s\n", name, str);
|
||||||
|
fflush(xtrerr);
|
||||||
|
}
|
||||||
|
setsparam(name, ztrdup(str));
|
||||||
}
|
}
|
||||||
list = (List) dupstruct(node->list);
|
state->pc = loop;
|
||||||
execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args));
|
execlist(state, 1, do_exec && args && empty(args));
|
||||||
if (breaks) {
|
if (breaks) {
|
||||||
breaks--;
|
breaks--;
|
||||||
if (breaks || !contflag)
|
if (breaks || !contflag)
|
||||||
break;
|
break;
|
||||||
contflag = 0;
|
contflag = 0;
|
||||||
}
|
}
|
||||||
if (node->condition && !errflag) {
|
if (retflag)
|
||||||
str = dupstring(node->advance);
|
break;
|
||||||
singsub(&str);
|
if (iscond && !errflag) {
|
||||||
|
if (atok) {
|
||||||
|
str = dupstring(advance);
|
||||||
|
singsub(&str);
|
||||||
|
} else
|
||||||
|
str = advance;
|
||||||
|
if (isset(XTRACE)) {
|
||||||
|
printprompt4();
|
||||||
|
fprintf(xtrerr, "%s\n", str);
|
||||||
|
fflush(xtrerr);
|
||||||
|
}
|
||||||
if (!errflag)
|
if (!errflag)
|
||||||
matheval(str);
|
matheval(str);
|
||||||
}
|
}
|
||||||
|
@ -123,44 +169,67 @@ execfor(Cmd cmd)
|
||||||
freeheap();
|
freeheap();
|
||||||
}
|
}
|
||||||
popheap();
|
popheap();
|
||||||
|
cmdpop();
|
||||||
loops--;
|
loops--;
|
||||||
|
state->pc = end;
|
||||||
return lastval;
|
return lastval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
execselect(Cmd cmd)
|
execselect(Estate state, int do_exec)
|
||||||
{
|
{
|
||||||
List list;
|
Wordcode end, loop;
|
||||||
Forcmd node;
|
wordcode code = state->pc[-1];
|
||||||
char *str, *s;
|
char *str, *s, *name;
|
||||||
LinkList args;
|
|
||||||
LinkNode n;
|
LinkNode n;
|
||||||
int i;
|
int i, usezle;
|
||||||
FILE *inp;
|
FILE *inp;
|
||||||
|
size_t more;
|
||||||
|
LinkList args;
|
||||||
|
|
||||||
node = cmd->u.forcmd;
|
end = state->pc + WC_FOR_SKIP(code);
|
||||||
args = cmd->args;
|
name = ecgetstr(state, EC_NODUP, NULL);
|
||||||
if (!node->inflag) {
|
|
||||||
|
if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) {
|
||||||
char **x;
|
char **x;
|
||||||
|
|
||||||
args = newlinklist();
|
args = newlinklist();
|
||||||
for (x = pparams; *x; x++)
|
for (x = pparams; *x; x++)
|
||||||
addlinknode(args, ztrdup(*x));
|
addlinknode(args, dupstring(*x));
|
||||||
|
} else {
|
||||||
|
int htok = 0;
|
||||||
|
|
||||||
|
if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
|
||||||
|
state->pc = end;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (htok)
|
||||||
|
execsubst(args);
|
||||||
}
|
}
|
||||||
if (empty(args))
|
if (!args || empty(args)) {
|
||||||
|
state->pc = end;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
loops++;
|
loops++;
|
||||||
lastval = 0;
|
lastval = 0;
|
||||||
pushheap();
|
pushheap();
|
||||||
inp = fdopen(dup((SHTTY == -1) ? 0 : SHTTY), "r");
|
cmdpush(CS_SELECT);
|
||||||
selectlist(args);
|
usezle = interact && SHTTY != -1 && isset(USEZLE);
|
||||||
|
inp = fdopen(dup(usezle ? SHTTY : 0), "r");
|
||||||
|
more = selectlist(args, 0);
|
||||||
|
loop = state->pc;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (empty(bufstack)) {
|
if (empty(bufstack)) {
|
||||||
if (interact && SHTTY != -1 && isset(USEZLE)) {
|
if (usezle) {
|
||||||
|
int oef = errflag;
|
||||||
|
|
||||||
isfirstln = 1;
|
isfirstln = 1;
|
||||||
str = (char *)zleread(prompt3, NULL, 0);
|
str = (char *)zleread(prompt3, NULL, 0);
|
||||||
|
if (errflag)
|
||||||
|
str = NULL;
|
||||||
|
errflag = oef;
|
||||||
} else {
|
} else {
|
||||||
str = promptexpand(prompt3, 0, NULL, NULL);
|
str = promptexpand(prompt3, 0, NULL, NULL);
|
||||||
zputs(str, stderr);
|
zputs(str, stderr);
|
||||||
|
@ -181,7 +250,7 @@ execselect(Cmd cmd)
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
if (*str)
|
if (*str)
|
||||||
break;
|
break;
|
||||||
selectlist(args);
|
more = selectlist(args, more);
|
||||||
}
|
}
|
||||||
setsparam("REPLY", ztrdup(str));
|
setsparam("REPLY", ztrdup(str));
|
||||||
i = atoi(str);
|
i = atoi(str);
|
||||||
|
@ -194,9 +263,9 @@ execselect(Cmd cmd)
|
||||||
else
|
else
|
||||||
str = "";
|
str = "";
|
||||||
}
|
}
|
||||||
setsparam(node->name, ztrdup(str));
|
setsparam(name, ztrdup(str));
|
||||||
list = (List) dupstruct(node->list);
|
state->pc = loop;
|
||||||
execlist(list, 1, 0);
|
execlist(state, 1, 0);
|
||||||
freeheap();
|
freeheap();
|
||||||
if (breaks) {
|
if (breaks) {
|
||||||
breaks--;
|
breaks--;
|
||||||
|
@ -204,21 +273,23 @@ execselect(Cmd cmd)
|
||||||
break;
|
break;
|
||||||
contflag = 0;
|
contflag = 0;
|
||||||
}
|
}
|
||||||
if (errflag)
|
if (retflag || errflag)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
cmdpop();
|
||||||
popheap();
|
popheap();
|
||||||
fclose(inp);
|
fclose(inp);
|
||||||
loops--;
|
loops--;
|
||||||
|
state->pc = end;
|
||||||
return lastval;
|
return lastval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And this is used to print select lists. */
|
/* And this is used to print select lists. */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static void
|
size_t
|
||||||
selectlist(LinkList l)
|
selectlist(LinkList l, size_t start)
|
||||||
{
|
{
|
||||||
size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
|
size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
|
||||||
LinkNode n;
|
LinkNode n;
|
||||||
|
@ -226,7 +297,7 @@ selectlist(LinkList l)
|
||||||
|
|
||||||
trashzle();
|
trashzle();
|
||||||
ct = countlinknodes(l);
|
ct = countlinknodes(l);
|
||||||
ap = arr = (char **)alloc((countlinknodes(l) + 1) * sizeof(char **));
|
ap = arr = (char **) zhalloc((countlinknodes(l) + 1) * sizeof(char **));
|
||||||
|
|
||||||
for (n = (LinkNode) firstnode(l); n; incnode(n))
|
for (n = (LinkNode) firstnode(l); n; incnode(n))
|
||||||
*ap++ = (char *)getdata(n);
|
*ap++ = (char *)getdata(n);
|
||||||
|
@ -245,7 +316,7 @@ selectlist(LinkList l)
|
||||||
else
|
else
|
||||||
fw = (columns - 1) / fct;
|
fw = (columns - 1) / fct;
|
||||||
colsz = (ct + fct - 1) / fct;
|
colsz = (ct + fct - 1) / fct;
|
||||||
for (t1 = 0; t1 != colsz; t1++) {
|
for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) {
|
||||||
ap = arr + t1;
|
ap = arr + t1;
|
||||||
do {
|
do {
|
||||||
int t2 = strlen(*ap) + 2, t3;
|
int t2 = strlen(*ap) + 2, t3;
|
||||||
|
@ -271,70 +342,86 @@ selectlist(LinkList l)
|
||||||
}
|
}
|
||||||
while (*ap);*/
|
while (*ap);*/
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
|
return t1 < colsz ? t1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
execwhile(Cmd cmd)
|
execwhile(Estate state, int do_exec)
|
||||||
{
|
{
|
||||||
List list;
|
Wordcode end, loop;
|
||||||
struct whilecmd *node;
|
wordcode code = state->pc[-1];
|
||||||
int olderrexit, oldval;
|
int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL);
|
||||||
|
|
||||||
|
end = state->pc + WC_WHILE_SKIP(code);
|
||||||
olderrexit = noerrexit;
|
olderrexit = noerrexit;
|
||||||
node = cmd->u.whilecmd;
|
|
||||||
oldval = 0;
|
oldval = 0;
|
||||||
pushheap();
|
pushheap();
|
||||||
|
cmdpush(isuntil ? CS_UNTIL : CS_WHILE);
|
||||||
loops++;
|
loops++;
|
||||||
|
loop = state->pc;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
list = (List) dupstruct(node->cont);
|
state->pc = loop;
|
||||||
noerrexit = 1;
|
noerrexit = 1;
|
||||||
execlist(list, 1, 0);
|
execlist(state, 1, 0);
|
||||||
noerrexit = olderrexit;
|
noerrexit = olderrexit;
|
||||||
if (!((lastval == 0) ^ node->cond)) {
|
if (!((lastval == 0) ^ isuntil)) {
|
||||||
if (breaks)
|
if (breaks)
|
||||||
breaks--;
|
breaks--;
|
||||||
lastval = oldval;
|
lastval = oldval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
list = (List) dupstruct(node->loop);
|
if (retflag) {
|
||||||
execlist(list, 1, 0);
|
lastval = oldval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
execlist(state, 1, 0);
|
||||||
if (breaks) {
|
if (breaks) {
|
||||||
breaks--;
|
breaks--;
|
||||||
if (breaks || !contflag)
|
if (breaks || !contflag)
|
||||||
break;
|
break;
|
||||||
contflag = 0;
|
contflag = 0;
|
||||||
}
|
}
|
||||||
freeheap();
|
|
||||||
if (errflag) {
|
if (errflag) {
|
||||||
lastval = 1;
|
lastval = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (retflag)
|
||||||
|
break;
|
||||||
|
freeheap();
|
||||||
oldval = lastval;
|
oldval = lastval;
|
||||||
}
|
}
|
||||||
|
cmdpop();
|
||||||
popheap();
|
popheap();
|
||||||
loops--;
|
loops--;
|
||||||
|
state->pc = end;
|
||||||
return lastval;
|
return lastval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
execrepeat(Cmd cmd)
|
execrepeat(Estate state, int do_exec)
|
||||||
{
|
{
|
||||||
List list;
|
Wordcode end, loop;
|
||||||
int count;
|
wordcode code = state->pc[-1];
|
||||||
|
int count, htok = 0;
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
end = state->pc + WC_REPEAT_SKIP(code);
|
||||||
|
|
||||||
lastval = 0;
|
lastval = 0;
|
||||||
if (empty(cmd->args) || nextnode(firstnode(cmd->args))) {
|
tmp = ecgetstr(state, EC_DUPTOK, &htok);
|
||||||
zerr("bad argument for repeat", NULL, 0);
|
if (htok)
|
||||||
return 1;
|
singsub(&tmp);
|
||||||
}
|
count = atoi(tmp);
|
||||||
count = atoi(peekfirst(cmd->args));
|
|
||||||
pushheap();
|
pushheap();
|
||||||
|
cmdpush(CS_REPEAT);
|
||||||
loops++;
|
loops++;
|
||||||
while (count--) {
|
loop = state->pc;
|
||||||
list = (List) dupstruct(cmd->u.list);
|
while (count-- > 0) {
|
||||||
execlist(list, 1, 0);
|
state->pc = loop;
|
||||||
|
execlist(state, 1, 0);
|
||||||
freeheap();
|
freeheap();
|
||||||
if (breaks) {
|
if (breaks) {
|
||||||
breaks--;
|
breaks--;
|
||||||
|
@ -346,76 +433,151 @@ execrepeat(Cmd cmd)
|
||||||
lastval = 1;
|
lastval = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (retflag)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cmdpop();
|
||||||
popheap();
|
popheap();
|
||||||
loops--;
|
loops--;
|
||||||
|
state->pc = end;
|
||||||
return lastval;
|
return lastval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
execif(Cmd cmd)
|
execif(Estate state, int do_exec)
|
||||||
{
|
{
|
||||||
struct ifcmd *node;
|
Wordcode end, next;
|
||||||
int olderrexit;
|
wordcode code = state->pc[-1];
|
||||||
List *i, *t;
|
int olderrexit, s = 0, run = 0;
|
||||||
|
|
||||||
olderrexit = noerrexit;
|
olderrexit = noerrexit;
|
||||||
node = cmd->u.ifcmd;
|
end = state->pc + WC_IF_SKIP(code);
|
||||||
i = node->ifls;
|
|
||||||
t = node->thenls;
|
|
||||||
|
|
||||||
if (!noerrexit)
|
if (!noerrexit)
|
||||||
noerrexit = 1;
|
noerrexit = 1;
|
||||||
while (*i) {
|
while (state->pc < end) {
|
||||||
execlist(*i, 1, 0);
|
code = *state->pc++;
|
||||||
if (!lastval)
|
if (wc_code(code) != WC_IF ||
|
||||||
|
(run = (WC_IF_TYPE(code) == WC_IF_ELSE))) {
|
||||||
|
if (run)
|
||||||
|
run = 2;
|
||||||
break;
|
break;
|
||||||
i++;
|
}
|
||||||
t++;
|
next = state->pc + WC_IF_SKIP(code);
|
||||||
|
cmdpush(s ? CS_ELIF : CS_IF);
|
||||||
|
execlist(state, 1, 0);
|
||||||
|
cmdpop();
|
||||||
|
if (!lastval) {
|
||||||
|
run = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (retflag)
|
||||||
|
break;
|
||||||
|
s = 1;
|
||||||
|
state->pc = next;
|
||||||
}
|
}
|
||||||
noerrexit = olderrexit;
|
noerrexit = olderrexit;
|
||||||
|
|
||||||
if (*t)
|
if (run) {
|
||||||
execlist(*t, 1, cmd->flags & CFLAG_EXEC);
|
cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN));
|
||||||
else
|
execlist(state, 1, do_exec);
|
||||||
|
cmdpop();
|
||||||
|
} else
|
||||||
lastval = 0;
|
lastval = 0;
|
||||||
|
state->pc = end;
|
||||||
|
|
||||||
return lastval;
|
return lastval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
int
|
int
|
||||||
execcase(Cmd cmd)
|
execcase(Estate state, int do_exec)
|
||||||
{
|
{
|
||||||
struct casecmd *node;
|
Wordcode end, next;
|
||||||
char *word;
|
wordcode code = state->pc[-1];
|
||||||
List *l;
|
char *word, *pat;
|
||||||
char **p;
|
int npat, save;
|
||||||
|
Patprog *spprog, pprog;
|
||||||
|
|
||||||
node = cmd->u.casecmd;
|
end = state->pc + WC_CASE_SKIP(code);
|
||||||
l = node->lists;
|
|
||||||
p = node->pats;
|
|
||||||
|
|
||||||
word = *p++;
|
word = ecgetstr(state, EC_DUP, NULL);
|
||||||
singsub(&word);
|
singsub(&word);
|
||||||
untokenize(word);
|
untokenize(word);
|
||||||
lastval = 0;
|
lastval = 0;
|
||||||
|
|
||||||
if (node) {
|
cmdpush(CS_CASE);
|
||||||
while (*p) {
|
while (state->pc < end) {
|
||||||
char *pat = *p + 1;
|
code = *state->pc++;
|
||||||
|
if (wc_code(code) != WC_CASE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pat = NULL;
|
||||||
|
pprog = NULL;
|
||||||
|
save = 0;
|
||||||
|
npat = state->pc[1];
|
||||||
|
spprog = state->prog->pats + npat;
|
||||||
|
|
||||||
|
next = state->pc + WC_CASE_SKIP(code);
|
||||||
|
|
||||||
|
if (isset(XTRACE)) {
|
||||||
|
char *pat2, *opat;
|
||||||
|
|
||||||
|
opat = pat = ecgetstr(state, EC_DUP, NULL);
|
||||||
singsub(&pat);
|
singsub(&pat);
|
||||||
if (matchpat(word, pat)) {
|
save = (!(state->prog->flags & EF_HEAP) &&
|
||||||
do {
|
!strcmp(pat, opat) && *spprog != dummy_patprog2);
|
||||||
execlist(*l++, 1, **p == ';' && (cmd->flags & CFLAG_EXEC));
|
|
||||||
} while(**p++ == '&' && *p);
|
pat2 = dupstring(pat);
|
||||||
break;
|
untokenize(pat2);
|
||||||
|
printprompt4();
|
||||||
|
fprintf(xtrerr, "case %s (%s)\n", word, pat2);
|
||||||
|
fflush(xtrerr);
|
||||||
|
state->pc++;
|
||||||
|
} else
|
||||||
|
state->pc += 2;
|
||||||
|
|
||||||
|
if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
|
||||||
|
pprog = *spprog;
|
||||||
|
|
||||||
|
if (!pprog) {
|
||||||
|
if (!pat) {
|
||||||
|
char *opat;
|
||||||
|
int htok = 0;
|
||||||
|
|
||||||
|
opat = pat = dupstring(ecrawstr(state->prog,
|
||||||
|
state->pc - 2, &htok));
|
||||||
|
if (htok)
|
||||||
|
singsub(&pat);
|
||||||
|
save = (!(state->prog->flags & EF_HEAP) &&
|
||||||
|
!strcmp(pat, opat) && *spprog != dummy_patprog2);
|
||||||
}
|
}
|
||||||
p++;
|
if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
|
||||||
l++;
|
NULL)))
|
||||||
|
zerr("bad pattern: %s", pat, 0);
|
||||||
|
else if (save)
|
||||||
|
*spprog = pprog;
|
||||||
}
|
}
|
||||||
|
if (pprog && pattry(pprog, word)) {
|
||||||
|
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
|
||||||
|
do_exec));
|
||||||
|
while (!retflag && wc_code(code) == WC_CASE &&
|
||||||
|
WC_CASE_TYPE(code) == WC_CASE_AND) {
|
||||||
|
state->pc = next;
|
||||||
|
code = *state->pc;
|
||||||
|
state->pc += 3;
|
||||||
|
next = state->pc + WC_CASE_SKIP(code) - 1;
|
||||||
|
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
|
||||||
|
do_exec));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
state->pc = next;
|
||||||
}
|
}
|
||||||
|
cmdpop();
|
||||||
|
|
||||||
|
state->pc = end;
|
||||||
|
|
||||||
return lastval;
|
return lastval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1816
Src/params.c
1816
Src/params.c
File diff suppressed because it is too large
Load diff
2773
Src/parse.c
2773
Src/parse.c
File diff suppressed because it is too large
Load diff
1124
Src/pattern.c
1124
Src/pattern.c
File diff suppressed because it is too large
Load diff
856
Src/text.c
856
Src/text.c
|
@ -31,7 +31,7 @@
|
||||||
#include "text.pro"
|
#include "text.pro"
|
||||||
|
|
||||||
static char *tptr, *tbuf, *tlim;
|
static char *tptr, *tbuf, *tlim;
|
||||||
static int tsiz, tindent, tnewlins;
|
static int tsiz, tindent, tnewlins, tjob;
|
||||||
|
|
||||||
/* add a character to the text buffer */
|
/* add a character to the text buffer */
|
||||||
|
|
||||||
|
@ -72,19 +72,18 @@ taddstr(char *s)
|
||||||
tptr += sl;
|
tptr += sl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* add an integer to the text buffer */
|
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
static void
|
||||||
taddint(int x)
|
taddlist(Estate state, int num)
|
||||||
{
|
{
|
||||||
char buf[DIGBUFSIZE];
|
if (num) {
|
||||||
|
while (num--) {
|
||||||
sprintf(buf, "%d", x);
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
taddstr(buf);
|
taddchr(' ');
|
||||||
|
}
|
||||||
|
tptr--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* add a newline, or something equivalent, to the text buffer */
|
/* add a newline, or something equivalent, to the text buffer */
|
||||||
|
|
||||||
|
@ -105,15 +104,26 @@ taddnl(void)
|
||||||
/* get a permanent textual representation of n */
|
/* get a permanent textual representation of n */
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
char *
|
mod_export char *
|
||||||
getpermtext(struct node *n)
|
getpermtext(Eprog prog, Wordcode c)
|
||||||
{
|
{
|
||||||
|
struct estate s;
|
||||||
|
|
||||||
|
if (!c)
|
||||||
|
c = prog->prog;
|
||||||
|
|
||||||
|
s.prog = prog;
|
||||||
|
s.pc = c;
|
||||||
|
s.strs = prog->strs;
|
||||||
|
|
||||||
tnewlins = 1;
|
tnewlins = 1;
|
||||||
tbuf = (char *)zalloc(tsiz = 32);
|
tbuf = (char *)zalloc(tsiz = 32);
|
||||||
tptr = tbuf;
|
tptr = tbuf;
|
||||||
tlim = tbuf + tsiz;
|
tlim = tbuf + tsiz;
|
||||||
tindent = 1;
|
tindent = 1;
|
||||||
gettext2(n);
|
tjob = 0;
|
||||||
|
if (prog->len)
|
||||||
|
gettext2(&s);
|
||||||
*tptr = '\0';
|
*tptr = '\0';
|
||||||
untokenize(tbuf);
|
untokenize(tbuf);
|
||||||
return tbuf;
|
return tbuf;
|
||||||
|
@ -123,344 +133,587 @@ getpermtext(struct node *n)
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
char *
|
char *
|
||||||
getjobtext(struct node *n)
|
getjobtext(Eprog prog, Wordcode c)
|
||||||
{
|
{
|
||||||
static char jbuf[JOBTEXTSIZE];
|
static char jbuf[JOBTEXTSIZE];
|
||||||
|
|
||||||
|
struct estate s;
|
||||||
|
|
||||||
|
if (!c)
|
||||||
|
c = prog->prog;
|
||||||
|
|
||||||
|
s.prog = prog;
|
||||||
|
s.pc = c;
|
||||||
|
s.strs = prog->strs;
|
||||||
|
|
||||||
tnewlins = 0;
|
tnewlins = 0;
|
||||||
tbuf = NULL;
|
tbuf = NULL;
|
||||||
tptr = jbuf;
|
tptr = jbuf;
|
||||||
tlim = tptr + JOBTEXTSIZE - 1;
|
tlim = tptr + JOBTEXTSIZE - 1;
|
||||||
tindent = 1;
|
tindent = 1;
|
||||||
gettext2(n);
|
tjob = 1;
|
||||||
|
gettext2(&s);
|
||||||
*tptr = '\0';
|
*tptr = '\0';
|
||||||
untokenize(jbuf);
|
untokenize(jbuf);
|
||||||
return jbuf;
|
return jbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define gt2(X) gettext2((struct node *) (X))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
"gettext2" or "type checking and how to avoid it"
|
* gettext2() shows one way to walk through the word code without
|
||||||
an epic function by Paul Falstad
|
* recursion. We start by reading a word code and executing the
|
||||||
*/
|
* action for it. Some codes have sub-structures (like, e.g. WC_FOR)
|
||||||
|
* and require something to be done after the sub-structure has been
|
||||||
|
* handled. For these codes a tstack structure which describes what
|
||||||
|
* has to be done is pushed onto a stack. Codes without sub-structures
|
||||||
|
* arrange for the next structure being taken from the stack so that
|
||||||
|
* the action for it is executed instead of the one for the next
|
||||||
|
* word code. If the stack is empty at this point, we have handled
|
||||||
|
* the whole structure we were called for.
|
||||||
|
*/
|
||||||
|
|
||||||
#define _Cond(X) ((Cond) (X))
|
typedef struct tstack *Tstack;
|
||||||
#define _Cmd(X) ((Cmd) (X))
|
|
||||||
#define _Pline(X) ((Pline) (X))
|
struct tstack {
|
||||||
#define _Sublist(X) ((Sublist) (X))
|
Tstack prev;
|
||||||
#define _List(X) ((List) (X))
|
wordcode code;
|
||||||
#define _casecmd(X) ((struct casecmd *) (X))
|
int pop;
|
||||||
#define _ifcmd(X) ((struct ifcmd *) (X))
|
union {
|
||||||
#define _whilecmd(X) ((struct whilecmd *) (X))
|
struct {
|
||||||
|
LinkList list;
|
||||||
|
} _redir;
|
||||||
|
struct {
|
||||||
|
char *strs;
|
||||||
|
Wordcode end;
|
||||||
|
} _funcdef;
|
||||||
|
struct {
|
||||||
|
Wordcode end;
|
||||||
|
} _case;
|
||||||
|
struct {
|
||||||
|
int cond;
|
||||||
|
Wordcode end;
|
||||||
|
} _if;
|
||||||
|
struct {
|
||||||
|
int par;
|
||||||
|
} _cond;
|
||||||
|
struct {
|
||||||
|
Wordcode end;
|
||||||
|
} _subsh;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Tstack tstack, tfree;
|
||||||
|
|
||||||
|
static Tstack
|
||||||
|
tpush(wordcode code, int pop)
|
||||||
|
{
|
||||||
|
Tstack s;
|
||||||
|
|
||||||
|
if ((s = tfree))
|
||||||
|
tfree = s->prev;
|
||||||
|
else
|
||||||
|
s = (Tstack) zalloc(sizeof(*s));
|
||||||
|
|
||||||
|
s->prev = tstack;
|
||||||
|
tstack = s;
|
||||||
|
s->code = code;
|
||||||
|
s->pop = pop;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
static void
|
static void
|
||||||
gettext2(struct node *n)
|
gettext2(Estate state)
|
||||||
{
|
{
|
||||||
Cmd nn;
|
Tstack s, n;
|
||||||
|
int stack = 0;
|
||||||
|
wordcode code;
|
||||||
|
|
||||||
if (!n || ((List) n) == &dummy_list)
|
while (1) {
|
||||||
return;
|
if (stack) {
|
||||||
switch (NT_TYPE(n->ntype)) {
|
if (!(s = tstack))
|
||||||
case N_LIST:
|
return;
|
||||||
gt2(_List(n)->left);
|
if (s->pop) {
|
||||||
if (_List(n)->type & Z_ASYNC) {
|
tstack = s->prev;
|
||||||
taddstr(" &");
|
s->prev = tfree;
|
||||||
if (_List(n)->type & Z_DISOWN)
|
tfree = s;
|
||||||
taddstr("|");
|
}
|
||||||
|
code = s->code;
|
||||||
|
stack = 0;
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
code = *state->pc++;
|
||||||
}
|
}
|
||||||
simplifyright(_List(n));
|
switch (wc_code(code)) {
|
||||||
if (_List(n)->right) {
|
case WC_LIST:
|
||||||
if (tnewlins)
|
if (!s) {
|
||||||
taddnl();
|
s = tpush(code, (WC_LIST_TYPE(code) & Z_END));
|
||||||
else
|
stack = 0;
|
||||||
taddstr((_List(n)->type & Z_ASYNC) ? " " : "; ");
|
|
||||||
gt2(_List(n)->right);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case N_SUBLIST:
|
|
||||||
if (_Sublist(n)->flags & PFLAG_NOT)
|
|
||||||
taddstr("! ");
|
|
||||||
if (_Sublist(n)->flags & PFLAG_COPROC)
|
|
||||||
taddstr("coproc ");
|
|
||||||
gt2(_Sublist(n)->left);
|
|
||||||
if (_Sublist(n)->right) {
|
|
||||||
taddstr((_Sublist(n)->type == ORNEXT) ? " || " : " && ");
|
|
||||||
gt2(_Sublist(n)->right);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case N_PLINE:
|
|
||||||
gt2(_Pline(n)->left);
|
|
||||||
if (_Pline(n)->type == PIPE) {
|
|
||||||
taddstr(" | ");
|
|
||||||
gt2(_Pline(n)->right);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case N_CMD:
|
|
||||||
nn = _Cmd(n);
|
|
||||||
switch (nn->type) {
|
|
||||||
case SIMPLE:
|
|
||||||
getsimptext(nn);
|
|
||||||
break;
|
|
||||||
case SUBSH:
|
|
||||||
taddstr("( ");
|
|
||||||
tindent++;
|
|
||||||
gt2(nn->u.list);
|
|
||||||
tindent--;
|
|
||||||
taddstr(" )");
|
|
||||||
break;
|
|
||||||
case ZCTIME:
|
|
||||||
taddstr("time ");
|
|
||||||
tindent++;
|
|
||||||
gt2(nn->u.pline);
|
|
||||||
tindent--;
|
|
||||||
break;
|
|
||||||
case FUNCDEF:
|
|
||||||
taddlist(nn->args);
|
|
||||||
taddstr(" () {");
|
|
||||||
tindent++;
|
|
||||||
taddnl();
|
|
||||||
gt2(nn->u.list);
|
|
||||||
tindent--;
|
|
||||||
taddnl();
|
|
||||||
taddstr("}");
|
|
||||||
break;
|
|
||||||
case CURSH:
|
|
||||||
taddstr("{ ");
|
|
||||||
tindent++;
|
|
||||||
gt2(nn->u.list);
|
|
||||||
tindent--;
|
|
||||||
taddstr(" }");
|
|
||||||
break;
|
|
||||||
case CFOR:
|
|
||||||
case CSELECT:
|
|
||||||
taddstr((nn->type == CFOR) ? "for " : "select ");
|
|
||||||
if (nn->u.forcmd->condition) {
|
|
||||||
taddstr("((");
|
|
||||||
taddstr(nn->u.forcmd->name);
|
|
||||||
taddstr("; ");
|
|
||||||
taddstr(nn->u.forcmd->condition);
|
|
||||||
taddstr("; ");
|
|
||||||
taddstr(nn->u.forcmd->advance);
|
|
||||||
taddstr(")) do");
|
|
||||||
} else {
|
} else {
|
||||||
taddstr(nn->u.forcmd->name);
|
if (WC_LIST_TYPE(code) & Z_ASYNC) {
|
||||||
if (nn->u.forcmd->inflag) {
|
taddstr(" &");
|
||||||
taddstr(" in ");
|
if (WC_LIST_TYPE(code) & Z_DISOWN)
|
||||||
taddlist(nn->args);
|
taddstr("|");
|
||||||
}
|
}
|
||||||
|
if (!(stack = (WC_LIST_TYPE(code) & Z_END))) {
|
||||||
|
if (tnewlins)
|
||||||
|
taddnl();
|
||||||
|
else
|
||||||
|
taddstr((WC_LIST_TYPE(code) & Z_ASYNC) ? " " : "; ");
|
||||||
|
s->code = *state->pc++;
|
||||||
|
s->pop = (WC_LIST_TYPE(s->code) & Z_END);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!stack && (WC_LIST_TYPE(s->code) & Z_SIMPLE))
|
||||||
|
state->pc++;
|
||||||
|
break;
|
||||||
|
case WC_SUBLIST:
|
||||||
|
if (!s) {
|
||||||
|
if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT)
|
||||||
|
taddstr("! ");
|
||||||
|
if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_COPROC)
|
||||||
|
taddstr("coproc ");
|
||||||
|
s = tpush(code, (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END));
|
||||||
|
} else {
|
||||||
|
if (!(stack = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END))) {
|
||||||
|
taddstr((WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) ?
|
||||||
|
" || " : " && ");
|
||||||
|
s->code = *state->pc++;
|
||||||
|
s->pop = (WC_SUBLIST_TYPE(s->code) == WC_SUBLIST_END);
|
||||||
|
if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT)
|
||||||
|
taddstr("! ");
|
||||||
|
if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_COPROC)
|
||||||
|
taddstr("coproc ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!stack && (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_SIMPLE))
|
||||||
|
state->pc++;
|
||||||
|
break;
|
||||||
|
case WC_PIPE:
|
||||||
|
if (!s) {
|
||||||
|
tpush(code, (WC_PIPE_TYPE(code) == WC_PIPE_END));
|
||||||
|
if (WC_PIPE_TYPE(code) == WC_PIPE_MID)
|
||||||
|
state->pc++;
|
||||||
|
} else {
|
||||||
|
if (!(stack = (WC_PIPE_TYPE(code) == WC_PIPE_END))) {
|
||||||
|
taddstr(" | ");
|
||||||
|
s->code = *state->pc++;
|
||||||
|
if (!(s->pop = (WC_PIPE_TYPE(s->code) == WC_PIPE_END)))
|
||||||
|
state->pc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_REDIR:
|
||||||
|
if (!s) {
|
||||||
|
state->pc--;
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._redir.list = ecgetredirs(state);
|
||||||
|
} else {
|
||||||
|
getredirs(s->u._redir.list);
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_ASSIGN:
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddchr('=');
|
||||||
|
if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) {
|
||||||
|
taddchr('(');
|
||||||
|
taddlist(state, WC_ASSIGN_NUM(code));
|
||||||
|
taddstr(") ");
|
||||||
|
} else {
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddchr(' ');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_SIMPLE:
|
||||||
|
taddlist(state, WC_SIMPLE_ARGC(code));
|
||||||
|
stack = 1;
|
||||||
|
break;
|
||||||
|
case WC_SUBSH:
|
||||||
|
if (!s) {
|
||||||
|
taddstr("( ");
|
||||||
|
tindent++;
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._subsh.end = state->pc + WC_SUBSH_SKIP(code);
|
||||||
|
} else {
|
||||||
|
state->pc = s->u._subsh.end;
|
||||||
|
tindent--;
|
||||||
|
taddstr(" )");
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_CURSH:
|
||||||
|
if (!s) {
|
||||||
|
taddstr("{ ");
|
||||||
|
tindent++;
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._subsh.end = state->pc + WC_CURSH_SKIP(code);
|
||||||
|
} else {
|
||||||
|
state->pc = s->u._subsh.end;
|
||||||
|
tindent--;
|
||||||
|
taddstr(" }");
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_TIMED:
|
||||||
|
if (!s) {
|
||||||
|
taddstr("time");
|
||||||
|
if (WC_TIMED_TYPE(code) == WC_TIMED_PIPE) {
|
||||||
|
taddchr(' ');
|
||||||
|
tindent++;
|
||||||
|
tpush(code, 1);
|
||||||
|
} else
|
||||||
|
stack = 1;
|
||||||
|
} else {
|
||||||
|
tindent--;
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_FUNCDEF:
|
||||||
|
if (!s) {
|
||||||
|
Wordcode p = state->pc;
|
||||||
|
Wordcode end = p + WC_FUNCDEF_SKIP(code);
|
||||||
|
|
||||||
|
taddlist(state, *state->pc++);
|
||||||
|
if (tjob) {
|
||||||
|
taddstr(" () { ... }");
|
||||||
|
state->pc = end;
|
||||||
|
stack = 1;
|
||||||
|
} else {
|
||||||
|
taddstr(" () {");
|
||||||
|
tindent++;
|
||||||
|
taddnl();
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._funcdef.strs = state->strs;
|
||||||
|
n->u._funcdef.end = end;
|
||||||
|
state->strs += *state->pc;
|
||||||
|
state->pc += 3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state->strs = s->u._funcdef.strs;
|
||||||
|
state->pc = s->u._funcdef.end;
|
||||||
|
tindent--;
|
||||||
|
taddnl();
|
||||||
|
taddstr("}");
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_FOR:
|
||||||
|
if (!s) {
|
||||||
|
taddstr("for ");
|
||||||
|
if (WC_FOR_TYPE(code) == WC_FOR_COND) {
|
||||||
|
taddstr("((");
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddstr("; ");
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddstr("; ");
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddstr(")) do");
|
||||||
|
} else {
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
|
||||||
|
taddstr(" in ");
|
||||||
|
taddlist(state, *state->pc++);
|
||||||
|
}
|
||||||
|
taddnl();
|
||||||
|
taddstr("do");
|
||||||
|
}
|
||||||
|
tindent++;
|
||||||
|
taddnl();
|
||||||
|
tpush(code, 1);
|
||||||
|
} else {
|
||||||
|
tindent--;
|
||||||
|
taddnl();
|
||||||
|
taddstr("done");
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_SELECT:
|
||||||
|
if (!s) {
|
||||||
|
taddstr("select ");
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
if (WC_SELECT_TYPE(code) == WC_SELECT_LIST) {
|
||||||
|
taddstr(" in ");
|
||||||
|
taddlist(state, *state->pc++);
|
||||||
|
}
|
||||||
|
tindent++;
|
||||||
|
taddnl();
|
||||||
|
tpush(code, 1);
|
||||||
|
} else {
|
||||||
|
tindent--;
|
||||||
|
taddnl();
|
||||||
|
taddstr("done");
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WC_WHILE:
|
||||||
|
if (!s) {
|
||||||
|
taddstr(WC_WHILE_TYPE(code) == WC_WHILE_UNTIL ?
|
||||||
|
"until " : "while ");
|
||||||
|
tindent++;
|
||||||
|
tpush(code, 0);
|
||||||
|
} else if (!s->pop) {
|
||||||
|
tindent--;
|
||||||
taddnl();
|
taddnl();
|
||||||
taddstr("do");
|
taddstr("do");
|
||||||
|
tindent++;
|
||||||
|
taddnl();
|
||||||
|
s->pop = 1;
|
||||||
|
} else {
|
||||||
|
tindent--;
|
||||||
|
taddnl();
|
||||||
|
taddstr("done");
|
||||||
|
stack = 1;
|
||||||
}
|
}
|
||||||
tindent++;
|
|
||||||
taddnl();
|
|
||||||
gt2(nn->u.forcmd->list);
|
|
||||||
tindent--;
|
|
||||||
taddnl();
|
|
||||||
taddstr("done");
|
|
||||||
break;
|
break;
|
||||||
case CIF:
|
case WC_REPEAT:
|
||||||
gt2(nn->u.ifcmd);
|
if (!s) {
|
||||||
taddstr("fi");
|
taddstr("repeat ");
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddnl();
|
||||||
|
taddstr("do");
|
||||||
|
tindent++;
|
||||||
|
taddnl();
|
||||||
|
tpush(code, 1);
|
||||||
|
} else {
|
||||||
|
tindent--;
|
||||||
|
taddnl();
|
||||||
|
taddstr("done");
|
||||||
|
stack = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CCASE:
|
case WC_CASE:
|
||||||
gt2(nn->u.casecmd);
|
if (!s) {
|
||||||
break;
|
Wordcode end = state->pc + WC_CASE_SKIP(code);
|
||||||
case COND:
|
|
||||||
taddstr("[[ ");
|
|
||||||
gt2(nn->u.cond);
|
|
||||||
taddstr(" ]]");
|
|
||||||
break;
|
|
||||||
case CARITH:
|
|
||||||
taddstr("((");
|
|
||||||
taddlist(nn->args);
|
|
||||||
taddstr("))");
|
|
||||||
break;
|
|
||||||
case CREPEAT:
|
|
||||||
taddstr("repeat ");
|
|
||||||
taddlist(nn->args);
|
|
||||||
taddnl();
|
|
||||||
taddstr("do");
|
|
||||||
tindent++;
|
|
||||||
taddnl();
|
|
||||||
gt2(nn->u.list);
|
|
||||||
tindent--;
|
|
||||||
taddnl();
|
|
||||||
taddstr("done");
|
|
||||||
break;
|
|
||||||
case CWHILE:
|
|
||||||
gt2(nn->u.whilecmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
getredirs(nn);
|
|
||||||
break;
|
|
||||||
case N_COND:
|
|
||||||
getcond(_Cond(n), 0);
|
|
||||||
break;
|
|
||||||
case N_CASE:
|
|
||||||
{
|
|
||||||
List *l;
|
|
||||||
char **p;
|
|
||||||
|
|
||||||
l = _casecmd(n)->lists;
|
taddstr("case ");
|
||||||
p = _casecmd(n)->pats;
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddstr(" in");
|
||||||
|
|
||||||
taddstr("case ");
|
if (state->pc >= end) {
|
||||||
taddstr(*p++);
|
if (tnewlins)
|
||||||
taddstr(" in");
|
taddnl();
|
||||||
tindent++;
|
else
|
||||||
for (; *l; p++, l++) {
|
taddchr(' ');
|
||||||
|
taddstr("esac");
|
||||||
|
stack = 1;
|
||||||
|
} else {
|
||||||
|
tindent++;
|
||||||
|
if (tnewlins)
|
||||||
|
taddnl();
|
||||||
|
else
|
||||||
|
taddchr(' ');
|
||||||
|
code = *state->pc++;
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
state->pc++;
|
||||||
|
taddstr(") ");
|
||||||
|
tindent++;
|
||||||
|
n = tpush(code, 0);
|
||||||
|
n->u._case.end = end;
|
||||||
|
n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end);
|
||||||
|
}
|
||||||
|
} else if (state->pc < s->u._case.end) {
|
||||||
|
tindent--;
|
||||||
|
taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
|
||||||
if (tnewlins)
|
if (tnewlins)
|
||||||
taddnl();
|
taddnl();
|
||||||
else
|
else
|
||||||
taddchr(' ');
|
taddchr(' ');
|
||||||
taddstr(*p + 1);
|
code = *state->pc++;
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
state->pc++;
|
||||||
taddstr(") ");
|
taddstr(") ");
|
||||||
tindent++;
|
tindent++;
|
||||||
gt2(*l);
|
s->code = code;
|
||||||
|
s->pop = ((state->pc - 2 + WC_CASE_SKIP(code)) >=
|
||||||
|
s->u._case.end);
|
||||||
|
} else {
|
||||||
tindent--;
|
tindent--;
|
||||||
taddstr(" ;");
|
taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
|
||||||
taddchr(**p);
|
tindent--;
|
||||||
|
if (tnewlins)
|
||||||
|
taddnl();
|
||||||
|
else
|
||||||
|
taddchr(' ');
|
||||||
|
taddstr("esac");
|
||||||
|
stack = 1;
|
||||||
}
|
}
|
||||||
tindent--;
|
|
||||||
if (tnewlins)
|
|
||||||
taddnl();
|
|
||||||
else
|
|
||||||
taddchr(' ');
|
|
||||||
taddstr("esac");
|
|
||||||
break;
|
break;
|
||||||
}
|
case WC_IF:
|
||||||
case N_IF:
|
if (!s) {
|
||||||
{
|
Wordcode end = state->pc + WC_IF_SKIP(code);
|
||||||
List *i, *t;
|
|
||||||
|
|
||||||
taddstr("if ");
|
taddstr("if ");
|
||||||
for (i = _ifcmd(n)->ifls, t = _ifcmd(n)->thenls; *i; i++, t++) {
|
|
||||||
tindent++;
|
tindent++;
|
||||||
gt2(*i);
|
state->pc++;
|
||||||
|
|
||||||
|
n = tpush(code, 0);
|
||||||
|
n->u._if.end = end;
|
||||||
|
n->u._if.cond = 1;
|
||||||
|
} else if (s->pop) {
|
||||||
|
stack = 1;
|
||||||
|
} else if (s->u._if.cond) {
|
||||||
tindent--;
|
tindent--;
|
||||||
taddnl();
|
taddnl();
|
||||||
taddstr("then");
|
taddstr("then");
|
||||||
tindent++;
|
tindent++;
|
||||||
taddnl();
|
taddnl();
|
||||||
gt2(*t);
|
s->u._if.cond = 0;
|
||||||
|
} else if (state->pc < s->u._if.end) {
|
||||||
tindent--;
|
tindent--;
|
||||||
taddnl();
|
taddnl();
|
||||||
if (i[1]) {
|
code = *state->pc++;
|
||||||
|
if (WC_IF_TYPE(code) == WC_IF_ELIF) {
|
||||||
taddstr("elif ");
|
taddstr("elif ");
|
||||||
|
tindent++;
|
||||||
|
s->u._if.cond = 1;
|
||||||
|
} else {
|
||||||
|
taddstr("else");
|
||||||
|
tindent++;
|
||||||
|
taddnl();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if (*t) {
|
s->pop = 1;
|
||||||
taddstr("else");
|
|
||||||
tindent++;
|
|
||||||
taddnl();
|
|
||||||
gt2(*t);
|
|
||||||
tindent--;
|
tindent--;
|
||||||
taddnl();
|
taddnl();
|
||||||
|
taddstr("fi");
|
||||||
|
stack = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case WC_COND:
|
||||||
case N_WHILE:
|
{
|
||||||
taddstr((_whilecmd(n)->cond) ? "until " : "while ");
|
static char *c1[] = {
|
||||||
tindent++;
|
"=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
|
||||||
gt2(_whilecmd(n)->cont);
|
"-ne", "-lt", "-gt", "-le", "-ge"
|
||||||
tindent--;
|
};
|
||||||
taddnl();
|
|
||||||
taddstr("do");
|
|
||||||
tindent++;
|
|
||||||
taddnl();
|
|
||||||
gt2(_whilecmd(n)->loop);
|
|
||||||
tindent--;
|
|
||||||
taddnl();
|
|
||||||
taddstr("done");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print a condition bracketed by [[ ... ]]. *
|
int ctype;
|
||||||
* With addpar non-zero, parenthesise the subexpression. */
|
|
||||||
|
|
||||||
/**/
|
if (!s) {
|
||||||
static void
|
taddstr("[[ ");
|
||||||
getcond(Cond nm, int addpar)
|
n = tpush(code, 1);
|
||||||
{
|
n->u._cond.par = 2;
|
||||||
static char *c1[] =
|
} else if (s->u._cond.par == 2) {
|
||||||
{
|
taddstr(" ]]");
|
||||||
"=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
|
stack = 1;
|
||||||
"-ne", "-lt", "-gt", "-le", "-ge"
|
break;
|
||||||
};
|
} else if (s->u._cond.par == 1) {
|
||||||
|
taddstr(" )");
|
||||||
|
stack = 1;
|
||||||
|
break;
|
||||||
|
} else if (WC_COND_TYPE(s->code) == COND_AND) {
|
||||||
|
taddstr(" && ");
|
||||||
|
code = *state->pc++;
|
||||||
|
if (WC_COND_TYPE(code) == COND_OR) {
|
||||||
|
taddstr("( ");
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._cond.par = 1;
|
||||||
|
}
|
||||||
|
} else if (WC_COND_TYPE(s->code) == COND_OR) {
|
||||||
|
taddstr(" || ");
|
||||||
|
code = *state->pc++;
|
||||||
|
if (WC_COND_TYPE(code) == COND_AND) {
|
||||||
|
taddstr("( ");
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._cond.par = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!stack) {
|
||||||
|
switch ((ctype = WC_COND_TYPE(code))) {
|
||||||
|
case COND_NOT:
|
||||||
|
taddstr("! ");
|
||||||
|
code = *state->pc++;
|
||||||
|
if (WC_COND_TYPE(code) <= COND_OR) {
|
||||||
|
taddstr("( ");
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._cond.par = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COND_AND:
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._cond.par = 0;
|
||||||
|
code = *state->pc++;
|
||||||
|
if (WC_COND_TYPE(code) == COND_OR) {
|
||||||
|
taddstr("( ");
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._cond.par = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COND_OR:
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._cond.par = 0;
|
||||||
|
code = *state->pc++;
|
||||||
|
if (WC_COND_TYPE(code) == COND_AND) {
|
||||||
|
taddstr("( ");
|
||||||
|
n = tpush(code, 1);
|
||||||
|
n->u._cond.par = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COND_MOD:
|
||||||
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
|
taddchr(' ');
|
||||||
|
taddlist(state, WC_COND_SKIP(code));
|
||||||
|
stack = 1;
|
||||||
|
break;
|
||||||
|
case COND_MODI:
|
||||||
|
{
|
||||||
|
char *name = ecgetstr(state, EC_NODUP, NULL);
|
||||||
|
|
||||||
if (addpar)
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
taddstr("( ");
|
taddchr(' ');
|
||||||
switch (nm->type) {
|
taddstr(name);
|
||||||
case COND_NOT:
|
taddchr(' ');
|
||||||
taddstr("! ");
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
getcond(nm->left, _Cond(nm->left)->type <= COND_OR);
|
stack = 1;
|
||||||
break;
|
}
|
||||||
case COND_AND:
|
break;
|
||||||
getcond(nm->left, _Cond(nm->left)->type == COND_OR);
|
default:
|
||||||
taddstr(" && ");
|
if (ctype <= COND_GE) {
|
||||||
getcond(nm->right, _Cond(nm->right)->type == COND_OR);
|
/* Binary test: `a = b' etc. */
|
||||||
break;
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
case COND_OR:
|
taddstr(" ");
|
||||||
/* This is deliberately over-generous with parentheses: *
|
taddstr(c1[ctype - COND_STREQ]);
|
||||||
* in fact omitting them gives correct precedence. */
|
taddstr(" ");
|
||||||
getcond(nm->left, _Cond(nm->left)->type == COND_AND);
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
taddstr(" || ");
|
if (ctype == COND_STREQ ||
|
||||||
getcond(nm->right, _Cond(nm->right)->type == COND_AND);
|
ctype == COND_STRNEQ)
|
||||||
break;
|
state->pc++;
|
||||||
default:
|
} else {
|
||||||
if (nm->type <= COND_GE) {
|
/* Unary test: `-f foo' etc. */
|
||||||
/* Binary test: `a = b' etc. */
|
char c2[4];
|
||||||
taddstr(nm->left);
|
|
||||||
taddstr(" ");
|
|
||||||
taddstr(c1[nm->type - COND_STREQ]);
|
|
||||||
taddstr(" ");
|
|
||||||
taddstr(nm->right);
|
|
||||||
} else {
|
|
||||||
/* Unary test: `-f foo' etc. */
|
|
||||||
char c2[4];
|
|
||||||
|
|
||||||
c2[0] = '-';
|
c2[0] = '-';
|
||||||
c2[1] = nm->type;
|
c2[1] = ctype;
|
||||||
c2[2] = ' ';
|
c2[2] = ' ';
|
||||||
c2[3] = '\0';
|
c2[3] = '\0';
|
||||||
taddstr(c2);
|
taddstr(c2);
|
||||||
taddstr(nm->left);
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
}
|
}
|
||||||
break;
|
stack = 1;
|
||||||
}
|
break;
|
||||||
if (addpar)
|
}
|
||||||
taddstr(" )");
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
/**/
|
case WC_ARITH:
|
||||||
static void
|
taddstr("((");
|
||||||
getsimptext(Cmd cmd)
|
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||||
{
|
taddstr("))");
|
||||||
LinkNode n;
|
stack = 1;
|
||||||
|
break;
|
||||||
for (n = firstnode(cmd->vars); n; incnode(n)) {
|
case WC_END:
|
||||||
struct varasg *v = (struct varasg *)getdata(n);
|
stack = 1;
|
||||||
|
break;
|
||||||
taddstr(v->name);
|
default:
|
||||||
taddchr('=');
|
DPUTS(1, "unknown word code in gettext2()");
|
||||||
if (PM_TYPE(v->type) == PM_ARRAY) {
|
return;
|
||||||
taddchr('(');
|
|
||||||
taddlist(v->arr);
|
|
||||||
taddstr(") ");
|
|
||||||
} else {
|
|
||||||
taddstr(v->str);
|
|
||||||
taddchr(' ');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
taddlist(cmd->args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
void
|
void
|
||||||
getredirs(Cmd cmd)
|
getredirs(LinkList redirs)
|
||||||
{
|
{
|
||||||
LinkNode n;
|
LinkNode n;
|
||||||
static char *fstr[] =
|
static char *fstr[] =
|
||||||
|
@ -468,10 +721,9 @@ getredirs(Cmd cmd)
|
||||||
">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
|
">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
|
||||||
"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
|
"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
|
||||||
};
|
};
|
||||||
|
|
||||||
taddchr(' ');
|
taddchr(' ');
|
||||||
for (n = firstnode(cmd->redir); n; incnode(n)) {
|
for (n = firstnode(redirs); n; incnode(n)) {
|
||||||
struct redir *f = (struct redir *)getdata(n);
|
Redir f = (Redir) getdata(n);
|
||||||
|
|
||||||
switch (f->type) {
|
switch (f->type) {
|
||||||
case WRITE:
|
case WRITE:
|
||||||
|
@ -493,7 +745,12 @@ getredirs(Cmd cmd)
|
||||||
taddchr('0' + f->fd1);
|
taddchr('0' + f->fd1);
|
||||||
taddstr(fstr[f->type]);
|
taddstr(fstr[f->type]);
|
||||||
taddchr(' ');
|
taddchr(' ');
|
||||||
taddstr(f->name);
|
if (f->type == HERESTR) {
|
||||||
|
taddchr('\'');
|
||||||
|
taddstr(bslashquote(f->name, NULL, 1));
|
||||||
|
taddchr('\'');
|
||||||
|
} else
|
||||||
|
taddstr(f->name);
|
||||||
taddchr(' ');
|
taddchr(' ');
|
||||||
break;
|
break;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -509,18 +766,3 @@ getredirs(Cmd cmd)
|
||||||
}
|
}
|
||||||
tptr--;
|
tptr--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
|
||||||
static void
|
|
||||||
taddlist(LinkList l)
|
|
||||||
{
|
|
||||||
LinkNode n;
|
|
||||||
|
|
||||||
if (!(n = firstnode(l)))
|
|
||||||
return;
|
|
||||||
for (; n; incnode(n)) {
|
|
||||||
taddstr(getdata(n));
|
|
||||||
taddchr(' ');
|
|
||||||
}
|
|
||||||
tptr--;
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,10 +11,11 @@
|
||||||
touch unmodified
|
touch unmodified
|
||||||
|
|
||||||
touch zerolength
|
touch zerolength
|
||||||
|
chgrp $EGID zerolength
|
||||||
print 'Garbuglio' >nonzerolength
|
print 'Garbuglio' >nonzerolength
|
||||||
|
|
||||||
touch modish
|
mkdir modish
|
||||||
chmod g+s modish
|
chmod g+xs modish
|
||||||
chmod u+s modish
|
chmod u+s modish
|
||||||
chmod +t modish
|
chmod +t modish
|
||||||
|
|
||||||
|
@ -26,7 +27,11 @@
|
||||||
0:-a cond
|
0:-a cond
|
||||||
|
|
||||||
# Find a block special file system. This is a little tricky.
|
# Find a block special file system. This is a little tricky.
|
||||||
block=$(df / | tail -1 | awk '{ print $1 }') &&
|
block=$(df / | awk '
|
||||||
|
$NF == "/" {print $1}
|
||||||
|
$1 == "/" && substr($2,0,1) == "(" {
|
||||||
|
if((l = index($2,")") - 2) < 0) l = length($2) - 1;
|
||||||
|
print substr($2,2,l)}') &&
|
||||||
[[ -b $block && ! -b zerolength ]]
|
[[ -b $block && ! -b zerolength ]]
|
||||||
0:-b cond
|
0:-b cond
|
||||||
|
|
||||||
|
@ -61,7 +66,11 @@
|
||||||
[[ -o rcs && ! -o norcs && -o noerrexit && ! -o errexit ]]
|
[[ -o rcs && ! -o norcs && -o noerrexit && ! -o errexit ]]
|
||||||
0:-o cond
|
0:-o cond
|
||||||
|
|
||||||
mknod pipe p
|
if whence mkfifo >/dev/null; then
|
||||||
|
mkfifo pipe
|
||||||
|
else
|
||||||
|
mknod pipe p
|
||||||
|
fi
|
||||||
[[ -p pipe && ! -p zerolength ]]
|
[[ -p pipe && ! -p zerolength ]]
|
||||||
0:-p cond
|
0:-p cond
|
||||||
|
|
||||||
|
@ -76,7 +85,7 @@
|
||||||
[[ -u modish && ! -u zerolength ]]
|
[[ -u modish && ! -u zerolength ]]
|
||||||
0:-u cond
|
0:-u cond
|
||||||
|
|
||||||
[[ -x $ZTST_testdir/ztst.zsh && ! -x zerolength ]]
|
[[ -x $ZTST_srcdir/ztst.zsh && ! -x zerolength ]]
|
||||||
0:-x cond
|
0:-x cond
|
||||||
|
|
||||||
[[ -z $bar && -z '' && ! -z $foo ]]
|
[[ -z $bar && -z '' && ! -z $foo ]]
|
||||||
|
@ -89,8 +98,6 @@
|
||||||
[[ -O zerolength ]]
|
[[ -O zerolength ]]
|
||||||
0:-O cond
|
0:-O cond
|
||||||
|
|
||||||
# there may be strange cases where this doesn't work, e.g.
|
|
||||||
# inherited funny groups for directories via setgid.
|
|
||||||
[[ -G zerolength ]]
|
[[ -G zerolength ]]
|
||||||
0:-G cond
|
0:-G cond
|
||||||
|
|
||||||
|
@ -132,4 +139,16 @@
|
||||||
0:|| and && in conds
|
0:|| and && in conds
|
||||||
|
|
||||||
[[ -e /dev/fd/0 ]]
|
[[ -e /dev/fd/0 ]]
|
||||||
0:/dev/fd support in conds
|
0:/dev/fd support in conds handled by access
|
||||||
|
|
||||||
|
[[ -O /dev/fd/0 ]]
|
||||||
|
0:/dev/fd support in conds handled by stat
|
||||||
|
|
||||||
|
[[ ( -z foo && -z foo ) || -z foo ]]
|
||||||
|
1:complex conds with skipping
|
||||||
|
|
||||||
|
[ '' != bar -a '' = '' ]
|
||||||
|
0:strings with `[' builtin
|
||||||
|
|
||||||
|
[ `echo 0` -lt `echo 1` ]
|
||||||
|
0:substituion in `[' builtin
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
# Tests for globbing
|
# Tests for globbing
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
|
mkdir glob.tmp
|
||||||
|
mkdir glob.tmp/dir1
|
||||||
|
mkdir glob.tmp/dir2
|
||||||
|
: >glob.tmp/{,{dir1,dir2}/}{a,b,c}
|
||||||
|
|
||||||
globtest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/../Misc/$1 }
|
globtest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/../Misc/$1 }
|
||||||
|
|
||||||
|
regress_absolute_path_and_core_dump() {
|
||||||
|
local absolute_dir=$(cd glob.tmp && pwd -P)
|
||||||
|
[[ -n $absolute_dir ]] || return 1
|
||||||
|
setopt localoptions extendedglob nullglob
|
||||||
|
print $absolute_dir/**/*~/*
|
||||||
|
setopt nonullglob nomatch
|
||||||
|
print glob.tmp/**/*~(.)#
|
||||||
|
}
|
||||||
|
|
||||||
%test
|
%test
|
||||||
|
|
||||||
globtest globtests
|
globtest globtests
|
||||||
|
@ -234,3 +248,8 @@
|
||||||
>0: [[ FOO = @(bar|(#i)foo) ]]
|
>0: [[ FOO = @(bar|(#i)foo) ]]
|
||||||
>0: [[ Modules = (#i)*m* ]]
|
>0: [[ Modules = (#i)*m* ]]
|
||||||
>0 tests failed.
|
>0 tests failed.
|
||||||
|
|
||||||
|
( regress_absolute_path_and_core_dump )
|
||||||
|
0:exclusions regression test
|
||||||
|
>
|
||||||
|
>glob.tmp/a glob.tmp/b glob.tmp/c glob.tmp/dir1 glob.tmp/dir1/a glob.tmp/dir1/b glob.tmp/dir1/c glob.tmp/dir2 glob.tmp/dir2/a glob.tmp/dir2/b glob.tmp/dir2/c
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
# Tests for completion system.
|
# Tests for completion system.
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
|
zmodload -i zsh/zpty
|
||||||
|
|
||||||
|
TERM=vt100
|
||||||
|
export ZTST_testdir ZTST_srcdir TERM
|
||||||
comptest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/comptest -z $ZTST_testdir/../Src/zsh -d $ZTST_testdir/compdump.tmp "$@" }
|
comptest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/comptest -z $ZTST_testdir/../Src/zsh -d $ZTST_testdir/compdump.tmp "$@" }
|
||||||
|
|
||||||
mkdir comp.tmp
|
mkdir comp.tmp
|
||||||
|
@ -104,11 +107,11 @@
|
||||||
>DESCRIPTION:{desc1}
|
>DESCRIPTION:{desc1}
|
||||||
>NO:{arg1}
|
>NO:{arg1}
|
||||||
|
|
||||||
# code='compdef _tst tst; _tst () { _arguments "-\+[opt]" }'
|
code='compdef _tst tst; _tst () { _arguments "-\+[opt]" }'
|
||||||
# comptest -c "$code" $'tst -\C-D'
|
comptest -c "$code" $'tst -\C-D'
|
||||||
#0:_arguments
|
0:_arguments
|
||||||
#>DESCRIPTION:{option}
|
>DESCRIPTION:{option}
|
||||||
#>NO:{-+ -- opt}
|
>NO:{-+ -- opt}
|
||||||
|
|
||||||
code='compdef _tst tst; _tst () { _arguments "1:desc1:(arg1)" }'
|
code='compdef _tst tst; _tst () { _arguments "1:desc1:(arg1)" }'
|
||||||
comptest -c "$code" $'tst \t'
|
comptest -c "$code" $'tst \t'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue