mirror of git://git.code.sf.net/p/zsh/code
Updated from list as far as 10376
This commit is contained in:
parent
e025336f2f
commit
4852545255
|
@ -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
|
||||
# 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:
|
||||
#
|
||||
# zrecompile -p \
|
||||
# -r ~/.zshrc -- \
|
||||
# -m ~/.zcompdump -- \
|
||||
# -R ~/.zshrc -- \
|
||||
# -M ~/.zcompdump -- \
|
||||
# ~/zsh/comp.zwc ~/zsh/Completion/*/_* \
|
||||
#
|
||||
# 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
|
||||
# for at least one of the files failed.
|
||||
|
||||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
setopt localoptions extendedglob
|
||||
|
||||
local opt check quiet zwc files re file pre ret map tmp mesg pats
|
||||
|
||||
|
@ -68,7 +67,7 @@ if [[ -n $pats ]]; then
|
|||
fi
|
||||
|
||||
files=( ${files:#*(.zwc|~)} )
|
||||
if [[ $files[1] = -[rm] ]]; then
|
||||
if [[ $files[1] = -[RM] ]]; then
|
||||
map=( $files[1] )
|
||||
shift 1 files
|
||||
else
|
||||
|
@ -146,10 +145,10 @@ for zwc; do
|
|||
# See if the wordcode file will be mapped.
|
||||
|
||||
if [[ $files[1] = *\(mapped\)* ]]; then
|
||||
map=-m
|
||||
map=-M
|
||||
mesg='succeeded (old saved)'
|
||||
else
|
||||
map=-r
|
||||
map=-R
|
||||
mesg=succeeded
|
||||
fi
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ local tmpf=${TMPPREFIX}zfcm$$
|
|||
|
||||
if [[ $ZFTP_SYSTEM = UNIX* ]]; then
|
||||
# hoo, aren't we lucky: this makes things so much easier
|
||||
setopt localoptions rcexpandparam
|
||||
setopt rcexpandparam
|
||||
local dir
|
||||
if [[ $1 = ?*/* ]]; then
|
||||
dir=${1%/*}
|
||||
|
@ -25,13 +25,15 @@ if [[ $ZFTP_SYSTEM = UNIX* ]]; then
|
|||
# If we're using -F, we get away with using a directory
|
||||
# to list, but not a glob. Don't ask me why.
|
||||
# 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))
|
||||
rm -f $tmpf
|
||||
if [[ $dir = / ]]; then
|
||||
reply=(${dir}$reply)
|
||||
[[ -n $dir && $dir != */ ]] && dir="$dir/"
|
||||
if [[ -n $WIDGET ]]; then
|
||||
_all_labels directories expl 'remote directory'
|
||||
compadd -S/ -q -P "$dir" - $reply
|
||||
elif [[ -n $dir ]]; then
|
||||
reply=($dir/$reply)
|
||||
reply=(${dir}$reply)
|
||||
fi
|
||||
else
|
||||
# I simply don't know what to do here.
|
||||
|
|
|
@ -10,18 +10,27 @@ fi
|
|||
local tmpf=${TMPPREFIX}zfgm$$
|
||||
|
||||
if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
|
||||
# On the first argument to ls, we usually get away with a glob.
|
||||
zftp ls "$1*$2" >$tmpf
|
||||
reply=($(<$tmpf))
|
||||
rm -f $tmpf
|
||||
else
|
||||
if (( $#zftp_fcache == 0 )); then
|
||||
# Always cache the current directory and use it
|
||||
# even if the system is UNIX.
|
||||
zftp ls >$tmpf
|
||||
zftp_fcache=($(<$tmpf))
|
||||
if [[ -n $WIDGET ]]; then
|
||||
local dir=${1:h}
|
||||
[[ $dir = */ ]] || dir="$dir/"
|
||||
zftp ls -LF $dir >$tmpf
|
||||
local reply
|
||||
reply=(${${${(f)"$(<$tmpf)"}##$dir}%\*})
|
||||
rm -f $tmpf
|
||||
_all_labels files expl 'remote file' compadd -P $dir - $reply
|
||||
else
|
||||
# On the first argument to ls, we usually get away with a glob.
|
||||
zftp ls "$1*$2" >$tmpf
|
||||
reply=($(<$tmpf))
|
||||
rm -f $tmpf
|
||||
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
|
||||
# }
|
||||
|
|
|
@ -1,89 +1,124 @@
|
|||
# incremental-complete-word() {
|
||||
|
||||
# Autoload this function, run `zle -N <func-name>' and bind <func-name>
|
||||
# to a key.
|
||||
|
||||
|
||||
# This allows incremental completion of a word. After starting this
|
||||
# command, a list of completion choices is shown after every character 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
|
||||
# abort back to the state when you started.
|
||||
# command, a list of completion choices can be shown after every character
|
||||
# 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, ^g to
|
||||
# abort back to the state when you started, and ^d to list the matches.
|
||||
#
|
||||
# Completion keys:
|
||||
# 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
|
||||
# This works only with the new function based completion system.
|
||||
|
||||
emulate -L zsh
|
||||
unsetopt autolist menucomplete automenu # doesn't work well
|
||||
# The main widget function.
|
||||
|
||||
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]" ]] &&
|
||||
set ${(s.:.)compconfig[incremental_completer]}
|
||||
pmpt="${compconfig[incremental_prompt]-incremental completion...}"
|
||||
local key lbuf="$LBUFFER" rbuf="$RBUFFER" pmpt pstr word
|
||||
local lastl lastr wid twid num post toolong
|
||||
local curcontext="${curcontext}" stop brk
|
||||
|
||||
if [[ -n "$compconfig[incremental_list]" ]]; then
|
||||
wid=list-choices
|
||||
else
|
||||
wid=complete-word
|
||||
fi
|
||||
[[ -z "$curcontext" ]] && curcontext=:::
|
||||
curcontext="incremental:${curcontext#*:}"
|
||||
|
||||
zle $wid "$@"
|
||||
LBUFFER="$lbuf"
|
||||
RBUFFER="$rbuf"
|
||||
if [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
|
||||
word=''
|
||||
else
|
||||
word="${_lastcomp[unambiguous]}"
|
||||
fi
|
||||
zle -R "${pmpt//\\%u/$word}"
|
||||
read -k key
|
||||
zstyle -s ":completion:${curcontext}" prompt pmpt ||
|
||||
pmpt='incremental (%c): %u%s %l'
|
||||
zstyle -s ":completion:${curcontext}" stop stop
|
||||
zstyle -s ":completion:${curcontext}" break brk
|
||||
|
||||
while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' &&
|
||||
'#key' -ne '#\\C-g' ]]; do
|
||||
twid=$wid
|
||||
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
|
||||
if zstyle -t ":completion:${curcontext}" list; then
|
||||
wid=list-choices
|
||||
post=( icw-list-helper )
|
||||
else
|
||||
LBUFFER="$LBUFFER$key"
|
||||
wid=complete-word
|
||||
post=()
|
||||
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"
|
||||
RBUFFER="$rbuf"
|
||||
fi
|
||||
zle -Rc
|
||||
# }
|
||||
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
|
||||
|
||||
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.
|
||||
# After predict-on, typing characters causes the editor to look backward
|
||||
# in the history for the first line beginning with what you have typed
|
||||
# so far. After predict-off, editing returns to normal for the line found.
|
||||
# in the history for the first line beginning with what you have typed so
|
||||
# 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
|
||||
# line doesn't match something in the history, adding a key at the end
|
||||
# behaves as normal --- though editing in the middle is liable to delete
|
||||
# line doesn't match something in the history, adding a key performs
|
||||
# standard completion --- though editing in the middle is liable to delete
|
||||
# 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:
|
||||
# autoload -U predict-on
|
||||
# zle -N predict-on
|
||||
# zle -N predict-off
|
||||
# bindkey '...' predict-on
|
||||
# bindkey '...' predict-off
|
||||
# Note that all the functions are defined when you first call type the
|
||||
# predict-on key, which means typing the predict-off key before that gives
|
||||
# a harmless error message.
|
||||
# Note that all functions are defined when you first type the predict-on
|
||||
# key, which means typing the predict-off key before that gives a harmless
|
||||
# error message.
|
||||
|
||||
predict-on() {
|
||||
zle -N self-insert insert-and-predict
|
||||
zle -N magic-space insert-and-predict
|
||||
zle -N backward-delete-char delete-backward-and-predict
|
||||
zle -N self-insert insert-and-predict
|
||||
zle -N magic-space insert-and-predict
|
||||
zle -N backward-delete-char delete-backward-and-predict
|
||||
zle -N delete-char-or-list delete-no-predict
|
||||
}
|
||||
predict-off() {
|
||||
zle -A .self-insert self-insert
|
||||
zle -A .magic-space magic-space
|
||||
zle -A .backward-delete-char backward-delete-char
|
||||
zle -A .self-insert self-insert
|
||||
zle -A .magic-space magic-space
|
||||
zle -A .backward-delete-char backward-delete-char
|
||||
}
|
||||
insert-and-predict () {
|
||||
emulate -L zsh
|
||||
if [[ ${RBUFFER[1]} = ${KEYS[-1]} ]]
|
||||
setopt localoptions noshwordsplit noksharrays
|
||||
if [[ $LBUFFER = *$'\012'* ]]
|
||||
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))
|
||||
else
|
||||
LBUFFER="$LBUFFER$KEYS"
|
||||
if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]]
|
||||
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
|
||||
return 0
|
||||
}
|
||||
delete-backward-and-predict() {
|
||||
emulate -L zsh
|
||||
if [[ -n "$LBUFFER" ]]
|
||||
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
|
||||
# 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
|
||||
((--CURSOR))
|
||||
zle .history-beginning-search-forward || RBUFFER=""
|
||||
return 0
|
||||
else
|
||||
# Depending on preference, you might call "predict-off" here,
|
||||
# and also set up forward deletions to turn off prediction.
|
||||
# Depending on preference, you might call "predict-off" here.
|
||||
LBUFFER="$LBUFFER[1,-2]"
|
||||
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 "$@"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/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;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -30,6 +30,13 @@
|
|||
#include "zpty.mdh"
|
||||
#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;
|
||||
|
||||
struct ptycmd {
|
||||
|
@ -158,7 +165,7 @@ get_pty(int *master, int *slave)
|
|||
|
||||
#else /* ! __osf__ */
|
||||
|
||||
#if __SVR4
|
||||
#if defined(__SVR4) || defined(sinix)
|
||||
|
||||
#include <sys/stropts.h>
|
||||
|
||||
|
@ -167,11 +174,12 @@ get_pty(int *master, int *slave)
|
|||
{
|
||||
int mfd, sfd;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
if ((mfd = open("/dev/ptmx", O_RDWR)) < 0)
|
||||
return 1;
|
||||
|
||||
if (!(name = ptsname(mfd)) || grantpt(mfd) || unlockpt(mfd)) {
|
||||
if (grantpt(mfd) || unlockpt(mfd) || !(name = ptsname(mfd))) {
|
||||
close(mfd);
|
||||
return 1;
|
||||
}
|
||||
|
@ -179,20 +187,31 @@ get_pty(int *master, int *slave)
|
|||
close(mfd);
|
||||
return 1;
|
||||
}
|
||||
if (ioctl(sfd, I_PUSH, "ptem") ||
|
||||
ioctl(sfd, I_PUSH, "ldterm") ||
|
||||
ioctl(sfd, I_PUSH, "ttcompat")) {
|
||||
close(mfd);
|
||||
close(sfd);
|
||||
return 1;
|
||||
}
|
||||
if ((ret = ioctl(sfd, I_FIND, "ptem")) != 1)
|
||||
if (ret == -1 || ioctl(sfd, I_PUSH, "ptem") == -1) {
|
||||
close(mfd);
|
||||
close(sfd);
|
||||
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;
|
||||
*slave = sfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* ! __SVR4 */
|
||||
#else /* ! (defined(__SVR4) || defind(sinix)) */
|
||||
|
||||
static int
|
||||
get_pty(int *master, int *slave)
|
||||
|
@ -242,17 +261,17 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
|
|||
char *cmd;
|
||||
|
||||
if (!(cmd = findcmd(*args, 1))) {
|
||||
zerrnam(nam, "unknown command: %s", *args, 0);
|
||||
zwarnnam(nam, "unknown command: %s", *args, 0);
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if ((pid = fork()) == -1) {
|
||||
close(master);
|
||||
close(slave);
|
||||
zerrnam(nam, "couldn't create pty command: %s", pname, 0);
|
||||
zwarnnam(nam, "couldn't create pty command: %s", pname, 0);
|
||||
return 1;
|
||||
} else if (!pid) {
|
||||
if (!echo) {
|
||||
|
@ -298,6 +317,8 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
|
|||
|
||||
close(slave);
|
||||
|
||||
setpgrp(0L, getpid());
|
||||
|
||||
execve(cmd, args, environ);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -307,9 +328,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
|
|||
p = (Ptycmd) zalloc(sizeof(*p));
|
||||
|
||||
p->name = ztrdup(pname);
|
||||
PERMALLOC {
|
||||
p->args = arrdup(args);
|
||||
} LASTALLOC;
|
||||
p->args = zarrdup(args);
|
||||
p->fd = master;
|
||||
p->pid = pid;
|
||||
p->echo = echo;
|
||||
|
@ -343,7 +362,9 @@ deleteptycmd(Ptycmd cmd)
|
|||
zsfree(p->name);
|
||||
freearray(p->args);
|
||||
|
||||
kill(p->pid, SIGHUP);
|
||||
/* We kill the process group the command put itself in. */
|
||||
|
||||
kill(-(p->pid), SIGHUP);
|
||||
|
||||
zclose(cmd->fd);
|
||||
|
||||
|
@ -375,7 +396,7 @@ checkptycmd(Ptycmd cmd)
|
|||
static int
|
||||
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);
|
||||
Patprog prog = NULL;
|
||||
|
||||
|
@ -383,57 +404,113 @@ ptyread(char *nam, Ptycmd cmd, char **args)
|
|||
char *p;
|
||||
|
||||
if (args[2]) {
|
||||
zerrnam(nam, "too many arguments", NULL, 0);
|
||||
zwarnnam(nam, "too many arguments", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
p = dupstring(args[1]);
|
||||
tokenize(p);
|
||||
remnulargs(p);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
buf = hrealloc(buf, blen, blen << 1);
|
||||
blen <<= 1;
|
||||
}
|
||||
}
|
||||
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)
|
||||
setsparam(*args, ztrdup(buf));
|
||||
else
|
||||
printf("%s", buf);
|
||||
|
||||
setsparam(*args, ztrdup(metafy(buf, used, META_HREALLOC)));
|
||||
else {
|
||||
fflush(stdout);
|
||||
write(1, buf, 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
|
||||
ptywrite(Ptycmd cmd, char **args, int nonl)
|
||||
{
|
||||
if (*args) {
|
||||
char sp = ' ';
|
||||
|
||||
while (*args) {
|
||||
write(cmd->fd, *args, strlen(*args));
|
||||
while (*args)
|
||||
if (ptywritestr(cmd, *args, strlen(*args)) ||
|
||||
(*++args && ptywritestr(cmd, &sp, 1)))
|
||||
return 1;
|
||||
|
||||
if (*++args)
|
||||
write(cmd->fd, &sp, 1);
|
||||
}
|
||||
if (!nonl) {
|
||||
sp = '\n';
|
||||
write(cmd->fd, &sp, 1);
|
||||
if (ptywritestr(cmd, &sp, 1))
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
int n;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
while ((n = read(0, buf, BUFSIZ)) > 0)
|
||||
write(cmd->fd, buf, n);
|
||||
if (ptywritestr(cmd, buf, n))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -449,17 +526,17 @@ bin_zpty(char *nam, char **args, char *ops, int func)
|
|||
ops['d'] || ops['L'])) ||
|
||||
(ops['d'] && (ops['b'] || ops['e'] || ops['L'])) ||
|
||||
(ops['L'] && (ops['b'] || ops['e']))) {
|
||||
zerrnam(nam, "illegal option combination", NULL, 0);
|
||||
zwarnnam(nam, "illegal option combination", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
if (ops['r'] || ops['w']) {
|
||||
Ptycmd p;
|
||||
|
||||
if (!*args) {
|
||||
zerrnam(nam, "missing pty command name", NULL, 0);
|
||||
zwarnnam(nam, "missing pty command name", NULL, 0);
|
||||
return 1;
|
||||
} 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;
|
||||
}
|
||||
checkptycmd(p);
|
||||
|
@ -486,11 +563,11 @@ bin_zpty(char *nam, char **args, char *ops, int func)
|
|||
return ret;
|
||||
} else if (*args) {
|
||||
if (!args[1]) {
|
||||
zerrnam(nam, "missing command", NULL, 0);
|
||||
zwarnnam(nam, "missing command", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
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 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;
|
||||
typedef struct compctl *Compctl;
|
||||
typedef struct compcond *Compcond;
|
||||
/* This is for explantion strings. */
|
||||
|
||||
/* node for compctl hash table (compctltab) */
|
||||
|
||||
struct compctlp {
|
||||
HashNode next; /* next in hash chain */
|
||||
char *nam; /* command name */
|
||||
int flags; /* CURRENTLY UNUSED */
|
||||
Compctl cc; /* pointer to the compctl desc. */
|
||||
struct cexpl {
|
||||
char *str; /* the string */
|
||||
int count; /* the number of matches */
|
||||
int fcount; /* number of matches with fignore ignored */
|
||||
};
|
||||
|
||||
/* compctl -x condition */
|
||||
/* This describes a group of matches. */
|
||||
|
||||
struct compcond {
|
||||
Compcond and, or; /* the next or'ed/and'ed conditions */
|
||||
int type; /* the type (CCT_*) */
|
||||
int n; /* the array length */
|
||||
union { /* these structs hold the data used to */
|
||||
struct { /* test this condition */
|
||||
int *a, *b; /* CCT_POS, CCT_NUMWORDS */
|
||||
}
|
||||
r;
|
||||
struct { /* CCT_CURSTR, CCT_CURPAT,... */
|
||||
int *p;
|
||||
char **s;
|
||||
}
|
||||
s;
|
||||
struct { /* CCT_RANGESTR,... */
|
||||
char **a, **b;
|
||||
}
|
||||
l;
|
||||
}
|
||||
u;
|
||||
struct cmgroup {
|
||||
char *name; /* the name of this group */
|
||||
Cmgroup prev; /* previous on the list */
|
||||
Cmgroup next; /* next one in list */
|
||||
int flags; /* see CGF_* below */
|
||||
int mcount; /* number of matches */
|
||||
Cmatch *matches; /* the matches */
|
||||
int lcount; /* number of things to list here */
|
||||
int llcount; /* number of line-displays */
|
||||
char **ylist; /* things to list */
|
||||
int ecount; /* number of explanation string */
|
||||
Cexpl *expls; /* explanation strings */
|
||||
int ccount; /* number of compctls used */
|
||||
LinkList lexpls; /* list of explanation string while building */
|
||||
LinkList lmatches; /* list of matches */
|
||||
LinkList lfmatches; /* list of matches without fignore */
|
||||
LinkList lallccs; /* list of used compctls */
|
||||
int num; /* number of this group */
|
||||
int nbrbeg; /* number of opened braces */
|
||||
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 {
|
||||
int refc; /* reference count */
|
||||
Compctl next; /* next compctl for -x */
|
||||
unsigned long mask; /* mask of things to complete (CC_*) */
|
||||
char *keyvar; /* for -k (variable) */
|
||||
char *glob; /* for -g (globbing) */
|
||||
char *str; /* for -s (expansion) */
|
||||
char *func; /* for -K (function) */
|
||||
char *explain; /* for -X (explanation) */
|
||||
char *ylist; /* for -y (user-defined desc. for listing) */
|
||||
char *prefix, *suffix; /* for -P and -S (prefix, suffix) */
|
||||
char *subcmd; /* for -l (command name to use) */
|
||||
char *withd; /* for -w (with directory */
|
||||
char *hpat; /* for -H (history pattern) */
|
||||
int hnum; /* for -H (number of events to search) */
|
||||
Compctl ext; /* for -x (first of the compctls after -x) */
|
||||
Compcond cond; /* for -x (condition for this compctl) */
|
||||
Compctl xor; /* for + (next of the xor'ed compctls) */
|
||||
/* This is the struct used to hold matches. */
|
||||
|
||||
struct cmatch {
|
||||
char *str; /* the match itself */
|
||||
char *ipre; /* ignored prefix, has to be re-inserted */
|
||||
char *ripre; /* ignored prefix, unquoted */
|
||||
char *isuf; /* ignored suffix */
|
||||
char *ppre; /* the path prefix */
|
||||
char *psuf; /* the path suffix */
|
||||
char *prpre; /* path prefix for opendir */
|
||||
char *pre; /* prefix string from -P */
|
||||
char *suf; /* suffix string from -S */
|
||||
char *disp; /* string to display (compadd -d) */
|
||||
char *autoq; /* closing quote to add automatically */
|
||||
int flags; /* see CMF_* below */
|
||||
int *brpl; /* places where to put the brace prefixes */
|
||||
int *brsl; /* ...and the suffixes */
|
||||
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 CC_FILES (1<<0)
|
||||
#define CC_COMMPATH (1<<1)
|
||||
#define CC_REMOVE (1<<2)
|
||||
#define CC_OPTIONS (1<<3)
|
||||
#define CC_VARS (1<<4)
|
||||
#define CC_BINDINGS (1<<5)
|
||||
#define CC_ARRAYS (1<<6)
|
||||
#define CC_INTVARS (1<<7)
|
||||
#define CC_SHFUNCS (1<<8)
|
||||
#define CC_PARAMS (1<<9)
|
||||
#define CC_ENVVARS (1<<10)
|
||||
#define CC_JOBS (1<<11)
|
||||
#define CC_RUNNING (1<<12)
|
||||
#define CC_STOPPED (1<<13)
|
||||
#define CC_BUILTINS (1<<14)
|
||||
#define CC_ALREG (1<<15)
|
||||
#define CC_ALGLOB (1<<16)
|
||||
#define CC_USERS (1<<17)
|
||||
#define CC_DISCMDS (1<<18)
|
||||
#define CC_EXCMDS (1<<19)
|
||||
#define CC_SCALARS (1<<20)
|
||||
#define CC_READONLYS (1<<21)
|
||||
#define CC_SPECIALS (1<<22)
|
||||
#define CC_DELETE (1<<23)
|
||||
#define CC_NAMED (1<<24)
|
||||
#define CC_QUOTEFLAG (1<<25)
|
||||
#define CC_EXTCMDS (1<<26)
|
||||
#define CC_RESWDS (1<<27)
|
||||
#define CC_DIRS (1<<28)
|
||||
#define CMF_FILE (1<< 0) /* this is a file */
|
||||
#define CMF_REMOVE (1<< 1) /* remove the suffix */
|
||||
#define CMF_ISPAR (1<< 2) /* is paramter expansion */
|
||||
#define CMF_PARBR (1<< 3) /* paramter expansion with a brace */
|
||||
#define CMF_PARNEST (1<< 4) /* nested paramter expansion */
|
||||
#define CMF_NOLIST (1<< 5) /* should not be listed */
|
||||
#define CMF_DISPLINE (1<< 6) /* display strings one per line */
|
||||
#define CMF_HIDE (1<< 7) /* temporarily hide this one */
|
||||
#define CMF_NOSPACE (1<< 8) /* don't add a space */
|
||||
#define CMF_PACKED (1<< 9) /* prefer LIST_PACKED */
|
||||
#define CMF_ROWS (1<<10) /* prefer LIST_ROWS_FIRST */
|
||||
#define CMF_MULT (1<<11) /* string appears more than once */
|
||||
#define CMF_FMULT (1<<12) /* first of multiple equal strings */
|
||||
|
||||
/* Stuff for completion matcher control. */
|
||||
|
||||
struct cmlist {
|
||||
Cmlist next; /* next one in the list of global matchers */
|
||||
Cmatcher matcher; /* the matcher definition */
|
||||
char *str; /* the string for it */
|
||||
};
|
||||
|
||||
struct cmatcher {
|
||||
int refc; /* reference counter */
|
||||
Cmatcher next; /* next matcher */
|
||||
int flags; /* see CMF_* below */
|
||||
Cpattern line; /* what matches on the line */
|
||||
int llen; /* length of line pattern */
|
||||
Cpattern word; /* what matches in the word */
|
||||
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.
|
||||
*
|
||||
|
@ -29,12 +29,50 @@
|
|||
|
||||
#include "complete.mdh"
|
||||
#include "complete.pro"
|
||||
#define GLOBAL_PROTOTYPES
|
||||
#include "zle_tricky.pro"
|
||||
#undef GLOBAL_PROTOTYPES
|
||||
|
||||
/* global variables for shell parameters in new style completion */
|
||||
|
||||
/**/
|
||||
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)
|
||||
{
|
||||
Cmlist n;
|
||||
|
@ -51,7 +89,7 @@ freecmlist(Cmlist l)
|
|||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
freecmatcher(Cmatcher m)
|
||||
{
|
||||
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. */
|
||||
|
||||
/**/
|
||||
Cmatcher
|
||||
mod_export Cmatcher
|
||||
cpcmatcher(Cmatcher m)
|
||||
{
|
||||
Cmatcher r = NULL, *p = &r, n;
|
||||
|
@ -155,37 +174,10 @@ cpcpattern(Cpattern o)
|
|||
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. */
|
||||
|
||||
/**/
|
||||
Cmatcher
|
||||
mod_export Cmatcher
|
||||
parse_cmatcher(char *name, char *s)
|
||||
{
|
||||
Cmatcher ret = NULL, r = NULL, n;
|
||||
|
@ -262,8 +254,11 @@ parse_cmatcher(char *name, char *s)
|
|||
return pcm_err;
|
||||
}
|
||||
word = NULL;
|
||||
wl = -1;
|
||||
s++;
|
||||
if (*++s == '*') {
|
||||
s++;
|
||||
wl = -2;
|
||||
} else
|
||||
wl = -1;
|
||||
} else {
|
||||
word = parse_pattern(name, &s, &wl, 0, &err);
|
||||
|
||||
|
@ -389,17 +384,17 @@ static int
|
|||
bin_compadd(char *name, char **argv, char *ops, int func)
|
||||
{
|
||||
struct cadata dat;
|
||||
char *p, **sp, *e, *m = NULL;
|
||||
char *p, **sp, *e, *m = NULL, *mstr = NULL;
|
||||
int dm;
|
||||
Cmatcher match = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre =
|
||||
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.flags = 0;
|
||||
dat.aflags = CAF_MATCH;
|
||||
|
@ -462,10 +457,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
|||
if (!(dat.aflags & CAF_UNIQALL))
|
||||
dat.aflags |= CAF_UNIQCON;
|
||||
break;
|
||||
case 'y':
|
||||
sp = &(dat.ylist);
|
||||
e = "string expected after -%c";
|
||||
break;
|
||||
case 'i':
|
||||
sp = &(dat.ipre);
|
||||
e = "string expected after -%c";
|
||||
|
@ -486,9 +477,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
|||
sp = &(dat.prpre);
|
||||
e = "string expected after -%c";
|
||||
break;
|
||||
case 'a':
|
||||
dat.aflags |= CAF_ALT;
|
||||
break;
|
||||
case 'M':
|
||||
sp = &m;
|
||||
e = "matching specification expected after -%c";
|
||||
|
@ -531,7 +519,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
|||
argv++;
|
||||
goto ca_args;
|
||||
default:
|
||||
zerrnam(name, "bad option: -%c", NULL, *p);
|
||||
zwarnnam(name, "bad option: -%c", NULL, *p);
|
||||
return 1;
|
||||
}
|
||||
if (sp) {
|
||||
|
@ -545,18 +533,29 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
|||
*sp = *argv;
|
||||
p = "" - 1;
|
||||
} else {
|
||||
zerrnam(name, e, NULL, *p);
|
||||
zwarnnam(name, e, NULL, *p);
|
||||
return 1;
|
||||
}
|
||||
if (dm && (match = parse_cmatcher(name, m)) == pcm_err) {
|
||||
match = NULL;
|
||||
return 1;
|
||||
if (dm) {
|
||||
if (mstr)
|
||||
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:
|
||||
if (!*argv)
|
||||
|
||||
if (!*argv && !dat.group &&
|
||||
!(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON)))
|
||||
return 1;
|
||||
|
||||
dat.match = match = cpcmatcher(match);
|
||||
|
@ -574,7 +573,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
|
|||
#define CVT_SUFPAT 5
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
ignore_prefix(int l)
|
||||
{
|
||||
if (l) {
|
||||
|
@ -598,7 +597,7 @@ ignore_prefix(int l)
|
|||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
ignore_suffix(int l)
|
||||
{
|
||||
if (l) {
|
||||
|
@ -621,7 +620,7 @@ ignore_suffix(int l)
|
|||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
restrict_range(int b, int e)
|
||||
{
|
||||
int wl = arrlen(compwords) - 1;
|
||||
|
@ -644,6 +643,7 @@ restrict_range(int b, int e)
|
|||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
static int
|
||||
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;
|
||||
|
||||
if (!(l = strlen(compprefix)))
|
||||
return 0;
|
||||
return ((na == 1 || na == -1) && pattry(pp, compprefix));
|
||||
if (na < 0) {
|
||||
p = compprefix + l;
|
||||
na = -na;
|
||||
|
@ -766,7 +766,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
|
|||
char *p;
|
||||
|
||||
if (!(ol = l = strlen(compsuffix)))
|
||||
return 0;
|
||||
return ((na == 1 || na == -1) && pattry(pp, compsuffix));
|
||||
if (na < 0) {
|
||||
p = compsuffix;
|
||||
na = -na;
|
||||
|
@ -798,11 +798,11 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
|||
char *sa = NULL, *sb = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
if (argv[0][0] != '-') {
|
||||
zerrnam(name, "missing option", NULL, 0);
|
||||
zwarnnam(name, "missing option", NULL, 0);
|
||||
return 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 'q': return set_comp_sep();
|
||||
default:
|
||||
zerrnam(name, "bad option -%c", NULL, argv[0][1]);
|
||||
zwarnnam(name, "bad option -%c", NULL, argv[0][1]);
|
||||
return 1;
|
||||
}
|
||||
if (argv[0][2]) {
|
||||
|
@ -823,7 +823,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
|||
na = 2;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
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 :
|
||||
(sb && argv[na]))) {
|
||||
zerrnam(name, "too many arguments", NULL, 0);
|
||||
zwarnnam(name, "too many arguments", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
switch (test) {
|
||||
|
@ -841,11 +841,9 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
|||
break;
|
||||
case CVT_RANGEPAT:
|
||||
tokenize(sa);
|
||||
sa = rembslash(sa);
|
||||
remnulargs(sa);
|
||||
if (sb) {
|
||||
tokenize(sb);
|
||||
sb = rembslash(sb);
|
||||
remnulargs(sb);
|
||||
}
|
||||
break;
|
||||
|
@ -861,7 +859,6 @@ bin_compset(char *name, char **argv, char *ops, int func)
|
|||
} else
|
||||
na = -1;
|
||||
tokenize(sa);
|
||||
sa = rembslash(sa);
|
||||
remnulargs(sa);
|
||||
break;
|
||||
}
|
||||
|
@ -892,9 +889,6 @@ static struct compparam comprparams[] = {
|
|||
|
||||
static struct compparam compkparams[] = {
|
||||
{ "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 },
|
||||
{ "parameter", PM_SCALAR, VAL(compparameter), 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 },
|
||||
{ "restore", PM_SCALAR, VAL(comprestore), NULL, NULL },
|
||||
{ "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 },
|
||||
{ "exact", PM_SCALAR, VAL(compexact), 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_insert", PM_SCALAR, VAL(compoldins), 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) },
|
||||
{ "all_quotes", PM_SCALAR | PM_READONLY, VAL(compqstack), NULL, NULL },
|
||||
{ "ignored", PM_INTEGER | PM_READONLY, VAL(compignored), NULL, NULL },
|
||||
{ NULL, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -976,7 +970,7 @@ makecompparams(void)
|
|||
|
||||
comprpms[CPN_COMPSTATE] = cpm;
|
||||
tht = paramtab;
|
||||
cpm->level = locallevel;
|
||||
cpm->level = locallevel + 1;
|
||||
cpm->gets.hfn = get_compstate;
|
||||
cpm->sets.hfn = set_compstate;
|
||||
cpm->unsetfn = compunsetfn;
|
||||
|
@ -1029,14 +1023,7 @@ set_compstate(Param pm, HashTable ht)
|
|||
static zlong
|
||||
get_nmatches(Param pm)
|
||||
{
|
||||
return num_matches(1);
|
||||
}
|
||||
|
||||
/**/
|
||||
static zlong
|
||||
get_anmatches(Param pm)
|
||||
{
|
||||
return num_matches(0);
|
||||
return (permmatches(0) ? 0 : nmatches);
|
||||
}
|
||||
|
||||
/**/
|
||||
|
@ -1083,14 +1070,37 @@ static void
|
|||
compunsetfn(Param pm, int exp)
|
||||
{
|
||||
if (exp) {
|
||||
if (PM_TYPE(pm->flags) == PM_SCALAR) {
|
||||
zsfree(*((char **) pm->u.data));
|
||||
*((char **) pm->u.data) = ztrdup("");
|
||||
} else if (PM_TYPE(pm->flags) == PM_ARRAY) {
|
||||
freearray(*((char ***) pm->u.data));
|
||||
*((char ***) pm->u.data) = zcalloc(sizeof(char *));
|
||||
if (pm->u.data) {
|
||||
if (PM_TYPE(pm->flags) == PM_SCALAR) {
|
||||
zsfree(*((char **) pm->u.data));
|
||||
*((char **) pm->u.data) = ztrdup("");
|
||||
} else if (PM_TYPE(pm->flags) == PM_ARRAY) {
|
||||
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)) {
|
||||
for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) {
|
||||
if (rset & 1)
|
||||
(*p)->flags &= ~PM_UNSET;
|
||||
if (runset & 1)
|
||||
(*p)->flags |= PM_UNSET;
|
||||
if (*p) {
|
||||
if (rset & 1)
|
||||
(*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++) {
|
||||
if (kset & 1)
|
||||
(*p)->flags &= ~PM_UNSET;
|
||||
if (kunset & 1)
|
||||
(*p)->flags |= PM_UNSET;
|
||||
if (*p) {
|
||||
if (kset & 1)
|
||||
(*p)->flags &= ~PM_UNSET;
|
||||
if (kunset & 1)
|
||||
(*p)->flags |= PM_UNSET;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
static int
|
||||
comp_wrapper(List list, FuncWrap w, char *name)
|
||||
comp_wrapper(Eprog prog, FuncWrap w, char *name)
|
||||
{
|
||||
if (incompfunc != 1)
|
||||
return 1;
|
||||
else {
|
||||
char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
|
||||
char *oqipre, *oqisuf, *oq, *oqi;
|
||||
char *oqipre, *oqisuf, *oq, *oqi, *oqs, *oaq;
|
||||
zlong ocur;
|
||||
unsigned int runset = 0, kunset = 0, m, sm;
|
||||
Param *pp;
|
||||
|
@ -1142,52 +1156,65 @@ comp_wrapper(List list, FuncWrap w, char *name)
|
|||
orest = comprestore;
|
||||
comprestore = ztrdup("auto");
|
||||
ocur = compcurrent;
|
||||
opre = dupstring(compprefix);
|
||||
osuf = dupstring(compsuffix);
|
||||
oipre = dupstring(compiprefix);
|
||||
oisuf = dupstring(compisuffix);
|
||||
oqipre = dupstring(compqiprefix);
|
||||
oqisuf = dupstring(compqisuffix);
|
||||
oq = dupstring(compquote);
|
||||
oqi = dupstring(compquoting);
|
||||
opre = ztrdup(compprefix);
|
||||
osuf = ztrdup(compsuffix);
|
||||
oipre = ztrdup(compiprefix);
|
||||
oisuf = ztrdup(compisuffix);
|
||||
oqipre = ztrdup(compqiprefix);
|
||||
oqisuf = ztrdup(compqisuffix);
|
||||
oq = ztrdup(compquote);
|
||||
oqi = ztrdup(compquoting);
|
||||
oqs = ztrdup(compqstack);
|
||||
oaq = ztrdup(autoq);
|
||||
owords = zarrdup(compwords);
|
||||
|
||||
HEAPALLOC {
|
||||
owords = arrdup(compwords);
|
||||
} LASTALLOC;
|
||||
|
||||
runshfunc(list, w, name);
|
||||
runshfunc(prog, w, name);
|
||||
|
||||
if (comprestore && !strcmp(comprestore, "auto")) {
|
||||
compcurrent = ocur;
|
||||
zsfree(compprefix);
|
||||
compprefix = ztrdup(opre);
|
||||
compprefix = opre;
|
||||
zsfree(compsuffix);
|
||||
compsuffix = ztrdup(osuf);
|
||||
compsuffix = osuf;
|
||||
zsfree(compiprefix);
|
||||
compiprefix = ztrdup(oipre);
|
||||
compiprefix = oipre;
|
||||
zsfree(compisuffix);
|
||||
compisuffix = ztrdup(oisuf);
|
||||
compisuffix = oisuf;
|
||||
zsfree(compqiprefix);
|
||||
compqiprefix = ztrdup(oqipre);
|
||||
compqiprefix = oqipre;
|
||||
zsfree(compqisuffix);
|
||||
compqisuffix = ztrdup(oqisuf);
|
||||
compqisuffix = oqisuf;
|
||||
zsfree(compquote);
|
||||
compquote = ztrdup(oq);
|
||||
compquote = oq;
|
||||
zsfree(compquoting);
|
||||
compquoting = ztrdup(oqi);
|
||||
compquoting = oqi;
|
||||
zsfree(compqstack);
|
||||
compqstack = oqs;
|
||||
zsfree(autoq);
|
||||
autoq = oaq;
|
||||
freearray(compwords);
|
||||
PERMALLOC {
|
||||
compwords = arrdup(owords);
|
||||
} LASTALLOC;
|
||||
compwords = owords;
|
||||
comp_setunset(CP_COMPSTATE |
|
||||
(~runset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
|
||||
CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX |
|
||||
CP_QIPREFIX | CP_QISUFFIX)),
|
||||
(runset & CP_ALLREALS),
|
||||
(~kunset & CP_RESTORE), (kunset & CP_ALLKEYS));
|
||||
} else
|
||||
} else {
|
||||
comp_setunset(CP_COMPSTATE, 0, (~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);
|
||||
comprestore = orest;
|
||||
|
||||
|
@ -1228,42 +1255,6 @@ cond_range(char **a, int id)
|
|||
(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[] = {
|
||||
BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL),
|
||||
BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL),
|
||||
|
@ -1280,53 +1271,108 @@ static struct funcwrap wrapper[] = {
|
|||
WRAPDEF(comp_wrapper),
|
||||
};
|
||||
|
||||
static struct paramdef patab[] = {
|
||||
PARAMDEF("compmatchers", PM_ARRAY|PM_SPECIAL, NULL, cmsetfn, cmgetfn, cmunsetfn)
|
||||
/* The order of the entries in this table has to match the *HOOK
|
||||
* 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
|
||||
setup_complete(Module m)
|
||||
setup_(Module m)
|
||||
{
|
||||
makecompparamsptr = makecompparams;
|
||||
comp_setunsetptr = comp_setunset;
|
||||
hasperm = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**/
|
||||
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)) |
|
||||
addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
|
||||
addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) |
|
||||
!addwrapper(m, wrapper)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
/**/
|
||||
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));
|
||||
deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
|
||||
deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab));
|
||||
deletewrapper(m, wrapper);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
finish_complete(Module m)
|
||||
finish_(Module m)
|
||||
{
|
||||
makecompparamsptr = NULL;
|
||||
comp_setunsetptr = NULL;
|
||||
if (compwords)
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,15 +28,8 @@
|
|||
*/
|
||||
|
||||
#include "complete.mdh"
|
||||
#define GLOBAL_PROTOTYPES
|
||||
#include "zle_tricky.pro"
|
||||
#undef GLOBAL_PROTOTYPES
|
||||
#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
|
||||
* equal. */
|
||||
|
||||
|
@ -75,14 +68,14 @@ cmp_cmatchers(Cmatcher a, Cmatcher b)
|
|||
/* Add the given matchers to the bmatcher list. */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
add_bmatchers(Cmatcher m)
|
||||
{
|
||||
Cmlist old = bmatchers, *q = &bmatchers, n;
|
||||
|
||||
for (; m; m = m->next) {
|
||||
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));
|
||||
n->matcher = m;
|
||||
q = &(n->next);
|
||||
|
@ -95,7 +88,7 @@ add_bmatchers(Cmatcher m)
|
|||
* ensure that the bmatchers list contains no matchers not in mstack. */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
update_bmatchers(void)
|
||||
{
|
||||
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->flags = fl;
|
||||
r->prefix = r->suffix = NULL;
|
||||
r->min = r->max = 0;
|
||||
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 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);
|
||||
char *ow;
|
||||
Cmlist ms;
|
||||
|
@ -553,7 +547,7 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
|
|||
} else
|
||||
t = match_str(l + llen + moff, tp + moff,
|
||||
NULL, 0, NULL, 0, 1, part);
|
||||
if (t || !both)
|
||||
if (t || (mp->wlen == -1 && !both))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -743,12 +737,15 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
|
|||
if (mp)
|
||||
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
|
||||
* character here, skip over it. */
|
||||
l += add; w += add;
|
||||
il++; iw++;
|
||||
ll--; lw--;
|
||||
l += add; w += (bslash ? (add + add ) : add);
|
||||
il++; iw += 1 + bslash;
|
||||
ll--; lw -= 1 + bslash;
|
||||
bc++;
|
||||
if (!test)
|
||||
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. */
|
||||
|
||||
/**/
|
||||
char *
|
||||
mod_export char *
|
||||
comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
|
||||
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))
|
||||
return NULL;
|
||||
|
||||
r = (qu ? quotename(r, NULL) : dupstring(r));
|
||||
if (qu == 2 && r[0] == '\\' && r[1] == '~')
|
||||
chuck(r);
|
||||
r = (qu == 2 ? tildequote(r, 0) : multiquote(r, !qu));
|
||||
|
||||
/* We still break it into parts here, trying to build a sensible
|
||||
* cline list for these matches, too. */
|
||||
w = dupstring(w);
|
||||
|
@ -866,10 +862,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
|
|||
Cline pli, plil;
|
||||
int mpl, rpl, wl;
|
||||
|
||||
w = (qu ? quotename(w, NULL) : dupstring(w));
|
||||
if (qu == 2 && w[0] == '\\' && w[1] == '~')
|
||||
chuck(w);
|
||||
|
||||
w = (qu == 2 ? tildequote(w, 0) : multiquote(w, !qu));
|
||||
wl = strlen(w);
|
||||
|
||||
/* Always try to match the prefix. */
|
||||
|
@ -1016,7 +1009,7 @@ bld_parts(char *str, int len, int plen, Cline *lp)
|
|||
while (len) {
|
||||
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
|
||||
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 &&
|
||||
pattern_match(mp->right, str, NULL, NULL)) {
|
||||
int olen = str - p, llen;
|
||||
|
@ -1136,7 +1129,7 @@ bld_line(Cpattern pat, char *line, char *lp,
|
|||
t = 0;
|
||||
for (ms = bmatchers; ms && !t; ms = ms->next) {
|
||||
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),
|
||||
NULL, ea) &&
|
||||
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. */
|
||||
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
|
||||
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) {
|
||||
/* The pattern has no anchors and the word
|
||||
* 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
|
||||
* string in both the line and the word and that have
|
||||
* 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
|
||||
* new one. */
|
||||
if (mp->llen <= ol && mp->wlen <= nl &&
|
||||
|
@ -1684,7 +1677,7 @@ join_mid(Cline o, Cline n)
|
|||
* didn't. */
|
||||
|
||||
/**/
|
||||
static void
|
||||
static int
|
||||
sub_join(Cline a, Cline b, Cline e, int anew)
|
||||
{
|
||||
if (!e->suffix && a->prefix) {
|
||||
|
@ -1707,31 +1700,28 @@ sub_join(Cline a, Cline b, Cline e, int anew)
|
|||
*p = e->prefix;
|
||||
ca = a->prefix;
|
||||
|
||||
while (n != op) {
|
||||
while (n) {
|
||||
e->prefix = cp_cline(n, 0);
|
||||
a->prefix = cp_cline(ca, 0);
|
||||
|
||||
if (anew) {
|
||||
join_psfx(e, a, NULL, NULL, 0);
|
||||
if (e->prefix) {
|
||||
e->min += min;
|
||||
e->max += max;
|
||||
break;
|
||||
}
|
||||
if (e->prefix)
|
||||
return max - min;
|
||||
} else {
|
||||
join_psfx(e, a, NULL, NULL, 0);
|
||||
if (a->prefix) {
|
||||
a->min += min;
|
||||
a->max += max;
|
||||
break;
|
||||
}
|
||||
join_psfx(a, e, NULL, NULL, 0);
|
||||
if (a->prefix)
|
||||
return max - min;
|
||||
}
|
||||
min -= n->min;
|
||||
max -= n->max;
|
||||
|
||||
if (n == op)
|
||||
break;
|
||||
n = n->next;
|
||||
}
|
||||
return max - min;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This simplifies the cline list given as the first argument so that
|
||||
|
@ -1748,7 +1738,8 @@ join_clines(Cline o, Cline n)
|
|||
if (!o)
|
||||
return n;
|
||||
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. */
|
||||
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);
|
||||
if (tn && cmp_anchors(tn, n, 0)) {
|
||||
sub_join(n, o, tn, 1);
|
||||
diff = sub_join(n, o, tn, 1);
|
||||
|
||||
if (po)
|
||||
po->next = tn;
|
||||
|
@ -1768,8 +1759,15 @@ join_clines(Cline o, Cline n)
|
|||
oo = tn;
|
||||
t->next = NULL;
|
||||
free_cline(o);
|
||||
x = o;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1778,10 +1776,16 @@ join_clines(Cline o, Cline n)
|
|||
|
||||
for (t = n; (tn = t->next) && (tn->flags & CLF_NEW); t = tn);
|
||||
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;
|
||||
o->flags |= CLF_MISS;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1809,6 +1813,7 @@ join_clines(Cline o, Cline n)
|
|||
t = tn);
|
||||
if (tn && cmp_anchors(tn, n, 1)) {
|
||||
sub_join(n, o, tn, 1);
|
||||
|
||||
if (po)
|
||||
po->next = tn;
|
||||
else
|
||||
|
@ -1837,24 +1842,41 @@ join_clines(Cline o, Cline n)
|
|||
for (t = n; (tn = t->next) && !cmp_anchors(o, tn, 1); t = 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;
|
||||
o->flags |= CLF_MISS;
|
||||
po = o;
|
||||
o = o->next;
|
||||
pn = n;
|
||||
n = n->next;
|
||||
continue;
|
||||
} else {
|
||||
for (t = o; (tn = t->next) && !cmp_anchors(n, tn, 1);
|
||||
t = tn);
|
||||
|
||||
if (tn) {
|
||||
sub_join(n, o, tn, 1);
|
||||
diff = sub_join(n, o, tn, 1);
|
||||
|
||||
if (po)
|
||||
po->next = tn;
|
||||
else
|
||||
oo = tn;
|
||||
x = o;
|
||||
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;
|
||||
} else {
|
||||
if (o->flags & CLF_SUF)
|
||||
|
|
|
@ -28,16 +28,8 @@
|
|||
*/
|
||||
|
||||
#include "complete.mdh"
|
||||
#define GLOBAL_PROTOTYPES
|
||||
#include "zle_tricky.pro"
|
||||
#undef GLOBAL_PROTOTYPES
|
||||
#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)
|
||||
|
||||
/* This cuts the cline list before the stuff that isn't worth
|
||||
|
@ -72,7 +64,8 @@ cut_cline(Cline l)
|
|||
q = p;
|
||||
}
|
||||
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->wlen = q->llen = 0;
|
||||
}
|
||||
|
@ -143,8 +136,9 @@ cline_str(Cline l, int ins, int *csp)
|
|||
|
||||
l = cut_cline(l);
|
||||
|
||||
pmm = smm = dm = 0;
|
||||
pmm = smm = dm = pcs = scs = 0;
|
||||
pm = pmax = sm = smax = d = mid = cbr = -1;
|
||||
brp = brs = NULL;
|
||||
|
||||
/* Get the information about the brace beginning and end we have
|
||||
* to re-insert. */
|
||||
|
@ -594,7 +588,7 @@ do_ambiguous(void)
|
|||
/* If we have to insert the first match, call do_single(). This is *
|
||||
* how REC_EXACT takes effect. We effectively turn the ambiguous *
|
||||
* 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;
|
||||
do_single(ainfo->exactm);
|
||||
invalidatelist();
|
||||
|
@ -616,6 +610,7 @@ do_ambiguous(void)
|
|||
do_ambig_menu();
|
||||
} else if (ainfo) {
|
||||
int atend = (cs == we), la, eq, tcs;
|
||||
VARARR(char, old, we - wb);
|
||||
|
||||
minfo.cur = NULL;
|
||||
minfo.asked = 0;
|
||||
|
@ -623,11 +618,24 @@ do_ambiguous(void)
|
|||
fixsuffix();
|
||||
|
||||
/* First remove the old string from the line. */
|
||||
tcs = cs;
|
||||
cs = wb;
|
||||
memcpy(old, (char *) line + wb, we - wb);
|
||||
foredel(we - wb);
|
||||
|
||||
/* Now get the unambiguous string and insert it into the line. */
|
||||
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) {
|
||||
tcs = cs;
|
||||
cs = lastend;
|
||||
|
@ -677,7 +685,7 @@ do_ambiguous(void)
|
|||
if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
|
||||
((!showinglist && (!listshown || !oldlist)) ||
|
||||
(usemenu == 3 && !oldlist)) &&
|
||||
(smatches >= 2 || (compforcelist && *compforcelist)))
|
||||
(smatches >= 2 || forcelist))
|
||||
showinglist = -2;
|
||||
|
||||
return ret;
|
||||
|
@ -690,7 +698,7 @@ do_ambiguous(void)
|
|||
* (l)stat(). */
|
||||
|
||||
/**/
|
||||
int
|
||||
mod_export int
|
||||
ztat(char *nam, struct stat *buf, int ls)
|
||||
{
|
||||
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. */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
do_single(Cmatch m)
|
||||
{
|
||||
int l, sr = 0, scs;
|
||||
|
@ -726,7 +734,8 @@ do_single(Cmatch m)
|
|||
/* We are currently not in a menu-completion, *
|
||||
* so set the position variables. */
|
||||
minfo.pos = wb;
|
||||
minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp));
|
||||
minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp) ||
|
||||
(!movetoend && cs == we));
|
||||
minfo.end = we;
|
||||
}
|
||||
/* If we are already in a menu-completion or if we have done a *
|
||||
|
@ -792,19 +801,40 @@ do_single(Cmatch m)
|
|||
else {
|
||||
/* Build the path name. */
|
||||
if (partest && !*psuf && !(m->flags & CMF_PARNEST)) {
|
||||
int ne = noerrs;
|
||||
int ne = noerrs, tryit = 1;
|
||||
|
||||
p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ?
|
||||
parpre : m->ripre) +
|
||||
strlen(str) + 2);
|
||||
sprintf(p, "%s%s%c",
|
||||
((m->flags & CMF_ISPAR) ? parpre : m->ripre), str,
|
||||
((m->flags & CMF_PARBR) ? Outbrace : '\0'));
|
||||
noerrs = 1;
|
||||
parsestr(p);
|
||||
singsub(&p);
|
||||
errflag = 0;
|
||||
noerrs = ne;
|
||||
((m->flags & CMF_PARBR) ? '}' : '\0'));
|
||||
if (*p == '$') {
|
||||
char *n;
|
||||
Param pm;
|
||||
|
||||
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 {
|
||||
p = (char *) zhalloc(strlen(prpre) + strlen(str) +
|
||||
strlen(psuf) + 3);
|
||||
|
@ -857,11 +887,13 @@ do_single(Cmatch m)
|
|||
/* If we didn't add a suffix, add a space, unless we are *
|
||||
* doing menu completion or we are completing files and *
|
||||
* the string doesn't name an existing file. */
|
||||
if (m->autoq && (!m->isuf || m->isuf[0] != m->autoq)) {
|
||||
inststrlen(&(m->autoq), 1, 1);
|
||||
minfo.insc++;
|
||||
if (m->autoq && (!m->isuf || !strpfx(m->autoq, m->isuf))) {
|
||||
int al = strlen(m->autoq);
|
||||
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);
|
||||
minfo.insc++;
|
||||
if (minfo.we)
|
||||
|
@ -897,7 +929,7 @@ do_single(Cmatch m)
|
|||
* insert the next completion. */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
do_menucmp(int lst)
|
||||
{
|
||||
/* Just list the matches if the list was requested. */
|
||||
|
@ -906,44 +938,40 @@ do_menucmp(int lst)
|
|||
return;
|
||||
}
|
||||
/* Otherwise go to the next match in the array... */
|
||||
HEAPALLOC {
|
||||
do {
|
||||
if (!*++(minfo.cur)) {
|
||||
do {
|
||||
if (!(minfo.group = (minfo.group)->next))
|
||||
minfo.group = amatches;
|
||||
} while (!(minfo.group)->mcount);
|
||||
minfo.cur = minfo.group->matches;
|
||||
}
|
||||
} while (menuacc &&
|
||||
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
||||
/* ... and insert it into the command line. */
|
||||
metafy_line();
|
||||
do_single(*(minfo.cur));
|
||||
unmetafy_line();
|
||||
} LASTALLOC;
|
||||
do {
|
||||
if (!*++(minfo.cur)) {
|
||||
do {
|
||||
if (!(minfo.group = (minfo.group)->next))
|
||||
minfo.group = amatches;
|
||||
} while (!(minfo.group)->mcount);
|
||||
minfo.cur = minfo.group->matches;
|
||||
}
|
||||
} while (menuacc &&
|
||||
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
||||
/* ... and insert it into the command line. */
|
||||
metafy_line();
|
||||
do_single(*(minfo.cur));
|
||||
unmetafy_line();
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
reverse_menu(Hookdef dummy, void *dummy2)
|
||||
{
|
||||
HEAPALLOC {
|
||||
do {
|
||||
if (minfo.cur == (minfo.group)->matches) {
|
||||
do {
|
||||
if (!(minfo.group = (minfo.group)->prev))
|
||||
minfo.group = lmatches;
|
||||
} while (!(minfo.group)->mcount);
|
||||
minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
|
||||
} else
|
||||
minfo.cur--;
|
||||
} while (menuacc &&
|
||||
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
||||
metafy_line();
|
||||
do_single(*(minfo.cur));
|
||||
unmetafy_line();
|
||||
} LASTALLOC;
|
||||
do {
|
||||
if (minfo.cur == (minfo.group)->matches) {
|
||||
do {
|
||||
if (!(minfo.group = (minfo.group)->prev))
|
||||
minfo.group = lmatches;
|
||||
} while (!(minfo.group)->mcount);
|
||||
minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
|
||||
} else
|
||||
minfo.cur--;
|
||||
} while (menuacc &&
|
||||
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
|
||||
metafy_line();
|
||||
do_single(*(minfo.cur));
|
||||
unmetafy_line();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -953,7 +981,7 @@ reverse_menu(Hookdef dummy, void *dummy2)
|
|||
* accept several selections from the list of matches. */
|
||||
|
||||
/**/
|
||||
int
|
||||
mod_export int
|
||||
accept_last(void)
|
||||
{
|
||||
if (!menuacc) {
|
||||
|
@ -1042,7 +1070,7 @@ do_ambig_menu(void)
|
|||
} else {
|
||||
if (oldlist) {
|
||||
if (oldins && minfo.cur)
|
||||
acceptlast();
|
||||
accept_last();
|
||||
} else
|
||||
minfo.cur = NULL;
|
||||
}
|
||||
|
@ -1074,24 +1102,6 @@ do_ambig_menu(void)
|
|||
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. */
|
||||
|
||||
/**/
|
||||
|
@ -1100,14 +1110,12 @@ list_lines(void)
|
|||
{
|
||||
Cmgroup oam;
|
||||
|
||||
PERMALLOC {
|
||||
permmatches(0);
|
||||
} LASTALLOC;
|
||||
permmatches(0);
|
||||
|
||||
oam = amatches;
|
||||
amatches = pmatches;
|
||||
listdat.valid = 0;
|
||||
calclist();
|
||||
calclist(0);
|
||||
listdat.valid = 0;
|
||||
amatches = oam;
|
||||
|
||||
|
@ -1124,132 +1132,25 @@ comp_list(char *v)
|
|||
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. */
|
||||
|
||||
/**/
|
||||
Cmatch *
|
||||
skipnolist(Cmatch *p)
|
||||
skipnolist(Cmatch *p, int showall)
|
||||
{
|
||||
while (*p && (((*p)->flags & (CMF_NOLIST | CMF_HIDE)) ||
|
||||
((*p)->disp && ((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
|
||||
int mask = (showall ? 0 : (CMF_NOLIST | CMF_MULT)) | CMF_HIDE;
|
||||
|
||||
while (*p && (((*p)->flags & mask) ||
|
||||
((*p)->disp &&
|
||||
((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
|
||||
p++;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
calclist(void)
|
||||
mod_export void
|
||||
calclist(int showall)
|
||||
{
|
||||
Cmgroup g;
|
||||
Cmatch *p, m;
|
||||
|
@ -1259,7 +1160,7 @@ calclist(void)
|
|||
VARARR(int, mlens, nmatches + 1);
|
||||
|
||||
if (listdat.valid && onlyexpl == listdat.onlyexpl &&
|
||||
menuacc == listdat.menuacc &&
|
||||
menuacc == listdat.menuacc && showall == listdat.showall &&
|
||||
lines == listdat.lines && columns == listdat.columns)
|
||||
return;
|
||||
|
||||
|
@ -1267,6 +1168,8 @@ calclist(void)
|
|||
char **pp = g->ylist;
|
||||
int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
|
||||
|
||||
g->flags |= CGF_PACKED | CGF_ROWS;
|
||||
|
||||
if (!onlyexpl && pp) {
|
||||
/* We have an ylist, lets see, if it contains newlines. */
|
||||
hidden = 1;
|
||||
|
@ -1283,8 +1186,8 @@ calclist(void)
|
|||
while ((sptr = *pp)) {
|
||||
while (sptr && *sptr) {
|
||||
nlines += (nlptr = strchr(sptr, '\n'))
|
||||
? 1 + (nlptr-sptr)/columns
|
||||
: strlen(sptr)/columns;
|
||||
? 1 + (nlptr-sptr) / columns
|
||||
: strlen(sptr) / columns;
|
||||
sptr = nlptr ? nlptr+1 : NULL;
|
||||
}
|
||||
nlines++;
|
||||
|
@ -1327,7 +1230,11 @@ calclist(void)
|
|||
mlens[m->gnum] = l;
|
||||
}
|
||||
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);
|
||||
ndisp++;
|
||||
if (l > glong)
|
||||
|
@ -1337,6 +1244,10 @@ calclist(void)
|
|||
totl += l;
|
||||
mlens[m->gnum] = l;
|
||||
nlist++;
|
||||
if (!(m->flags & CMF_PACKED))
|
||||
g->flags &= ~CGF_PACKED;
|
||||
if (!(m->flags & CMF_ROWS))
|
||||
g->flags &= ~CGF_ROWS;
|
||||
} else
|
||||
hidden = 1;
|
||||
}
|
||||
|
@ -1361,9 +1272,11 @@ calclist(void)
|
|||
}
|
||||
}
|
||||
if (!onlyexpl) {
|
||||
char **pp;
|
||||
int *ws, tlines, tline, tcols, maxlen, nth, width, glines;
|
||||
|
||||
for (g = amatches; g; g = g->next) {
|
||||
char **pp;
|
||||
int glines = 0;
|
||||
glines = 0;
|
||||
|
||||
zfree(g->widths, 0);
|
||||
g->widths = NULL;
|
||||
|
@ -1396,20 +1309,19 @@ calclist(void)
|
|||
if (m->disp) {
|
||||
if (!(m->flags & CMF_DISPLINE))
|
||||
glines += 1 + (mlens[m->gnum] / columns);
|
||||
} else if (!(m->flags & CMF_NOLIST))
|
||||
glines += 1 + ((1 + mlens[m->gnum]) / columns);
|
||||
} else if (showall ||
|
||||
!(m->flags & (CMF_NOLIST | CMF_MULT)))
|
||||
glines += 1 + ((mlens[m->gnum]) / columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
g->lins = glines;
|
||||
nlines += glines;
|
||||
}
|
||||
}
|
||||
if (!onlyexpl && isset(LISTPACKED)) {
|
||||
char **pp;
|
||||
int *ws, tlines, tline, tcols, maxlen, nth, width;
|
||||
|
||||
for (g = amatches; g; g = g->next) {
|
||||
if (!(g->flags & CGF_PACKED))
|
||||
continue;
|
||||
|
||||
ws = g->widths = (int *) zalloc(columns * sizeof(int));
|
||||
memset(ws, 0, columns * sizeof(int));
|
||||
tlines = g->lins;
|
||||
|
@ -1424,11 +1336,13 @@ calclist(void)
|
|||
for (i = 0; *pp; i++, pp++)
|
||||
ylens[i] = strlen(*pp) + add;
|
||||
|
||||
if (isset(LISTROWSFIRST)) {
|
||||
if (g->flags & CGF_ROWS) {
|
||||
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 =
|
||||
llines = tcol = 0,
|
||||
count = g->dcount;
|
||||
|
@ -1452,17 +1366,33 @@ calclist(void)
|
|||
ws[tcol++] = maxlen;
|
||||
width += maxlen;
|
||||
}
|
||||
if (!count && width < columns)
|
||||
if (!count && width < columns &&
|
||||
(tcols <= 0 || beg == end))
|
||||
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)
|
||||
tlines = maxlines;
|
||||
} else {
|
||||
for (tlines = ((g->totl + columns) / columns);
|
||||
tlines < g->lins; tlines++) {
|
||||
int beg = ((g->totl + columns) / columns);
|
||||
int end = g->lins;
|
||||
|
||||
while (1) {
|
||||
tlines = (beg + end) >> 1;
|
||||
|
||||
for (pp = g->ylist, nth = tline = width =
|
||||
maxlen = tcols = 0;
|
||||
*pp; nth++, pp++) {
|
||||
*pp; pp++) {
|
||||
if (ylens[nth] > maxlen)
|
||||
maxlen = ylens[nth];
|
||||
if (++tline == tlines) {
|
||||
|
@ -1471,24 +1401,41 @@ calclist(void)
|
|||
ws[tcols++] = maxlen;
|
||||
maxlen = tline = 0;
|
||||
}
|
||||
nth++;
|
||||
}
|
||||
if (tline) {
|
||||
ws[tcols++] = maxlen;
|
||||
width += maxlen;
|
||||
}
|
||||
if (nth == yl && width < columns)
|
||||
if (nth == yl && width < columns &&
|
||||
(beg == end || tlines >= g->lins))
|
||||
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) {
|
||||
if (isset(LISTROWSFIRST)) {
|
||||
if (g->flags & CGF_ROWS) {
|
||||
int addlen, count, tcol, maxlines = 0, llines, i;
|
||||
int beg = columns / g->shortest, end = g->cols;
|
||||
Cmatch *first;
|
||||
|
||||
for (tcols = columns / g->shortest; tcols > g->cols;
|
||||
tcols--) {
|
||||
p = first = skipnolist(g->matches);
|
||||
while (1) {
|
||||
tcols = (beg + end) >> 1;
|
||||
|
||||
p = first = skipnolist(g->matches, showall);
|
||||
for (maxlen = width = maxlines = llines = tcol = 0,
|
||||
count = g->dcount;
|
||||
count > 0; count--) {
|
||||
|
@ -1497,7 +1444,7 @@ calclist(void)
|
|||
if (addlen > maxlen)
|
||||
maxlen = addlen;
|
||||
for (i = tcols; i && *p; i--)
|
||||
p = skipnolist(p + 1);
|
||||
p = skipnolist(p + 1, showall);
|
||||
|
||||
llines++;
|
||||
if (!*p) {
|
||||
|
@ -1510,29 +1457,46 @@ calclist(void)
|
|||
ws[tcol++] = maxlen;
|
||||
maxlen = 0;
|
||||
|
||||
p = first = skipnolist(first + 1);
|
||||
p = first = skipnolist(first + 1, showall);
|
||||
}
|
||||
}
|
||||
if (tlines) {
|
||||
ws[tcol++] = maxlen;
|
||||
width += maxlen;
|
||||
}
|
||||
if (!count && width < columns)
|
||||
if (!count && width < columns &&
|
||||
(tcols <= 0 || beg == end))
|
||||
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)
|
||||
tlines = maxlines;
|
||||
} else {
|
||||
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 =
|
||||
maxlen = tcols = 0;
|
||||
(m = *p); p++, nth++) {
|
||||
(m = *p); p++) {
|
||||
if (!(m->flags &
|
||||
(m->disp ? (CMF_DISPLINE | CMF_HIDE) :
|
||||
(CMF_NOLIST | CMF_HIDE)))) {
|
||||
smask))) {
|
||||
addlen = mlens[m->gnum] + add;
|
||||
if (addlen > maxlen)
|
||||
maxlen = addlen;
|
||||
|
@ -1542,15 +1506,30 @@ calclist(void)
|
|||
ws[tcols++] = maxlen;
|
||||
maxlen = tline = 0;
|
||||
}
|
||||
nth++;
|
||||
}
|
||||
}
|
||||
if (tline) {
|
||||
ws[tcols++] = maxlen;
|
||||
width += maxlen;
|
||||
}
|
||||
if (nth == g->dcount && width < columns)
|
||||
if (nth == g->dcount && width < columns &&
|
||||
(beg == end || tlines >= g->lins))
|
||||
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) {
|
||||
|
@ -1584,21 +1563,23 @@ calclist(void)
|
|||
listdat.onlyexpl = onlyexpl;
|
||||
listdat.columns = columns;
|
||||
listdat.lines = lines;
|
||||
listdat.showall = showall;
|
||||
}
|
||||
|
||||
/**/
|
||||
int asklist(void)
|
||||
mod_export int asklist(void)
|
||||
{
|
||||
/* Set the cursor below the prompt. */
|
||||
trashzle();
|
||||
showinglist = listshown = 0;
|
||||
|
||||
clearflag = (isset(USEZLE) && !termflags &&
|
||||
complastprompt && *complastprompt);
|
||||
clearflag = (isset(USEZLE) && !termflags && dolastprompt);
|
||||
lastlistlen = 0;
|
||||
|
||||
/* Maybe we have to ask if the user wants to see the list. */
|
||||
if ((!minfo.cur || !minfo.asked) &&
|
||||
((complistmax && listdat.nlist > complistmax) ||
|
||||
((complistmax > 0 && listdat.nlist >= complistmax) ||
|
||||
(complistmax < 0 && listdat.nlines <= -complistmax) ||
|
||||
(!complistmax && listdat.nlines >= lines))) {
|
||||
int qup;
|
||||
zsetterm();
|
||||
|
@ -1614,8 +1595,7 @@ int asklist(void)
|
|||
tcmultout(TCUP, TCMULTUP, nlnct);
|
||||
} else
|
||||
putc('\n', shout);
|
||||
if (minfo.cur)
|
||||
minfo.asked = 2;
|
||||
minfo.asked = 2;
|
||||
return 1;
|
||||
}
|
||||
if (clearflag) {
|
||||
|
@ -1626,15 +1606,14 @@ int asklist(void)
|
|||
} else
|
||||
putc('\n', shout);
|
||||
settyinfo(&shttyinfo);
|
||||
if (minfo.cur)
|
||||
minfo.asked = 1;
|
||||
minfo.asked = 1;
|
||||
}
|
||||
return 0;
|
||||
return (minfo.asked ? minfo.asked - 1 : 0);
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
printlist(int over, CLPrintFunc printm)
|
||||
mod_export int
|
||||
printlist(int over, CLPrintFunc printm, int showall)
|
||||
{
|
||||
Cmgroup g;
|
||||
Cmatch *p, m;
|
||||
|
@ -1715,7 +1694,7 @@ printlist(int over, CLPrintFunc printm)
|
|||
while (a--)
|
||||
putc(' ', shout);
|
||||
}
|
||||
pq += (isset(LISTROWSFIRST) ? 1 : nc);
|
||||
pq += ((g->flags & CGF_ROWS) ? 1 : nc);
|
||||
mc++;
|
||||
n--;
|
||||
}
|
||||
|
@ -1728,10 +1707,11 @@ printlist(int over, CLPrintFunc printm)
|
|||
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;
|
||||
Cmatch *q;
|
||||
|
||||
|
@ -1765,7 +1745,7 @@ printlist(int over, CLPrintFunc printm)
|
|||
tcout(TCCLEAREOD);
|
||||
}
|
||||
}
|
||||
for (p = skipnolist(g->matches); n && nl--;) {
|
||||
for (p = skipnolist(g->matches, showall); n && nl--;) {
|
||||
i = g->cols;
|
||||
mc = 0;
|
||||
q = p;
|
||||
|
@ -1794,14 +1774,16 @@ printlist(int over, CLPrintFunc printm)
|
|||
printed++;
|
||||
|
||||
if (--n)
|
||||
for (j = (isset(LISTROWSFIRST) ? 1 : nc); j && *q; j--)
|
||||
q = skipnolist(q + 1);
|
||||
for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
|
||||
j && *q; j--)
|
||||
q = skipnolist(q + 1, showall);
|
||||
mc++;
|
||||
}
|
||||
while (i-- > 0)
|
||||
printm(g, NULL, mc++, ml, (!i),
|
||||
while (i-- > 0) {
|
||||
printm(g, NULL, mc, ml, (!i),
|
||||
(g->widths ? g->widths[mc] : g->width), NULL, NULL);
|
||||
|
||||
mc++;
|
||||
}
|
||||
if (n) {
|
||||
putc('\n', shout);
|
||||
ml++;
|
||||
|
@ -1811,25 +1793,30 @@ printlist(int over, CLPrintFunc printm)
|
|||
tcout(TCCLEAREOD);
|
||||
}
|
||||
if (nl)
|
||||
for (j = (isset(LISTROWSFIRST) ? g->cols : 1); j && *p; j--)
|
||||
p = skipnolist(p + 1);
|
||||
for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
|
||||
j && *p; j--)
|
||||
p = skipnolist(p + 1, showall);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (g->lcount)
|
||||
if (g->lcount || (showall && g->mcount))
|
||||
pnl = 1;
|
||||
g = g->next;
|
||||
}
|
||||
lastlistlen = 0;
|
||||
if (clearflag) {
|
||||
/* Move the cursor up to the prompt, if always_last_prompt *
|
||||
* is set and all that... */
|
||||
if ((ml = listdat.nlines + nlnct - 1) < lines) {
|
||||
tcmultout(TCUP, TCMULTUP, ml);
|
||||
showinglist = -1;
|
||||
|
||||
lastlistlen = listdat.nlines;
|
||||
} else
|
||||
clearflag = 0, putc('\n', shout);
|
||||
} else
|
||||
putc('\n', shout);
|
||||
|
||||
listshown = (clearflag ? 1 : -1);
|
||||
|
||||
return printed;
|
||||
|
@ -1858,9 +1845,8 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
|
|||
nicezputs(m->str, shout);
|
||||
len = niceztrlen(m->str);
|
||||
|
||||
if (isset(LISTTYPES)) {
|
||||
if (buf)
|
||||
putc(file_type(buf->st_mode), shout);
|
||||
if (isset(LISTTYPES) && buf) {
|
||||
putc(file_type(buf->st_mode), shout);
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
@ -1876,7 +1862,7 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
|
|||
int
|
||||
ilistmatches(Hookdef dummy, Chdata dat)
|
||||
{
|
||||
calclist();
|
||||
calclist(0);
|
||||
|
||||
if (!listdat.nlines) {
|
||||
showinglist = listshown = 0;
|
||||
|
@ -1885,7 +1871,7 @@ ilistmatches(Hookdef dummy, Chdata dat)
|
|||
if (asklist())
|
||||
return 0;
|
||||
|
||||
printlist(0, iprintm);
|
||||
printlist(0, iprintm, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1897,6 +1883,7 @@ int
|
|||
list_matches(Hookdef dummy, void *dummy2)
|
||||
{
|
||||
struct chdata dat;
|
||||
int ret;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Sanity check */
|
||||
|
@ -1909,18 +1896,20 @@ list_matches(Hookdef dummy, void *dummy2)
|
|||
dat.matches = amatches;
|
||||
dat.num = nmatches;
|
||||
dat.cur = NULL;
|
||||
return runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
|
||||
ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Invalidate the completion list. */
|
||||
|
||||
/**/
|
||||
int
|
||||
mod_export int
|
||||
invalidate_list(void)
|
||||
{
|
||||
if (showinglist == -2)
|
||||
listmatches();
|
||||
if (validlist) {
|
||||
if (showinglist == -2)
|
||||
zrefresh();
|
||||
freematches(lastmatches);
|
||||
lastmatches = NULL;
|
||||
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-word", backwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX
|
||||
"backward-word", backwardword, 0
|
||||
"beep", handlefeep, 0
|
||||
"beginning-of-buffer-or-history", beginningofbufferorhistory, 0
|
||||
"beginning-of-history", beginningofhistory, 0
|
||||
"beginning-of-line", beginningofline, 0
|
||||
"beginning-of-line-hist", beginningoflinehist, 0
|
||||
"capitalize-word", capitalizeword, 0
|
||||
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"copy-prev-word", copyprevword, 0
|
||||
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
|
||||
"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||
"copy-prev-word", copyprevword, ZLE_KEEPSUFFIX
|
||||
"copy-region-as-kill", copyregionaskill, 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
|
||||
"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-history", downhistory, 0
|
||||
"down-line-or-history", downlineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
|
||||
|
@ -43,13 +44,14 @@
|
|||
"end-of-history", endofhistory, 0
|
||||
"end-of-line", endofline, 0
|
||||
"end-of-line-hist", endoflinehist, 0
|
||||
"end-of-list", endoflist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"exchange-point-and-mark", exchangepointandmark, 0
|
||||
"execute-last-named-cmd", NULL, 0
|
||||
"execute-named-cmd", NULL, 0
|
||||
"expand-cmd-path", expandcmdpath, 0
|
||||
"expand-history", expandhistory, 0
|
||||
"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||
"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||
"expand-word", expandword, 0
|
||||
"forward-char", forwardchar, 0
|
||||
"forward-word", forwardword, 0
|
||||
|
@ -68,12 +70,12 @@
|
|||
"kill-region", killregion, ZLE_KILL | ZLE_KEEPSUFFIX
|
||||
"kill-whole-line", killwholeline, 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
|
||||
"magic-space", magicspace, 0
|
||||
"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||
"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||
"neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
|
||||
"overwrite-mode", overwritemode, 0
|
||||
"pound-insert", poundinsert, 0
|
||||
"push-input", pushinput, 0
|
||||
|
@ -83,19 +85,20 @@
|
|||
"quote-line", quoteline, 0
|
||||
"quote-region", quoteregion, 0
|
||||
"redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"redo", redo, 0
|
||||
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"redo", redo, ZLE_KEEPSUFFIX
|
||||
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
|
||||
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"send-break", sendbreak, 0
|
||||
"set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"spell-word", spellword, 0
|
||||
"set-local-history", setlocalhistory, 0
|
||||
"transpose-chars", transposechars, 0
|
||||
"transpose-words", transposewords, 0
|
||||
"undefined-key", undefinedkey, 0
|
||||
"undo", undo, 0
|
||||
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"undo", undo, ZLE_KEEPSUFFIX
|
||||
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
|
||||
"up-case-word", upcaseword, 0
|
||||
"up-history", uphistory, 0
|
||||
"up-line-or-history", uplineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
|
||||
|
@ -145,8 +148,8 @@
|
|||
"vi-open-line-below", viopenlinebelow, 0
|
||||
"vi-oper-swap-case", vioperswapcase, 0
|
||||
"vi-pound-insert", vipoundinsert, 0
|
||||
"vi-put-after", viputafter, ZLE_YANK
|
||||
"vi-put-before", viputbefore, ZLE_YANK
|
||||
"vi-put-after", viputafter, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||
"vi-put-before", viputbefore, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||
"vi-quoted-insert", viquotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
|
||||
"vi-repeat-change", virepeatchange, 0
|
||||
"vi-repeat-find", virepeatfind, 0
|
||||
|
@ -159,7 +162,7 @@
|
|||
"vi-set-mark", visetmark, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"vi-substitute", visubstitute, 0
|
||||
"vi-swap-case", viswapcase, 0
|
||||
"vi-undo-change", viundochange, 0
|
||||
"vi-undo-change", viundochange, ZLE_KEEPSUFFIX
|
||||
"vi-unindent", viunindent, 0
|
||||
"vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE
|
||||
"vi-yank", viyank, 0
|
||||
|
@ -168,5 +171,5 @@
|
|||
"what-cursor-position", whatcursorposition, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"where-is", whereis, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"which-command", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
|
||||
"yank", yank, ZLE_YANK
|
||||
"yank-pop", yankpop, ZLE_YANK
|
||||
"yank", yank, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||
"yank-pop", yankpop, ZLE_YANK | ZLE_KEEPSUFFIX
|
||||
|
|
|
@ -53,7 +53,7 @@ struct cutbuffer vibuf[35];
|
|||
/**/
|
||||
char *lastline;
|
||||
/**/
|
||||
int lastlinesz, lastll;
|
||||
int lastlinesz, lastll, lastcs;
|
||||
|
||||
/* size of line buffer */
|
||||
|
||||
|
@ -73,7 +73,7 @@ sizeline(int sz)
|
|||
/* insert space for ct chars at cursor position */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
spaceinline(int ct)
|
||||
{
|
||||
int i;
|
||||
|
@ -105,7 +105,7 @@ shiftchars(int to, int cnt)
|
|||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
backkill(int ct, int dir)
|
||||
{
|
||||
int i = (cs -= ct);
|
||||
|
@ -115,7 +115,7 @@ backkill(int ct, int dir)
|
|||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
forekill(int ct, int dir)
|
||||
{
|
||||
int i = cs;
|
||||
|
@ -191,14 +191,14 @@ cut(int i, int ct, int dir)
|
|||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
backdel(int ct)
|
||||
{
|
||||
shiftchars(cs -= ct, ct);
|
||||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
foredel(int 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. */
|
||||
|
||||
/**/
|
||||
int
|
||||
mod_export int
|
||||
getzlequery(void)
|
||||
{
|
||||
int c;
|
||||
|
@ -409,19 +409,11 @@ showmsg(char const *msg)
|
|||
/* handle the error flag */
|
||||
|
||||
/**/
|
||||
void
|
||||
feep(void)
|
||||
int
|
||||
handlefeep(char **args)
|
||||
{
|
||||
feepflag = 1;
|
||||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
handlefeep(void)
|
||||
{
|
||||
if(feepflag)
|
||||
beep();
|
||||
feepflag = 0;
|
||||
zbeep();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************/
|
||||
|
@ -446,6 +438,7 @@ initundo(void)
|
|||
curchange->del = curchange->ins = NULL;
|
||||
lastline = zalloc(lastlinesz = linesz);
|
||||
memcpy(lastline, line, lastll = ll);
|
||||
lastcs = cs;
|
||||
}
|
||||
|
||||
/**/
|
||||
|
@ -519,6 +512,8 @@ mkundoent(void)
|
|||
ch->next = NULL;
|
||||
ch->hist = histline;
|
||||
ch->off = pre;
|
||||
ch->old_cs = lastcs;
|
||||
ch->new_cs = cs;
|
||||
if(suf + pre == lastll)
|
||||
ch->del = NULL;
|
||||
else
|
||||
|
@ -549,32 +544,36 @@ setlastline(void)
|
|||
if(lastlinesz != linesz)
|
||||
lastline = realloc(lastline, lastlinesz = linesz);
|
||||
memcpy(lastline, line, lastll = ll);
|
||||
lastcs = cs;
|
||||
}
|
||||
|
||||
/* move backwards through the change list */
|
||||
|
||||
/**/
|
||||
void
|
||||
undo(void)
|
||||
int
|
||||
undo(char **args)
|
||||
{
|
||||
handleundo();
|
||||
do {
|
||||
if(!curchange->prev) {
|
||||
feep();
|
||||
return;
|
||||
}
|
||||
unapplychange(curchange = curchange->prev);
|
||||
if(!curchange->prev)
|
||||
return 1;
|
||||
if (unapplychange(curchange->prev))
|
||||
curchange = curchange->prev;
|
||||
else
|
||||
break;
|
||||
} while(curchange->flags & CH_PREV);
|
||||
setlastline();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
static void
|
||||
static int
|
||||
unapplychange(struct change *ch)
|
||||
{
|
||||
if(ch->hist != histline) {
|
||||
remember_edits();
|
||||
setline(zle_get_event(histline = ch->hist));
|
||||
zle_setline(quietgethist(ch->hist));
|
||||
cs = ch->new_cs;
|
||||
return 0;
|
||||
}
|
||||
cs = ch->off;
|
||||
if(ch->ins)
|
||||
|
@ -589,33 +588,37 @@ unapplychange(struct change *ch)
|
|||
else
|
||||
line[cs++] = STOUC(*c);
|
||||
}
|
||||
cs = ch->old_cs;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* move forwards through the change list */
|
||||
|
||||
/**/
|
||||
void
|
||||
redo(void)
|
||||
int
|
||||
redo(char **args)
|
||||
{
|
||||
handleundo();
|
||||
do {
|
||||
if(!curchange->next) {
|
||||
feep();
|
||||
return;
|
||||
}
|
||||
applychange(curchange);
|
||||
curchange = curchange->next;
|
||||
if(!curchange->next)
|
||||
return 1;
|
||||
if (applychange(curchange))
|
||||
curchange = curchange->next;
|
||||
else
|
||||
break;
|
||||
} while(curchange->prev->flags & CH_NEXT);
|
||||
setlastline();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
static void
|
||||
static int
|
||||
applychange(struct change *ch)
|
||||
{
|
||||
if(ch->hist != histline) {
|
||||
remember_edits();
|
||||
setline(zle_get_event(histline = ch->hist));
|
||||
zle_setline(quietgethist(ch->hist));
|
||||
cs = ch->old_cs;
|
||||
return 0;
|
||||
}
|
||||
cs = ch->off;
|
||||
if(ch->del)
|
||||
|
@ -630,13 +633,15 @@ applychange(struct change *ch)
|
|||
else
|
||||
line[cs++] = STOUC(*c);
|
||||
}
|
||||
cs = ch->new_cs;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* vi undo: toggle between the end of the undo list and the preceding point */
|
||||
|
||||
/**/
|
||||
void
|
||||
viundochange(void)
|
||||
int
|
||||
viundochange(char **args)
|
||||
{
|
||||
handleundo();
|
||||
if(curchange->next) {
|
||||
|
@ -645,6 +650,7 @@ viundochange(void)
|
|||
curchange = curchange->next;
|
||||
} while(curchange->next);
|
||||
setlastline();
|
||||
return 0;
|
||||
} 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 "cond.pro"
|
||||
|
||||
int tracingcond;
|
||||
|
||||
static char *condstr[COND_MOD] = {
|
||||
"!", "&&", "||", "==", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
|
||||
"-ne", "-lt", "-gt", "-le", "-ge"
|
||||
};
|
||||
|
||||
/**/
|
||||
int
|
||||
evalcond(Cond c)
|
||||
evalcond(Estate state)
|
||||
{
|
||||
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:
|
||||
return !evalcond(c->left);
|
||||
if (tracingcond)
|
||||
fprintf(xtrerr, " %s", condstr[ctype]);
|
||||
return !evalcond(state);
|
||||
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:
|
||||
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);
|
||||
untokenize(c->left);
|
||||
if (c->right) {
|
||||
singsub((char **)&c->right);
|
||||
if (c->type != COND_STREQ && c->type != COND_STRNEQ)
|
||||
untokenize(c->right);
|
||||
left = ecgetstr(state, EC_DUPTOK, &htok);
|
||||
if (htok) {
|
||||
singsub(&left);
|
||||
untokenize(left);
|
||||
}
|
||||
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:
|
||||
return matchpat(c->left, c->right);
|
||||
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:
|
||||
return strcmp(c->left, c->right) < 0;
|
||||
return strcmp(left, right) < 0;
|
||||
case COND_STRGTR:
|
||||
return strcmp(c->left, c->right) > 0;
|
||||
return strcmp(left, right) > 0;
|
||||
case 'e':
|
||||
case 'a':
|
||||
return (doaccess(c->left, F_OK));
|
||||
return (doaccess(left, F_OK));
|
||||
case 'b':
|
||||
return (S_ISBLK(dostat(c->left)));
|
||||
return (S_ISBLK(dostat(left)));
|
||||
case 'c':
|
||||
return (S_ISCHR(dostat(c->left)));
|
||||
return (S_ISCHR(dostat(left)));
|
||||
case 'd':
|
||||
return (S_ISDIR(dostat(c->left)));
|
||||
return (S_ISDIR(dostat(left)));
|
||||
case 'f':
|
||||
return (S_ISREG(dostat(c->left)));
|
||||
return (S_ISREG(dostat(left)));
|
||||
case 'g':
|
||||
return (!!(dostat(c->left) & S_ISGID));
|
||||
return (!!(dostat(left) & S_ISGID));
|
||||
case 'k':
|
||||
return (!!(dostat(c->left) & S_ISVTX));
|
||||
return (!!(dostat(left) & S_ISVTX));
|
||||
case 'n':
|
||||
return (!!strlen(c->left));
|
||||
return (!!strlen(left));
|
||||
case 'o':
|
||||
return (optison(c->left));
|
||||
return (optison(left));
|
||||
case 'p':
|
||||
return (S_ISFIFO(dostat(c->left)));
|
||||
return (S_ISFIFO(dostat(left)));
|
||||
case 'r':
|
||||
return (doaccess(c->left, R_OK));
|
||||
return (doaccess(left, R_OK));
|
||||
case 's':
|
||||
return ((st = getstat(c->left)) && !!(st->st_size));
|
||||
return ((st = getstat(left)) && !!(st->st_size));
|
||||
case 'S':
|
||||
return (S_ISSOCK(dostat(c->left)));
|
||||
return (S_ISSOCK(dostat(left)));
|
||||
case 'u':
|
||||
return (!!(dostat(c->left) & S_ISUID));
|
||||
return (!!(dostat(left) & S_ISUID));
|
||||
case 'w':
|
||||
return (doaccess(c->left, W_OK));
|
||||
return (doaccess(left, W_OK));
|
||||
case 'x':
|
||||
if (privasserted()) {
|
||||
mode_t mode = dostat(c->left);
|
||||
mode_t mode = dostat(left);
|
||||
return (mode & S_IXUGO) || S_ISDIR(mode);
|
||||
}
|
||||
return doaccess(c->left, X_OK);
|
||||
return doaccess(left, X_OK);
|
||||
case 'z':
|
||||
return (!strlen(c->left));
|
||||
return (!strlen(left));
|
||||
case 'h':
|
||||
case 'L':
|
||||
return (S_ISLNK(dolstat(c->left)));
|
||||
return (S_ISLNK(dolstat(left)));
|
||||
case 'O':
|
||||
return ((st = getstat(c->left)) && st->st_uid == geteuid());
|
||||
return ((st = getstat(left)) && st->st_uid == geteuid());
|
||||
case 'G':
|
||||
return ((st = getstat(c->left)) && st->st_gid == getegid());
|
||||
return ((st = getstat(left)) && st->st_gid == getegid());
|
||||
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':
|
||||
return isatty(matheval(c->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);
|
||||
return isatty(mathevali(left));
|
||||
case COND_NT:
|
||||
case COND_OT:
|
||||
{
|
||||
time_t a;
|
||||
|
||||
if (!(st = getstat(c->left)))
|
||||
if (!(st = getstat(left)))
|
||||
return 0;
|
||||
a = st->st_mtime;
|
||||
if (!(st = getstat(c->right)))
|
||||
if (!(st = getstat(right)))
|
||||
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:
|
||||
{
|
||||
dev_t d;
|
||||
ino_t i;
|
||||
|
||||
if (!(st = getstat(c->left)))
|
||||
if (!(st = getstat(left)))
|
||||
return 0;
|
||||
d = st->st_dev;
|
||||
i = st->st_ino;
|
||||
if (!(st = getstat(c->right)))
|
||||
if (!(st = getstat(right)))
|
||||
return 0;
|
||||
return d == st->st_dev && i == st->st_ino;
|
||||
}
|
||||
default:
|
||||
zerr("bad cond structure", NULL, 0);
|
||||
zerr("bad cond code", NULL, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -158,6 +310,10 @@ evalcond(Cond c)
|
|||
static int
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -224,3 +380,59 @@ optison(char *s)
|
|||
else
|
||||
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 */
|
||||
|
||||
/**/
|
||||
unsigned
|
||||
mod_export unsigned
|
||||
hasher(char *str)
|
||||
{
|
||||
unsigned hashval = 0;
|
||||
unsigned hashval = 0, c;
|
||||
|
||||
while (*str)
|
||||
hashval += (hashval << 5) + ((unsigned) *str++);
|
||||
while ((c = *((unsigned char *) str++)))
|
||||
hashval += (hashval << 5) + c;
|
||||
|
||||
return hashval;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ hasher(char *str)
|
|||
/* Get a new hash table */
|
||||
|
||||
/**/
|
||||
HashTable
|
||||
mod_export HashTable
|
||||
newhashtable(int size, char const *name, PrintTableStats printinfo)
|
||||
{
|
||||
HashTable ht;
|
||||
|
@ -112,6 +112,7 @@ newhashtable(int size, char const *name, PrintTableStats printinfo)
|
|||
ht->hsize = size;
|
||||
ht->ct = 0;
|
||||
ht->scan = NULL;
|
||||
ht->scantab = NULL;
|
||||
return ht;
|
||||
}
|
||||
|
||||
|
@ -119,7 +120,7 @@ newhashtable(int size, char const *name, PrintTableStats printinfo)
|
|||
* existing pointers to the hash table are invalid. */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
deletehashtable(HashTable ht)
|
||||
{
|
||||
ht->emptytable(ht);
|
||||
|
@ -132,13 +133,14 @@ deletehashtable(HashTable ht)
|
|||
ht->last->next = ht->next;
|
||||
else
|
||||
firstht = ht->next;
|
||||
zsfree(ht->tablename);
|
||||
#endif /* ZSH_HASH_DEBUG */
|
||||
zfree(ht->nodes, ht->hsize * sizeof(HashNode));
|
||||
zfree(ht, sizeof(*ht));
|
||||
}
|
||||
|
||||
/* Add a node to a hash table. *
|
||||
* nam is the key to use in hashing. dat is a pointer *
|
||||
* nam is the key to use in hashing. nodeptr points *
|
||||
* to the node to add. If there is already a node in *
|
||||
* the table with the same key, it is first freed, and *
|
||||
* then the new node is added. If the number of nodes *
|
||||
|
@ -146,8 +148,19 @@ deletehashtable(HashTable ht)
|
|||
* the table is then expanded. */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
addhashnode(HashTable ht, char *nam, void *nodeptr)
|
||||
{
|
||||
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
|
||||
if (oldnode)
|
||||
ht->freenode(oldnode);
|
||||
}
|
||||
|
||||
/* Add a node to a hash table, returning the old node on replacment. */
|
||||
|
||||
/**/
|
||||
HashNode
|
||||
addhashnode2(HashTable ht, char *nam, void *nodeptr)
|
||||
{
|
||||
unsigned hashval;
|
||||
HashNode hn, hp, hq;
|
||||
|
@ -164,15 +177,15 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
|||
ht->nodes[hashval] = hn;
|
||||
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
|
||||
expandhashtable(ht);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* else check if the first node contains the same key */
|
||||
if (!strcmp(hp->nam, hn->nam)) {
|
||||
if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
|
||||
ht->nodes[hashval] = hn;
|
||||
replacing:
|
||||
hn->next = hp->next;
|
||||
if(ht->scan)
|
||||
if(ht->scan) {
|
||||
if(ht->scan->sorted) {
|
||||
HashNode *tab = ht->scan->u.s.tab;
|
||||
int i;
|
||||
|
@ -181,15 +194,15 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
|||
tab[i] = hn;
|
||||
} else if(ht->scan->u.u == hp)
|
||||
ht->scan->u.u = hn;
|
||||
ht->freenode(hp);
|
||||
return;
|
||||
}
|
||||
return hp;
|
||||
}
|
||||
|
||||
/* else run through the list and check all the keys */
|
||||
hq = hp;
|
||||
hp = hp->next;
|
||||
for (; hp; hq = hp, hp = hp->next) {
|
||||
if (!strcmp(hp->nam, hn->nam)) {
|
||||
if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
|
||||
hq->next = hn;
|
||||
goto replacing;
|
||||
}
|
||||
|
@ -200,6 +213,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
|||
ht->nodes[hashval] = hn;
|
||||
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
|
||||
expandhashtable(ht);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get an enabled entry in a hash table. *
|
||||
|
@ -208,7 +222,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
|
|||
* or isn't found, it returns NULL */
|
||||
|
||||
/**/
|
||||
HashNode
|
||||
mod_export HashNode
|
||||
gethashnode(HashTable ht, char *nam)
|
||||
{
|
||||
unsigned hashval;
|
||||
|
@ -216,7 +230,7 @@ gethashnode(HashTable ht, char *nam)
|
|||
|
||||
hashval = ht->hash(nam) % ht->hsize;
|
||||
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
|
||||
if (!strcmp(hp->nam, nam)) {
|
||||
if (ht->cmpnodes(hp->nam, nam) == 0) {
|
||||
if (hp->flags & DISABLED)
|
||||
return NULL;
|
||||
else
|
||||
|
@ -232,7 +246,7 @@ gethashnode(HashTable ht, char *nam)
|
|||
* it returns NULL. */
|
||||
|
||||
/**/
|
||||
HashNode
|
||||
mod_export HashNode
|
||||
gethashnode2(HashTable ht, char *nam)
|
||||
{
|
||||
unsigned hashval;
|
||||
|
@ -240,7 +254,7 @@ gethashnode2(HashTable ht, char *nam)
|
|||
|
||||
hashval = ht->hash(nam) % ht->hsize;
|
||||
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
|
||||
if (!strcmp(hp->nam, nam))
|
||||
if (ht->cmpnodes(hp->nam, nam) == 0)
|
||||
return hp;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -252,7 +266,7 @@ gethashnode2(HashTable ht, char *nam)
|
|||
* is no such node, then it returns NULL */
|
||||
|
||||
/**/
|
||||
HashNode
|
||||
mod_export HashNode
|
||||
removehashnode(HashTable ht, char *nam)
|
||||
{
|
||||
unsigned hashval;
|
||||
|
@ -266,11 +280,11 @@ removehashnode(HashTable ht, char *nam)
|
|||
return NULL;
|
||||
|
||||
/* else check if the key in the first one matches */
|
||||
if (!strcmp(hp->nam, nam)) {
|
||||
if (ht->cmpnodes(hp->nam, nam) == 0) {
|
||||
ht->nodes[hashval] = hp->next;
|
||||
gotit:
|
||||
ht->ct--;
|
||||
if(ht->scan)
|
||||
if(ht->scan) {
|
||||
if(ht->scan->sorted) {
|
||||
HashNode *tab = ht->scan->u.s.tab;
|
||||
int i;
|
||||
|
@ -279,6 +293,7 @@ removehashnode(HashTable ht, char *nam)
|
|||
tab[i] = NULL;
|
||||
} else if(ht->scan->u.u == hp)
|
||||
ht->scan->u.u = hp->next;
|
||||
}
|
||||
return hp;
|
||||
}
|
||||
|
||||
|
@ -286,7 +301,7 @@ removehashnode(HashTable ht, char *nam)
|
|||
hq = hp;
|
||||
hp = hp->next;
|
||||
for (; hp; hq = hp, hp = hp->next) {
|
||||
if (!strcmp(hp->nam, nam)) {
|
||||
if (ht->cmpnodes(hp->nam, nam) == 0) {
|
||||
hq->next = hp->next;
|
||||
goto gotit;
|
||||
}
|
||||
|
@ -314,7 +329,7 @@ enablehashnode(HashNode hn, int flags)
|
|||
hn->flags &= ~DISABLED;
|
||||
}
|
||||
|
||||
/* Compare two hash table entries */
|
||||
/* Compare two hash table entries by name */
|
||||
|
||||
/**/
|
||||
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)
|
||||
{
|
||||
struct scanstatus st;
|
||||
|
||||
if (ht->scantab) {
|
||||
ht->scantab(ht, scanfunc, scanflags);
|
||||
return;
|
||||
}
|
||||
if (sorted) {
|
||||
int i, ct = ht->ct;
|
||||
VARARR(HashNode, hnsorttab, ct);
|
||||
|
@ -399,7 +418,7 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun
|
|||
|
||||
/**/
|
||||
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;
|
||||
HashNode *nodes = ht->nodes;
|
||||
|
@ -414,9 +433,10 @@ scanmatchtable(HashTable ht, Comp com, int flags1, int flags2, ScanFunc scanfunc
|
|||
HashNode hn = st.u.u;
|
||||
st.u.u = st.u.u->next;
|
||||
if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2) &&
|
||||
domatch(hn->nam, com, 0))
|
||||
pattry(pprog, hn->nam)) {
|
||||
scanfunc(hn, scanflags);
|
||||
match++;
|
||||
}
|
||||
}
|
||||
|
||||
ht->scan = NULL;
|
||||
|
@ -489,12 +509,13 @@ resizehashtable(HashTable ht, int newsize)
|
|||
/* Generic method to empty a hash table */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
emptyhashtable(HashTable ht)
|
||||
{
|
||||
resizehashtable(ht, ht->hsize);
|
||||
}
|
||||
|
||||
/**/
|
||||
#ifdef ZSH_HASH_DEBUG
|
||||
|
||||
/* Print info about hash table */
|
||||
|
@ -547,6 +568,7 @@ bin_hashinfo(char *nam, char **args, char *ops, int func)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
#endif /* ZSH_HASH_DEBUG */
|
||||
|
||||
/********************************/
|
||||
|
@ -556,12 +578,12 @@ bin_hashinfo(char *nam, char **args, char *ops, int func)
|
|||
/* hash table containing external commands */
|
||||
|
||||
/**/
|
||||
HashTable cmdnamtab;
|
||||
mod_export HashTable cmdnamtab;
|
||||
|
||||
/* how far we've hashed the PATH so far */
|
||||
|
||||
/**/
|
||||
char **pathchecked;
|
||||
mod_export char **pathchecked;
|
||||
|
||||
/* Create a new command hash table */
|
||||
|
||||
|
@ -574,6 +596,7 @@ createcmdnamtable(void)
|
|||
cmdnamtab->hash = hasher;
|
||||
cmdnamtab->emptytable = emptycmdnamtable;
|
||||
cmdnamtab->filltable = fillcmdnamtable;
|
||||
cmdnamtab->cmpnodes = strcmp;
|
||||
cmdnamtab->addnode = addhashnode;
|
||||
cmdnamtab->getnode = gethashnode2;
|
||||
cmdnamtab->getnode2 = gethashnode2;
|
||||
|
@ -604,6 +627,9 @@ hashdir(char **dirp)
|
|||
Cmdnam cn;
|
||||
DIR *dir;
|
||||
char *fn;
|
||||
#ifdef _WIN32
|
||||
char *exe;
|
||||
#endif
|
||||
|
||||
if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp))))
|
||||
return;
|
||||
|
@ -615,6 +641,23 @@ hashdir(char **dirp)
|
|||
cn->u.name = dirp;
|
||||
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);
|
||||
}
|
||||
|
@ -713,7 +756,7 @@ printcmdnamnode(HashNode hn, int printflags)
|
|||
/* hash table containing the shell functions */
|
||||
|
||||
/**/
|
||||
HashTable shfunctab;
|
||||
mod_export HashTable shfunctab;
|
||||
|
||||
/**/
|
||||
void
|
||||
|
@ -724,6 +767,7 @@ createshfunctable(void)
|
|||
shfunctab->hash = hasher;
|
||||
shfunctab->emptytable = NULL;
|
||||
shfunctab->filltable = NULL;
|
||||
shfunctab->cmpnodes = strcmp;
|
||||
shfunctab->addnode = addhashnode;
|
||||
shfunctab->getnode = gethashnode;
|
||||
shfunctab->getnode2 = gethashnode2;
|
||||
|
@ -798,7 +842,7 @@ freeshfuncnode(HashNode hn)
|
|||
|
||||
zsfree(shf->nam);
|
||||
if (shf->funcdef)
|
||||
freestruct(shf->funcdef);
|
||||
freeeprog(shf->funcdef);
|
||||
zfree(shf, sizeof(struct shfunc));
|
||||
}
|
||||
|
||||
|
@ -828,21 +872,34 @@ printshfuncnode(HashNode hn, int printflags)
|
|||
}
|
||||
|
||||
if (f->flags & PM_UNDEFINED)
|
||||
printf("undefined ");
|
||||
if (f->flags & PM_TAGGED)
|
||||
printf("traced ");
|
||||
if ((f->flags & PM_UNDEFINED) || !f->funcdef) {
|
||||
nicezputs(f->nam, stdout);
|
||||
printf(" () { }\n");
|
||||
return;
|
||||
t = tricat("builtin autoload -X",
|
||||
((f->flags & PM_UNALIASED)? "U" : ""),
|
||||
((f->flags & PM_TAGGED)? "t" : ""));
|
||||
else {
|
||||
if (!f->funcdef)
|
||||
t = 0;
|
||||
else
|
||||
t = getpermtext(f->funcdef, NULL);
|
||||
}
|
||||
|
||||
t = getpermtext((void *) dupstruct((void *) f->funcdef));
|
||||
|
||||
quotedzputs(f->nam, stdout);
|
||||
printf(" () {\n\t");
|
||||
zputs(t, stdout);
|
||||
printf("\n}\n");
|
||||
zsfree(t);
|
||||
if (t) {
|
||||
printf(" () {\n\t");
|
||||
if (f->flags & PM_UNDEFINED)
|
||||
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 */
|
||||
|
||||
/**/
|
||||
HashTable reswdtab;
|
||||
mod_export HashTable reswdtab;
|
||||
|
||||
/* Build the hash table containing zsh's reserved words. */
|
||||
|
||||
|
@ -897,6 +954,7 @@ createreswdtable(void)
|
|||
reswdtab->hash = hasher;
|
||||
reswdtab->emptytable = NULL;
|
||||
reswdtab->filltable = NULL;
|
||||
reswdtab->cmpnodes = strcmp;
|
||||
reswdtab->addnode = addhashnode;
|
||||
reswdtab->getnode = gethashnode;
|
||||
reswdtab->getnode2 = gethashnode2;
|
||||
|
@ -944,7 +1002,7 @@ printreswdnode(HashNode hn, int printflags)
|
|||
/* hash table containing the aliases */
|
||||
|
||||
/**/
|
||||
HashTable aliastab;
|
||||
mod_export HashTable aliastab;
|
||||
|
||||
/* Create new hash table for aliases */
|
||||
|
||||
|
@ -957,6 +1015,7 @@ createaliastable(void)
|
|||
aliastab->hash = hasher;
|
||||
aliastab->emptytable = NULL;
|
||||
aliastab->filltable = NULL;
|
||||
aliastab->cmpnodes = strcmp;
|
||||
aliastab->addnode = addhashnode;
|
||||
aliastab->getnode = gethashnode;
|
||||
aliastab->getnode2 = gethashnode2;
|
||||
|
@ -974,7 +1033,7 @@ createaliastable(void)
|
|||
/* Create a new alias node */
|
||||
|
||||
/**/
|
||||
Alias
|
||||
mod_export Alias
|
||||
createaliasnode(char *txt, int flags)
|
||||
{
|
||||
Alias al;
|
||||
|
@ -1061,101 +1120,25 @@ printaliasnode(HashNode hn, int printflags)
|
|||
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 */
|
||||
/****************************************/
|
||||
|
||||
#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 */
|
||||
|
||||
/**/
|
||||
HashTable nameddirtab;
|
||||
mod_export HashTable nameddirtab;
|
||||
|
||||
/* != 0 if all the usernames have already been *
|
||||
* added to the named directory hash table. */
|
||||
|
@ -1173,6 +1156,7 @@ createnameddirtable(void)
|
|||
nameddirtab->hash = hasher;
|
||||
nameddirtab->emptytable = emptynameddirtable;
|
||||
nameddirtab->filltable = fillnameddirtable;
|
||||
nameddirtab->cmpnodes = strcmp;
|
||||
nameddirtab->addnode = addnameddirnode;
|
||||
nameddirtab->getnode = gethashnode;
|
||||
nameddirtab->getnode2 = gethashnode2;
|
||||
|
@ -1200,12 +1184,122 @@ emptynameddirtable(HashTable ht)
|
|||
/* Add all the usernames in the password file/database *
|
||||
* 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
|
||||
fillnameddirtable(HashTable ht)
|
||||
{
|
||||
#ifdef HAVE_GETPWENT
|
||||
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;
|
||||
|
||||
setpwent();
|
||||
|
@ -1213,13 +1307,13 @@ fillnameddirtable(HashTable ht)
|
|||
/* loop through the password file/database *
|
||||
* and add all entries returned. */
|
||||
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();
|
||||
#endif /* HAVE_GETPWENT */
|
||||
#endif
|
||||
allusersadded = 1;
|
||||
}
|
||||
return;
|
||||
#endif /* HAVE_GETPWENT */
|
||||
}
|
||||
|
||||
/* Add an entry to the named directory hash *
|
||||
|
@ -1283,3 +1377,137 @@ printnameddirnode(HashNode hn, int printflags)
|
|||
quotedzputs(nd->dir, stdout);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* History Line Hash Table Functions */
|
||||
/*************************************/
|
||||
|
||||
/**/
|
||||
void
|
||||
createhisttable(void)
|
||||
{
|
||||
histtab = newhashtable(599, "histtab", NULL);
|
||||
|
||||
histtab->hash = histhasher;
|
||||
histtab->emptytable = emptyhisttable;
|
||||
histtab->filltable = NULL;
|
||||
histtab->cmpnodes = histstrcmp;
|
||||
histtab->addnode = addhistnode;
|
||||
histtab->getnode = gethashnode2;
|
||||
histtab->getnode2 = gethashnode2;
|
||||
histtab->removenode = removehashnode;
|
||||
histtab->disablenode = NULL;
|
||||
histtab->enablenode = NULL;
|
||||
histtab->freenode = freehistnode;
|
||||
histtab->printnode = NULL;
|
||||
}
|
||||
|
||||
/**/
|
||||
unsigned
|
||||
histhasher(char *str)
|
||||
{
|
||||
unsigned hashval = 0;
|
||||
|
||||
while (inblank(*str)) str++;
|
||||
|
||||
while (*str) {
|
||||
if (inblank(*str)) {
|
||||
do str++; while (inblank(*str));
|
||||
if (*str)
|
||||
hashval += (hashval << 5) + ' ';
|
||||
}
|
||||
else
|
||||
hashval += (hashval << 5) + *(unsigned char *)str++;
|
||||
}
|
||||
return hashval;
|
||||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
emptyhisttable(HashTable ht)
|
||||
{
|
||||
emptyhashtable(ht);
|
||||
if (hist_ring)
|
||||
histremovedups();
|
||||
}
|
||||
|
||||
/* Compare two strings with normalized white-space */
|
||||
|
||||
/**/
|
||||
int
|
||||
histstrcmp(const char *str1, const char *str2)
|
||||
{
|
||||
while (inblank(*str1)) str1++;
|
||||
while (inblank(*str2)) str2++;
|
||||
while (*str1 && *str2) {
|
||||
if (inblank(*str1)) {
|
||||
if (!inblank(*str2))
|
||||
break;
|
||||
do str1++; while (inblank(*str1));
|
||||
do str2++; while (inblank(*str2));
|
||||
}
|
||||
else {
|
||||
if (*str1 != *str2)
|
||||
break;
|
||||
str1++;
|
||||
str2++;
|
||||
}
|
||||
}
|
||||
return *str1 - *str2;
|
||||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
addhistnode(HashTable ht, char *nam, void *nodeptr)
|
||||
{
|
||||
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
|
||||
Histent he = (Histent)nodeptr;
|
||||
if (oldnode && oldnode != (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 */
|
||||
|
||||
/**/
|
||||
pid_t mypgrp;
|
||||
mod_export pid_t mypgrp;
|
||||
|
||||
/* the job we are working on */
|
||||
|
||||
/**/
|
||||
int thisjob;
|
||||
mod_export int thisjob;
|
||||
|
||||
/* the current job (+) */
|
||||
|
||||
|
@ -53,8 +53,8 @@ int prevjob;
|
|||
/* the job table */
|
||||
|
||||
/**/
|
||||
struct job jobtab[MAXJOB];
|
||||
|
||||
mod_export struct job jobtab[MAXJOB];
|
||||
|
||||
/* shell timings */
|
||||
|
||||
/**/
|
||||
|
@ -64,13 +64,18 @@ struct tms shtms;
|
|||
|
||||
/**/
|
||||
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;
|
||||
|
||||
/**/
|
||||
int numpipestats, pipestats[MAX_PIPESTATS];
|
||||
|
||||
/* Diff two timevals for elapsed-time computations */
|
||||
|
||||
/**/
|
||||
|
@ -96,9 +101,13 @@ makerunning(Job jn)
|
|||
|
||||
jn->stat &= ~STAT_STOPPED;
|
||||
for (pn = jn->procs; pn; pn = pn->next)
|
||||
#if 0
|
||||
if (WIFSTOPPED(pn->status) &&
|
||||
(!(jn->stat & STAT_SUPERJOB) || pn->next))
|
||||
pn->status = SP_RUNNING;
|
||||
#endif
|
||||
if (WIFSTOPPED(pn->status))
|
||||
pn->status = SP_RUNNING;
|
||||
|
||||
if (jn->stat & STAT_SUPERJOB)
|
||||
makerunning(jobtab + jn->other);
|
||||
|
@ -125,6 +134,86 @@ findproc(pid_t pid, Job *jptr, Process *pptr)
|
|||
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 */
|
||||
|
||||
/**/
|
||||
|
@ -175,16 +264,31 @@ update_job(Job jn)
|
|||
jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
|
||||
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;
|
||||
} else { /* job is done, so remember return value */
|
||||
}
|
||||
}
|
||||
{ /* job is done or stopped, remember return value */
|
||||
lastval2 = val;
|
||||
/* If last process was run in the current shell, keep old status
|
||||
* and let it handle its own traps
|
||||
* and let it handle its own traps, but always allow the test
|
||||
* for the pgrp.
|
||||
*/
|
||||
if (job == thisjob && !(jn->stat & STAT_CURSH)) {
|
||||
lastval = val;
|
||||
inforeground = 1;
|
||||
if (jn->stat & STAT_CURSH)
|
||||
inforeground = 1;
|
||||
else if (job == thisjob) {
|
||||
lastval = val;
|
||||
inforeground = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,15 +302,72 @@ update_job(Job jn)
|
|||
/* is this job in the foreground of an interactive shell? */
|
||||
if (mypgrp != pgrp && inforeground &&
|
||||
(jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
|
||||
attachtty(mypgrp);
|
||||
adjustwinsize(); /* check window size and adjust if necessary */
|
||||
if (list_pipe) {
|
||||
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)
|
||||
return;
|
||||
jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
|
||||
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) {
|
||||
prevjob = curjob;
|
||||
curjob = job;
|
||||
|
@ -214,7 +375,7 @@ update_job(Job jn)
|
|||
if ((isset(NOTIFY) || job == thisjob) && (jn->stat & STAT_LOCKED)) {
|
||||
printjob(jn, !!isset(LONGLISTJOBS), 0);
|
||||
if (zleactive)
|
||||
refresh();
|
||||
zrefresh();
|
||||
}
|
||||
if (sigtrapped[SIGCHLD] && job != thisjob)
|
||||
dotrap(SIGCHLD);
|
||||
|
@ -223,7 +384,7 @@ update_job(Job jn)
|
|||
* process group from the shell, so the shell will not receive *
|
||||
* terminal signals, therefore we we pretend that the shell got *
|
||||
* the signal too. */
|
||||
if (inforeground && isset(MONITOR) && WIFSIGNALED(status)) {
|
||||
if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) {
|
||||
int sig = WTERMSIG(status);
|
||||
|
||||
if (sig == SIGINT || sig == SIGQUIT) {
|
||||
|
@ -256,13 +417,14 @@ setprevjob(void)
|
|||
|
||||
for (i = MAXJOB - 1; i; i--)
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
@ -409,6 +571,7 @@ dumptime(Job jn)
|
|||
static int
|
||||
should_report_time(Job j)
|
||||
{
|
||||
struct value vbuf;
|
||||
Value v;
|
||||
char *s = "REPORTTIME";
|
||||
int reporttime;
|
||||
|
@ -417,9 +580,10 @@ should_report_time(Job j)
|
|||
if (j->stat & STAT_TIMED)
|
||||
return 1;
|
||||
|
||||
if (!(v = getvalue(&s, 0)) || (reporttime = getintvalue(v)) < 0)
|
||||
if (!(v = getvalue(&vbuf, &s, 0)) ||
|
||||
(reporttime = getintvalue(v)) < 0) {
|
||||
return 0;
|
||||
|
||||
}
|
||||
/* can this ever happen? */
|
||||
if (!j->procs)
|
||||
return 0;
|
||||
|
@ -462,10 +626,10 @@ printjob(Job jn, int lng, int synch)
|
|||
if (jn->stat & STAT_SUPERJOB &&
|
||||
jn->procs->status == SP_RUNNING && !pn->next)
|
||||
pn->status = SP_RUNNING;
|
||||
if (pn->status != SP_RUNNING)
|
||||
if (pn->status != SP_RUNNING) {
|
||||
if (WIFSIGNALED(pn->status)) {
|
||||
sig = WTERMSIG(pn->status);
|
||||
llen = strlen(sigmsg[sig]);
|
||||
llen = strlen(sigmsg(sig));
|
||||
if (WCOREDUMP(pn->status))
|
||||
llen += 14;
|
||||
if (llen > len)
|
||||
|
@ -476,13 +640,14 @@ printjob(Job jn, int lng, int synch)
|
|||
doputnl = 1;
|
||||
} else if (WIFSTOPPED(pn->status)) {
|
||||
sig = WSTOPSIG(pn->status);
|
||||
if ((int)strlen(sigmsg[sig]) > len)
|
||||
len = strlen(sigmsg[sig]);
|
||||
if ((int)strlen(sigmsg(sig)) > len)
|
||||
len = strlen(sigmsg(sig));
|
||||
if (job == thisjob && sig == SIGTSTP)
|
||||
doputnl = 1;
|
||||
} else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
|
||||
WEXITSTATUS(pn->status))
|
||||
sflag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* print if necessary */
|
||||
|
@ -508,7 +673,7 @@ printjob(Job jn, int lng, int synch)
|
|||
break;
|
||||
len2 += strlen(qn->text) + 2;
|
||||
}
|
||||
if (job != thisjob)
|
||||
if (job != thisjob) {
|
||||
if (fline)
|
||||
fprintf(fout, "[%ld] %c ",
|
||||
(long)(jn - jobtab),
|
||||
|
@ -516,7 +681,7 @@ printjob(Job jn, int lng, int synch)
|
|||
: (job == prevjob) ? '-' : ' ');
|
||||
else
|
||||
fprintf(fout, (job > 9) ? " " : " ");
|
||||
else
|
||||
} else
|
||||
fprintf(fout, "zsh: ");
|
||||
if (lng & 1)
|
||||
fprintf(fout, "%ld ", (long) pn->pid);
|
||||
|
@ -531,25 +696,26 @@ printjob(Job jn, int lng, int synch)
|
|||
lng &= ~3;
|
||||
} else
|
||||
fprintf(fout, "%*s", skip, "");
|
||||
if (pn->status == SP_RUNNING)
|
||||
if (pn->status == SP_RUNNING) {
|
||||
if (!conted)
|
||||
fprintf(fout, "running%*s", len - 7 + 2, "");
|
||||
else
|
||||
fprintf(fout, "continued%*s", len - 9 + 2, "");
|
||||
else if (WIFEXITED(pn->status))
|
||||
}
|
||||
else if (WIFEXITED(pn->status)) {
|
||||
if (WEXITSTATUS(pn->status))
|
||||
fprintf(fout, "exit %-4d%*s", WEXITSTATUS(pn->status),
|
||||
len - 9 + 2, "");
|
||||
else
|
||||
fprintf(fout, "done%*s", len - 4 + 2, "");
|
||||
else if (WIFSTOPPED(pn->status))
|
||||
fprintf(fout, "%-*s", len + 2, sigmsg[WSTOPSIG(pn->status)]);
|
||||
} else if (WIFSTOPPED(pn->status))
|
||||
fprintf(fout, "%-*s", len + 2, sigmsg(WSTOPSIG(pn->status)));
|
||||
else if (WCOREDUMP(pn->status))
|
||||
fprintf(fout, "%s (core dumped)%*s",
|
||||
sigmsg[WTERMSIG(pn->status)],
|
||||
(int)(len - 14 + 2 - strlen(sigmsg[WTERMSIG(pn->status)])), "");
|
||||
sigmsg(WTERMSIG(pn->status)),
|
||||
(int)(len - 14 + 2 - strlen(sigmsg(WTERMSIG(pn->status)))), "");
|
||||
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)
|
||||
fprintf(fout, (pn->next) ? "%s | " : "%s", pn->text);
|
||||
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
|
||||
*/
|
||||
|
||||
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");
|
||||
fprintdir((lng & 4) ? jn->pwd : pwd, shout);
|
||||
fprintf(shout, ")\n");
|
||||
|
@ -607,20 +774,31 @@ deletejob(Job jn)
|
|||
{
|
||||
struct process *pn, *nx;
|
||||
|
||||
if (jn->stat & STAT_ATTACH) {
|
||||
attachtty(mypgrp);
|
||||
adjustwinsize(0);
|
||||
}
|
||||
|
||||
pn = jn->procs;
|
||||
jn->procs = NULL;
|
||||
for (; pn; pn = nx) {
|
||||
nx = pn->next;
|
||||
zfree(pn, sizeof(struct process));
|
||||
}
|
||||
zsfree(jn->pwd);
|
||||
|
||||
deletefilelist(jn->filelist);
|
||||
|
||||
if (jn->ty)
|
||||
zfree(jn->ty, sizeof(struct ttyinfo));
|
||||
|
||||
*jn = zero;
|
||||
if (jn->pwd)
|
||||
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 */
|
||||
|
@ -729,40 +907,20 @@ waitjob(int job, int sig)
|
|||
what this might be. --oberon
|
||||
|
||||
errflag = 0; */
|
||||
if (jn->stat & STAT_SUPERJOB) {
|
||||
Job sj = jobtab + jn->other;
|
||||
if (sj->stat & STAT_DONE) {
|
||||
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 (subsh) {
|
||||
killjb(jn, SIGCONT);
|
||||
jn->stat &= ~STAT_STOPPED;
|
||||
}
|
||||
if (jn->stat & STAT_SUPERJOB)
|
||||
if (handle_sub(jn - jobtab, 1))
|
||||
break;
|
||||
child_block();
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
deletejob(jn);
|
||||
pipestats[0] = lastval;
|
||||
numpipestats = 1;
|
||||
}
|
||||
child_unblock();
|
||||
}
|
||||
|
||||
|
@ -772,24 +930,29 @@ waitjob(int job, int sig)
|
|||
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;
|
||||
}
|
||||
|
||||
/* clear job table when entering subshells */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
clearjobtab(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < MAXJOB; i++) {
|
||||
if (jobtab[i].pwd)
|
||||
zsfree(jobtab[i].pwd);
|
||||
for (i = 1; i < MAXJOB; i++)
|
||||
if (jobtab[i].ty)
|
||||
zfree(jobtab[i].ty, sizeof(struct ttyinfo));
|
||||
}
|
||||
|
||||
memset(jobtab, 0, sizeof(jobtab)); /* zero out table */
|
||||
}
|
||||
|
@ -805,7 +968,8 @@ initjob(void)
|
|||
for (i = 1; i < MAXJOB; i++)
|
||||
if (!jobtab[i].stat) {
|
||||
jobtab[i].stat = STAT_INUSE;
|
||||
jobtab[i].pwd = ztrdup(pwd);
|
||||
if (jobtab[i].pwd)
|
||||
zsfree(jobtab[i].pwd);
|
||||
jobtab[i].gleader = 0;
|
||||
return i;
|
||||
}
|
||||
|
@ -814,6 +978,21 @@ initjob(void)
|
|||
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 & */
|
||||
|
||||
/**/
|
||||
|
@ -1071,7 +1250,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
|
|||
/* If you immediately type "exit" after "jobs", this *
|
||||
* will prevent zexit from complaining about stopped jobs */
|
||||
stopmsg = 2;
|
||||
if (!*argv)
|
||||
if (!*argv) {
|
||||
/* 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
|
||||
jobs. */
|
||||
|
@ -1100,6 +1279,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
|
|||
waitjob(job, SIGINT);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -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 */
|
||||
printjob(jobtab + job, (stopped) ? -1 : 0, 1);
|
||||
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 : ");
|
||||
fprintdir(jobtab[job].pwd, shout);
|
||||
fprintf(shout, ")\n");
|
||||
|
@ -1165,7 +1345,14 @@ bin_fg(char *name, char **argv, char *ops, int func)
|
|||
fflush(shout);
|
||||
if (func != BIN_WAIT) { /* fg */
|
||||
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) {
|
||||
|
|
380
Src/loop.c
380
Src/loop.c
|
@ -43,47 +43,79 @@ int contflag;
|
|||
/* # of break levels */
|
||||
|
||||
/**/
|
||||
int breaks;
|
||||
|
||||
mod_export int breaks;
|
||||
|
||||
/**/
|
||||
int
|
||||
execfor(Cmd cmd)
|
||||
execfor(Estate state, int do_exec)
|
||||
{
|
||||
List list;
|
||||
Forcmd node;
|
||||
char *str;
|
||||
int val;
|
||||
LinkList args;
|
||||
Wordcode end, loop;
|
||||
wordcode code = state->pc[-1];
|
||||
int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0;
|
||||
char *name, *str, *cond = NULL, *advance = NULL;
|
||||
zlong val = 0;
|
||||
LinkList args = NULL;
|
||||
|
||||
node = cmd->u.forcmd;
|
||||
args = cmd->args;
|
||||
if (node->condition) {
|
||||
str = node->name;
|
||||
name = ecgetstr(state, EC_NODUP, NULL);
|
||||
end = state->pc + WC_FOR_SKIP(code);
|
||||
|
||||
if (iscond) {
|
||||
str = dupstring(name);
|
||||
singsub(&str);
|
||||
if (isset(XTRACE)) {
|
||||
char *str2 = dupstring(str);
|
||||
untokenize(str2);
|
||||
printprompt4();
|
||||
fprintf(xtrerr, "%s\n", str2);
|
||||
fflush(xtrerr);
|
||||
}
|
||||
if (!errflag)
|
||||
matheval(str);
|
||||
if (errflag)
|
||||
if (errflag) {
|
||||
state->pc = end;
|
||||
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;
|
||||
|
||||
args = newlinklist();
|
||||
for (x = pparams; *x; x++)
|
||||
addlinknode(args, ztrdup(*x));
|
||||
addlinknode(args, dupstring(*x));
|
||||
}
|
||||
lastval = 0;
|
||||
loops++;
|
||||
pushheap();
|
||||
cmdpush(CS_FOR);
|
||||
loop = state->pc;
|
||||
for (;;) {
|
||||
if (node->condition) {
|
||||
str = dupstring(node->condition);
|
||||
singsub(&str);
|
||||
if (iscond) {
|
||||
if (ctok) {
|
||||
str = dupstring(cond);
|
||||
singsub(&str);
|
||||
} else
|
||||
str = cond;
|
||||
if (!errflag) {
|
||||
while (iblank(*str))
|
||||
str++;
|
||||
if (*str)
|
||||
val = matheval(str);
|
||||
else
|
||||
if (*str) {
|
||||
if (isset(XTRACE)) {
|
||||
printprompt4();
|
||||
fprintf(xtrerr, "%s\n", str);
|
||||
fflush(xtrerr);
|
||||
}
|
||||
val = mathevali(str);
|
||||
} else
|
||||
val = 1;
|
||||
}
|
||||
if (errflag) {
|
||||
|
@ -95,22 +127,36 @@ execfor(Cmd cmd)
|
|||
if (!val)
|
||||
break;
|
||||
} else {
|
||||
str = (char *) ugetnode(args);
|
||||
if (!str)
|
||||
if (!args || !(str = (char *) ugetnode(args)))
|
||||
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);
|
||||
execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args));
|
||||
state->pc = loop;
|
||||
execlist(state, 1, do_exec && args && empty(args));
|
||||
if (breaks) {
|
||||
breaks--;
|
||||
if (breaks || !contflag)
|
||||
break;
|
||||
contflag = 0;
|
||||
}
|
||||
if (node->condition && !errflag) {
|
||||
str = dupstring(node->advance);
|
||||
singsub(&str);
|
||||
if (retflag)
|
||||
break;
|
||||
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)
|
||||
matheval(str);
|
||||
}
|
||||
|
@ -123,44 +169,67 @@ execfor(Cmd cmd)
|
|||
freeheap();
|
||||
}
|
||||
popheap();
|
||||
cmdpop();
|
||||
loops--;
|
||||
state->pc = end;
|
||||
return lastval;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
execselect(Cmd cmd)
|
||||
execselect(Estate state, int do_exec)
|
||||
{
|
||||
List list;
|
||||
Forcmd node;
|
||||
char *str, *s;
|
||||
LinkList args;
|
||||
Wordcode end, loop;
|
||||
wordcode code = state->pc[-1];
|
||||
char *str, *s, *name;
|
||||
LinkNode n;
|
||||
int i;
|
||||
int i, usezle;
|
||||
FILE *inp;
|
||||
size_t more;
|
||||
LinkList args;
|
||||
|
||||
node = cmd->u.forcmd;
|
||||
args = cmd->args;
|
||||
if (!node->inflag) {
|
||||
end = state->pc + WC_FOR_SKIP(code);
|
||||
name = ecgetstr(state, EC_NODUP, NULL);
|
||||
|
||||
if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) {
|
||||
char **x;
|
||||
|
||||
args = newlinklist();
|
||||
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;
|
||||
}
|
||||
loops++;
|
||||
lastval = 0;
|
||||
pushheap();
|
||||
inp = fdopen(dup((SHTTY == -1) ? 0 : SHTTY), "r");
|
||||
selectlist(args);
|
||||
cmdpush(CS_SELECT);
|
||||
usezle = interact && SHTTY != -1 && isset(USEZLE);
|
||||
inp = fdopen(dup(usezle ? SHTTY : 0), "r");
|
||||
more = selectlist(args, 0);
|
||||
loop = state->pc;
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
if (empty(bufstack)) {
|
||||
if (interact && SHTTY != -1 && isset(USEZLE)) {
|
||||
if (usezle) {
|
||||
int oef = errflag;
|
||||
|
||||
isfirstln = 1;
|
||||
str = (char *)zleread(prompt3, NULL, 0);
|
||||
if (errflag)
|
||||
str = NULL;
|
||||
errflag = oef;
|
||||
} else {
|
||||
str = promptexpand(prompt3, 0, NULL, NULL);
|
||||
zputs(str, stderr);
|
||||
|
@ -181,7 +250,7 @@ execselect(Cmd cmd)
|
|||
*s = '\0';
|
||||
if (*str)
|
||||
break;
|
||||
selectlist(args);
|
||||
more = selectlist(args, more);
|
||||
}
|
||||
setsparam("REPLY", ztrdup(str));
|
||||
i = atoi(str);
|
||||
|
@ -194,9 +263,9 @@ execselect(Cmd cmd)
|
|||
else
|
||||
str = "";
|
||||
}
|
||||
setsparam(node->name, ztrdup(str));
|
||||
list = (List) dupstruct(node->list);
|
||||
execlist(list, 1, 0);
|
||||
setsparam(name, ztrdup(str));
|
||||
state->pc = loop;
|
||||
execlist(state, 1, 0);
|
||||
freeheap();
|
||||
if (breaks) {
|
||||
breaks--;
|
||||
|
@ -204,21 +273,23 @@ execselect(Cmd cmd)
|
|||
break;
|
||||
contflag = 0;
|
||||
}
|
||||
if (errflag)
|
||||
if (retflag || errflag)
|
||||
break;
|
||||
}
|
||||
done:
|
||||
cmdpop();
|
||||
popheap();
|
||||
fclose(inp);
|
||||
loops--;
|
||||
state->pc = end;
|
||||
return lastval;
|
||||
}
|
||||
|
||||
/* And this is used to print select lists. */
|
||||
|
||||
/**/
|
||||
static void
|
||||
selectlist(LinkList l)
|
||||
size_t
|
||||
selectlist(LinkList l, size_t start)
|
||||
{
|
||||
size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
|
||||
LinkNode n;
|
||||
|
@ -226,7 +297,7 @@ selectlist(LinkList l)
|
|||
|
||||
trashzle();
|
||||
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))
|
||||
*ap++ = (char *)getdata(n);
|
||||
|
@ -245,7 +316,7 @@ selectlist(LinkList l)
|
|||
else
|
||||
fw = (columns - 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;
|
||||
do {
|
||||
int t2 = strlen(*ap) + 2, t3;
|
||||
|
@ -271,70 +342,86 @@ selectlist(LinkList l)
|
|||
}
|
||||
while (*ap);*/
|
||||
fflush(stderr);
|
||||
|
||||
return t1 < colsz ? t1 : 0;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
execwhile(Cmd cmd)
|
||||
execwhile(Estate state, int do_exec)
|
||||
{
|
||||
List list;
|
||||
struct whilecmd *node;
|
||||
int olderrexit, oldval;
|
||||
Wordcode end, loop;
|
||||
wordcode code = state->pc[-1];
|
||||
int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL);
|
||||
|
||||
end = state->pc + WC_WHILE_SKIP(code);
|
||||
olderrexit = noerrexit;
|
||||
node = cmd->u.whilecmd;
|
||||
oldval = 0;
|
||||
pushheap();
|
||||
cmdpush(isuntil ? CS_UNTIL : CS_WHILE);
|
||||
loops++;
|
||||
loop = state->pc;
|
||||
for (;;) {
|
||||
list = (List) dupstruct(node->cont);
|
||||
state->pc = loop;
|
||||
noerrexit = 1;
|
||||
execlist(list, 1, 0);
|
||||
execlist(state, 1, 0);
|
||||
noerrexit = olderrexit;
|
||||
if (!((lastval == 0) ^ node->cond)) {
|
||||
if (!((lastval == 0) ^ isuntil)) {
|
||||
if (breaks)
|
||||
breaks--;
|
||||
lastval = oldval;
|
||||
break;
|
||||
}
|
||||
list = (List) dupstruct(node->loop);
|
||||
execlist(list, 1, 0);
|
||||
if (retflag) {
|
||||
lastval = oldval;
|
||||
break;
|
||||
}
|
||||
execlist(state, 1, 0);
|
||||
if (breaks) {
|
||||
breaks--;
|
||||
if (breaks || !contflag)
|
||||
break;
|
||||
contflag = 0;
|
||||
}
|
||||
freeheap();
|
||||
if (errflag) {
|
||||
lastval = 1;
|
||||
break;
|
||||
}
|
||||
if (retflag)
|
||||
break;
|
||||
freeheap();
|
||||
oldval = lastval;
|
||||
}
|
||||
cmdpop();
|
||||
popheap();
|
||||
loops--;
|
||||
state->pc = end;
|
||||
return lastval;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
execrepeat(Cmd cmd)
|
||||
execrepeat(Estate state, int do_exec)
|
||||
{
|
||||
List list;
|
||||
int count;
|
||||
Wordcode end, loop;
|
||||
wordcode code = state->pc[-1];
|
||||
int count, htok = 0;
|
||||
char *tmp;
|
||||
|
||||
end = state->pc + WC_REPEAT_SKIP(code);
|
||||
|
||||
lastval = 0;
|
||||
if (empty(cmd->args) || nextnode(firstnode(cmd->args))) {
|
||||
zerr("bad argument for repeat", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
count = atoi(peekfirst(cmd->args));
|
||||
tmp = ecgetstr(state, EC_DUPTOK, &htok);
|
||||
if (htok)
|
||||
singsub(&tmp);
|
||||
count = atoi(tmp);
|
||||
pushheap();
|
||||
cmdpush(CS_REPEAT);
|
||||
loops++;
|
||||
while (count--) {
|
||||
list = (List) dupstruct(cmd->u.list);
|
||||
execlist(list, 1, 0);
|
||||
loop = state->pc;
|
||||
while (count-- > 0) {
|
||||
state->pc = loop;
|
||||
execlist(state, 1, 0);
|
||||
freeheap();
|
||||
if (breaks) {
|
||||
breaks--;
|
||||
|
@ -346,76 +433,151 @@ execrepeat(Cmd cmd)
|
|||
lastval = 1;
|
||||
break;
|
||||
}
|
||||
if (retflag)
|
||||
break;
|
||||
}
|
||||
cmdpop();
|
||||
popheap();
|
||||
loops--;
|
||||
state->pc = end;
|
||||
return lastval;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
execif(Cmd cmd)
|
||||
execif(Estate state, int do_exec)
|
||||
{
|
||||
struct ifcmd *node;
|
||||
int olderrexit;
|
||||
List *i, *t;
|
||||
Wordcode end, next;
|
||||
wordcode code = state->pc[-1];
|
||||
int olderrexit, s = 0, run = 0;
|
||||
|
||||
olderrexit = noerrexit;
|
||||
node = cmd->u.ifcmd;
|
||||
i = node->ifls;
|
||||
t = node->thenls;
|
||||
end = state->pc + WC_IF_SKIP(code);
|
||||
|
||||
if (!noerrexit)
|
||||
noerrexit = 1;
|
||||
while (*i) {
|
||||
execlist(*i, 1, 0);
|
||||
if (!lastval)
|
||||
while (state->pc < end) {
|
||||
code = *state->pc++;
|
||||
if (wc_code(code) != WC_IF ||
|
||||
(run = (WC_IF_TYPE(code) == WC_IF_ELSE))) {
|
||||
if (run)
|
||||
run = 2;
|
||||
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;
|
||||
|
||||
if (*t)
|
||||
execlist(*t, 1, cmd->flags & CFLAG_EXEC);
|
||||
else
|
||||
if (run) {
|
||||
cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN));
|
||||
execlist(state, 1, do_exec);
|
||||
cmdpop();
|
||||
} else
|
||||
lastval = 0;
|
||||
state->pc = end;
|
||||
|
||||
return lastval;
|
||||
}
|
||||
|
||||
/**/
|
||||
int
|
||||
execcase(Cmd cmd)
|
||||
execcase(Estate state, int do_exec)
|
||||
{
|
||||
struct casecmd *node;
|
||||
char *word;
|
||||
List *l;
|
||||
char **p;
|
||||
Wordcode end, next;
|
||||
wordcode code = state->pc[-1];
|
||||
char *word, *pat;
|
||||
int npat, save;
|
||||
Patprog *spprog, pprog;
|
||||
|
||||
node = cmd->u.casecmd;
|
||||
l = node->lists;
|
||||
p = node->pats;
|
||||
end = state->pc + WC_CASE_SKIP(code);
|
||||
|
||||
word = *p++;
|
||||
word = ecgetstr(state, EC_DUP, NULL);
|
||||
singsub(&word);
|
||||
untokenize(word);
|
||||
lastval = 0;
|
||||
|
||||
if (node) {
|
||||
while (*p) {
|
||||
char *pat = *p + 1;
|
||||
cmdpush(CS_CASE);
|
||||
while (state->pc < end) {
|
||||
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);
|
||||
if (matchpat(word, pat)) {
|
||||
do {
|
||||
execlist(*l++, 1, **p == ';' && (cmd->flags & CFLAG_EXEC));
|
||||
} while(**p++ == '&' && *p);
|
||||
break;
|
||||
save = (!(state->prog->flags & EF_HEAP) &&
|
||||
!strcmp(pat, opat) && *spprog != dummy_patprog2);
|
||||
|
||||
pat2 = dupstring(pat);
|
||||
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++;
|
||||
l++;
|
||||
if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
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"
|
||||
|
||||
static char *tptr, *tbuf, *tlim;
|
||||
static int tsiz, tindent, tnewlins;
|
||||
static int tsiz, tindent, tnewlins, tjob;
|
||||
|
||||
/* add a character to the text buffer */
|
||||
|
||||
|
@ -72,19 +72,18 @@ taddstr(char *s)
|
|||
tptr += sl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* add an integer to the text buffer */
|
||||
|
||||
/**/
|
||||
void
|
||||
taddint(int x)
|
||||
static void
|
||||
taddlist(Estate state, int num)
|
||||
{
|
||||
char buf[DIGBUFSIZE];
|
||||
|
||||
sprintf(buf, "%d", x);
|
||||
taddstr(buf);
|
||||
if (num) {
|
||||
while (num--) {
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
taddchr(' ');
|
||||
}
|
||||
tptr--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* add a newline, or something equivalent, to the text buffer */
|
||||
|
||||
|
@ -105,15 +104,26 @@ taddnl(void)
|
|||
/* get a permanent textual representation of n */
|
||||
|
||||
/**/
|
||||
char *
|
||||
getpermtext(struct node *n)
|
||||
mod_export char *
|
||||
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;
|
||||
tbuf = (char *)zalloc(tsiz = 32);
|
||||
tptr = tbuf;
|
||||
tlim = tbuf + tsiz;
|
||||
tindent = 1;
|
||||
gettext2(n);
|
||||
tjob = 0;
|
||||
if (prog->len)
|
||||
gettext2(&s);
|
||||
*tptr = '\0';
|
||||
untokenize(tbuf);
|
||||
return tbuf;
|
||||
|
@ -123,344 +133,587 @@ getpermtext(struct node *n)
|
|||
|
||||
/**/
|
||||
char *
|
||||
getjobtext(struct node *n)
|
||||
getjobtext(Eprog prog, Wordcode c)
|
||||
{
|
||||
static char jbuf[JOBTEXTSIZE];
|
||||
|
||||
struct estate s;
|
||||
|
||||
if (!c)
|
||||
c = prog->prog;
|
||||
|
||||
s.prog = prog;
|
||||
s.pc = c;
|
||||
s.strs = prog->strs;
|
||||
|
||||
tnewlins = 0;
|
||||
tbuf = NULL;
|
||||
tptr = jbuf;
|
||||
tlim = tptr + JOBTEXTSIZE - 1;
|
||||
tindent = 1;
|
||||
gettext2(n);
|
||||
tjob = 1;
|
||||
gettext2(&s);
|
||||
*tptr = '\0';
|
||||
untokenize(jbuf);
|
||||
return jbuf;
|
||||
}
|
||||
|
||||
#define gt2(X) gettext2((struct node *) (X))
|
||||
|
||||
/*
|
||||
"gettext2" or "type checking and how to avoid it"
|
||||
an epic function by Paul Falstad
|
||||
*/
|
||||
* gettext2() shows one way to walk through the word code without
|
||||
* 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))
|
||||
#define _Cmd(X) ((Cmd) (X))
|
||||
#define _Pline(X) ((Pline) (X))
|
||||
#define _Sublist(X) ((Sublist) (X))
|
||||
#define _List(X) ((List) (X))
|
||||
#define _casecmd(X) ((struct casecmd *) (X))
|
||||
#define _ifcmd(X) ((struct ifcmd *) (X))
|
||||
#define _whilecmd(X) ((struct whilecmd *) (X))
|
||||
typedef struct tstack *Tstack;
|
||||
|
||||
struct tstack {
|
||||
Tstack prev;
|
||||
wordcode code;
|
||||
int pop;
|
||||
union {
|
||||
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
|
||||
gettext2(struct node *n)
|
||||
gettext2(Estate state)
|
||||
{
|
||||
Cmd nn;
|
||||
Tstack s, n;
|
||||
int stack = 0;
|
||||
wordcode code;
|
||||
|
||||
if (!n || ((List) n) == &dummy_list)
|
||||
return;
|
||||
switch (NT_TYPE(n->ntype)) {
|
||||
case N_LIST:
|
||||
gt2(_List(n)->left);
|
||||
if (_List(n)->type & Z_ASYNC) {
|
||||
taddstr(" &");
|
||||
if (_List(n)->type & Z_DISOWN)
|
||||
taddstr("|");
|
||||
while (1) {
|
||||
if (stack) {
|
||||
if (!(s = tstack))
|
||||
return;
|
||||
if (s->pop) {
|
||||
tstack = s->prev;
|
||||
s->prev = tfree;
|
||||
tfree = s;
|
||||
}
|
||||
code = s->code;
|
||||
stack = 0;
|
||||
} else {
|
||||
s = NULL;
|
||||
code = *state->pc++;
|
||||
}
|
||||
simplifyright(_List(n));
|
||||
if (_List(n)->right) {
|
||||
if (tnewlins)
|
||||
taddnl();
|
||||
else
|
||||
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");
|
||||
switch (wc_code(code)) {
|
||||
case WC_LIST:
|
||||
if (!s) {
|
||||
s = tpush(code, (WC_LIST_TYPE(code) & Z_END));
|
||||
stack = 0;
|
||||
} else {
|
||||
taddstr(nn->u.forcmd->name);
|
||||
if (nn->u.forcmd->inflag) {
|
||||
taddstr(" in ");
|
||||
taddlist(nn->args);
|
||||
if (WC_LIST_TYPE(code) & Z_ASYNC) {
|
||||
taddstr(" &");
|
||||
if (WC_LIST_TYPE(code) & Z_DISOWN)
|
||||
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();
|
||||
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;
|
||||
case CIF:
|
||||
gt2(nn->u.ifcmd);
|
||||
taddstr("fi");
|
||||
case WC_REPEAT:
|
||||
if (!s) {
|
||||
taddstr("repeat ");
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
taddnl();
|
||||
taddstr("do");
|
||||
tindent++;
|
||||
taddnl();
|
||||
tpush(code, 1);
|
||||
} else {
|
||||
tindent--;
|
||||
taddnl();
|
||||
taddstr("done");
|
||||
stack = 1;
|
||||
}
|
||||
break;
|
||||
case CCASE:
|
||||
gt2(nn->u.casecmd);
|
||||
break;
|
||||
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;
|
||||
case WC_CASE:
|
||||
if (!s) {
|
||||
Wordcode end = state->pc + WC_CASE_SKIP(code);
|
||||
|
||||
l = _casecmd(n)->lists;
|
||||
p = _casecmd(n)->pats;
|
||||
taddstr("case ");
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
taddstr(" in");
|
||||
|
||||
taddstr("case ");
|
||||
taddstr(*p++);
|
||||
taddstr(" in");
|
||||
tindent++;
|
||||
for (; *l; p++, l++) {
|
||||
if (state->pc >= end) {
|
||||
if (tnewlins)
|
||||
taddnl();
|
||||
else
|
||||
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)
|
||||
taddnl();
|
||||
else
|
||||
taddchr(' ');
|
||||
taddstr(*p + 1);
|
||||
code = *state->pc++;
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
state->pc++;
|
||||
taddstr(") ");
|
||||
tindent++;
|
||||
gt2(*l);
|
||||
s->code = code;
|
||||
s->pop = ((state->pc - 2 + WC_CASE_SKIP(code)) >=
|
||||
s->u._case.end);
|
||||
} else {
|
||||
tindent--;
|
||||
taddstr(" ;");
|
||||
taddchr(**p);
|
||||
taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
|
||||
tindent--;
|
||||
if (tnewlins)
|
||||
taddnl();
|
||||
else
|
||||
taddchr(' ');
|
||||
taddstr("esac");
|
||||
stack = 1;
|
||||
}
|
||||
tindent--;
|
||||
if (tnewlins)
|
||||
taddnl();
|
||||
else
|
||||
taddchr(' ');
|
||||
taddstr("esac");
|
||||
break;
|
||||
}
|
||||
case N_IF:
|
||||
{
|
||||
List *i, *t;
|
||||
case WC_IF:
|
||||
if (!s) {
|
||||
Wordcode end = state->pc + WC_IF_SKIP(code);
|
||||
|
||||
taddstr("if ");
|
||||
for (i = _ifcmd(n)->ifls, t = _ifcmd(n)->thenls; *i; i++, t++) {
|
||||
taddstr("if ");
|
||||
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--;
|
||||
taddnl();
|
||||
taddstr("then");
|
||||
tindent++;
|
||||
taddnl();
|
||||
gt2(*t);
|
||||
s->u._if.cond = 0;
|
||||
} else if (state->pc < s->u._if.end) {
|
||||
tindent--;
|
||||
taddnl();
|
||||
if (i[1]) {
|
||||
code = *state->pc++;
|
||||
if (WC_IF_TYPE(code) == WC_IF_ELIF) {
|
||||
taddstr("elif ");
|
||||
tindent++;
|
||||
s->u._if.cond = 1;
|
||||
} else {
|
||||
taddstr("else");
|
||||
tindent++;
|
||||
taddnl();
|
||||
}
|
||||
}
|
||||
if (*t) {
|
||||
taddstr("else");
|
||||
tindent++;
|
||||
taddnl();
|
||||
gt2(*t);
|
||||
} else {
|
||||
s->pop = 1;
|
||||
tindent--;
|
||||
taddnl();
|
||||
taddstr("fi");
|
||||
stack = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case N_WHILE:
|
||||
taddstr((_whilecmd(n)->cond) ? "until " : "while ");
|
||||
tindent++;
|
||||
gt2(_whilecmd(n)->cont);
|
||||
tindent--;
|
||||
taddnl();
|
||||
taddstr("do");
|
||||
tindent++;
|
||||
taddnl();
|
||||
gt2(_whilecmd(n)->loop);
|
||||
tindent--;
|
||||
taddnl();
|
||||
taddstr("done");
|
||||
break;
|
||||
}
|
||||
}
|
||||
case WC_COND:
|
||||
{
|
||||
static char *c1[] = {
|
||||
"=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
|
||||
"-ne", "-lt", "-gt", "-le", "-ge"
|
||||
};
|
||||
|
||||
/* Print a condition bracketed by [[ ... ]]. *
|
||||
* With addpar non-zero, parenthesise the subexpression. */
|
||||
int ctype;
|
||||
|
||||
/**/
|
||||
static void
|
||||
getcond(Cond nm, int addpar)
|
||||
{
|
||||
static char *c1[] =
|
||||
{
|
||||
"=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
|
||||
"-ne", "-lt", "-gt", "-le", "-ge"
|
||||
};
|
||||
if (!s) {
|
||||
taddstr("[[ ");
|
||||
n = tpush(code, 1);
|
||||
n->u._cond.par = 2;
|
||||
} else if (s->u._cond.par == 2) {
|
||||
taddstr(" ]]");
|
||||
stack = 1;
|
||||
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("( ");
|
||||
switch (nm->type) {
|
||||
case COND_NOT:
|
||||
taddstr("! ");
|
||||
getcond(nm->left, _Cond(nm->left)->type <= COND_OR);
|
||||
break;
|
||||
case COND_AND:
|
||||
getcond(nm->left, _Cond(nm->left)->type == COND_OR);
|
||||
taddstr(" && ");
|
||||
getcond(nm->right, _Cond(nm->right)->type == COND_OR);
|
||||
break;
|
||||
case COND_OR:
|
||||
/* This is deliberately over-generous with parentheses: *
|
||||
* in fact omitting them gives correct precedence. */
|
||||
getcond(nm->left, _Cond(nm->left)->type == COND_AND);
|
||||
taddstr(" || ");
|
||||
getcond(nm->right, _Cond(nm->right)->type == COND_AND);
|
||||
break;
|
||||
default:
|
||||
if (nm->type <= COND_GE) {
|
||||
/* Binary test: `a = b' etc. */
|
||||
taddstr(nm->left);
|
||||
taddstr(" ");
|
||||
taddstr(c1[nm->type - COND_STREQ]);
|
||||
taddstr(" ");
|
||||
taddstr(nm->right);
|
||||
} else {
|
||||
/* Unary test: `-f foo' etc. */
|
||||
char c2[4];
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
taddchr(' ');
|
||||
taddstr(name);
|
||||
taddchr(' ');
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
stack = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ctype <= COND_GE) {
|
||||
/* Binary test: `a = b' etc. */
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
taddstr(" ");
|
||||
taddstr(c1[ctype - COND_STREQ]);
|
||||
taddstr(" ");
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
if (ctype == COND_STREQ ||
|
||||
ctype == COND_STRNEQ)
|
||||
state->pc++;
|
||||
} else {
|
||||
/* Unary test: `-f foo' etc. */
|
||||
char c2[4];
|
||||
|
||||
c2[0] = '-';
|
||||
c2[1] = nm->type;
|
||||
c2[2] = ' ';
|
||||
c2[3] = '\0';
|
||||
taddstr(c2);
|
||||
taddstr(nm->left);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (addpar)
|
||||
taddstr(" )");
|
||||
}
|
||||
|
||||
/**/
|
||||
static void
|
||||
getsimptext(Cmd cmd)
|
||||
{
|
||||
LinkNode n;
|
||||
|
||||
for (n = firstnode(cmd->vars); n; incnode(n)) {
|
||||
struct varasg *v = (struct varasg *)getdata(n);
|
||||
|
||||
taddstr(v->name);
|
||||
taddchr('=');
|
||||
if (PM_TYPE(v->type) == PM_ARRAY) {
|
||||
taddchr('(');
|
||||
taddlist(v->arr);
|
||||
taddstr(") ");
|
||||
} else {
|
||||
taddstr(v->str);
|
||||
taddchr(' ');
|
||||
c2[0] = '-';
|
||||
c2[1] = ctype;
|
||||
c2[2] = ' ';
|
||||
c2[3] = '\0';
|
||||
taddstr(c2);
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
}
|
||||
stack = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WC_ARITH:
|
||||
taddstr("((");
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
taddstr("))");
|
||||
stack = 1;
|
||||
break;
|
||||
case WC_END:
|
||||
stack = 1;
|
||||
break;
|
||||
default:
|
||||
DPUTS(1, "unknown word code in gettext2()");
|
||||
return;
|
||||
}
|
||||
}
|
||||
taddlist(cmd->args);
|
||||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
getredirs(Cmd cmd)
|
||||
getredirs(LinkList redirs)
|
||||
{
|
||||
LinkNode n;
|
||||
static char *fstr[] =
|
||||
|
@ -468,10 +721,9 @@ getredirs(Cmd cmd)
|
|||
">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
|
||||
"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
|
||||
};
|
||||
|
||||
taddchr(' ');
|
||||
for (n = firstnode(cmd->redir); n; incnode(n)) {
|
||||
struct redir *f = (struct redir *)getdata(n);
|
||||
for (n = firstnode(redirs); n; incnode(n)) {
|
||||
Redir f = (Redir) getdata(n);
|
||||
|
||||
switch (f->type) {
|
||||
case WRITE:
|
||||
|
@ -493,7 +745,12 @@ getredirs(Cmd cmd)
|
|||
taddchr('0' + f->fd1);
|
||||
taddstr(fstr[f->type]);
|
||||
taddchr(' ');
|
||||
taddstr(f->name);
|
||||
if (f->type == HERESTR) {
|
||||
taddchr('\'');
|
||||
taddstr(bslashquote(f->name, NULL, 1));
|
||||
taddchr('\'');
|
||||
} else
|
||||
taddstr(f->name);
|
||||
taddchr(' ');
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
|
@ -509,18 +766,3 @@ getredirs(Cmd cmd)
|
|||
}
|
||||
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 zerolength
|
||||
chgrp $EGID zerolength
|
||||
print 'Garbuglio' >nonzerolength
|
||||
|
||||
touch modish
|
||||
chmod g+s modish
|
||||
mkdir modish
|
||||
chmod g+xs modish
|
||||
chmod u+s modish
|
||||
chmod +t modish
|
||||
|
||||
|
@ -26,7 +27,11 @@
|
|||
0:-a cond
|
||||
|
||||
# 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 ]]
|
||||
0:-b cond
|
||||
|
||||
|
@ -61,7 +66,11 @@
|
|||
[[ -o rcs && ! -o norcs && -o noerrexit && ! -o errexit ]]
|
||||
0:-o cond
|
||||
|
||||
mknod pipe p
|
||||
if whence mkfifo >/dev/null; then
|
||||
mkfifo pipe
|
||||
else
|
||||
mknod pipe p
|
||||
fi
|
||||
[[ -p pipe && ! -p zerolength ]]
|
||||
0:-p cond
|
||||
|
||||
|
@ -76,7 +85,7 @@
|
|||
[[ -u modish && ! -u zerolength ]]
|
||||
0:-u cond
|
||||
|
||||
[[ -x $ZTST_testdir/ztst.zsh && ! -x zerolength ]]
|
||||
[[ -x $ZTST_srcdir/ztst.zsh && ! -x zerolength ]]
|
||||
0:-x cond
|
||||
|
||||
[[ -z $bar && -z '' && ! -z $foo ]]
|
||||
|
@ -89,8 +98,6 @@
|
|||
[[ -O zerolength ]]
|
||||
0:-O cond
|
||||
|
||||
# there may be strange cases where this doesn't work, e.g.
|
||||
# inherited funny groups for directories via setgid.
|
||||
[[ -G zerolength ]]
|
||||
0:-G cond
|
||||
|
||||
|
@ -132,4 +139,16 @@
|
|||
0:|| and && in conds
|
||||
|
||||
[[ -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
|
||||
|
||||
%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 }
|
||||
|
||||
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
|
||||
|
||||
globtest globtests
|
||||
|
@ -234,3 +248,8 @@
|
|||
>0: [[ FOO = @(bar|(#i)foo) ]]
|
||||
>0: [[ Modules = (#i)*m* ]]
|
||||
>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.
|
||||
|
||||
%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 "$@" }
|
||||
|
||||
mkdir comp.tmp
|
||||
|
@ -104,11 +107,11 @@
|
|||
>DESCRIPTION:{desc1}
|
||||
>NO:{arg1}
|
||||
|
||||
# code='compdef _tst tst; _tst () { _arguments "-\+[opt]" }'
|
||||
# comptest -c "$code" $'tst -\C-D'
|
||||
#0:_arguments
|
||||
#>DESCRIPTION:{option}
|
||||
#>NO:{-+ -- opt}
|
||||
code='compdef _tst tst; _tst () { _arguments "-\+[opt]" }'
|
||||
comptest -c "$code" $'tst -\C-D'
|
||||
0:_arguments
|
||||
>DESCRIPTION:{option}
|
||||
>NO:{-+ -- opt}
|
||||
|
||||
code='compdef _tst tst; _tst () { _arguments "1:desc1:(arg1)" }'
|
||||
comptest -c "$code" $'tst \t'
|
||||
|
|
Loading…
Reference in New Issue