1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-23 04:30:24 +02:00

Updated from list as far as 10376

This commit is contained in:
Peter Stephenson 2000-04-01 20:49:47 +00:00
parent e025336f2f
commit 4852545255
31 changed files with 13782 additions and 5610 deletions

View file

@ -1,4 +1,4 @@
# $Id: is-at-least,v 1.1 2000/02/11 19:46:46 akr Exp $ -*- shell-script -*- # $Id: is-at-least,v 1.2 2000/04/01 20:49:47 pws Exp $ -*- shell-script -*-
# #
# Test whether $ZSH_VERSION (or some value of your choice, if a second argument # Test whether $ZSH_VERSION (or some value of your choice, if a second argument
# is provided) is greater than or equal to x.y.z-r (in argument one). In fact, # is provided) is greater than or equal to x.y.z-r (in argument one). In fact,

View file

@ -18,8 +18,8 @@
# seperated by `--'. For example: # seperated by `--'. For example:
# #
# zrecompile -p \ # zrecompile -p \
# -r ~/.zshrc -- \ # -R ~/.zshrc -- \
# -m ~/.zcompdump -- \ # -M ~/.zcompdump -- \
# ~/zsh/comp.zwc ~/zsh/Completion/*/_* \ # ~/zsh/comp.zwc ~/zsh/Completion/*/_* \
# #
# This makes ~/.zshrc be compiled into ~/.zshrc.zwc if that doesn't # This makes ~/.zshrc be compiled into ~/.zshrc.zwc if that doesn't
@ -33,8 +33,7 @@
# that needed re-compilation could be compiled and non-zero if compilation # that needed re-compilation could be compiled and non-zero if compilation
# for at least one of the files failed. # for at least one of the files failed.
emulate -L zsh setopt localoptions extendedglob
setopt extendedglob
local opt check quiet zwc files re file pre ret map tmp mesg pats local opt check quiet zwc files re file pre ret map tmp mesg pats
@ -68,7 +67,7 @@ if [[ -n $pats ]]; then
fi fi
files=( ${files:#*(.zwc|~)} ) files=( ${files:#*(.zwc|~)} )
if [[ $files[1] = -[rm] ]]; then if [[ $files[1] = -[RM] ]]; then
map=( $files[1] ) map=( $files[1] )
shift 1 files shift 1 files
else else
@ -146,10 +145,10 @@ for zwc; do
# See if the wordcode file will be mapped. # See if the wordcode file will be mapped.
if [[ $files[1] = *\(mapped\)* ]]; then if [[ $files[1] = *\(mapped\)* ]]; then
map=-m map=-M
mesg='succeeded (old saved)' mesg='succeeded (old saved)'
else else
map=-r map=-R
mesg=succeeded mesg=succeeded
fi fi

View file

@ -15,7 +15,7 @@ local tmpf=${TMPPREFIX}zfcm$$
if [[ $ZFTP_SYSTEM = UNIX* ]]; then if [[ $ZFTP_SYSTEM = UNIX* ]]; then
# hoo, aren't we lucky: this makes things so much easier # hoo, aren't we lucky: this makes things so much easier
setopt localoptions rcexpandparam setopt rcexpandparam
local dir local dir
if [[ $1 = ?*/* ]]; then if [[ $1 = ?*/* ]]; then
dir=${1%/*} dir=${1%/*}
@ -25,13 +25,15 @@ if [[ $ZFTP_SYSTEM = UNIX* ]]; then
# If we're using -F, we get away with using a directory # If we're using -F, we get away with using a directory
# to list, but not a glob. Don't ask me why. # to list, but not a glob. Don't ask me why.
# I hate having to rely on awk here. # I hate having to rely on awk here.
zftp ls -F $dir >$tmpf zftp ls -LF $dir >$tmpf
reply=($(awk '/\/$/ { print substr($1, 0, length($1)-1) }' $tmpf)) reply=($(awk '/\/$/ { print substr($1, 0, length($1)-1) }' $tmpf))
rm -f $tmpf rm -f $tmpf
if [[ $dir = / ]]; then [[ -n $dir && $dir != */ ]] && dir="$dir/"
reply=(${dir}$reply) if [[ -n $WIDGET ]]; then
_all_labels directories expl 'remote directory'
compadd -S/ -q -P "$dir" - $reply
elif [[ -n $dir ]]; then elif [[ -n $dir ]]; then
reply=($dir/$reply) reply=(${dir}$reply)
fi fi
else else
# I simply don't know what to do here. # I simply don't know what to do here.

View file

@ -10,18 +10,27 @@ fi
local tmpf=${TMPPREFIX}zfgm$$ local tmpf=${TMPPREFIX}zfgm$$
if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
# On the first argument to ls, we usually get away with a glob. if [[ -n $WIDGET ]]; then
zftp ls "$1*$2" >$tmpf local dir=${1:h}
reply=($(<$tmpf)) [[ $dir = */ ]] || dir="$dir/"
rm -f $tmpf zftp ls -LF $dir >$tmpf
else local reply
if (( $#zftp_fcache == 0 )); then reply=(${${${(f)"$(<$tmpf)"}##$dir}%\*})
# Always cache the current directory and use it rm -f $tmpf
# even if the system is UNIX. _all_labels files expl 'remote file' compadd -P $dir - $reply
zftp ls >$tmpf else
zftp_fcache=($(<$tmpf)) # On the first argument to ls, we usually get away with a glob.
zftp ls "$1*$2" >$tmpf
reply=($(<$tmpf))
rm -f $tmpf rm -f $tmpf
fi fi
reply=($zftp_fcache); else
local fcache_name
zffcache
if [[ -n $WIDGET ]]; then
_all_labels files expl 'remote file' compadd -F fignore - ${(P)fcache_name}
else
reply=(${(P)fcache_name});
fi
fi fi
# } # }

View file

@ -1,89 +1,124 @@
# incremental-complete-word() {
# Autoload this function, run `zle -N <func-name>' and bind <func-name> # Autoload this function, run `zle -N <func-name>' and bind <func-name>
# to a key. # to a key.
# This allows incremental completion of a word. After starting this # This allows incremental completion of a word. After starting this
# command, a list of completion choices is shown after every character you # command, a list of completion choices can be shown after every character
# type, which you can delete with ^h or DEL. RET will accept the # you type, which you can delete with ^h or DEL. RET will accept the
# completion so far. You can hit TAB to do normal completion and ^g to # completion so far. You can hit TAB to do normal completion, ^g to
# abort back to the state when you started. # abort back to the state when you started, and ^d to list the matches.
# #
# Completion keys: # This works only with the new function based completion system.
# incremental_prompt Prompt to show in status line during icompletion;
# the sequence `%u' is replaced by the unambiguous
# part of all matches if there is any and it is
# different from the word on the line
# incremental_stop Pattern matching keys which will cause icompletion
# to stop and the key to be re-executed
# incremental_break Pattern matching keys which will cause icompletion
# to stop and the key to be discarded
# incremental_completer Set of completers, like the `completer' key
# incremental_list If set to a non-empty string, the matches will be
# listed on every key-press
emulate -L zsh # The main widget function.
unsetopt autolist menucomplete automenu # doesn't work well
local key lbuf="$LBUFFER" rbuf="$RBUFFER" pmpt word lastl lastr wid twid incremental-complete-word() {
#emulate -L zsh
unsetopt autolist menucomplete automenu # doesn't work well
[[ -n "$compconfig[incremental_completer]" ]] && local key lbuf="$LBUFFER" rbuf="$RBUFFER" pmpt pstr word
set ${(s.:.)compconfig[incremental_completer]} local lastl lastr wid twid num post toolong
pmpt="${compconfig[incremental_prompt]-incremental completion...}" local curcontext="${curcontext}" stop brk
if [[ -n "$compconfig[incremental_list]" ]]; then [[ -z "$curcontext" ]] && curcontext=:::
wid=list-choices curcontext="incremental:${curcontext#*:}"
else
wid=complete-word
fi
zle $wid "$@" zstyle -s ":completion:${curcontext}" prompt pmpt ||
LBUFFER="$lbuf" pmpt='incremental (%c): %u%s %l'
RBUFFER="$rbuf" zstyle -s ":completion:${curcontext}" stop stop
if [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then zstyle -s ":completion:${curcontext}" break brk
word=''
else
word="${_lastcomp[unambiguous]}"
fi
zle -R "${pmpt//\\%u/$word}"
read -k key
while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' && if zstyle -t ":completion:${curcontext}" list; then
'#key' -ne '#\\C-g' ]]; do wid=list-choices
twid=$wid post=( icw-list-helper )
if [[ "$key" = ${~compconfig[incremental_stop]} ]]; then
zle -U "$key"
return
elif [[ "$key" = ${~compconfig[incremental_break]} ]]; then
return
elif [[ '#key' -eq '#\\C-h' || '#key' -eq '#\\C-?' ]]; then
[[ $#LBUFFER -gt $#l ]] && LBUFFER="$LBUFFER[1,-2]"
elif [[ '#key' -eq '#\\t' ]]; then
zle complete-word "$@"
lbuf="$LBUFFER"
rbuf="$RBUFFER"
elif [[ '#key' -eq '#\\C-d' ]]; then
twid=list-choices
else else
LBUFFER="$LBUFFER$key" wid=complete-word
post=()
fi fi
lastl="$LBUFFER"
lastr="$RBUFFER"
zle $twid "$@"
LBUFFER="$lastl"
RBUFFER="$lastr"
if [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
word=''
else
word="${_lastcomp[unambiguous]}"
fi
zle -R "${pmpt//\\%u/$word}"
read -k key
done
if [[ '#key' -eq '#\\C-g' ]]; then comppostfuncs=( "$post[@]" )
zle $wid "$@"
LBUFFER="$lbuf" LBUFFER="$lbuf"
RBUFFER="$rbuf" RBUFFER="$rbuf"
fi num=$_lastcomp[nmatches]
zle -Rc if (( ! num )); then
# } word=''
state='-no match-'
elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
word=''
state='-no prefix-'
else
word="${_lastcomp[unambiguous]}"
state=''
fi
zformat -f pstr "$pmpt" "u:${word}" "s:$state" "n:$num" \
"l:$toolong" "c:${_lastcomp[completer][2,-1]}"
zle -R "$pstr"
read -k key
while [[ '#key' -ne '#\\r' && '#key' -ne '#\\n' &&
'#key' -ne '#\\C-g' ]]; do
twid=$wid
if [[ "$key" = ${~stop} ]]; then
zle -U "$key"
return
elif [[ "$key" = ${~brk} ]]; then
return
elif [[ '#key' -eq '#\\C-h' || '#key' -eq '#\\C-?' ]]; then
[[ $#LBUFFER -gt $#l ]] && LBUFFER="$LBUFFER[1,-2]"
elif [[ '#key' -eq '#\\t' ]]; then
zle complete-word "$@"
lbuf="$LBUFFER"
rbuf="$RBUFFER"
elif [[ '#key' -eq '#\\C-d' ]]; then
twid=list-choices
else
LBUFFER="$LBUFFER$key"
fi
lastl="$LBUFFER"
lastr="$RBUFFER"
[[ "$twid" = "$wid" ]] && comppostfuncs=( "$post[@]" )
toolong=''
zle $twid "$@"
LBUFFER="$lastl"
RBUFFER="$lastr"
num=$_lastcomp[nmatches]
if (( ! num )); then
word=''
state='-no match-'
elif [[ "${LBUFFER}${RBUFFER}" = *${_lastcomp[unambiguous]}* ]]; then
word=''
state='-no prefix-'
else
word="${_lastcomp[unambiguous]}"
state=''
fi
zformat -f pstr "$pmpt" "u:${word}" "s:$state" "n:$num" \
"l:$toolong" "c:${_lastcomp[completer][2,-1]}"
zle -R "$pstr"
read -k key
done
if [[ '#key' -eq '#\\C-g' ]]; then
LBUFFER="$lbuf"
RBUFFER="$rbuf"
fi
zle -Rc
}
# Helper function used as a completion post-function used to make sure that
# the list of matches in only shown if it fits on the screen.
icw-list-helper() {
# +1 for the status line we will add...
if [[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]]; then
compstate[list]='list explanations'
[[ compstate[list_lines]+BUFFERLINES+1 -gt LINES ]] && compstate[list]=''
toolong='...'
fi
}
incremental-complete-word "$@"

View file

@ -1,64 +1,141 @@
# This set of functions implements a sort of magic history searching. # This set of functions implements a sort of magic history searching.
# After predict-on, typing characters causes the editor to look backward # After predict-on, typing characters causes the editor to look backward
# in the history for the first line beginning with what you have typed # in the history for the first line beginning with what you have typed so
# so far. After predict-off, editing returns to normal for the line found. # far. After predict-off, editing returns to normal for the line found.
# In fact, you often don't even need to use predict-off, because if the # In fact, you often don't even need to use predict-off, because if the
# line doesn't match something in the history, adding a key at the end # line doesn't match something in the history, adding a key performs
# behaves as normal --- though editing in the middle is liable to delete # standard completion --- though editing in the middle is liable to delete
# the rest of the line. # the rest of the line.
# #
# With the function based completion system (which is needed for this),
# you should be able to type TAB at almost any point to advance the cursor
# to the next "interesting" character position (usually the end of the
# current word, but sometimes somewhere in the middle of the word). And
# of course as soon as the entire line is what you want, you can accept
# with RETURN, without needing to move the cursor to the end first.
#
# To use it: # To use it:
# autoload -U predict-on # autoload -U predict-on
# zle -N predict-on # zle -N predict-on
# zle -N predict-off # zle -N predict-off
# bindkey '...' predict-on # bindkey '...' predict-on
# bindkey '...' predict-off # bindkey '...' predict-off
# Note that all the functions are defined when you first call type the # Note that all functions are defined when you first type the predict-on
# predict-on key, which means typing the predict-off key before that gives # key, which means typing the predict-off key before that gives a harmless
# a harmless error message. # error message.
predict-on() { predict-on() {
zle -N self-insert insert-and-predict zle -N self-insert insert-and-predict
zle -N magic-space insert-and-predict zle -N magic-space insert-and-predict
zle -N backward-delete-char delete-backward-and-predict zle -N backward-delete-char delete-backward-and-predict
zle -N delete-char-or-list delete-no-predict
} }
predict-off() { predict-off() {
zle -A .self-insert self-insert zle -A .self-insert self-insert
zle -A .magic-space magic-space zle -A .magic-space magic-space
zle -A .backward-delete-char backward-delete-char zle -A .backward-delete-char backward-delete-char
} }
insert-and-predict () { insert-and-predict () {
emulate -L zsh setopt localoptions noshwordsplit noksharrays
if [[ ${RBUFFER[1]} = ${KEYS[-1]} ]] if [[ $LBUFFER = *$'\012'* ]]
then then
# same as what's typed, just move on # Editing a multiline buffer, it's unlikely prediction is wanted
zle .$WIDGET "$@"
return
elif [[ ${RBUFFER[1]} = ${KEYS[-1]} ]]
then
# Same as what's typed, just move on
((++CURSOR)) ((++CURSOR))
else else
LBUFFER="$LBUFFER$KEYS" LBUFFER="$LBUFFER$KEYS"
if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]] if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]]
then then
zle .history-beginning-search-backward || RBUFFER="" if ! zle .history-beginning-search-backward
then
RBUFFER=""
if [[ ${KEYS[-1]} != ' ' ]]
then
unsetopt automenu recexact
integer curs=$CURSOR pos nchar=${#LBUFFER//[^${KEYS[-1]}]}
local -a +h comppostfuncs
local crs curcontext="${curcontext}"
[[ -z "$curcontext" ]] && curcontext=:::
curcontext="predict:${curcontext#*:}"
comppostfuncs=( predict-limit-list )
zle complete-word
# Decide where to leave the cursor. The dummy loop is used to
# get out of that `case'.
repeat 1
do
zstyle -s ":completion:${curcontext}:" cursor crs
case $crs in
(complete)
# At the place where the completion left it, if it is after
# the character typed.
[[ ${LBUFFER[-1]} = ${KEYS[-1]} ]] && break
;&
(key)
# Or maybe at the n'th occurrence of the character typed.
pos=${BUFFER[(in:nchar:)${KEYS[-1]}]}
if [[ pos -gt curs ]]
then
CURSOR=$pos
break
fi
;&
(*)
# Or else at the previous position.
CURSOR=$curs
esac
done
fi
fi
fi fi
fi fi
return 0 return 0
} }
delete-backward-and-predict() { delete-backward-and-predict() {
emulate -L zsh
if [[ -n "$LBUFFER" ]] if [[ -n "$LBUFFER" ]]
then then
setopt localoptions noshwordsplit noksharrays
if [[ $LBUFFER = *$'\012'* ]] then
# Editing a multiline buffer, it's unlikely prediction is wanted
zle .$WIDGET "$@"
# If the last widget was e.g. a motion, then probably the intent is # If the last widget was e.g. a motion, then probably the intent is
# to actually edit the line, not change the search prefix. # to actually edit the line, not change the search prefix.
if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]] elif [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) ]]
then then
((--CURSOR)) ((--CURSOR))
zle .history-beginning-search-forward || RBUFFER="" zle .history-beginning-search-forward || RBUFFER=""
return 0 return 0
else else
# Depending on preference, you might call "predict-off" here, # Depending on preference, you might call "predict-off" here.
# and also set up forward deletions to turn off prediction.
LBUFFER="$LBUFFER[1,-2]" LBUFFER="$LBUFFER[1,-2]"
fi fi
fi fi
} }
delete-no-predict() {
[[ $WIDGET != delete-char-or-list || -n $RBUFFER ]] && predict-off
zle .$WIDGET "$@"
}
# This is a helper function for autocompletion to prevent long lists
# of matches from forcing a "do you wish to see all ...?" prompt.
predict-limit-list() {
if (( compstate[list_lines]+BUFFERLINES > LINES ||
( compstate[list_max] != 0 &&
compstate[nmatches] > compstate[list_max] ) ))
then
compstate[list]=''
elif zstyle -t ":completion:predict::::" list always
then
compstate[list]='force list'
fi
}
# Handle zsh autoloading conventions
[[ -o kshautoload ]] || predict-on "$@" [[ -o kshautoload ]] || predict-on "$@"

View file

@ -1,6 +1,6 @@
#!/usr/bin/perl -w #!/usr/bin/perl -w
# #
# $Id: make-zsh-urls,v 1.1 1999/11/09 02:36:42 akr Exp $ # $Id: make-zsh-urls,v 1.2 2000/04/01 20:49:47 pws Exp $
use strict; use strict;

File diff suppressed because it is too large Load diff

View file

@ -30,6 +30,13 @@
#include "zpty.mdh" #include "zpty.mdh"
#include "zpty.pro" #include "zpty.pro"
/* The number of bytes we normally read when given no pattern and the
* upper bound on the number of bytes we read (even if we are give a
* pattern). */
#define READ_LEN 1024
#define READ_MAX (1024 * 1024)
typedef struct ptycmd *Ptycmd; typedef struct ptycmd *Ptycmd;
struct ptycmd { struct ptycmd {
@ -158,7 +165,7 @@ get_pty(int *master, int *slave)
#else /* ! __osf__ */ #else /* ! __osf__ */
#if __SVR4 #if defined(__SVR4) || defined(sinix)
#include <sys/stropts.h> #include <sys/stropts.h>
@ -167,11 +174,12 @@ get_pty(int *master, int *slave)
{ {
int mfd, sfd; int mfd, sfd;
char *name; char *name;
int ret;
if ((mfd = open("/dev/ptmx", O_RDWR)) < 0) if ((mfd = open("/dev/ptmx", O_RDWR)) < 0)
return 1; return 1;
if (!(name = ptsname(mfd)) || grantpt(mfd) || unlockpt(mfd)) { if (grantpt(mfd) || unlockpt(mfd) || !(name = ptsname(mfd))) {
close(mfd); close(mfd);
return 1; return 1;
} }
@ -179,20 +187,31 @@ get_pty(int *master, int *slave)
close(mfd); close(mfd);
return 1; return 1;
} }
if (ioctl(sfd, I_PUSH, "ptem") || if ((ret = ioctl(sfd, I_FIND, "ptem")) != 1)
ioctl(sfd, I_PUSH, "ldterm") || if (ret == -1 || ioctl(sfd, I_PUSH, "ptem") == -1) {
ioctl(sfd, I_PUSH, "ttcompat")) { close(mfd);
close(mfd); close(sfd);
close(sfd); return 1;
return 1; }
} if ((ret = ioctl(sfd, I_FIND, "ldterm")) != 1)
if (ret == -1 || ioctl(sfd, I_PUSH, "ldterm") == -1) {
close(mfd);
close(sfd);
return 1;
}
if ((ret = ioctl(sfd, I_FIND, "ttcompat")) != 1)
if (ret == -1 || ioctl(sfd, I_PUSH, "ttcompat") == -1) {
close(mfd);
close(sfd);
return 1;
}
*master = mfd; *master = mfd;
*slave = sfd; *slave = sfd;
return 0; return 0;
} }
#else /* ! __SVR4 */ #else /* ! (defined(__SVR4) || defind(sinix)) */
static int static int
get_pty(int *master, int *slave) get_pty(int *master, int *slave)
@ -242,17 +261,17 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
char *cmd; char *cmd;
if (!(cmd = findcmd(*args, 1))) { if (!(cmd = findcmd(*args, 1))) {
zerrnam(nam, "unknown command: %s", *args, 0); zwarnnam(nam, "unknown command: %s", *args, 0);
return 1; return 1;
} }
if (get_pty(&master, &slave)) { if (get_pty(&master, &slave)) {
zerrnam(nam, "can't open pseudo terminal", NULL, 0); zwarnnam(nam, "can't open pseudo terminal", NULL, 0);
return 1; return 1;
} }
if ((pid = fork()) == -1) { if ((pid = fork()) == -1) {
close(master); close(master);
close(slave); close(slave);
zerrnam(nam, "couldn't create pty command: %s", pname, 0); zwarnnam(nam, "couldn't create pty command: %s", pname, 0);
return 1; return 1;
} else if (!pid) { } else if (!pid) {
if (!echo) { if (!echo) {
@ -298,6 +317,8 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
close(slave); close(slave);
setpgrp(0L, getpid());
execve(cmd, args, environ); execve(cmd, args, environ);
exit(0); exit(0);
} }
@ -307,9 +328,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
p = (Ptycmd) zalloc(sizeof(*p)); p = (Ptycmd) zalloc(sizeof(*p));
p->name = ztrdup(pname); p->name = ztrdup(pname);
PERMALLOC { p->args = zarrdup(args);
p->args = arrdup(args);
} LASTALLOC;
p->fd = master; p->fd = master;
p->pid = pid; p->pid = pid;
p->echo = echo; p->echo = echo;
@ -343,7 +362,9 @@ deleteptycmd(Ptycmd cmd)
zsfree(p->name); zsfree(p->name);
freearray(p->args); freearray(p->args);
kill(p->pid, SIGHUP); /* We kill the process group the command put itself in. */
kill(-(p->pid), SIGHUP);
zclose(cmd->fd); zclose(cmd->fd);
@ -375,7 +396,7 @@ checkptycmd(Ptycmd cmd)
static int static int
ptyread(char *nam, Ptycmd cmd, char **args) ptyread(char *nam, Ptycmd cmd, char **args)
{ {
int blen = 256, used = 0, ret; int blen = 256, used = 0, ret = 1;
char *buf = (char *) zhalloc(blen + 1); char *buf = (char *) zhalloc(blen + 1);
Patprog prog = NULL; Patprog prog = NULL;
@ -383,57 +404,113 @@ ptyread(char *nam, Ptycmd cmd, char **args)
char *p; char *p;
if (args[2]) { if (args[2]) {
zerrnam(nam, "too many arguments", NULL, 0); zwarnnam(nam, "too many arguments", NULL, 0);
return 1; return 1;
} }
p = dupstring(args[1]); p = dupstring(args[1]);
tokenize(p); tokenize(p);
remnulargs(p); remnulargs(p);
if (!(prog = patcompile(p, PAT_STATIC, NULL))) { if (!(prog = patcompile(p, PAT_STATIC, NULL))) {
zerrnam(nam, "bad pattern: %s", args[1], 0); zwarnnam(nam, "bad pattern: %s", args[1], 0);
return 1; return 1;
} }
} }
do { do {
while ((ret = read(cmd->fd, buf + used, 1)) == 1) { if (!ret) {
checkptycmd(cmd);
if (cmd->fin)
break;
}
if ((ret = read(cmd->fd, buf + used, 1)) == 1) {
if (++used == blen) { if (++used == blen) {
buf = hrealloc(buf, blen, blen << 1); buf = hrealloc(buf, blen, blen << 1);
blen <<= 1; blen <<= 1;
} }
} }
buf[used] = '\0'; buf[used] = '\0';
} while (prog && !pattry(prog, buf));
/**** Hm. If we leave the loop when ret < 0 the user would have
* to make sure that `zpty -r' is tried more than once if
* there will be some output and we only got the ret == -1
* because the output is not yet available.
* The same for the `write' below. */
if (ret < 0 && (cmd->block
#ifdef EWOULDBLOCK
|| errno != EWOULDBLOCK
#else
#ifdef EAGAIN
|| errno != EAGAIN
#endif
#endif
))
break;
if (!prog && !ret)
break;
} while (!errflag &&
(prog ? (used < READ_MAX && (!ret || !pattry(prog, buf))) :
(used < READ_LEN)));
if (*args) if (*args)
setsparam(*args, ztrdup(buf)); setsparam(*args, ztrdup(metafy(buf, used, META_HREALLOC)));
else else {
printf("%s", buf); fflush(stdout);
write(1, buf, used);
}
return !used; return !used;
} }
static int
ptywritestr(Ptycmd cmd, char *s, int len)
{
int written;
for (; len; len -= written, s += written) {
if ((written = write(cmd->fd, s, len)) < 0 &&
(cmd->block
#ifdef EWOULDBLOCK
|| errno != EWOULDBLOCK
#else
#ifdef EAGAIN
|| errno != EAGAIN
#endif
#endif
))
return 1;
if (written < 0) {
checkptycmd(cmd);
if (cmd->fin)
break;
written = 0;
}
}
return 0;
}
static int static int
ptywrite(Ptycmd cmd, char **args, int nonl) ptywrite(Ptycmd cmd, char **args, int nonl)
{ {
if (*args) { if (*args) {
char sp = ' '; char sp = ' ';
while (*args) { while (*args)
write(cmd->fd, *args, strlen(*args)); if (ptywritestr(cmd, *args, strlen(*args)) ||
(*++args && ptywritestr(cmd, &sp, 1)))
return 1;
if (*++args)
write(cmd->fd, &sp, 1);
}
if (!nonl) { if (!nonl) {
sp = '\n'; sp = '\n';
write(cmd->fd, &sp, 1); if (ptywritestr(cmd, &sp, 1))
return 1;
} }
} else { } else {
int n; int n;
char buf[BUFSIZ]; char buf[BUFSIZ];
while ((n = read(0, buf, BUFSIZ)) > 0) while ((n = read(0, buf, BUFSIZ)) > 0)
write(cmd->fd, buf, n); if (ptywritestr(cmd, buf, n))
return 1;
} }
return 0; return 0;
} }
@ -449,17 +526,17 @@ bin_zpty(char *nam, char **args, char *ops, int func)
ops['d'] || ops['L'])) || ops['d'] || ops['L'])) ||
(ops['d'] && (ops['b'] || ops['e'] || ops['L'])) || (ops['d'] && (ops['b'] || ops['e'] || ops['L'])) ||
(ops['L'] && (ops['b'] || ops['e']))) { (ops['L'] && (ops['b'] || ops['e']))) {
zerrnam(nam, "illegal option combination", NULL, 0); zwarnnam(nam, "illegal option combination", NULL, 0);
return 1; return 1;
} }
if (ops['r'] || ops['w']) { if (ops['r'] || ops['w']) {
Ptycmd p; Ptycmd p;
if (!*args) { if (!*args) {
zerrnam(nam, "missing pty command name", NULL, 0); zwarnnam(nam, "missing pty command name", NULL, 0);
return 1; return 1;
} else if (!(p = getptycmd(*args))) { } else if (!(p = getptycmd(*args))) {
zerrnam(nam, "no such pty command: %s", *args, 0); zwarnnam(nam, "no such pty command: %s", *args, 0);
return 1; return 1;
} }
checkptycmd(p); checkptycmd(p);
@ -486,11 +563,11 @@ bin_zpty(char *nam, char **args, char *ops, int func)
return ret; return ret;
} else if (*args) { } else if (*args) {
if (!args[1]) { if (!args[1]) {
zerrnam(nam, "missing command", NULL, 0); zwarnnam(nam, "missing command", NULL, 0);
return 1; return 1;
} }
if (getptycmd(*args)) { if (getptycmd(*args)) {
zerrnam(nam, "pty command name already used: %s", *args, 0); zwarnnam(nam, "pty command name already used: %s", *args, 0);
return 1; return 1;
} }
return newptycmd(nam, *args, args + 1, ops['e'], ops['b']); return newptycmd(nam, *args, args + 1, ops['e'], ops['b']);

View file

@ -27,111 +27,362 @@
* *
*/ */
#undef compctlread typedef struct cmatcher *Cmatcher;
typedef struct cmlist *Cmlist;
typedef struct cpattern *Cpattern;
typedef struct menuinfo *Menuinfo;
typedef struct cexpl *Cexpl;
typedef struct cmgroup *Cmgroup;
typedef struct cmatch *Cmatch;
typedef struct compctlp *Compctlp; /* This is for explantion strings. */
typedef struct compctl *Compctl;
typedef struct compcond *Compcond;
/* node for compctl hash table (compctltab) */ struct cexpl {
char *str; /* the string */
struct compctlp { int count; /* the number of matches */
HashNode next; /* next in hash chain */ int fcount; /* number of matches with fignore ignored */
char *nam; /* command name */
int flags; /* CURRENTLY UNUSED */
Compctl cc; /* pointer to the compctl desc. */
}; };
/* compctl -x condition */ /* This describes a group of matches. */
struct compcond { struct cmgroup {
Compcond and, or; /* the next or'ed/and'ed conditions */ char *name; /* the name of this group */
int type; /* the type (CCT_*) */ Cmgroup prev; /* previous on the list */
int n; /* the array length */ Cmgroup next; /* next one in list */
union { /* these structs hold the data used to */ int flags; /* see CGF_* below */
struct { /* test this condition */ int mcount; /* number of matches */
int *a, *b; /* CCT_POS, CCT_NUMWORDS */ Cmatch *matches; /* the matches */
} int lcount; /* number of things to list here */
r; int llcount; /* number of line-displays */
struct { /* CCT_CURSTR, CCT_CURPAT,... */ char **ylist; /* things to list */
int *p; int ecount; /* number of explanation string */
char **s; Cexpl *expls; /* explanation strings */
} int ccount; /* number of compctls used */
s; LinkList lexpls; /* list of explanation string while building */
struct { /* CCT_RANGESTR,... */ LinkList lmatches; /* list of matches */
char **a, **b; LinkList lfmatches; /* list of matches without fignore */
} LinkList lallccs; /* list of used compctls */
l; int num; /* number of this group */
} int nbrbeg; /* number of opened braces */
u; int nbrend; /* number of closed braces */
/* The following is collected/used during listing. */
int dcount; /* number of matches to list in columns */
int cols; /* number of columns */
int lins; /* number of lines */
int width; /* column width */
int *widths; /* column widths for listpacked */
int totl; /* total length */
int shortest; /* length of shortest match */
Cmgroup perm; /* perm. alloced version of this group */
int new; /* new matches since last permalloc() */
}; };
#define CCT_UNUSED 0
#define CCT_POS 1
#define CCT_CURSTR 2
#define CCT_CURPAT 3
#define CCT_WORDSTR 4
#define CCT_WORDPAT 5
#define CCT_CURSUF 6
#define CCT_CURPRE 7
#define CCT_CURSUB 8
#define CCT_CURSUBC 9
#define CCT_NUMWORDS 10
#define CCT_RANGESTR 11
#define CCT_RANGEPAT 12
/* Contains the real description for compctls */ #define CGF_NOSORT 1 /* don't sort this group */
#define CGF_LINES 2 /* these are to be printed on different lines */
#define CGF_HASDL 4 /* has display strings printed on separate lines */
#define CGF_UNIQALL 8 /* remove all duplicates */
#define CGF_UNIQCON 16 /* remove consecutive duplicates */
#define CGF_PACKED 32 /* LIST_PACKED for this group */
#define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */
struct compctl { /* This is the struct used to hold matches. */
int refc; /* reference count */
Compctl next; /* next compctl for -x */ struct cmatch {
unsigned long mask; /* mask of things to complete (CC_*) */ char *str; /* the match itself */
char *keyvar; /* for -k (variable) */ char *ipre; /* ignored prefix, has to be re-inserted */
char *glob; /* for -g (globbing) */ char *ripre; /* ignored prefix, unquoted */
char *str; /* for -s (expansion) */ char *isuf; /* ignored suffix */
char *func; /* for -K (function) */ char *ppre; /* the path prefix */
char *explain; /* for -X (explanation) */ char *psuf; /* the path suffix */
char *ylist; /* for -y (user-defined desc. for listing) */ char *prpre; /* path prefix for opendir */
char *prefix, *suffix; /* for -P and -S (prefix, suffix) */ char *pre; /* prefix string from -P */
char *subcmd; /* for -l (command name to use) */ char *suf; /* suffix string from -S */
char *withd; /* for -w (with directory */ char *disp; /* string to display (compadd -d) */
char *hpat; /* for -H (history pattern) */ char *autoq; /* closing quote to add automatically */
int hnum; /* for -H (number of events to search) */ int flags; /* see CMF_* below */
Compctl ext; /* for -x (first of the compctls after -x) */ int *brpl; /* places where to put the brace prefixes */
Compcond cond; /* for -x (condition for this compctl) */ int *brsl; /* ...and the suffixes */
Compctl xor; /* for + (next of the xor'ed compctls) */ char *rems; /* when to remove the suffix */
char *remf; /* shell function to call for suffix-removal */
int qipl; /* length of quote-prefix */
int qisl; /* length of quote-suffix */
int rnum; /* group relative number */
int gnum; /* global number */
}; };
/* objects to complete */ #define CMF_FILE (1<< 0) /* this is a file */
#define CC_FILES (1<<0) #define CMF_REMOVE (1<< 1) /* remove the suffix */
#define CC_COMMPATH (1<<1) #define CMF_ISPAR (1<< 2) /* is paramter expansion */
#define CC_REMOVE (1<<2) #define CMF_PARBR (1<< 3) /* paramter expansion with a brace */
#define CC_OPTIONS (1<<3) #define CMF_PARNEST (1<< 4) /* nested paramter expansion */
#define CC_VARS (1<<4) #define CMF_NOLIST (1<< 5) /* should not be listed */
#define CC_BINDINGS (1<<5) #define CMF_DISPLINE (1<< 6) /* display strings one per line */
#define CC_ARRAYS (1<<6) #define CMF_HIDE (1<< 7) /* temporarily hide this one */
#define CC_INTVARS (1<<7) #define CMF_NOSPACE (1<< 8) /* don't add a space */
#define CC_SHFUNCS (1<<8) #define CMF_PACKED (1<< 9) /* prefer LIST_PACKED */
#define CC_PARAMS (1<<9) #define CMF_ROWS (1<<10) /* prefer LIST_ROWS_FIRST */
#define CC_ENVVARS (1<<10) #define CMF_MULT (1<<11) /* string appears more than once */
#define CC_JOBS (1<<11) #define CMF_FMULT (1<<12) /* first of multiple equal strings */
#define CC_RUNNING (1<<12)
#define CC_STOPPED (1<<13) /* Stuff for completion matcher control. */
#define CC_BUILTINS (1<<14)
#define CC_ALREG (1<<15) struct cmlist {
#define CC_ALGLOB (1<<16) Cmlist next; /* next one in the list of global matchers */
#define CC_USERS (1<<17) Cmatcher matcher; /* the matcher definition */
#define CC_DISCMDS (1<<18) char *str; /* the string for it */
#define CC_EXCMDS (1<<19) };
#define CC_SCALARS (1<<20)
#define CC_READONLYS (1<<21) struct cmatcher {
#define CC_SPECIALS (1<<22) int refc; /* reference counter */
#define CC_DELETE (1<<23) Cmatcher next; /* next matcher */
#define CC_NAMED (1<<24) int flags; /* see CMF_* below */
#define CC_QUOTEFLAG (1<<25) Cpattern line; /* what matches on the line */
#define CC_EXTCMDS (1<<26) int llen; /* length of line pattern */
#define CC_RESWDS (1<<27) Cpattern word; /* what matches in the word */
#define CC_DIRS (1<<28) int wlen; /* length of word pattern */
Cpattern left; /* left anchor */
int lalen; /* length of left anchor */
Cpattern right; /* right anchor */
int ralen; /* length of right anchor */
};
#define CMF_LINE 1
#define CMF_LEFT 2
#define CMF_RIGHT 4
struct cpattern {
Cpattern next; /* next sub-pattern */
unsigned char tab[256]; /* table of matched characters */
int equiv; /* if this is a {...} class */
};
/* This is a special return value for parse_cmatcher(), *
* signalling an error. */
#define pcm_err ((Cmatcher) 1)
/* Information about what to put on the line as the unambiguous string.
* The code always keeps lists of these structs up to date while
* matches are added (in the aminfo structs below).
* The lists have two levels: in the first one we have one struct per
* word-part, where parts are separated by the anchors of `*' patterns.
* These structs have pointers (in the prefix and suffix fields) to
* lists of cline structs describing the strings before or after the
* the anchor. */
typedef struct cline *Cline;
typedef struct clsub Clsub;
struct cline {
Cline next;
int flags;
char *line;
int llen;
char *word;
int wlen;
char *orig;
int olen;
int slen;
Cline prefix, suffix;
int min, max;
};
#define CLF_MISS 1
#define CLF_DIFF 2
#define CLF_SUF 4
#define CLF_MID 8
#define CLF_NEW 16
#define CLF_LINE 32
#define CLF_JOIN 64
#define CLF_MATCHED 128
/* Information for ambiguous completions. One for fignore ignored and *
* one for normal completion. */
typedef struct aminfo *Aminfo;
struct aminfo {
Cmatch firstm; /* the first match */
int exact; /* if there was an exact match */
Cmatch exactm; /* the exact match (if any) */
int count; /* number of matches */
Cline line; /* unambiguous line string */
};
/* Information about menucompletion stuff. */
struct menuinfo {
Cmgroup group; /* position in the group list */
Cmatch *cur; /* match currently inserted */
int pos; /* begin on line */
int len; /* length of inserted string */
int end; /* end on the line */
int we; /* non-zero if the cursor was at the end */
int insc; /* length of suffix inserted */
int asked; /* we asked if the list should be shown */
char *prebr; /* prefix before a brace, if any */
char *postbr; /* suffix after a brace */
};
/* Flags for compadd and addmatches(). */
#define CAF_QUOTE 1
#define CAF_NOSORT 2
#define CAF_MATCH 4
#define CAF_UNIQCON 8
#define CAF_UNIQALL 16
/* Data for compadd and addmatches() */
typedef struct cadata *Cadata;
struct cadata {
char *ipre; /* ignored prefix (-i) */
char *isuf; /* ignored suffix (-I) */
char *ppre; /* `path' prefix (-p) */
char *psuf; /* `path' suffix (-s) */
char *prpre; /* expanded `path' prefix (-W) */
char *pre; /* prefix to insert (-P) */
char *suf; /* suffix to insert (-S) */
char *group; /* name of the group (-[JV]) */
char *rems; /* remove suffix on chars... (-r) */
char *remf; /* function to remove suffix (-R) */
char *ign; /* ignored suffixes (-F) */
int flags; /* CMF_* flags (-[fqn]) */
int aflags; /* CAF_* flags (-[QUa]) */
Cmatcher match; /* match spec (parsed from -M) */
char *exp; /* explanation (-X) */
char *apar; /* array to store matches in (-A) */
char *opar; /* array to store originals in (-O) */
char *dpar; /* array to delete non-matches in (-D) */
char *disp; /* array with display lists (-d) */
};
/* List data. */
typedef struct cldata *Cldata;
struct cldata {
int columns; /* screen width */
int lines; /* screen height */
int menuacc; /* value of global menuacc */
int valid; /* no need to calculate anew */
int nlist; /* number of matches to list */
int nlines; /* number of lines needed */
int hidden; /* != 0 if there are hidden matches */
int onlyexpl; /* != 0 if only explanations to print */
int showall; /* != 0 if hidden matches should be shown */
};
typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int,
char *, struct stat *);
/* Flags for fromcomp. */
#define FC_LINE 1
#define FC_INWORD 2
/* Flags for special parameters. */
#define CPN_WORDS 0
#define CP_WORDS (1 << CPN_WORDS)
#define CPN_CURRENT 1
#define CP_CURRENT (1 << CPN_CURRENT)
#define CPN_PREFIX 2
#define CP_PREFIX (1 << CPN_PREFIX)
#define CPN_SUFFIX 3
#define CP_SUFFIX (1 << CPN_SUFFIX)
#define CPN_IPREFIX 4
#define CP_IPREFIX (1 << CPN_IPREFIX)
#define CPN_ISUFFIX 5
#define CP_ISUFFIX (1 << CPN_ISUFFIX)
#define CPN_QIPREFIX 6
#define CP_QIPREFIX (1 << CPN_QIPREFIX)
#define CPN_QISUFFIX 7
#define CP_QISUFFIX (1 << CPN_QISUFFIX)
#define CPN_COMPSTATE 8
#define CP_COMPSTATE (1 << CPN_COMPSTATE)
#define CP_REALPARAMS 9
#define CP_ALLREALS ((unsigned int) 0x1ff)
#define CPN_NMATCHES 0
#define CP_NMATCHES (1 << CPN_NMATCHES)
#define CPN_CONTEXT 1
#define CP_CONTEXT (1 << CPN_CONTEXT)
#define CPN_PARAMETER 2
#define CP_PARAMETER (1 << CPN_PARAMETER)
#define CPN_REDIRECT 3
#define CP_REDIRECT (1 << CPN_REDIRECT)
#define CPN_QUOTE 4
#define CP_QUOTE (1 << CPN_QUOTE)
#define CPN_QUOTING 5
#define CP_QUOTING (1 << CPN_QUOTING)
#define CPN_RESTORE 6
#define CP_RESTORE (1 << CPN_RESTORE)
#define CPN_LIST 7
#define CP_LIST (1 << CPN_LIST)
#define CPN_INSERT 8
#define CP_INSERT (1 << CPN_INSERT)
#define CPN_EXACT 9
#define CP_EXACT (1 << CPN_EXACT)
#define CPN_EXACTSTR 10
#define CP_EXACTSTR (1 << CPN_EXACTSTR)
#define CPN_PATMATCH 11
#define CP_PATMATCH (1 << CPN_PATMATCH)
#define CPN_PATINSERT 12
#define CP_PATINSERT (1 << CPN_PATINSERT)
#define CPN_UNAMBIG 13
#define CP_UNAMBIG (1 << CPN_UNAMBIG)
#define CPN_UNAMBIGC 14
#define CP_UNAMBIGC (1 << CPN_UNAMBIGC)
#define CPN_LISTMAX 15
#define CP_LISTMAX (1 << CPN_LISTMAX)
#define CPN_LASTPROMPT 16
#define CP_LASTPROMPT (1 << CPN_LASTPROMPT)
#define CPN_TOEND 17
#define CP_TOEND (1 << CPN_TOEND)
#define CPN_OLDLIST 18
#define CP_OLDLIST (1 << CPN_OLDLIST)
#define CPN_OLDINS 19
#define CP_OLDINS (1 << CPN_OLDINS)
#define CPN_VARED 20
#define CP_VARED (1 << CPN_VARED)
#define CPN_LISTLINES 21
#define CP_LISTLINES (1 << CPN_LISTLINES)
#define CPN_QUOTES 22
#define CP_QUOTES (1 << CPN_QUOTES)
#define CPN_IGNORED 23
#define CP_IGNORED (1 << CPN_IGNORED)
#define CP_KEYPARAMS 24
#define CP_ALLKEYS ((unsigned int) 0xffffff)
/* Hooks. */
#define INSERTMATCHHOOK (comphooks + 0)
#define MENUSTARTHOOK (comphooks + 1)
#define COMPCTLMAKEHOOK (comphooks + 2)
#define COMPCTLCLEANUPHOOK (comphooks + 3)
#define COMPLISTMATCHESHOOK (comphooks + 4)
/* compctl hook data struct */
struct ccmakedat {
char *str;
int incmd;
int lst;
};
/* Data given to offered hooks. */
typedef struct chdata *Chdata;
struct chdata {
Cmgroup matches; /* the matches generated */
int num; /* the number of matches */
Cmatch cur; /* current match or NULL */
};
#define CC_EXPANDEXPL (1<<30)
#define CC_RESERVED (1<<31)

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* /*
* complete.c - the complete module * complete.c - the complete module, interface part
* *
* This file is part of zsh, the Z shell. * This file is part of zsh, the Z shell.
* *
@ -29,12 +29,50 @@
#include "complete.mdh" #include "complete.mdh"
#include "complete.pro" #include "complete.pro"
#define GLOBAL_PROTOTYPES
#include "zle_tricky.pro" /* global variables for shell parameters in new style completion */
#undef GLOBAL_PROTOTYPES
/**/ /**/
void mod_export zlong compcurrent;
/**/
zlong complistmax,
complistlines,
compignored;
/**/
mod_export
char **compwords,
*compprefix,
*compsuffix,
*compisuffix,
*compqiprefix,
*compqisuffix,
*compquote,
*compqstack,
*comppatmatch,
*complastprompt;
/**/
char *compiprefix,
*compcontext,
*compparameter,
*compredirect,
*compquoting,
*comprestore,
*complist,
*compinsert,
*compexact,
*compexactstr,
*comppatinsert,
*comptoend,
*compoldlist,
*compoldins,
*compvared;
/**/
Param *comprpms, *compkpms;
/**/
mod_export void
freecmlist(Cmlist l) freecmlist(Cmlist l)
{ {
Cmlist n; Cmlist n;
@ -51,7 +89,7 @@ freecmlist(Cmlist l)
} }
/**/ /**/
void mod_export void
freecmatcher(Cmatcher m) freecmatcher(Cmatcher m)
{ {
Cmatcher n; Cmatcher n;
@ -86,29 +124,10 @@ freecpattern(Cpattern p)
} }
} }
/* Copy a list of completion matchers. */
static Cmlist
cpcmlist(Cmlist l)
{
Cmlist r = NULL, *p = &r, n;
while (l) {
*p = n = (Cmlist) zalloc(sizeof(struct cmlist));
n->next = NULL;
n->matcher = cpcmatcher(l->matcher);
n->str = ztrdup(l->str);
p = &(n->next);
l = l->next;
}
return r;
}
/* Copy a completion matcher list. */ /* Copy a completion matcher list. */
/**/ /**/
Cmatcher mod_export Cmatcher
cpcmatcher(Cmatcher m) cpcmatcher(Cmatcher m)
{ {
Cmatcher r = NULL, *p = &r, n; Cmatcher r = NULL, *p = &r, n;
@ -155,37 +174,10 @@ cpcpattern(Cpattern o)
return r; return r;
} }
/* Set the global match specs. */
/**/
int
set_gmatcher(char *name, char **argv)
{
Cmlist l = NULL, *q = &l, n;
Cmatcher m;
while (*argv) {
if ((m = parse_cmatcher(name, *argv)) == pcm_err)
return 1;
*q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
n->next = NULL;
n->matcher = m;
n->str = *argv++;
q = &(n->next);
}
freecmlist(cmatcher);
PERMALLOC {
cmatcher = cpcmlist(l);
} LASTALLOC;
return 1;
}
/* Parse a string for matcher control, containing multiple matchers. */ /* Parse a string for matcher control, containing multiple matchers. */
/**/ /**/
Cmatcher mod_export Cmatcher
parse_cmatcher(char *name, char *s) parse_cmatcher(char *name, char *s)
{ {
Cmatcher ret = NULL, r = NULL, n; Cmatcher ret = NULL, r = NULL, n;
@ -262,8 +254,11 @@ parse_cmatcher(char *name, char *s)
return pcm_err; return pcm_err;
} }
word = NULL; word = NULL;
wl = -1; if (*++s == '*') {
s++; s++;
wl = -2;
} else
wl = -1;
} else { } else {
word = parse_pattern(name, &s, &wl, 0, &err); word = parse_pattern(name, &s, &wl, 0, &err);
@ -389,17 +384,17 @@ static int
bin_compadd(char *name, char **argv, char *ops, int func) bin_compadd(char *name, char **argv, char *ops, int func)
{ {
struct cadata dat; struct cadata dat;
char *p, **sp, *e, *m = NULL; char *p, **sp, *e, *m = NULL, *mstr = NULL;
int dm; int dm;
Cmatcher match = NULL; Cmatcher match = NULL;
if (incompfunc != 1) { if (incompfunc != 1) {
zerrnam(name, "can only be called from completion function", NULL, 0); zwarnnam(name, "can only be called from completion function", NULL, 0);
return 1; return 1;
} }
dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre =
dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp = dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp =
dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = dat.ylist = NULL; dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
dat.match = NULL; dat.match = NULL;
dat.flags = 0; dat.flags = 0;
dat.aflags = CAF_MATCH; dat.aflags = CAF_MATCH;
@ -462,10 +457,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
if (!(dat.aflags & CAF_UNIQALL)) if (!(dat.aflags & CAF_UNIQALL))
dat.aflags |= CAF_UNIQCON; dat.aflags |= CAF_UNIQCON;
break; break;
case 'y':
sp = &(dat.ylist);
e = "string expected after -%c";
break;
case 'i': case 'i':
sp = &(dat.ipre); sp = &(dat.ipre);
e = "string expected after -%c"; e = "string expected after -%c";
@ -486,9 +477,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
sp = &(dat.prpre); sp = &(dat.prpre);
e = "string expected after -%c"; e = "string expected after -%c";
break; break;
case 'a':
dat.aflags |= CAF_ALT;
break;
case 'M': case 'M':
sp = &m; sp = &m;
e = "matching specification expected after -%c"; e = "matching specification expected after -%c";
@ -531,7 +519,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
argv++; argv++;
goto ca_args; goto ca_args;
default: default:
zerrnam(name, "bad option: -%c", NULL, *p); zwarnnam(name, "bad option: -%c", NULL, *p);
return 1; return 1;
} }
if (sp) { if (sp) {
@ -545,18 +533,29 @@ bin_compadd(char *name, char **argv, char *ops, int func)
*sp = *argv; *sp = *argv;
p = "" - 1; p = "" - 1;
} else { } else {
zerrnam(name, e, NULL, *p); zwarnnam(name, e, NULL, *p);
return 1; return 1;
} }
if (dm && (match = parse_cmatcher(name, m)) == pcm_err) { if (dm) {
match = NULL; if (mstr)
return 1; mstr = tricat(mstr, " ", m);
else
mstr = ztrdup(m);
m = NULL;
} }
} }
} }
} }
if (mstr && (match = parse_cmatcher(name, mstr)) == pcm_err) {
zsfree(mstr);
return 1;
}
zsfree(mstr);
ca_args: ca_args:
if (!*argv)
if (!*argv && !dat.group &&
!(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON)))
return 1; return 1;
dat.match = match = cpcmatcher(match); dat.match = match = cpcmatcher(match);
@ -574,7 +573,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
#define CVT_SUFPAT 5 #define CVT_SUFPAT 5
/**/ /**/
void mod_export void
ignore_prefix(int l) ignore_prefix(int l)
{ {
if (l) { if (l) {
@ -598,7 +597,7 @@ ignore_prefix(int l)
} }
/**/ /**/
void mod_export void
ignore_suffix(int l) ignore_suffix(int l)
{ {
if (l) { if (l) {
@ -621,7 +620,7 @@ ignore_suffix(int l)
} }
/**/ /**/
void mod_export void
restrict_range(int b, int e) restrict_range(int b, int e)
{ {
int wl = arrlen(compwords) - 1; int wl = arrlen(compwords) - 1;
@ -644,6 +643,7 @@ restrict_range(int b, int e)
} }
} }
/**/
static int static int
do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod) do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
{ {
@ -740,7 +740,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
char *p, sav; char *p, sav;
if (!(l = strlen(compprefix))) if (!(l = strlen(compprefix)))
return 0; return ((na == 1 || na == -1) && pattry(pp, compprefix));
if (na < 0) { if (na < 0) {
p = compprefix + l; p = compprefix + l;
na = -na; na = -na;
@ -766,7 +766,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
char *p; char *p;
if (!(ol = l = strlen(compsuffix))) if (!(ol = l = strlen(compsuffix)))
return 0; return ((na == 1 || na == -1) && pattry(pp, compsuffix));
if (na < 0) { if (na < 0) {
p = compsuffix; p = compsuffix;
na = -na; na = -na;
@ -798,11 +798,11 @@ bin_compset(char *name, char **argv, char *ops, int func)
char *sa = NULL, *sb = NULL; char *sa = NULL, *sb = NULL;
if (incompfunc != 1) { if (incompfunc != 1) {
zerrnam(name, "can only be called from completion function", NULL, 0); zwarnnam(name, "can only be called from completion function", NULL, 0);
return 1; return 1;
} }
if (argv[0][0] != '-') { if (argv[0][0] != '-') {
zerrnam(name, "missing option", NULL, 0); zwarnnam(name, "missing option", NULL, 0);
return 1; return 1;
} }
switch (argv[0][1]) { switch (argv[0][1]) {
@ -814,7 +814,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
case 'S': test = CVT_SUFPAT; break; case 'S': test = CVT_SUFPAT; break;
case 'q': return set_comp_sep(); case 'q': return set_comp_sep();
default: default:
zerrnam(name, "bad option -%c", NULL, argv[0][1]); zwarnnam(name, "bad option -%c", NULL, argv[0][1]);
return 1; return 1;
} }
if (argv[0][2]) { if (argv[0][2]) {
@ -823,7 +823,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
na = 2; na = 2;
} else { } else {
if (!(sa = argv[1])) { if (!(sa = argv[1])) {
zerrnam(name, "missing string for option -%c", NULL, argv[0][1]); zwarnnam(name, "missing string for option -%c", NULL, argv[0][1]);
return 1; return 1;
} }
sb = argv[2]; sb = argv[2];
@ -831,7 +831,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
} }
if (((test == CVT_PRENUM || test == CVT_SUFNUM) ? !!sb : if (((test == CVT_PRENUM || test == CVT_SUFNUM) ? !!sb :
(sb && argv[na]))) { (sb && argv[na]))) {
zerrnam(name, "too many arguments", NULL, 0); zwarnnam(name, "too many arguments", NULL, 0);
return 1; return 1;
} }
switch (test) { switch (test) {
@ -841,11 +841,9 @@ bin_compset(char *name, char **argv, char *ops, int func)
break; break;
case CVT_RANGEPAT: case CVT_RANGEPAT:
tokenize(sa); tokenize(sa);
sa = rembslash(sa);
remnulargs(sa); remnulargs(sa);
if (sb) { if (sb) {
tokenize(sb); tokenize(sb);
sb = rembslash(sb);
remnulargs(sb); remnulargs(sb);
} }
break; break;
@ -861,7 +859,6 @@ bin_compset(char *name, char **argv, char *ops, int func)
} else } else
na = -1; na = -1;
tokenize(sa); tokenize(sa);
sa = rembslash(sa);
remnulargs(sa); remnulargs(sa);
break; break;
} }
@ -892,9 +889,6 @@ static struct compparam comprparams[] = {
static struct compparam compkparams[] = { static struct compparam compkparams[] = {
{ "nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_nmatches) }, { "nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_nmatches) },
{ "matcher", PM_INTEGER, VAL(compmatcher), NULL, NULL },
{ "matcher_string", PM_SCALAR, VAL(compmatcherstr), NULL, NULL },
{ "total_matchers", PM_INTEGER, VAL(compmatchertot), NULL, NULL },
{ "context", PM_SCALAR, VAL(compcontext), NULL, NULL }, { "context", PM_SCALAR, VAL(compcontext), NULL, NULL },
{ "parameter", PM_SCALAR, VAL(compparameter), NULL, NULL }, { "parameter", PM_SCALAR, VAL(compparameter), NULL, NULL },
{ "redirect", PM_SCALAR, VAL(compredirect), NULL, NULL }, { "redirect", PM_SCALAR, VAL(compredirect), NULL, NULL },
@ -902,7 +896,6 @@ static struct compparam compkparams[] = {
{ "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL, NULL }, { "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL, NULL },
{ "restore", PM_SCALAR, VAL(comprestore), NULL, NULL }, { "restore", PM_SCALAR, VAL(comprestore), NULL, NULL },
{ "list", PM_SCALAR, NULL, VAL(set_complist), VAL(get_complist) }, { "list", PM_SCALAR, NULL, VAL(set_complist), VAL(get_complist) },
{ "force_list", PM_SCALAR, VAL(compforcelist), NULL, NULL },
{ "insert", PM_SCALAR, VAL(compinsert), NULL, NULL }, { "insert", PM_SCALAR, VAL(compinsert), NULL, NULL },
{ "exact", PM_SCALAR, VAL(compexact), NULL, NULL }, { "exact", PM_SCALAR, VAL(compexact), NULL, NULL },
{ "exact_string", PM_SCALAR, VAL(compexactstr), NULL, NULL }, { "exact_string", PM_SCALAR, VAL(compexactstr), NULL, NULL },
@ -917,8 +910,9 @@ static struct compparam compkparams[] = {
{ "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL }, { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
{ "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL }, { "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL },
{ "vared", PM_SCALAR, VAL(compvared), NULL, NULL }, { "vared", PM_SCALAR, VAL(compvared), NULL, NULL },
{ "alternate_nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_anmatches) },
{ "list_lines", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_listlines) }, { "list_lines", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_listlines) },
{ "all_quotes", PM_SCALAR | PM_READONLY, VAL(compqstack), NULL, NULL },
{ "ignored", PM_INTEGER | PM_READONLY, VAL(compignored), NULL, NULL },
{ NULL, 0, NULL, NULL, NULL } { NULL, 0, NULL, NULL, NULL }
}; };
@ -976,7 +970,7 @@ makecompparams(void)
comprpms[CPN_COMPSTATE] = cpm; comprpms[CPN_COMPSTATE] = cpm;
tht = paramtab; tht = paramtab;
cpm->level = locallevel; cpm->level = locallevel + 1;
cpm->gets.hfn = get_compstate; cpm->gets.hfn = get_compstate;
cpm->sets.hfn = set_compstate; cpm->sets.hfn = set_compstate;
cpm->unsetfn = compunsetfn; cpm->unsetfn = compunsetfn;
@ -1029,14 +1023,7 @@ set_compstate(Param pm, HashTable ht)
static zlong static zlong
get_nmatches(Param pm) get_nmatches(Param pm)
{ {
return num_matches(1); return (permmatches(0) ? 0 : nmatches);
}
/**/
static zlong
get_anmatches(Param pm)
{
return num_matches(0);
} }
/**/ /**/
@ -1083,14 +1070,37 @@ static void
compunsetfn(Param pm, int exp) compunsetfn(Param pm, int exp)
{ {
if (exp) { if (exp) {
if (PM_TYPE(pm->flags) == PM_SCALAR) { if (pm->u.data) {
zsfree(*((char **) pm->u.data)); if (PM_TYPE(pm->flags) == PM_SCALAR) {
*((char **) pm->u.data) = ztrdup(""); zsfree(*((char **) pm->u.data));
} else if (PM_TYPE(pm->flags) == PM_ARRAY) { *((char **) pm->u.data) = ztrdup("");
freearray(*((char ***) pm->u.data)); } else if (PM_TYPE(pm->flags) == PM_ARRAY) {
*((char ***) pm->u.data) = zcalloc(sizeof(char *)); freearray(*((char ***) pm->u.data));
*((char ***) pm->u.data) = zcalloc(sizeof(char *));
} else if (PM_TYPE(pm->flags) == PM_HASHED) {
deleteparamtable(pm->u.hash);
pm->u.hash = NULL;
}
} }
pm->flags |= PM_UNSET; } else if (PM_TYPE(pm->flags) == PM_HASHED) {
Param *p;
int i;
deletehashtable(pm->u.hash);
pm->u.hash = NULL;
for (p = compkpms, i = CP_KEYPARAMS; i--; p++)
*p = NULL;
}
if (!exp) {
Param *p;
int i;
for (p = comprpms, i = CP_REALPARAMS; i; p++, i--)
if (*p == pm) {
*p = NULL;
break;
}
} }
} }
@ -1102,31 +1112,35 @@ comp_setunset(int rset, int runset, int kset, int kunset)
if (comprpms && (rset >= 0 || runset >= 0)) { if (comprpms && (rset >= 0 || runset >= 0)) {
for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) { for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) {
if (rset & 1) if (*p) {
(*p)->flags &= ~PM_UNSET; if (rset & 1)
if (runset & 1) (*p)->flags &= ~PM_UNSET;
(*p)->flags |= PM_UNSET; if (runset & 1)
(*p)->flags |= PM_UNSET;
}
} }
} }
if (comprpms && (kset >= 0 || kunset >= 0)) { if (compkpms && (kset >= 0 || kunset >= 0)) {
for (p = compkpms; kset || kunset; kset >>= 1, kunset >>= 1, p++) { for (p = compkpms; kset || kunset; kset >>= 1, kunset >>= 1, p++) {
if (kset & 1) if (*p) {
(*p)->flags &= ~PM_UNSET; if (kset & 1)
if (kunset & 1) (*p)->flags &= ~PM_UNSET;
(*p)->flags |= PM_UNSET; if (kunset & 1)
(*p)->flags |= PM_UNSET;
}
} }
} }
} }
/**/ /**/
static int static int
comp_wrapper(List list, FuncWrap w, char *name) comp_wrapper(Eprog prog, FuncWrap w, char *name)
{ {
if (incompfunc != 1) if (incompfunc != 1)
return 1; return 1;
else { else {
char *orest, *opre, *osuf, *oipre, *oisuf, **owords; char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
char *oqipre, *oqisuf, *oq, *oqi; char *oqipre, *oqisuf, *oq, *oqi, *oqs, *oaq;
zlong ocur; zlong ocur;
unsigned int runset = 0, kunset = 0, m, sm; unsigned int runset = 0, kunset = 0, m, sm;
Param *pp; Param *pp;
@ -1142,52 +1156,65 @@ comp_wrapper(List list, FuncWrap w, char *name)
orest = comprestore; orest = comprestore;
comprestore = ztrdup("auto"); comprestore = ztrdup("auto");
ocur = compcurrent; ocur = compcurrent;
opre = dupstring(compprefix); opre = ztrdup(compprefix);
osuf = dupstring(compsuffix); osuf = ztrdup(compsuffix);
oipre = dupstring(compiprefix); oipre = ztrdup(compiprefix);
oisuf = dupstring(compisuffix); oisuf = ztrdup(compisuffix);
oqipre = dupstring(compqiprefix); oqipre = ztrdup(compqiprefix);
oqisuf = dupstring(compqisuffix); oqisuf = ztrdup(compqisuffix);
oq = dupstring(compquote); oq = ztrdup(compquote);
oqi = dupstring(compquoting); oqi = ztrdup(compquoting);
oqs = ztrdup(compqstack);
oaq = ztrdup(autoq);
owords = zarrdup(compwords);
HEAPALLOC { runshfunc(prog, w, name);
owords = arrdup(compwords);
} LASTALLOC;
runshfunc(list, w, name);
if (comprestore && !strcmp(comprestore, "auto")) { if (comprestore && !strcmp(comprestore, "auto")) {
compcurrent = ocur; compcurrent = ocur;
zsfree(compprefix); zsfree(compprefix);
compprefix = ztrdup(opre); compprefix = opre;
zsfree(compsuffix); zsfree(compsuffix);
compsuffix = ztrdup(osuf); compsuffix = osuf;
zsfree(compiprefix); zsfree(compiprefix);
compiprefix = ztrdup(oipre); compiprefix = oipre;
zsfree(compisuffix); zsfree(compisuffix);
compisuffix = ztrdup(oisuf); compisuffix = oisuf;
zsfree(compqiprefix); zsfree(compqiprefix);
compqiprefix = ztrdup(oqipre); compqiprefix = oqipre;
zsfree(compqisuffix); zsfree(compqisuffix);
compqisuffix = ztrdup(oqisuf); compqisuffix = oqisuf;
zsfree(compquote); zsfree(compquote);
compquote = ztrdup(oq); compquote = oq;
zsfree(compquoting); zsfree(compquoting);
compquoting = ztrdup(oqi); compquoting = oqi;
zsfree(compqstack);
compqstack = oqs;
zsfree(autoq);
autoq = oaq;
freearray(compwords); freearray(compwords);
PERMALLOC { compwords = owords;
compwords = arrdup(owords);
} LASTALLOC;
comp_setunset(CP_COMPSTATE | comp_setunset(CP_COMPSTATE |
(~runset & (CP_WORDS | CP_CURRENT | CP_PREFIX | (~runset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX | CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX |
CP_QIPREFIX | CP_QISUFFIX)), CP_QIPREFIX | CP_QISUFFIX)),
(runset & CP_ALLREALS), (runset & CP_ALLREALS),
(~kunset & CP_RESTORE), (kunset & CP_ALLKEYS)); (~kunset & CP_RESTORE), (kunset & CP_ALLKEYS));
} else } else {
comp_setunset(CP_COMPSTATE, 0, (~kunset & CP_RESTORE), comp_setunset(CP_COMPSTATE, 0, (~kunset & CP_RESTORE),
(kunset & CP_RESTORE)); (kunset & CP_RESTORE));
zsfree(opre);
zsfree(osuf);
zsfree(oipre);
zsfree(oisuf);
zsfree(oqipre);
zsfree(oqisuf);
zsfree(oq);
zsfree(oqi);
zsfree(oqs);
zsfree(oaq);
freearray(owords);
}
zsfree(comprestore); zsfree(comprestore);
comprestore = orest; comprestore = orest;
@ -1228,42 +1255,6 @@ cond_range(char **a, int id)
(id ? cond_str(a, 1, 1) : NULL), 0); (id ? cond_str(a, 1, 1) : NULL), 0);
} }
/**/
static void
cmsetfn(Param pm, char **v)
{
set_gmatcher(pm->nam, v);
}
/**/
static char **
cmgetfn(Param pm)
{
int num;
Cmlist p;
char **ret, **q;
for (num = 0, p = cmatcher; p; p = p->next, num++);
ret = (char **) zhalloc((num + 1) * sizeof(char *));
for (q = ret, p = cmatcher; p; p = p->next, q++)
*q = dupstring(p->str);
*q = NULL;
return ret;
}
/**/
static void
cmunsetfn(Param pm, int exp)
{
char *dummy[1];
dummy[0] = NULL;
set_gmatcher(pm->nam, dummy);
}
static struct builtin bintab[] = { static struct builtin bintab[] = {
BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL), BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL),
BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL), BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL),
@ -1280,53 +1271,108 @@ static struct funcwrap wrapper[] = {
WRAPDEF(comp_wrapper), WRAPDEF(comp_wrapper),
}; };
static struct paramdef patab[] = { /* The order of the entries in this table has to match the *HOOK
PARAMDEF("compmatchers", PM_ARRAY|PM_SPECIAL, NULL, cmsetfn, cmgetfn, cmunsetfn) * macros in comp.h */
/**/
struct hookdef comphooks[] = {
HOOKDEF("insert_match", NULL, HOOKF_ALL),
HOOKDEF("menu_start", NULL, HOOKF_ALL),
HOOKDEF("compctl_make", NULL, 0),
HOOKDEF("compctl_cleanup", NULL, 0),
HOOKDEF("comp_list_matches", ilistmatches, 0),
}; };
/**/ /**/
int int
setup_complete(Module m) setup_(Module m)
{ {
makecompparamsptr = makecompparams; hasperm = 0;
comp_setunsetptr = comp_setunset;
comprpms = compkpms = NULL;
compwords = NULL;
compprefix = compsuffix = compiprefix = compisuffix =
compqiprefix = compqisuffix =
compcontext = compparameter = compredirect = compquote =
compquoting = comprestore = complist = compinsert =
compexact = compexactstr = comppatmatch = comppatinsert =
complastprompt = comptoend = compoldlist = compoldins =
compvared = compqstack = NULL;
hascompmod = 1;
return 0; return 0;
} }
/**/ /**/
int int
boot_complete(Module m) boot_(Module m)
{ {
addhookfunc("complete", (Hookfn) do_completion);
addhookfunc("before_complete", (Hookfn) before_complete);
addhookfunc("after_complete", (Hookfn) after_complete);
addhookfunc("accept_completion", (Hookfn) accept_last);
addhookfunc("reverse_menu", (Hookfn) reverse_menu);
addhookfunc("list_matches", (Hookfn) list_matches);
addhookfunc("invalidate_list", (Hookfn) invalidate_list);
addhookdefs(m->nam, comphooks, sizeof(comphooks)/sizeof(*comphooks));
if (!(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | if (!(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) | addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) |
!addwrapper(m, wrapper))) !addwrapper(m, wrapper)))
return 1; return 1;
return 0; return 0;
} }
#ifdef MODULE
/**/ /**/
int int
cleanup_complete(Module m) cleanup_(Module m)
{ {
deletehookfunc("complete", (Hookfn) do_completion);
deletehookfunc("before_complete", (Hookfn) before_complete);
deletehookfunc("after_complete", (Hookfn) after_complete);
deletehookfunc("accept_completion", (Hookfn) accept_last);
deletehookfunc("reverse_menu", (Hookfn) reverse_menu);
deletehookfunc("list_matches", (Hookfn) list_matches);
deletehookfunc("invalidate_list", (Hookfn) invalidate_list);
deletehookdefs(m->nam, comphooks, sizeof(comphooks)/sizeof(*comphooks));
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab));
deletewrapper(m, wrapper); deletewrapper(m, wrapper);
return 0; return 0;
} }
/**/ /**/
int int
finish_complete(Module m) finish_(Module m)
{ {
makecompparamsptr = NULL; if (compwords)
comp_setunsetptr = NULL; freearray(compwords);
zsfree(compprefix);
zsfree(compsuffix);
zsfree(compiprefix);
zsfree(compisuffix);
zsfree(compqiprefix);
zsfree(compqisuffix);
zsfree(compcontext);
zsfree(compparameter);
zsfree(compredirect);
zsfree(compquote);
zsfree(compqstack);
zsfree(compquoting);
zsfree(comprestore);
zsfree(complist);
zsfree(compinsert);
zsfree(compexact);
zsfree(compexactstr);
zsfree(comppatmatch);
zsfree(comppatinsert);
zsfree(complastprompt);
zsfree(comptoend);
zsfree(compoldlist);
zsfree(compoldins);
zsfree(compvared);
hascompmod = 0;
return 0; return 0;
} }
#endif

View file

@ -28,15 +28,8 @@
*/ */
#include "complete.mdh" #include "complete.mdh"
#define GLOBAL_PROTOTYPES
#include "zle_tricky.pro"
#undef GLOBAL_PROTOTYPES
#include "compmatch.pro" #include "compmatch.pro"
/* Convenience macro for calling bslashquote() (formerly quotename()). */
#define quotename(s, e) bslashquote(s, e, instring)
/* This compares two cpattern lists and returns non-zero if they are /* This compares two cpattern lists and returns non-zero if they are
* equal. */ * equal. */
@ -75,14 +68,14 @@ cmp_cmatchers(Cmatcher a, Cmatcher b)
/* Add the given matchers to the bmatcher list. */ /* Add the given matchers to the bmatcher list. */
/**/ /**/
void mod_export void
add_bmatchers(Cmatcher m) add_bmatchers(Cmatcher m)
{ {
Cmlist old = bmatchers, *q = &bmatchers, n; Cmlist old = bmatchers, *q = &bmatchers, n;
for (; m; m = m->next) { for (; m; m = m->next) {
if ((!m->flags && m->wlen > 0 && m->llen > 0) || if ((!m->flags && m->wlen > 0 && m->llen > 0) ||
(m->flags == CMF_RIGHT && m->wlen == -1 && !m->llen)) { (m->flags == CMF_RIGHT && m->wlen < 0 && !m->llen)) {
*q = n = (Cmlist) zhalloc(sizeof(struct cmlist)); *q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
n->matcher = m; n->matcher = m;
q = &(n->next); q = &(n->next);
@ -95,7 +88,7 @@ add_bmatchers(Cmatcher m)
* ensure that the bmatchers list contains no matchers not in mstack. */ * ensure that the bmatchers list contains no matchers not in mstack. */
/**/ /**/
void mod_export void
update_bmatchers(void) update_bmatchers(void)
{ {
Cmlist p = bmatchers, q = NULL, ms; Cmlist p = bmatchers, q = NULL, ms;
@ -141,6 +134,7 @@ get_cline(char *l, int ll, char *w, int wl, char *o, int ol, int fl)
r->slen = 0; r->slen = 0;
r->flags = fl; r->flags = fl;
r->prefix = r->suffix = NULL; r->prefix = r->suffix = NULL;
r->min = r->max = 0;
return r; return r;
} }
@ -443,7 +437,7 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
int sfx, int test, int part) int sfx, int test, int part)
{ {
int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw; int ll = strlen(l), lw = strlen(w), oll = ll, olw = lw;
int il = 0, iw = 0, t, ind, add, he = 0, bpc, obc = bc; int il = 0, iw = 0, t, ind, add, he = 0, bpc, obc = bc, bslash;
VARARR(unsigned char, ea, ll + 1); VARARR(unsigned char, ea, ll + 1);
char *ow; char *ow;
Cmlist ms; Cmlist ms;
@ -553,7 +547,7 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
} else } else
t = match_str(l + llen + moff, tp + moff, t = match_str(l + llen + moff, tp + moff,
NULL, 0, NULL, 0, 1, part); NULL, 0, NULL, 0, 1, part);
if (t || !both) if (t || (mp->wlen == -1 && !both))
break; break;
} }
} }
@ -743,12 +737,15 @@ match_str(char *l, char *w, Brinfo *bpp, int bc, int *rwlp,
if (mp) if (mp)
continue; continue;
if (l[ind] == w[ind]) { bslash = 0;
if (l[ind] == w[ind] ||
(bslash = (lw > 1 && w[ind] == '\\' &&
(ind ? (w[0] == l[0]) : (w[1] == l[0]))))) {
/* No matcher could be used, but the strings have the same /* No matcher could be used, but the strings have the same
* character here, skip over it. */ * character here, skip over it. */
l += add; w += add; l += add; w += (bslash ? (add + add ) : add);
il++; iw++; il++; iw += 1 + bslash;
ll--; lw--; ll--; lw -= 1 + bslash;
bc++; bc++;
if (!test) if (!test)
while (bp && bc >= (useqbr ? bp->qpos : bp->pos)) { while (bp && bc >= (useqbr ? bp->qpos : bp->pos)) {
@ -839,7 +836,7 @@ match_parts(char *l, char *w, int n, int part)
* and the suffix don't match the word w. */ * and the suffix don't match the word w. */
/**/ /**/
char * mod_export char *
comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu, comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
Brinfo *bpl, int bcp, Brinfo *bsl, int bcs, int *exact) Brinfo *bpl, int bcp, Brinfo *bsl, int bcs, int *exact)
{ {
@ -853,9 +850,8 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
if (!pattry(cp, r)) if (!pattry(cp, r))
return NULL; return NULL;
r = (qu ? quotename(r, NULL) : dupstring(r)); r = (qu == 2 ? tildequote(r, 0) : multiquote(r, !qu));
if (qu == 2 && r[0] == '\\' && r[1] == '~')
chuck(r);
/* We still break it into parts here, trying to build a sensible /* We still break it into parts here, trying to build a sensible
* cline list for these matches, too. */ * cline list for these matches, too. */
w = dupstring(w); w = dupstring(w);
@ -866,10 +862,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
Cline pli, plil; Cline pli, plil;
int mpl, rpl, wl; int mpl, rpl, wl;
w = (qu ? quotename(w, NULL) : dupstring(w)); w = (qu == 2 ? tildequote(w, 0) : multiquote(w, !qu));
if (qu == 2 && w[0] == '\\' && w[1] == '~')
chuck(w);
wl = strlen(w); wl = strlen(w);
/* Always try to match the prefix. */ /* Always try to match the prefix. */
@ -1016,7 +1009,7 @@ bld_parts(char *str, int len, int plen, Cline *lp)
while (len) { while (len) {
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
mp = ms->matcher; mp = ms->matcher;
if (mp->flags == CMF_RIGHT && mp->wlen == -1 && if (mp && mp->flags == CMF_RIGHT && mp->wlen < 0 &&
!mp->llen && len >= mp->ralen && mp->ralen && !mp->llen && len >= mp->ralen && mp->ralen &&
pattern_match(mp->right, str, NULL, NULL)) { pattern_match(mp->right, str, NULL, NULL)) {
int olen = str - p, llen; int olen = str - p, llen;
@ -1136,7 +1129,7 @@ bld_line(Cpattern pat, char *line, char *lp,
t = 0; t = 0;
for (ms = bmatchers; ms && !t; ms = ms->next) { for (ms = bmatchers; ms && !t; ms = ms->next) {
mp = ms->matcher; mp = ms->matcher;
if (!mp->flags && mp->wlen <= wlen && mp->llen <= l && if (mp && !mp->flags && mp->wlen <= wlen && mp->llen <= l &&
pattern_match(mp->line, (sfx ? line - mp->llen : line), pattern_match(mp->line, (sfx ? line - mp->llen : line),
NULL, ea) && NULL, ea) &&
pattern_match(mp->word, (sfx ? word - mp->wlen : word), pattern_match(mp->word, (sfx ? word - mp->wlen : word),
@ -1186,7 +1179,7 @@ join_strs(int la, char *sa, int lb, char *sb)
/* Different characters, try the matchers. */ /* Different characters, try the matchers. */
for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
mp = ms->matcher; mp = ms->matcher;
if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && if (mp && !mp->flags && mp->wlen > 0 && mp->llen > 0 &&
mp->wlen <= la && mp->wlen <= lb) { mp->wlen <= la && mp->wlen <= lb) {
/* The pattern has no anchors and the word /* The pattern has no anchors and the word
* pattern fits, try it. */ * pattern fits, try it. */
@ -1373,7 +1366,7 @@ join_sub(Cmdata md, char *str, int len, int *mlen, int sfx, int join)
/* We use only those patterns that match a non-empty /* We use only those patterns that match a non-empty
* string in both the line and the word and that have * string in both the line and the word and that have
* no anchors. */ * no anchors. */
if (!mp->flags && mp->wlen > 0 && mp->llen > 0) { if (mp && !mp->flags && mp->wlen > 0 && mp->llen > 0) {
/* We first test, if the old string matches already the /* We first test, if the old string matches already the
* new one. */ * new one. */
if (mp->llen <= ol && mp->wlen <= nl && if (mp->llen <= ol && mp->wlen <= nl &&
@ -1684,7 +1677,7 @@ join_mid(Cline o, Cline n)
* didn't. */ * didn't. */
/**/ /**/
static void static int
sub_join(Cline a, Cline b, Cline e, int anew) sub_join(Cline a, Cline b, Cline e, int anew)
{ {
if (!e->suffix && a->prefix) { if (!e->suffix && a->prefix) {
@ -1707,31 +1700,28 @@ sub_join(Cline a, Cline b, Cline e, int anew)
*p = e->prefix; *p = e->prefix;
ca = a->prefix; ca = a->prefix;
while (n != op) { while (n) {
e->prefix = cp_cline(n, 0); e->prefix = cp_cline(n, 0);
a->prefix = cp_cline(ca, 0); a->prefix = cp_cline(ca, 0);
if (anew) { if (anew) {
join_psfx(e, a, NULL, NULL, 0); join_psfx(e, a, NULL, NULL, 0);
if (e->prefix) { if (e->prefix)
e->min += min; return max - min;
e->max += max;
break;
}
} else { } else {
join_psfx(e, a, NULL, NULL, 0); join_psfx(a, e, NULL, NULL, 0);
if (a->prefix) { if (a->prefix)
a->min += min; return max - min;
a->max += max;
break;
}
} }
min -= n->min; min -= n->min;
max -= n->max;
if (n == op)
break;
n = n->next; n = n->next;
} }
return max - min;
} }
return 0;
} }
/* This simplifies the cline list given as the first argument so that /* This simplifies the cline list given as the first argument so that
@ -1748,7 +1738,8 @@ join_clines(Cline o, Cline n)
if (!o) if (!o)
return n; return n;
else { else {
Cline oo = o, nn = n, po = NULL, pn = NULL; Cline oo = o, nn = n, po = NULL, pn = NULL, x;
int diff;
/* Walk through the lists. */ /* Walk through the lists. */
while (o && n) { while (o && n) {
@ -1760,7 +1751,7 @@ join_clines(Cline o, Cline n)
for (t = o; (tn = t->next) && (tn->flags & CLF_NEW); t = tn); for (t = o; (tn = t->next) && (tn->flags & CLF_NEW); t = tn);
if (tn && cmp_anchors(tn, n, 0)) { if (tn && cmp_anchors(tn, n, 0)) {
sub_join(n, o, tn, 1); diff = sub_join(n, o, tn, 1);
if (po) if (po)
po->next = tn; po->next = tn;
@ -1768,8 +1759,15 @@ join_clines(Cline o, Cline n)
oo = tn; oo = tn;
t->next = NULL; t->next = NULL;
free_cline(o); free_cline(o);
x = o;
o = tn; o = tn;
o->flags |= CLF_MISS; if (po && cmp_anchors(x, po, 0)) {
po->flags |= CLF_MISS;
po->max += diff;
} else {
o->flags |= CLF_MISS;
o->max += diff;
}
continue; continue;
} }
} }
@ -1778,10 +1776,16 @@ join_clines(Cline o, Cline n)
for (t = n; (tn = t->next) && (tn->flags & CLF_NEW); t = tn); for (t = n; (tn = t->next) && (tn->flags & CLF_NEW); t = tn);
if (tn && cmp_anchors(o, tn, 0)) { if (tn && cmp_anchors(o, tn, 0)) {
sub_join(o, n, tn, 0); diff = sub_join(o, n, tn, 0);
if (po && cmp_anchors(n, pn, 0)) {
po->flags |= CLF_MISS;
po->max += diff;
} else {
o->flags |= CLF_MISS;
o->max += diff;
}
n = tn; n = tn;
o->flags |= CLF_MISS;
continue; continue;
} }
} }
@ -1809,6 +1813,7 @@ join_clines(Cline o, Cline n)
t = tn); t = tn);
if (tn && cmp_anchors(tn, n, 1)) { if (tn && cmp_anchors(tn, n, 1)) {
sub_join(n, o, tn, 1); sub_join(n, o, tn, 1);
if (po) if (po)
po->next = tn; po->next = tn;
else else
@ -1837,24 +1842,41 @@ join_clines(Cline o, Cline n)
for (t = n; (tn = t->next) && !cmp_anchors(o, tn, 1); t = tn); for (t = n; (tn = t->next) && !cmp_anchors(o, tn, 1); t = tn);
if (tn) { if (tn) {
sub_join(o, n, tn, 0); diff = sub_join(o, n, tn, 0);
if (po && cmp_anchors(n, pn, 0)) {
po->flags |= CLF_MISS;
po->max += diff;
} else {
o->flags |= CLF_MISS;
o->max += diff;
}
n = tn; n = tn;
o->flags |= CLF_MISS; po = o;
o = o->next;
pn = n;
n = n->next;
continue; continue;
} else { } else {
for (t = o; (tn = t->next) && !cmp_anchors(n, tn, 1); for (t = o; (tn = t->next) && !cmp_anchors(n, tn, 1);
t = tn); t = tn);
if (tn) { if (tn) {
sub_join(n, o, tn, 1); diff = sub_join(n, o, tn, 1);
if (po) if (po)
po->next = tn; po->next = tn;
else else
oo = tn; oo = tn;
x = o;
o = tn; o = tn;
o->flags |= CLF_MISS; if (po && cmp_anchors(x, po, 0)) {
po->flags |= CLF_MISS;
po->max += diff;
} else {
o->flags |= CLF_MISS;
o->max += diff;
}
continue; continue;
} else { } else {
if (o->flags & CLF_SUF) if (o->flags & CLF_SUF)

View file

@ -28,16 +28,8 @@
*/ */
#include "complete.mdh" #include "complete.mdh"
#define GLOBAL_PROTOTYPES
#include "zle_tricky.pro"
#undef GLOBAL_PROTOTYPES
#include "compresult.pro" #include "compresult.pro"
/* Convenience macro for calling bslashquote() (formerly quotename()). *
* This uses the instring variable above. */
#define quotename(s, e) bslashquote(s, e, instring)
#define inststr(X) inststrlen((X),1,-1) #define inststr(X) inststrlen((X),1,-1)
/* This cuts the cline list before the stuff that isn't worth /* This cuts the cline list before the stuff that isn't worth
@ -72,7 +64,8 @@ cut_cline(Cline l)
q = p; q = p;
} }
if (!e && q && !q->orig && !q->olen && (q->flags & CLF_MISS) && if (!e && q && !q->orig && !q->olen && (q->flags & CLF_MISS) &&
!(q->flags & CLF_MATCHED) && (q->word ? q->wlen : q->llen) < 3) { (!(q->flags & CLF_MATCHED) || (!q->prefix && !q->suffix)) &&
(q->word ? q->wlen : q->llen) < 3) {
q->word = q->line = NULL; q->word = q->line = NULL;
q->wlen = q->llen = 0; q->wlen = q->llen = 0;
} }
@ -143,8 +136,9 @@ cline_str(Cline l, int ins, int *csp)
l = cut_cline(l); l = cut_cline(l);
pmm = smm = dm = 0; pmm = smm = dm = pcs = scs = 0;
pm = pmax = sm = smax = d = mid = cbr = -1; pm = pmax = sm = smax = d = mid = cbr = -1;
brp = brs = NULL;
/* Get the information about the brace beginning and end we have /* Get the information about the brace beginning and end we have
* to re-insert. */ * to re-insert. */
@ -594,7 +588,7 @@ do_ambiguous(void)
/* If we have to insert the first match, call do_single(). This is * /* If we have to insert the first match, call do_single(). This is *
* how REC_EXACT takes effect. We effectively turn the ambiguous * * how REC_EXACT takes effect. We effectively turn the ambiguous *
* completion into an unambiguous one. */ * completion into an unambiguous one. */
if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) { if (ainfo && ainfo->exact == 1 && !(fromcomp & FC_LINE)) {
minfo.cur = NULL; minfo.cur = NULL;
do_single(ainfo->exactm); do_single(ainfo->exactm);
invalidatelist(); invalidatelist();
@ -616,6 +610,7 @@ do_ambiguous(void)
do_ambig_menu(); do_ambig_menu();
} else if (ainfo) { } else if (ainfo) {
int atend = (cs == we), la, eq, tcs; int atend = (cs == we), la, eq, tcs;
VARARR(char, old, we - wb);
minfo.cur = NULL; minfo.cur = NULL;
minfo.asked = 0; minfo.asked = 0;
@ -623,11 +618,24 @@ do_ambiguous(void)
fixsuffix(); fixsuffix();
/* First remove the old string from the line. */ /* First remove the old string from the line. */
tcs = cs;
cs = wb; cs = wb;
memcpy(old, (char *) line + wb, we - wb);
foredel(we - wb); foredel(we - wb);
/* Now get the unambiguous string and insert it into the line. */ /* Now get the unambiguous string and insert it into the line. */
cline_str(ainfo->line, 1, NULL); cline_str(ainfo->line, 1, NULL);
/* Sometimes the different match specs used may result in a cline
* that gives an empty string. If that happened, we re-insert the
* old string. Unless there were matches added with -U, that is. */
if (!(lastend - wb) && !hasunmatched) {
cs = wb;
foredel(lastend - wb);
inststrlen(old, 0, we - wb);
lastend = we;
cs = tcs;
}
if (eparq) { if (eparq) {
tcs = cs; tcs = cs;
cs = lastend; cs = lastend;
@ -677,7 +685,7 @@ do_ambiguous(void)
if (uselist && (usemenu != 2 || (!listshown && !oldlist)) && if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
((!showinglist && (!listshown || !oldlist)) || ((!showinglist && (!listshown || !oldlist)) ||
(usemenu == 3 && !oldlist)) && (usemenu == 3 && !oldlist)) &&
(smatches >= 2 || (compforcelist && *compforcelist))) (smatches >= 2 || forcelist))
showinglist = -2; showinglist = -2;
return ret; return ret;
@ -690,7 +698,7 @@ do_ambiguous(void)
* (l)stat(). */ * (l)stat(). */
/**/ /**/
int mod_export int
ztat(char *nam, struct stat *buf, int ls) ztat(char *nam, struct stat *buf, int ls)
{ {
char b[PATH_MAX], *p; char b[PATH_MAX], *p;
@ -708,7 +716,7 @@ ztat(char *nam, struct stat *buf, int ls)
/* Insert a single match in the command line. */ /* Insert a single match in the command line. */
/**/ /**/
void mod_export void
do_single(Cmatch m) do_single(Cmatch m)
{ {
int l, sr = 0, scs; int l, sr = 0, scs;
@ -726,7 +734,8 @@ do_single(Cmatch m)
/* We are currently not in a menu-completion, * /* We are currently not in a menu-completion, *
* so set the position variables. */ * so set the position variables. */
minfo.pos = wb; minfo.pos = wb;
minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp)); minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp) ||
(!movetoend && cs == we));
minfo.end = we; minfo.end = we;
} }
/* If we are already in a menu-completion or if we have done a * /* If we are already in a menu-completion or if we have done a *
@ -792,19 +801,40 @@ do_single(Cmatch m)
else { else {
/* Build the path name. */ /* Build the path name. */
if (partest && !*psuf && !(m->flags & CMF_PARNEST)) { if (partest && !*psuf && !(m->flags & CMF_PARNEST)) {
int ne = noerrs; int ne = noerrs, tryit = 1;
p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ? p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ?
parpre : m->ripre) + parpre : m->ripre) +
strlen(str) + 2); strlen(str) + 2);
sprintf(p, "%s%s%c", sprintf(p, "%s%s%c",
((m->flags & CMF_ISPAR) ? parpre : m->ripre), str, ((m->flags & CMF_ISPAR) ? parpre : m->ripre), str,
((m->flags & CMF_PARBR) ? Outbrace : '\0')); ((m->flags & CMF_PARBR) ? '}' : '\0'));
noerrs = 1; if (*p == '$') {
parsestr(p); char *n;
singsub(&p); Param pm;
errflag = 0;
noerrs = ne; if (p[1] == '{') {
char *e;
n = dupstring(p + 2);
e = n + strlen(n) - 1;
if (*e == '}')
*e = '\0';
} else
n = p + 1;
if ((pm = (Param) paramtab->getnode(paramtab, n)) &&
PM_TYPE(pm->flags) != PM_SCALAR)
tryit = 0;
}
if (tryit) {
noerrs = 1;
parsestr(p);
singsub(&p);
errflag = 0;
noerrs = ne;
}
} else { } else {
p = (char *) zhalloc(strlen(prpre) + strlen(str) + p = (char *) zhalloc(strlen(prpre) + strlen(str) +
strlen(psuf) + 3); strlen(psuf) + 3);
@ -857,11 +887,13 @@ do_single(Cmatch m)
/* If we didn't add a suffix, add a space, unless we are * /* If we didn't add a suffix, add a space, unless we are *
* doing menu completion or we are completing files and * * doing menu completion or we are completing files and *
* the string doesn't name an existing file. */ * the string doesn't name an existing file. */
if (m->autoq && (!m->isuf || m->isuf[0] != m->autoq)) { if (m->autoq && (!m->isuf || !strpfx(m->autoq, m->isuf))) {
inststrlen(&(m->autoq), 1, 1); int al = strlen(m->autoq);
minfo.insc++; inststrlen(m->autoq, 1, al);
minfo.insc += al;
} }
if (!menucmp && (usemenu != 3 || insspace)) { if (!menucmp && !(m->flags & CMF_NOSPACE) &&
(usemenu != 3 || insspace)) {
inststrlen(" ", 1, 1); inststrlen(" ", 1, 1);
minfo.insc++; minfo.insc++;
if (minfo.we) if (minfo.we)
@ -897,7 +929,7 @@ do_single(Cmatch m)
* insert the next completion. */ * insert the next completion. */
/**/ /**/
void mod_export void
do_menucmp(int lst) do_menucmp(int lst)
{ {
/* Just list the matches if the list was requested. */ /* Just list the matches if the list was requested. */
@ -906,44 +938,40 @@ do_menucmp(int lst)
return; return;
} }
/* Otherwise go to the next match in the array... */ /* Otherwise go to the next match in the array... */
HEAPALLOC { do {
do { if (!*++(minfo.cur)) {
if (!*++(minfo.cur)) { do {
do { if (!(minfo.group = (minfo.group)->next))
if (!(minfo.group = (minfo.group)->next)) minfo.group = amatches;
minfo.group = amatches; } while (!(minfo.group)->mcount);
} while (!(minfo.group)->mcount); minfo.cur = minfo.group->matches;
minfo.cur = minfo.group->matches; }
} } while (menuacc &&
} while (menuacc && !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)); /* ... and insert it into the command line. */
/* ... and insert it into the command line. */ metafy_line();
metafy_line(); do_single(*(minfo.cur));
do_single(*(minfo.cur)); unmetafy_line();
unmetafy_line();
} LASTALLOC;
} }
/**/ /**/
int int
reverse_menu(Hookdef dummy, void *dummy2) reverse_menu(Hookdef dummy, void *dummy2)
{ {
HEAPALLOC { do {
do { if (minfo.cur == (minfo.group)->matches) {
if (minfo.cur == (minfo.group)->matches) { do {
do { if (!(minfo.group = (minfo.group)->prev))
if (!(minfo.group = (minfo.group)->prev)) minfo.group = lmatches;
minfo.group = lmatches; } while (!(minfo.group)->mcount);
} while (!(minfo.group)->mcount); minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1; } else
} else minfo.cur--;
minfo.cur--; } while (menuacc &&
} while (menuacc && !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
!hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)); metafy_line();
metafy_line(); do_single(*(minfo.cur));
do_single(*(minfo.cur)); unmetafy_line();
unmetafy_line();
} LASTALLOC;
return 0; return 0;
} }
@ -953,7 +981,7 @@ reverse_menu(Hookdef dummy, void *dummy2)
* accept several selections from the list of matches. */ * accept several selections from the list of matches. */
/**/ /**/
int mod_export int
accept_last(void) accept_last(void)
{ {
if (!menuacc) { if (!menuacc) {
@ -1042,7 +1070,7 @@ do_ambig_menu(void)
} else { } else {
if (oldlist) { if (oldlist) {
if (oldins && minfo.cur) if (oldins && minfo.cur)
acceptlast(); accept_last();
} else } else
minfo.cur = NULL; minfo.cur = NULL;
} }
@ -1074,24 +1102,6 @@ do_ambig_menu(void)
minfo.cur = mc; minfo.cur = mc;
} }
/* Return the real number of matches. */
/**/
zlong
num_matches(int normal)
{
int alt;
PERMALLOC {
alt = permmatches(0);
} LASTALLOC;
if (normal)
return (alt ? 0 : nmatches);
else
return (alt ? nmatches : 0);
}
/* Return the number of screen lines needed for the list. */ /* Return the number of screen lines needed for the list. */
/**/ /**/
@ -1100,14 +1110,12 @@ list_lines(void)
{ {
Cmgroup oam; Cmgroup oam;
PERMALLOC { permmatches(0);
permmatches(0);
} LASTALLOC;
oam = amatches; oam = amatches;
amatches = pmatches; amatches = pmatches;
listdat.valid = 0; listdat.valid = 0;
calclist(); calclist(0);
listdat.valid = 0; listdat.valid = 0;
amatches = oam; amatches = oam;
@ -1124,132 +1132,25 @@ comp_list(char *v)
onlyexpl = (v && strstr(v, "expl")); onlyexpl = (v && strstr(v, "expl"));
} }
/* This is used to print the explanation string. *
* It returns the number of lines printed. */
/**/
int
printfmt(char *fmt, int n, int dopr, int doesc)
{
char *p = fmt, nc[DIGBUFSIZE];
int l = 0, cc = 0, b = 0, s = 0, u = 0, m;
for (; *p; p++) {
/* Handle the `%' stuff (%% == %, %n == <number of matches>). */
if (doesc && *p == '%') {
if (*++p) {
m = 0;
switch (*p) {
case '%':
if (dopr)
putc('%', shout);
cc++;
break;
case 'n':
sprintf(nc, "%d", n);
if (dopr)
fprintf(shout, nc);
cc += strlen(nc);
break;
case 'B':
b = 1;
if (dopr)
tcout(TCBOLDFACEBEG);
break;
case 'b':
b = 0; m = 1;
if (dopr)
tcout(TCALLATTRSOFF);
break;
case 'S':
s = 1;
if (dopr)
tcout(TCSTANDOUTBEG);
break;
case 's':
s = 0; m = 1;
if (dopr)
tcout(TCSTANDOUTEND);
break;
case 'U':
u = 1;
if (dopr)
tcout(TCUNDERLINEBEG);
break;
case 'u':
u = 0; m = 1;
if (dopr)
tcout(TCUNDERLINEEND);
break;
case '{':
for (p++; *p && (*p != '%' || p[1] != '}'); p++, cc++)
if (dopr)
putc(*p, shout);
if (*p)
p++;
else
p--;
break;
}
if (dopr && m) {
if (b)
tcout(TCBOLDFACEBEG);
if (s)
tcout(TCSTANDOUTBEG);
if (u)
tcout(TCUNDERLINEBEG);
}
} else
break;
} else {
cc++;
if (*p == '\n') {
if (dopr) {
if (tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
else {
int s = columns - 1 - (cc % columns);
while (s-- > 0)
putc(' ', shout);
}
}
l += 1 + (cc / columns);
cc = 0;
}
if (dopr)
putc(*p, shout);
}
}
if (dopr) {
if (tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
else {
int s = columns - 1 - (cc % columns);
while (s-- > 0)
putc(' ', shout);
}
}
return l + (cc / columns);
}
/* This skips over matches that are not to be listed. */ /* This skips over matches that are not to be listed. */
/**/ /**/
Cmatch * Cmatch *
skipnolist(Cmatch *p) skipnolist(Cmatch *p, int showall)
{ {
while (*p && (((*p)->flags & (CMF_NOLIST | CMF_HIDE)) || int mask = (showall ? 0 : (CMF_NOLIST | CMF_MULT)) | CMF_HIDE;
((*p)->disp && ((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
while (*p && (((*p)->flags & mask) ||
((*p)->disp &&
((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
p++; p++;
return p; return p;
} }
/**/ /**/
void mod_export void
calclist(void) calclist(int showall)
{ {
Cmgroup g; Cmgroup g;
Cmatch *p, m; Cmatch *p, m;
@ -1259,7 +1160,7 @@ calclist(void)
VARARR(int, mlens, nmatches + 1); VARARR(int, mlens, nmatches + 1);
if (listdat.valid && onlyexpl == listdat.onlyexpl && if (listdat.valid && onlyexpl == listdat.onlyexpl &&
menuacc == listdat.menuacc && menuacc == listdat.menuacc && showall == listdat.showall &&
lines == listdat.lines && columns == listdat.columns) lines == listdat.lines && columns == listdat.columns)
return; return;
@ -1267,6 +1168,8 @@ calclist(void)
char **pp = g->ylist; char **pp = g->ylist;
int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0; int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
g->flags |= CGF_PACKED | CGF_ROWS;
if (!onlyexpl && pp) { if (!onlyexpl && pp) {
/* We have an ylist, lets see, if it contains newlines. */ /* We have an ylist, lets see, if it contains newlines. */
hidden = 1; hidden = 1;
@ -1283,8 +1186,8 @@ calclist(void)
while ((sptr = *pp)) { while ((sptr = *pp)) {
while (sptr && *sptr) { while (sptr && *sptr) {
nlines += (nlptr = strchr(sptr, '\n')) nlines += (nlptr = strchr(sptr, '\n'))
? 1 + (nlptr-sptr)/columns ? 1 + (nlptr-sptr) / columns
: strlen(sptr)/columns; : strlen(sptr) / columns;
sptr = nlptr ? nlptr+1 : NULL; sptr = nlptr ? nlptr+1 : NULL;
} }
nlines++; nlines++;
@ -1327,7 +1230,11 @@ calclist(void)
mlens[m->gnum] = l; mlens[m->gnum] = l;
} }
nlist++; nlist++;
} else if (!(m->flags & CMF_NOLIST)) { if (!(m->flags & CMF_PACKED))
g->flags &= ~CGF_PACKED;
if (!(m->flags & CMF_ROWS))
g->flags &= ~CGF_ROWS;
} else if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) {
l = niceztrlen(m->str); l = niceztrlen(m->str);
ndisp++; ndisp++;
if (l > glong) if (l > glong)
@ -1337,6 +1244,10 @@ calclist(void)
totl += l; totl += l;
mlens[m->gnum] = l; mlens[m->gnum] = l;
nlist++; nlist++;
if (!(m->flags & CMF_PACKED))
g->flags &= ~CGF_PACKED;
if (!(m->flags & CMF_ROWS))
g->flags &= ~CGF_ROWS;
} else } else
hidden = 1; hidden = 1;
} }
@ -1361,9 +1272,11 @@ calclist(void)
} }
} }
if (!onlyexpl) { if (!onlyexpl) {
char **pp;
int *ws, tlines, tline, tcols, maxlen, nth, width, glines;
for (g = amatches; g; g = g->next) { for (g = amatches; g; g = g->next) {
char **pp; glines = 0;
int glines = 0;
zfree(g->widths, 0); zfree(g->widths, 0);
g->widths = NULL; g->widths = NULL;
@ -1396,20 +1309,19 @@ calclist(void)
if (m->disp) { if (m->disp) {
if (!(m->flags & CMF_DISPLINE)) if (!(m->flags & CMF_DISPLINE))
glines += 1 + (mlens[m->gnum] / columns); glines += 1 + (mlens[m->gnum] / columns);
} else if (!(m->flags & CMF_NOLIST)) } else if (showall ||
glines += 1 + ((1 + mlens[m->gnum]) / columns); !(m->flags & (CMF_NOLIST | CMF_MULT)))
glines += 1 + ((mlens[m->gnum]) / columns);
} }
} }
} }
g->lins = glines; g->lins = glines;
nlines += glines; nlines += glines;
} }
}
if (!onlyexpl && isset(LISTPACKED)) {
char **pp;
int *ws, tlines, tline, tcols, maxlen, nth, width;
for (g = amatches; g; g = g->next) { for (g = amatches; g; g = g->next) {
if (!(g->flags & CGF_PACKED))
continue;
ws = g->widths = (int *) zalloc(columns * sizeof(int)); ws = g->widths = (int *) zalloc(columns * sizeof(int));
memset(ws, 0, columns * sizeof(int)); memset(ws, 0, columns * sizeof(int));
tlines = g->lins; tlines = g->lins;
@ -1424,11 +1336,13 @@ calclist(void)
for (i = 0; *pp; i++, pp++) for (i = 0; *pp; i++, pp++)
ylens[i] = strlen(*pp) + add; ylens[i] = strlen(*pp) + add;
if (isset(LISTROWSFIRST)) { if (g->flags & CGF_ROWS) {
int count, tcol, first, maxlines = 0, llines; int count, tcol, first, maxlines = 0, llines;
int beg = columns / g->shortest, end = g->cols;
while (1) {
tcols = (beg + end) >> 1;
for (tcols = columns / g->shortest; tcols > g->cols;
tcols--) {
for (nth = first = maxlen = width = maxlines = for (nth = first = maxlen = width = maxlines =
llines = tcol = 0, llines = tcol = 0,
count = g->dcount; count = g->dcount;
@ -1452,17 +1366,33 @@ calclist(void)
ws[tcol++] = maxlen; ws[tcol++] = maxlen;
width += maxlen; width += maxlen;
} }
if (!count && width < columns) if (!count && width < columns &&
(tcols <= 0 || beg == end))
break; break;
if (beg == end) {
beg--;
end--;
} else if (width < columns) {
if ((end = tcols) == beg - 1)
end++;
} else {
if ((beg = tcols) - 1 == end)
end++;
}
} }
if (tcols > g->cols) if (tcols > g->cols)
tlines = maxlines; tlines = maxlines;
} else { } else {
for (tlines = ((g->totl + columns) / columns); int beg = ((g->totl + columns) / columns);
tlines < g->lins; tlines++) { int end = g->lins;
while (1) {
tlines = (beg + end) >> 1;
for (pp = g->ylist, nth = tline = width = for (pp = g->ylist, nth = tline = width =
maxlen = tcols = 0; maxlen = tcols = 0;
*pp; nth++, pp++) { *pp; pp++) {
if (ylens[nth] > maxlen) if (ylens[nth] > maxlen)
maxlen = ylens[nth]; maxlen = ylens[nth];
if (++tline == tlines) { if (++tline == tlines) {
@ -1471,24 +1401,41 @@ calclist(void)
ws[tcols++] = maxlen; ws[tcols++] = maxlen;
maxlen = tline = 0; maxlen = tline = 0;
} }
nth++;
} }
if (tline) { if (tline) {
ws[tcols++] = maxlen; ws[tcols++] = maxlen;
width += maxlen; width += maxlen;
} }
if (nth == yl && width < columns) if (nth == yl && width < columns &&
(beg == end || tlines >= g->lins))
break; break;
if (beg == end) {
beg++;
end++;
} else if (width < columns) {
if ((end = tlines) == beg + 1)
end--;
} else {
if ((beg = tlines) + 1 == end)
end--;
}
} }
if (tlines > g->lins)
tlines = g->lins;
} }
} }
} else if (g->width) { } else if (g->width) {
if (isset(LISTROWSFIRST)) { if (g->flags & CGF_ROWS) {
int addlen, count, tcol, maxlines = 0, llines, i; int addlen, count, tcol, maxlines = 0, llines, i;
int beg = columns / g->shortest, end = g->cols;
Cmatch *first; Cmatch *first;
for (tcols = columns / g->shortest; tcols > g->cols; while (1) {
tcols--) { tcols = (beg + end) >> 1;
p = first = skipnolist(g->matches);
p = first = skipnolist(g->matches, showall);
for (maxlen = width = maxlines = llines = tcol = 0, for (maxlen = width = maxlines = llines = tcol = 0,
count = g->dcount; count = g->dcount;
count > 0; count--) { count > 0; count--) {
@ -1497,7 +1444,7 @@ calclist(void)
if (addlen > maxlen) if (addlen > maxlen)
maxlen = addlen; maxlen = addlen;
for (i = tcols; i && *p; i--) for (i = tcols; i && *p; i--)
p = skipnolist(p + 1); p = skipnolist(p + 1, showall);
llines++; llines++;
if (!*p) { if (!*p) {
@ -1510,29 +1457,46 @@ calclist(void)
ws[tcol++] = maxlen; ws[tcol++] = maxlen;
maxlen = 0; maxlen = 0;
p = first = skipnolist(first + 1); p = first = skipnolist(first + 1, showall);
} }
} }
if (tlines) { if (tlines) {
ws[tcol++] = maxlen; ws[tcol++] = maxlen;
width += maxlen; width += maxlen;
} }
if (!count && width < columns) if (!count && width < columns &&
(tcols <= 0 || beg == end))
break; break;
if (beg == end) {
beg--;
end--;
} else if (width < columns) {
if ((end = tcols) == beg - 1)
end++;
} else {
if ((beg = tcols) - 1 == end)
end++;
}
} }
if (tcols > g->cols) if (tcols > g->cols)
tlines = maxlines; tlines = maxlines;
} else { } else {
int addlen; int addlen;
int smask = ((showall ? 0 : (CMF_NOLIST | CMF_MULT)) |
CMF_HIDE);
int beg = ((g->totl + columns) / columns);
int end = g->lins;
while (1) {
tlines = (beg + end) >> 1;
for (tlines = ((g->totl + columns) / columns);
tlines < g->lins; tlines++) {
for (p = g->matches, nth = tline = width = for (p = g->matches, nth = tline = width =
maxlen = tcols = 0; maxlen = tcols = 0;
(m = *p); p++, nth++) { (m = *p); p++) {
if (!(m->flags & if (!(m->flags &
(m->disp ? (CMF_DISPLINE | CMF_HIDE) : (m->disp ? (CMF_DISPLINE | CMF_HIDE) :
(CMF_NOLIST | CMF_HIDE)))) { smask))) {
addlen = mlens[m->gnum] + add; addlen = mlens[m->gnum] + add;
if (addlen > maxlen) if (addlen > maxlen)
maxlen = addlen; maxlen = addlen;
@ -1542,15 +1506,30 @@ calclist(void)
ws[tcols++] = maxlen; ws[tcols++] = maxlen;
maxlen = tline = 0; maxlen = tline = 0;
} }
nth++;
} }
} }
if (tline) { if (tline) {
ws[tcols++] = maxlen; ws[tcols++] = maxlen;
width += maxlen; width += maxlen;
} }
if (nth == g->dcount && width < columns) if (nth == g->dcount && width < columns &&
(beg == end || tlines >= g->lins))
break; break;
if (beg == end) {
beg++;
end++;
} else if (width < columns) {
if ((end = tlines) == beg + 1)
end--;
} else {
if ((beg = tlines) + 1 == end)
end--;
}
} }
if (tlines > g->lins)
tlines = g->lins;
} }
} }
if (tlines == g->lins) { if (tlines == g->lins) {
@ -1584,21 +1563,23 @@ calclist(void)
listdat.onlyexpl = onlyexpl; listdat.onlyexpl = onlyexpl;
listdat.columns = columns; listdat.columns = columns;
listdat.lines = lines; listdat.lines = lines;
listdat.showall = showall;
} }
/**/ /**/
int asklist(void) mod_export int asklist(void)
{ {
/* Set the cursor below the prompt. */ /* Set the cursor below the prompt. */
trashzle(); trashzle();
showinglist = listshown = 0; showinglist = listshown = 0;
clearflag = (isset(USEZLE) && !termflags && clearflag = (isset(USEZLE) && !termflags && dolastprompt);
complastprompt && *complastprompt); lastlistlen = 0;
/* Maybe we have to ask if the user wants to see the list. */ /* Maybe we have to ask if the user wants to see the list. */
if ((!minfo.cur || !minfo.asked) && if ((!minfo.cur || !minfo.asked) &&
((complistmax && listdat.nlist > complistmax) || ((complistmax > 0 && listdat.nlist >= complistmax) ||
(complistmax < 0 && listdat.nlines <= -complistmax) ||
(!complistmax && listdat.nlines >= lines))) { (!complistmax && listdat.nlines >= lines))) {
int qup; int qup;
zsetterm(); zsetterm();
@ -1614,8 +1595,7 @@ int asklist(void)
tcmultout(TCUP, TCMULTUP, nlnct); tcmultout(TCUP, TCMULTUP, nlnct);
} else } else
putc('\n', shout); putc('\n', shout);
if (minfo.cur) minfo.asked = 2;
minfo.asked = 2;
return 1; return 1;
} }
if (clearflag) { if (clearflag) {
@ -1626,15 +1606,14 @@ int asklist(void)
} else } else
putc('\n', shout); putc('\n', shout);
settyinfo(&shttyinfo); settyinfo(&shttyinfo);
if (minfo.cur) minfo.asked = 1;
minfo.asked = 1;
} }
return 0; return (minfo.asked ? minfo.asked - 1 : 0);
} }
/**/ /**/
int mod_export int
printlist(int over, CLPrintFunc printm) printlist(int over, CLPrintFunc printm, int showall)
{ {
Cmgroup g; Cmgroup g;
Cmatch *p, m; Cmatch *p, m;
@ -1715,7 +1694,7 @@ printlist(int over, CLPrintFunc printm)
while (a--) while (a--)
putc(' ', shout); putc(' ', shout);
} }
pq += (isset(LISTROWSFIRST) ? 1 : nc); pq += ((g->flags & CGF_ROWS) ? 1 : nc);
mc++; mc++;
n--; n--;
} }
@ -1728,10 +1707,11 @@ printlist(int over, CLPrintFunc printm)
tcout(TCCLEAREOD); tcout(TCCLEAREOD);
} }
} }
pp += (isset(LISTROWSFIRST) ? g->cols : 1); pp += ((g->flags & CGF_ROWS) ? g->cols : 1);
} }
} }
} else if (!listdat.onlyexpl && g->lcount) { } else if (!listdat.onlyexpl &&
(g->lcount || (showall && g->mcount))) {
int n = g->dcount, nl, nc, i, j, wid; int n = g->dcount, nl, nc, i, j, wid;
Cmatch *q; Cmatch *q;
@ -1765,7 +1745,7 @@ printlist(int over, CLPrintFunc printm)
tcout(TCCLEAREOD); tcout(TCCLEAREOD);
} }
} }
for (p = skipnolist(g->matches); n && nl--;) { for (p = skipnolist(g->matches, showall); n && nl--;) {
i = g->cols; i = g->cols;
mc = 0; mc = 0;
q = p; q = p;
@ -1794,14 +1774,16 @@ printlist(int over, CLPrintFunc printm)
printed++; printed++;
if (--n) if (--n)
for (j = (isset(LISTROWSFIRST) ? 1 : nc); j && *q; j--) for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
q = skipnolist(q + 1); j && *q; j--)
q = skipnolist(q + 1, showall);
mc++; mc++;
} }
while (i-- > 0) while (i-- > 0) {
printm(g, NULL, mc++, ml, (!i), printm(g, NULL, mc, ml, (!i),
(g->widths ? g->widths[mc] : g->width), NULL, NULL); (g->widths ? g->widths[mc] : g->width), NULL, NULL);
mc++;
}
if (n) { if (n) {
putc('\n', shout); putc('\n', shout);
ml++; ml++;
@ -1811,25 +1793,30 @@ printlist(int over, CLPrintFunc printm)
tcout(TCCLEAREOD); tcout(TCCLEAREOD);
} }
if (nl) if (nl)
for (j = (isset(LISTROWSFIRST) ? g->cols : 1); j && *p; j--) for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
p = skipnolist(p + 1); j && *p; j--)
p = skipnolist(p + 1, showall);
} }
} }
} }
if (g->lcount) if (g->lcount || (showall && g->mcount))
pnl = 1; pnl = 1;
g = g->next; g = g->next;
} }
lastlistlen = 0;
if (clearflag) { if (clearflag) {
/* Move the cursor up to the prompt, if always_last_prompt * /* Move the cursor up to the prompt, if always_last_prompt *
* is set and all that... */ * is set and all that... */
if ((ml = listdat.nlines + nlnct - 1) < lines) { if ((ml = listdat.nlines + nlnct - 1) < lines) {
tcmultout(TCUP, TCMULTUP, ml); tcmultout(TCUP, TCMULTUP, ml);
showinglist = -1; showinglist = -1;
lastlistlen = listdat.nlines;
} else } else
clearflag = 0, putc('\n', shout); clearflag = 0, putc('\n', shout);
} else } else
putc('\n', shout); putc('\n', shout);
listshown = (clearflag ? 1 : -1); listshown = (clearflag ? 1 : -1);
return printed; return printed;
@ -1858,9 +1845,8 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
nicezputs(m->str, shout); nicezputs(m->str, shout);
len = niceztrlen(m->str); len = niceztrlen(m->str);
if (isset(LISTTYPES)) { if (isset(LISTTYPES) && buf) {
if (buf) putc(file_type(buf->st_mode), shout);
putc(file_type(buf->st_mode), shout);
len++; len++;
} }
} }
@ -1876,7 +1862,7 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
int int
ilistmatches(Hookdef dummy, Chdata dat) ilistmatches(Hookdef dummy, Chdata dat)
{ {
calclist(); calclist(0);
if (!listdat.nlines) { if (!listdat.nlines) {
showinglist = listshown = 0; showinglist = listshown = 0;
@ -1885,7 +1871,7 @@ ilistmatches(Hookdef dummy, Chdata dat)
if (asklist()) if (asklist())
return 0; return 0;
printlist(0, iprintm); printlist(0, iprintm, 0);
return 0; return 0;
} }
@ -1897,6 +1883,7 @@ int
list_matches(Hookdef dummy, void *dummy2) list_matches(Hookdef dummy, void *dummy2)
{ {
struct chdata dat; struct chdata dat;
int ret;
#ifdef DEBUG #ifdef DEBUG
/* Sanity check */ /* Sanity check */
@ -1909,18 +1896,20 @@ list_matches(Hookdef dummy, void *dummy2)
dat.matches = amatches; dat.matches = amatches;
dat.num = nmatches; dat.num = nmatches;
dat.cur = NULL; dat.cur = NULL;
return runhookdef(COMPLISTMATCHESHOOK, (void *) &dat); ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
return ret;
} }
/* Invalidate the completion list. */ /* Invalidate the completion list. */
/**/ /**/
int mod_export int
invalidate_list(void) invalidate_list(void)
{ {
if (showinglist == -2)
listmatches();
if (validlist) { if (validlist) {
if (showinglist == -2)
zrefresh();
freematches(lastmatches); freematches(lastmatches);
lastmatches = NULL; lastmatches = NULL;
hasoldlist = 0; hasoldlist = 0;

File diff suppressed because it is too large Load diff

View file

@ -19,20 +19,21 @@
"backward-kill-line", backwardkillline, ZLE_KILL | ZLE_KEEPSUFFIX "backward-kill-line", backwardkillline, ZLE_KILL | ZLE_KEEPSUFFIX
"backward-kill-word", backwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX "backward-kill-word", backwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX
"backward-word", backwardword, 0 "backward-word", backwardword, 0
"beep", handlefeep, 0
"beginning-of-buffer-or-history", beginningofbufferorhistory, 0 "beginning-of-buffer-or-history", beginningofbufferorhistory, 0
"beginning-of-history", beginningofhistory, 0 "beginning-of-history", beginningofhistory, 0
"beginning-of-line", beginningofline, 0 "beginning-of-line", beginningofline, 0
"beginning-of-line-hist", beginningoflinehist, 0 "beginning-of-line-hist", beginningoflinehist, 0
"capitalize-word", capitalizeword, 0 "capitalize-word", capitalizeword, 0
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX "complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"copy-prev-word", copyprevword, 0 "copy-prev-word", copyprevword, ZLE_KEEPSUFFIX
"copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX "copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX
"delete-char", deletechar, ZLE_KEEPSUFFIX "delete-char", deletechar, ZLE_KEEPSUFFIX
"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX "delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"delete-word", deleteword, ZLE_KEEPSUFFIX "delete-word", deleteword, ZLE_KEEPSUFFIX
"describe-key-briefly", describekeybriefly, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "describe-key-briefly", describekeybriefly, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"digit-argument", digitargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "digit-argument", digitargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"down-case-word", downcaseword, 0 "down-case-word", downcaseword, 0
"down-history", downhistory, 0 "down-history", downhistory, 0
"down-line-or-history", downlineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL "down-line-or-history", downlineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
@ -43,13 +44,14 @@
"end-of-history", endofhistory, 0 "end-of-history", endofhistory, 0
"end-of-line", endofline, 0 "end-of-line", endofline, 0
"end-of-line-hist", endoflinehist, 0 "end-of-line-hist", endoflinehist, 0
"end-of-list", endoflist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"exchange-point-and-mark", exchangepointandmark, 0 "exchange-point-and-mark", exchangepointandmark, 0
"execute-last-named-cmd", NULL, 0 "execute-last-named-cmd", NULL, 0
"execute-named-cmd", NULL, 0 "execute-named-cmd", NULL, 0
"expand-cmd-path", expandcmdpath, 0 "expand-cmd-path", expandcmdpath, 0
"expand-history", expandhistory, 0 "expand-history", expandhistory, 0
"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX "expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX "expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"expand-word", expandword, 0 "expand-word", expandword, 0
"forward-char", forwardchar, 0 "forward-char", forwardchar, 0
"forward-word", forwardword, 0 "forward-word", forwardword, 0
@ -68,12 +70,12 @@
"kill-region", killregion, ZLE_KILL | ZLE_KEEPSUFFIX "kill-region", killregion, ZLE_KILL | ZLE_KEEPSUFFIX
"kill-whole-line", killwholeline, ZLE_KILL | ZLE_KEEPSUFFIX "kill-whole-line", killwholeline, ZLE_KILL | ZLE_KEEPSUFFIX
"kill-word", killword, ZLE_KILL | ZLE_KEEPSUFFIX "kill-word", killword, ZLE_KILL | ZLE_KEEPSUFFIX
"list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_ISCOMP
"list-expand", listexpand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "list-expand", listexpand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"magic-space", magicspace, 0 "magic-space", magicspace, 0
"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX "menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX "menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"overwrite-mode", overwritemode, 0 "overwrite-mode", overwritemode, 0
"pound-insert", poundinsert, 0 "pound-insert", poundinsert, 0
"push-input", pushinput, 0 "push-input", pushinput, 0
@ -83,19 +85,20 @@
"quote-line", quoteline, 0 "quote-line", quoteline, 0
"quote-region", quoteregion, 0 "quote-region", quoteregion, 0
"redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"redo", redo, 0 "redo", redo, ZLE_KEEPSUFFIX
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX "reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX "self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX "self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"send-break", sendbreak, 0 "send-break", sendbreak, 0
"set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"spell-word", spellword, 0 "spell-word", spellword, 0
"set-local-history", setlocalhistory, 0
"transpose-chars", transposechars, 0 "transpose-chars", transposechars, 0
"transpose-words", transposewords, 0 "transpose-words", transposewords, 0
"undefined-key", undefinedkey, 0 "undefined-key", undefinedkey, 0
"undo", undo, 0 "undo", undo, ZLE_KEEPSUFFIX
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"up-case-word", upcaseword, 0 "up-case-word", upcaseword, 0
"up-history", uphistory, 0 "up-history", uphistory, 0
"up-line-or-history", uplineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL "up-line-or-history", uplineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
@ -145,8 +148,8 @@
"vi-open-line-below", viopenlinebelow, 0 "vi-open-line-below", viopenlinebelow, 0
"vi-oper-swap-case", vioperswapcase, 0 "vi-oper-swap-case", vioperswapcase, 0
"vi-pound-insert", vipoundinsert, 0 "vi-pound-insert", vipoundinsert, 0
"vi-put-after", viputafter, ZLE_YANK "vi-put-after", viputafter, ZLE_YANK | ZLE_KEEPSUFFIX
"vi-put-before", viputbefore, ZLE_YANK "vi-put-before", viputbefore, ZLE_YANK | ZLE_KEEPSUFFIX
"vi-quoted-insert", viquotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX "vi-quoted-insert", viquotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"vi-repeat-change", virepeatchange, 0 "vi-repeat-change", virepeatchange, 0
"vi-repeat-find", virepeatfind, 0 "vi-repeat-find", virepeatfind, 0
@ -159,7 +162,7 @@
"vi-set-mark", visetmark, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "vi-set-mark", visetmark, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"vi-substitute", visubstitute, 0 "vi-substitute", visubstitute, 0
"vi-swap-case", viswapcase, 0 "vi-swap-case", viswapcase, 0
"vi-undo-change", viundochange, 0 "vi-undo-change", viundochange, ZLE_KEEPSUFFIX
"vi-unindent", viunindent, 0 "vi-unindent", viunindent, 0
"vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE "vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE
"vi-yank", viyank, 0 "vi-yank", viyank, 0
@ -168,5 +171,5 @@
"what-cursor-position", whatcursorposition, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "what-cursor-position", whatcursorposition, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"where-is", whereis, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "where-is", whereis, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"which-command", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "which-command", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"yank", yank, ZLE_YANK "yank", yank, ZLE_YANK | ZLE_KEEPSUFFIX
"yank-pop", yankpop, ZLE_YANK "yank-pop", yankpop, ZLE_YANK | ZLE_KEEPSUFFIX

View file

@ -53,7 +53,7 @@ struct cutbuffer vibuf[35];
/**/ /**/
char *lastline; char *lastline;
/**/ /**/
int lastlinesz, lastll; int lastlinesz, lastll, lastcs;
/* size of line buffer */ /* size of line buffer */
@ -73,7 +73,7 @@ sizeline(int sz)
/* insert space for ct chars at cursor position */ /* insert space for ct chars at cursor position */
/**/ /**/
void mod_export void
spaceinline(int ct) spaceinline(int ct)
{ {
int i; int i;
@ -105,7 +105,7 @@ shiftchars(int to, int cnt)
} }
/**/ /**/
void mod_export void
backkill(int ct, int dir) backkill(int ct, int dir)
{ {
int i = (cs -= ct); int i = (cs -= ct);
@ -115,7 +115,7 @@ backkill(int ct, int dir)
} }
/**/ /**/
void mod_export void
forekill(int ct, int dir) forekill(int ct, int dir)
{ {
int i = cs; int i = cs;
@ -191,14 +191,14 @@ cut(int i, int ct, int dir)
} }
/**/ /**/
void mod_export void
backdel(int ct) backdel(int ct)
{ {
shiftchars(cs -= ct, ct); shiftchars(cs -= ct, ct);
} }
/**/ /**/
void mod_export void
foredel(int ct) foredel(int ct)
{ {
shiftchars(cs, ct); shiftchars(cs, ct);
@ -283,7 +283,7 @@ hstrnstr(char *haystack, int pos, char *needle, int len, int dir, int sens)
* characters are read. Case is folded. */ * characters are read. Case is folded. */
/**/ /**/
int mod_export int
getzlequery(void) getzlequery(void)
{ {
int c; int c;
@ -409,19 +409,11 @@ showmsg(char const *msg)
/* handle the error flag */ /* handle the error flag */
/**/ /**/
void int
feep(void) handlefeep(char **args)
{ {
feepflag = 1; zbeep();
} return 0;
/**/
void
handlefeep(void)
{
if(feepflag)
beep();
feepflag = 0;
} }
/***************/ /***************/
@ -446,6 +438,7 @@ initundo(void)
curchange->del = curchange->ins = NULL; curchange->del = curchange->ins = NULL;
lastline = zalloc(lastlinesz = linesz); lastline = zalloc(lastlinesz = linesz);
memcpy(lastline, line, lastll = ll); memcpy(lastline, line, lastll = ll);
lastcs = cs;
} }
/**/ /**/
@ -519,6 +512,8 @@ mkundoent(void)
ch->next = NULL; ch->next = NULL;
ch->hist = histline; ch->hist = histline;
ch->off = pre; ch->off = pre;
ch->old_cs = lastcs;
ch->new_cs = cs;
if(suf + pre == lastll) if(suf + pre == lastll)
ch->del = NULL; ch->del = NULL;
else else
@ -549,32 +544,36 @@ setlastline(void)
if(lastlinesz != linesz) if(lastlinesz != linesz)
lastline = realloc(lastline, lastlinesz = linesz); lastline = realloc(lastline, lastlinesz = linesz);
memcpy(lastline, line, lastll = ll); memcpy(lastline, line, lastll = ll);
lastcs = cs;
} }
/* move backwards through the change list */ /* move backwards through the change list */
/**/ /**/
void int
undo(void) undo(char **args)
{ {
handleundo(); handleundo();
do { do {
if(!curchange->prev) { if(!curchange->prev)
feep(); return 1;
return; if (unapplychange(curchange->prev))
} curchange = curchange->prev;
unapplychange(curchange = curchange->prev); else
break;
} while(curchange->flags & CH_PREV); } while(curchange->flags & CH_PREV);
setlastline(); setlastline();
return 0;
} }
/**/ /**/
static void static int
unapplychange(struct change *ch) unapplychange(struct change *ch)
{ {
if(ch->hist != histline) { if(ch->hist != histline) {
remember_edits(); zle_setline(quietgethist(ch->hist));
setline(zle_get_event(histline = ch->hist)); cs = ch->new_cs;
return 0;
} }
cs = ch->off; cs = ch->off;
if(ch->ins) if(ch->ins)
@ -589,33 +588,37 @@ unapplychange(struct change *ch)
else else
line[cs++] = STOUC(*c); line[cs++] = STOUC(*c);
} }
cs = ch->old_cs;
return 1;
} }
/* move forwards through the change list */ /* move forwards through the change list */
/**/ /**/
void int
redo(void) redo(char **args)
{ {
handleundo(); handleundo();
do { do {
if(!curchange->next) { if(!curchange->next)
feep(); return 1;
return; if (applychange(curchange))
} curchange = curchange->next;
applychange(curchange); else
curchange = curchange->next; break;
} while(curchange->prev->flags & CH_NEXT); } while(curchange->prev->flags & CH_NEXT);
setlastline(); setlastline();
return 0;
} }
/**/ /**/
static void static int
applychange(struct change *ch) applychange(struct change *ch)
{ {
if(ch->hist != histline) { if(ch->hist != histline) {
remember_edits(); zle_setline(quietgethist(ch->hist));
setline(zle_get_event(histline = ch->hist)); cs = ch->old_cs;
return 0;
} }
cs = ch->off; cs = ch->off;
if(ch->del) if(ch->del)
@ -630,13 +633,15 @@ applychange(struct change *ch)
else else
line[cs++] = STOUC(*c); line[cs++] = STOUC(*c);
} }
cs = ch->new_cs;
return 1;
} }
/* vi undo: toggle between the end of the undo list and the preceding point */ /* vi undo: toggle between the end of the undo list and the preceding point */
/**/ /**/
void int
viundochange(void) viundochange(char **args)
{ {
handleundo(); handleundo();
if(curchange->next) { if(curchange->next) {
@ -645,6 +650,7 @@ viundochange(void)
curchange = curchange->next; curchange = curchange->next;
} while(curchange->next); } while(curchange->next);
setlastline(); setlastline();
return 0;
} else } else
undo(); return undo(args);
} }

File diff suppressed because it is too large Load diff

View file

@ -30,125 +30,277 @@
#include "zsh.mdh" #include "zsh.mdh"
#include "cond.pro" #include "cond.pro"
int tracingcond;
static char *condstr[COND_MOD] = {
"!", "&&", "||", "==", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
"-ne", "-lt", "-gt", "-le", "-ge"
};
/**/ /**/
int int
evalcond(Cond c) evalcond(Estate state)
{ {
struct stat *st; struct stat *st;
char *left, *right;
Wordcode pcode;
wordcode code;
int ctype, htok = 0;
switch (c->type) { rec:
left = right = NULL;
pcode = state->pc++;
code = *pcode;
ctype = WC_COND_TYPE(code);
switch (ctype) {
case COND_NOT: case COND_NOT:
return !evalcond(c->left); if (tracingcond)
fprintf(xtrerr, " %s", condstr[ctype]);
return !evalcond(state);
case COND_AND: case COND_AND:
return evalcond(c->left) && evalcond(c->right); if (evalcond(state)) {
if (tracingcond)
fprintf(xtrerr, " %s", condstr[ctype]);
goto rec;
} else {
state->pc = pcode + (WC_COND_SKIP(code) + 1);
return 0;
}
case COND_OR: case COND_OR:
return evalcond(c->left) || evalcond(c->right); if (!evalcond(state)) {
if (tracingcond)
fprintf(xtrerr, " %s", condstr[ctype]);
goto rec;
} else {
state->pc = pcode + (WC_COND_SKIP(code) + 1);
return 1;
}
case COND_MOD:
case COND_MODI:
{
Conddef cd;
char *name = ecgetstr(state, EC_NODUP, NULL), **strs;
int l = WC_COND_SKIP(code);
if (ctype == COND_MOD)
strs = ecgetarr(state, l, EC_DUP, NULL);
else {
char *sbuf[3];
sbuf[0] = ecgetstr(state, EC_NODUP, NULL);
sbuf[1] = ecgetstr(state, EC_NODUP, NULL);
sbuf[2] = NULL;
strs = arrdup(sbuf);
l = 2;
}
if ((cd = getconddef((ctype == COND_MODI), name + 1, 1))) {
if (ctype == COND_MOD &&
(l < cd->min || (cd->max >= 0 && l > cd->max))) {
zerr("unrecognized condition: `%s'", name, 0);
return 0;
}
if (tracingcond)
tracemodcond(name, strs, ctype == COND_MODI);
return cd->handler(strs, cd->condid);
}
else {
char *s = strs[0];
strs[0] = dupstring(name);
name = s;
if (name && name[0] == '-' &&
(cd = getconddef(0, name + 1, 1))) {
if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
zerr("unrecognized condition: `%s'", name, 0);
return 0;
}
if (tracingcond)
tracemodcond(name, strs, ctype == COND_MODI);
return cd->handler(strs, cd->condid);
} else
zerr("unrecognized condition: `%s'", name, 0);
}
return 0;
}
} }
singsub((char **)&c->left); left = ecgetstr(state, EC_DUPTOK, &htok);
untokenize(c->left); if (htok) {
if (c->right) { singsub(&left);
singsub((char **)&c->right); untokenize(left);
if (c->type != COND_STREQ && c->type != COND_STRNEQ)
untokenize(c->right);
} }
switch (c->type) { if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) {
right = ecgetstr(state, EC_DUPTOK, &htok);
if (htok) {
singsub(&right);
untokenize(right);
}
}
if (tracingcond) {
if (ctype < COND_MOD) {
char *rt = (char *) right;
if (ctype == COND_STREQ || ctype == COND_STRNEQ) {
rt = dupstring(ecrawstr(state->prog, state->pc, NULL));
singsub(&rt);
untokenize(rt);
}
fprintf(xtrerr, " %s %s %s", left, condstr[ctype], rt);
} else
fprintf(xtrerr, " -%c %s", ctype, left);
}
if (ctype >= COND_EQ && ctype <= COND_GE) {
mnumber mn1, mn2;
mn1 = matheval(left);
mn2 = matheval(right);
if (((mn1.type|mn2.type) & (MN_INTEGER|MN_FLOAT)) ==
(MN_INTEGER|MN_FLOAT)) {
/* promote to float */
if (mn1.type & MN_INTEGER) {
mn1.type = MN_FLOAT;
mn1.u.d = (double)mn1.u.l;
}
if (mn2.type & MN_INTEGER) {
mn2.type = MN_FLOAT;
mn2.u.d = (double)mn2.u.l;
}
}
switch(ctype) {
case COND_EQ:
return (mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) :
(mn1.u.l == mn2.u.l);
case COND_NE:
return (mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) :
(mn1.u.l != mn2.u.l);
case COND_LT:
return (mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) :
(mn1.u.l < mn2.u.l);
case COND_GT:
return (mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) :
(mn1.u.l > mn2.u.l);
case COND_LE:
return (mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) :
(mn1.u.l <= mn2.u.l);
case COND_GE:
return (mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) :
(mn1.u.l >= mn2.u.l);
}
}
switch (ctype) {
case COND_STREQ: case COND_STREQ:
return matchpat(c->left, c->right);
case COND_STRNEQ: case COND_STRNEQ:
return !matchpat(c->left, c->right); {
int test, npat = state->pc[1];
Patprog pprog = state->prog->pats[npat];
if (pprog == dummy_patprog1 || pprog == dummy_patprog2) {
char *opat;
int save;
right = opat = dupstring(ecrawstr(state->prog, state->pc,
&htok));
if (htok)
singsub(&right);
save = (!(state->prog->flags & EF_HEAP) &&
!strcmp(opat, right) && pprog != dummy_patprog2);
if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC),
NULL)))
zerr("bad pattern: %s", right, 0);
else if (save)
state->prog->pats[npat] = pprog;
}
state->pc += 2;
test = (pprog && pattry(pprog, left));
return (ctype == COND_STREQ ? test : !test);
}
case COND_STRLT: case COND_STRLT:
return strcmp(c->left, c->right) < 0; return strcmp(left, right) < 0;
case COND_STRGTR: case COND_STRGTR:
return strcmp(c->left, c->right) > 0; return strcmp(left, right) > 0;
case 'e': case 'e':
case 'a': case 'a':
return (doaccess(c->left, F_OK)); return (doaccess(left, F_OK));
case 'b': case 'b':
return (S_ISBLK(dostat(c->left))); return (S_ISBLK(dostat(left)));
case 'c': case 'c':
return (S_ISCHR(dostat(c->left))); return (S_ISCHR(dostat(left)));
case 'd': case 'd':
return (S_ISDIR(dostat(c->left))); return (S_ISDIR(dostat(left)));
case 'f': case 'f':
return (S_ISREG(dostat(c->left))); return (S_ISREG(dostat(left)));
case 'g': case 'g':
return (!!(dostat(c->left) & S_ISGID)); return (!!(dostat(left) & S_ISGID));
case 'k': case 'k':
return (!!(dostat(c->left) & S_ISVTX)); return (!!(dostat(left) & S_ISVTX));
case 'n': case 'n':
return (!!strlen(c->left)); return (!!strlen(left));
case 'o': case 'o':
return (optison(c->left)); return (optison(left));
case 'p': case 'p':
return (S_ISFIFO(dostat(c->left))); return (S_ISFIFO(dostat(left)));
case 'r': case 'r':
return (doaccess(c->left, R_OK)); return (doaccess(left, R_OK));
case 's': case 's':
return ((st = getstat(c->left)) && !!(st->st_size)); return ((st = getstat(left)) && !!(st->st_size));
case 'S': case 'S':
return (S_ISSOCK(dostat(c->left))); return (S_ISSOCK(dostat(left)));
case 'u': case 'u':
return (!!(dostat(c->left) & S_ISUID)); return (!!(dostat(left) & S_ISUID));
case 'w': case 'w':
return (doaccess(c->left, W_OK)); return (doaccess(left, W_OK));
case 'x': case 'x':
if (privasserted()) { if (privasserted()) {
mode_t mode = dostat(c->left); mode_t mode = dostat(left);
return (mode & S_IXUGO) || S_ISDIR(mode); return (mode & S_IXUGO) || S_ISDIR(mode);
} }
return doaccess(c->left, X_OK); return doaccess(left, X_OK);
case 'z': case 'z':
return (!strlen(c->left)); return (!strlen(left));
case 'h': case 'h':
case 'L': case 'L':
return (S_ISLNK(dolstat(c->left))); return (S_ISLNK(dolstat(left)));
case 'O': case 'O':
return ((st = getstat(c->left)) && st->st_uid == geteuid()); return ((st = getstat(left)) && st->st_uid == geteuid());
case 'G': case 'G':
return ((st = getstat(c->left)) && st->st_gid == getegid()); return ((st = getstat(left)) && st->st_gid == getegid());
case 'N': case 'N':
return ((st = getstat(c->left)) && st->st_atime <= st->st_mtime); return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
case 't': case 't':
return isatty(matheval(c->left)); return isatty(mathevali(left));
case COND_EQ:
return matheval(c->left) == matheval(c->right);
case COND_NE:
return matheval(c->left) != matheval(c->right);
case COND_LT:
return matheval(c->left) < matheval(c->right);
case COND_GT:
return matheval(c->left) > matheval(c->right);
case COND_LE:
return matheval(c->left) <= matheval(c->right);
case COND_GE:
return matheval(c->left) >= matheval(c->right);
case COND_NT: case COND_NT:
case COND_OT: case COND_OT:
{ {
time_t a; time_t a;
if (!(st = getstat(c->left))) if (!(st = getstat(left)))
return 0; return 0;
a = st->st_mtime; a = st->st_mtime;
if (!(st = getstat(c->right))) if (!(st = getstat(right)))
return 0; return 0;
return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime; return (ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
} }
case COND_EF: case COND_EF:
{ {
dev_t d; dev_t d;
ino_t i; ino_t i;
if (!(st = getstat(c->left))) if (!(st = getstat(left)))
return 0; return 0;
d = st->st_dev; d = st->st_dev;
i = st->st_ino; i = st->st_ino;
if (!(st = getstat(c->right))) if (!(st = getstat(right)))
return 0; return 0;
return d == st->st_dev && i == st->st_ino; return d == st->st_dev && i == st->st_ino;
} }
default: default:
zerr("bad cond structure", NULL, 0); zerr("bad cond code", NULL, 0);
} }
return 0; return 0;
} }
@ -158,6 +310,10 @@ evalcond(Cond c)
static int static int
doaccess(char *s, int c) doaccess(char *s, int c)
{ {
#ifdef HAVE_FACCESSX
if (!strncmp(s, "/dev/fd/", 8))
return !faccessx(atoi(s + 8), c, ACC_SELF);
#endif
return !access(unmeta(s), c); return !access(unmeta(s), c);
} }
@ -224,3 +380,59 @@ optison(char *s)
else else
return isset(i); return isset(i);
} }
/**/
mod_export char *
cond_str(char **args, int num, int raw)
{
char *s = args[num];
if (has_token(s)) {
singsub(&s);
if (!raw)
untokenize(s);
}
return s;
}
/**/
mod_export zlong
cond_val(char **args, int num)
{
char *s = args[num];
if (has_token(s)) {
singsub(&s);
untokenize(s);
}
return mathevali(s);
}
/**/
mod_export int
cond_match(char **args, int num, char *str)
{
char *s = args[num];
singsub(&s);
return matchpat(str, s);
}
/**/
static void
tracemodcond(char *name, char **args, int inf)
{
char **aptr;
args = arrdup(args);
for (aptr = args; *aptr; aptr++)
untokenize(*aptr);
if (inf) {
fprintf(xtrerr, " %s %s %s", args[0], name, args[1]);
} else {
fprintf(xtrerr, " %s", name);
while (*args)
fprintf(xtrerr, " %s", *args++);
}
}

1868
Src/exec.c

File diff suppressed because it is too large Load diff

View file

@ -77,13 +77,13 @@ static HashTable firstht, lastht;
/* Generic hash function */ /* Generic hash function */
/**/ /**/
unsigned mod_export unsigned
hasher(char *str) hasher(char *str)
{ {
unsigned hashval = 0; unsigned hashval = 0, c;
while (*str) while ((c = *((unsigned char *) str++)))
hashval += (hashval << 5) + ((unsigned) *str++); hashval += (hashval << 5) + c;
return hashval; return hashval;
} }
@ -91,7 +91,7 @@ hasher(char *str)
/* Get a new hash table */ /* Get a new hash table */
/**/ /**/
HashTable mod_export HashTable
newhashtable(int size, char const *name, PrintTableStats printinfo) newhashtable(int size, char const *name, PrintTableStats printinfo)
{ {
HashTable ht; HashTable ht;
@ -112,6 +112,7 @@ newhashtable(int size, char const *name, PrintTableStats printinfo)
ht->hsize = size; ht->hsize = size;
ht->ct = 0; ht->ct = 0;
ht->scan = NULL; ht->scan = NULL;
ht->scantab = NULL;
return ht; return ht;
} }
@ -119,7 +120,7 @@ newhashtable(int size, char const *name, PrintTableStats printinfo)
* existing pointers to the hash table are invalid. */ * existing pointers to the hash table are invalid. */
/**/ /**/
void mod_export void
deletehashtable(HashTable ht) deletehashtable(HashTable ht)
{ {
ht->emptytable(ht); ht->emptytable(ht);
@ -132,13 +133,14 @@ deletehashtable(HashTable ht)
ht->last->next = ht->next; ht->last->next = ht->next;
else else
firstht = ht->next; firstht = ht->next;
zsfree(ht->tablename);
#endif /* ZSH_HASH_DEBUG */ #endif /* ZSH_HASH_DEBUG */
zfree(ht->nodes, ht->hsize * sizeof(HashNode)); zfree(ht->nodes, ht->hsize * sizeof(HashNode));
zfree(ht, sizeof(*ht)); zfree(ht, sizeof(*ht));
} }
/* Add a node to a hash table. * /* Add a node to a hash table. *
* nam is the key to use in hashing. dat is a pointer * * nam is the key to use in hashing. nodeptr points *
* to the node to add. If there is already a node in * * to the node to add. If there is already a node in *
* the table with the same key, it is first freed, and * * the table with the same key, it is first freed, and *
* then the new node is added. If the number of nodes * * then the new node is added. If the number of nodes *
@ -146,8 +148,19 @@ deletehashtable(HashTable ht)
* the table is then expanded. */ * the table is then expanded. */
/**/ /**/
void mod_export void
addhashnode(HashTable ht, char *nam, void *nodeptr) addhashnode(HashTable ht, char *nam, void *nodeptr)
{
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
if (oldnode)
ht->freenode(oldnode);
}
/* Add a node to a hash table, returning the old node on replacment. */
/**/
HashNode
addhashnode2(HashTable ht, char *nam, void *nodeptr)
{ {
unsigned hashval; unsigned hashval;
HashNode hn, hp, hq; HashNode hn, hp, hq;
@ -164,15 +177,15 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
ht->nodes[hashval] = hn; ht->nodes[hashval] = hn;
if (++ht->ct >= ht->hsize * 2 && !ht->scan) if (++ht->ct >= ht->hsize * 2 && !ht->scan)
expandhashtable(ht); expandhashtable(ht);
return; return NULL;
} }
/* else check if the first node contains the same key */ /* else check if the first node contains the same key */
if (!strcmp(hp->nam, hn->nam)) { if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
ht->nodes[hashval] = hn; ht->nodes[hashval] = hn;
replacing: replacing:
hn->next = hp->next; hn->next = hp->next;
if(ht->scan) if(ht->scan) {
if(ht->scan->sorted) { if(ht->scan->sorted) {
HashNode *tab = ht->scan->u.s.tab; HashNode *tab = ht->scan->u.s.tab;
int i; int i;
@ -181,15 +194,15 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
tab[i] = hn; tab[i] = hn;
} else if(ht->scan->u.u == hp) } else if(ht->scan->u.u == hp)
ht->scan->u.u = hn; ht->scan->u.u = hn;
ht->freenode(hp); }
return; return hp;
} }
/* else run through the list and check all the keys */ /* else run through the list and check all the keys */
hq = hp; hq = hp;
hp = hp->next; hp = hp->next;
for (; hp; hq = hp, hp = hp->next) { for (; hp; hq = hp, hp = hp->next) {
if (!strcmp(hp->nam, hn->nam)) { if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
hq->next = hn; hq->next = hn;
goto replacing; goto replacing;
} }
@ -200,6 +213,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
ht->nodes[hashval] = hn; ht->nodes[hashval] = hn;
if (++ht->ct >= ht->hsize * 2 && !ht->scan) if (++ht->ct >= ht->hsize * 2 && !ht->scan)
expandhashtable(ht); expandhashtable(ht);
return NULL;
} }
/* Get an enabled entry in a hash table. * /* Get an enabled entry in a hash table. *
@ -208,7 +222,7 @@ addhashnode(HashTable ht, char *nam, void *nodeptr)
* or isn't found, it returns NULL */ * or isn't found, it returns NULL */
/**/ /**/
HashNode mod_export HashNode
gethashnode(HashTable ht, char *nam) gethashnode(HashTable ht, char *nam)
{ {
unsigned hashval; unsigned hashval;
@ -216,7 +230,7 @@ gethashnode(HashTable ht, char *nam)
hashval = ht->hash(nam) % ht->hsize; hashval = ht->hash(nam) % ht->hsize;
for (hp = ht->nodes[hashval]; hp; hp = hp->next) { for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
if (!strcmp(hp->nam, nam)) { if (ht->cmpnodes(hp->nam, nam) == 0) {
if (hp->flags & DISABLED) if (hp->flags & DISABLED)
return NULL; return NULL;
else else
@ -232,7 +246,7 @@ gethashnode(HashTable ht, char *nam)
* it returns NULL. */ * it returns NULL. */
/**/ /**/
HashNode mod_export HashNode
gethashnode2(HashTable ht, char *nam) gethashnode2(HashTable ht, char *nam)
{ {
unsigned hashval; unsigned hashval;
@ -240,7 +254,7 @@ gethashnode2(HashTable ht, char *nam)
hashval = ht->hash(nam) % ht->hsize; hashval = ht->hash(nam) % ht->hsize;
for (hp = ht->nodes[hashval]; hp; hp = hp->next) { for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
if (!strcmp(hp->nam, nam)) if (ht->cmpnodes(hp->nam, nam) == 0)
return hp; return hp;
} }
return NULL; return NULL;
@ -252,7 +266,7 @@ gethashnode2(HashTable ht, char *nam)
* is no such node, then it returns NULL */ * is no such node, then it returns NULL */
/**/ /**/
HashNode mod_export HashNode
removehashnode(HashTable ht, char *nam) removehashnode(HashTable ht, char *nam)
{ {
unsigned hashval; unsigned hashval;
@ -266,11 +280,11 @@ removehashnode(HashTable ht, char *nam)
return NULL; return NULL;
/* else check if the key in the first one matches */ /* else check if the key in the first one matches */
if (!strcmp(hp->nam, nam)) { if (ht->cmpnodes(hp->nam, nam) == 0) {
ht->nodes[hashval] = hp->next; ht->nodes[hashval] = hp->next;
gotit: gotit:
ht->ct--; ht->ct--;
if(ht->scan) if(ht->scan) {
if(ht->scan->sorted) { if(ht->scan->sorted) {
HashNode *tab = ht->scan->u.s.tab; HashNode *tab = ht->scan->u.s.tab;
int i; int i;
@ -279,6 +293,7 @@ removehashnode(HashTable ht, char *nam)
tab[i] = NULL; tab[i] = NULL;
} else if(ht->scan->u.u == hp) } else if(ht->scan->u.u == hp)
ht->scan->u.u = hp->next; ht->scan->u.u = hp->next;
}
return hp; return hp;
} }
@ -286,7 +301,7 @@ removehashnode(HashTable ht, char *nam)
hq = hp; hq = hp;
hp = hp->next; hp = hp->next;
for (; hp; hq = hp, hp = hp->next) { for (; hp; hq = hp, hp = hp->next) {
if (!strcmp(hp->nam, nam)) { if (ht->cmpnodes(hp->nam, nam) == 0) {
hq->next = hp->next; hq->next = hp->next;
goto gotit; goto gotit;
} }
@ -314,7 +329,7 @@ enablehashnode(HashNode hn, int flags)
hn->flags &= ~DISABLED; hn->flags &= ~DISABLED;
} }
/* Compare two hash table entries */ /* Compare two hash table entries by name */
/**/ /**/
static int static int
@ -343,11 +358,15 @@ hnamcmp(const void *ap, const void *bp)
*/ */
/**/ /**/
void mod_export void
scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfunc, int scanflags) scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfunc, int scanflags)
{ {
struct scanstatus st; struct scanstatus st;
if (ht->scantab) {
ht->scantab(ht, scanfunc, scanflags);
return;
}
if (sorted) { if (sorted) {
int i, ct = ht->ct; int i, ct = ht->ct;
VARARR(HashNode, hnsorttab, ct); VARARR(HashNode, hnsorttab, ct);
@ -399,7 +418,7 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun
/**/ /**/
int int
scanmatchtable(HashTable ht, Comp com, int flags1, int flags2, ScanFunc scanfunc, int scanflags) scanmatchtable(HashTable ht, Patprog pprog, int flags1, int flags2, ScanFunc scanfunc, int scanflags)
{ {
int i, hsize = ht->hsize; int i, hsize = ht->hsize;
HashNode *nodes = ht->nodes; HashNode *nodes = ht->nodes;
@ -414,9 +433,10 @@ scanmatchtable(HashTable ht, Comp com, int flags1, int flags2, ScanFunc scanfunc
HashNode hn = st.u.u; HashNode hn = st.u.u;
st.u.u = st.u.u->next; st.u.u = st.u.u->next;
if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2) && if ((hn->flags & flags1) + !flags1 && !(hn->flags & flags2) &&
domatch(hn->nam, com, 0)) pattry(pprog, hn->nam)) {
scanfunc(hn, scanflags); scanfunc(hn, scanflags);
match++; match++;
}
} }
ht->scan = NULL; ht->scan = NULL;
@ -489,12 +509,13 @@ resizehashtable(HashTable ht, int newsize)
/* Generic method to empty a hash table */ /* Generic method to empty a hash table */
/**/ /**/
void mod_export void
emptyhashtable(HashTable ht) emptyhashtable(HashTable ht)
{ {
resizehashtable(ht, ht->hsize); resizehashtable(ht, ht->hsize);
} }
/**/
#ifdef ZSH_HASH_DEBUG #ifdef ZSH_HASH_DEBUG
/* Print info about hash table */ /* Print info about hash table */
@ -547,6 +568,7 @@ bin_hashinfo(char *nam, char **args, char *ops, int func)
return 0; return 0;
} }
/**/
#endif /* ZSH_HASH_DEBUG */ #endif /* ZSH_HASH_DEBUG */
/********************************/ /********************************/
@ -556,12 +578,12 @@ bin_hashinfo(char *nam, char **args, char *ops, int func)
/* hash table containing external commands */ /* hash table containing external commands */
/**/ /**/
HashTable cmdnamtab; mod_export HashTable cmdnamtab;
/* how far we've hashed the PATH so far */ /* how far we've hashed the PATH so far */
/**/ /**/
char **pathchecked; mod_export char **pathchecked;
/* Create a new command hash table */ /* Create a new command hash table */
@ -574,6 +596,7 @@ createcmdnamtable(void)
cmdnamtab->hash = hasher; cmdnamtab->hash = hasher;
cmdnamtab->emptytable = emptycmdnamtable; cmdnamtab->emptytable = emptycmdnamtable;
cmdnamtab->filltable = fillcmdnamtable; cmdnamtab->filltable = fillcmdnamtable;
cmdnamtab->cmpnodes = strcmp;
cmdnamtab->addnode = addhashnode; cmdnamtab->addnode = addhashnode;
cmdnamtab->getnode = gethashnode2; cmdnamtab->getnode = gethashnode2;
cmdnamtab->getnode2 = gethashnode2; cmdnamtab->getnode2 = gethashnode2;
@ -604,6 +627,9 @@ hashdir(char **dirp)
Cmdnam cn; Cmdnam cn;
DIR *dir; DIR *dir;
char *fn; char *fn;
#ifdef _WIN32
char *exe;
#endif
if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp)))) if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp))))
return; return;
@ -615,6 +641,23 @@ hashdir(char **dirp)
cn->u.name = dirp; cn->u.name = dirp;
cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn); cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
} }
#ifdef _WIN32
/* Hash foo.exe as foo, since when no real foo exists, foo.exe
will get executed by DOS automatically. This quiets
spurious corrections when CORRECT or CORRECT_ALL is set. */
if ((exe = strrchr(fn, '.')) &&
(exe[1] == 'E' || exe[1] == 'e') &&
(exe[2] == 'X' || exe[2] == 'x') &&
(exe[3] == 'E' || exe[3] == 'e') && exe[4] == 0) {
*exe = 0;
if (!cmdnamtab->getnode(cmdnamtab, fn)) {
cn = (Cmdnam) zcalloc(sizeof *cn);
cn->flags = 0;
cn->u.name = dirp;
cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
}
}
#endif /* _WIN32 */
} }
closedir(dir); closedir(dir);
} }
@ -713,7 +756,7 @@ printcmdnamnode(HashNode hn, int printflags)
/* hash table containing the shell functions */ /* hash table containing the shell functions */
/**/ /**/
HashTable shfunctab; mod_export HashTable shfunctab;
/**/ /**/
void void
@ -724,6 +767,7 @@ createshfunctable(void)
shfunctab->hash = hasher; shfunctab->hash = hasher;
shfunctab->emptytable = NULL; shfunctab->emptytable = NULL;
shfunctab->filltable = NULL; shfunctab->filltable = NULL;
shfunctab->cmpnodes = strcmp;
shfunctab->addnode = addhashnode; shfunctab->addnode = addhashnode;
shfunctab->getnode = gethashnode; shfunctab->getnode = gethashnode;
shfunctab->getnode2 = gethashnode2; shfunctab->getnode2 = gethashnode2;
@ -798,7 +842,7 @@ freeshfuncnode(HashNode hn)
zsfree(shf->nam); zsfree(shf->nam);
if (shf->funcdef) if (shf->funcdef)
freestruct(shf->funcdef); freeeprog(shf->funcdef);
zfree(shf, sizeof(struct shfunc)); zfree(shf, sizeof(struct shfunc));
} }
@ -828,21 +872,34 @@ printshfuncnode(HashNode hn, int printflags)
} }
if (f->flags & PM_UNDEFINED) if (f->flags & PM_UNDEFINED)
printf("undefined "); t = tricat("builtin autoload -X",
if (f->flags & PM_TAGGED) ((f->flags & PM_UNALIASED)? "U" : ""),
printf("traced "); ((f->flags & PM_TAGGED)? "t" : ""));
if ((f->flags & PM_UNDEFINED) || !f->funcdef) { else {
nicezputs(f->nam, stdout); if (!f->funcdef)
printf(" () { }\n"); t = 0;
return; else
t = getpermtext(f->funcdef, NULL);
} }
t = getpermtext((void *) dupstruct((void *) f->funcdef));
quotedzputs(f->nam, stdout); quotedzputs(f->nam, stdout);
printf(" () {\n\t"); if (t) {
zputs(t, stdout); printf(" () {\n\t");
printf("\n}\n"); if (f->flags & PM_UNDEFINED)
zsfree(t); printf("%c undefined\n\t", hashchar);
if (f->flags & PM_TAGGED)
printf("%c traced\n\t", hashchar);
zputs(t, stdout);
if (f->funcdef && (f->funcdef->flags & EF_RUN)) {
printf("\n\t");
quotedzputs(f->nam, stdout);
printf(" \"$@\"");
}
printf("\n}\n");
zsfree(t);
} else {
printf(" () { }\n");
}
} }
/**************************************/ /**************************************/
@ -882,7 +939,7 @@ static struct reswd reswds[] = {
/* hash table containing the reserved words */ /* hash table containing the reserved words */
/**/ /**/
HashTable reswdtab; mod_export HashTable reswdtab;
/* Build the hash table containing zsh's reserved words. */ /* Build the hash table containing zsh's reserved words. */
@ -897,6 +954,7 @@ createreswdtable(void)
reswdtab->hash = hasher; reswdtab->hash = hasher;
reswdtab->emptytable = NULL; reswdtab->emptytable = NULL;
reswdtab->filltable = NULL; reswdtab->filltable = NULL;
reswdtab->cmpnodes = strcmp;
reswdtab->addnode = addhashnode; reswdtab->addnode = addhashnode;
reswdtab->getnode = gethashnode; reswdtab->getnode = gethashnode;
reswdtab->getnode2 = gethashnode2; reswdtab->getnode2 = gethashnode2;
@ -944,7 +1002,7 @@ printreswdnode(HashNode hn, int printflags)
/* hash table containing the aliases */ /* hash table containing the aliases */
/**/ /**/
HashTable aliastab; mod_export HashTable aliastab;
/* Create new hash table for aliases */ /* Create new hash table for aliases */
@ -957,6 +1015,7 @@ createaliastable(void)
aliastab->hash = hasher; aliastab->hash = hasher;
aliastab->emptytable = NULL; aliastab->emptytable = NULL;
aliastab->filltable = NULL; aliastab->filltable = NULL;
aliastab->cmpnodes = strcmp;
aliastab->addnode = addhashnode; aliastab->addnode = addhashnode;
aliastab->getnode = gethashnode; aliastab->getnode = gethashnode;
aliastab->getnode2 = gethashnode2; aliastab->getnode2 = gethashnode2;
@ -974,7 +1033,7 @@ createaliastable(void)
/* Create a new alias node */ /* Create a new alias node */
/**/ /**/
Alias mod_export Alias
createaliasnode(char *txt, int flags) createaliasnode(char *txt, int flags)
{ {
Alias al; Alias al;
@ -1061,101 +1120,25 @@ printaliasnode(HashNode hn, int printflags)
putchar('\n'); putchar('\n');
} }
/**********************************/
/* Parameter Hash Table Functions */
/**********************************/
/**/
void
freeparamnode(HashNode hn)
{
Param pm = (Param) hn;
zsfree(pm->nam);
zfree(pm, sizeof(struct param));
}
/* Print a parameter */
/**/
void
printparamnode(HashNode hn, int printflags)
{
Param p = (Param) hn;
char *t, **u;
if (p->flags & PM_UNSET)
return;
/* Print the attributes of the parameter */
if (printflags & PRINT_TYPE) {
if (p->flags & PM_INTEGER)
printf("integer ");
if (p->flags & PM_ARRAY)
printf("array ");
if (p->flags & PM_LEFT)
printf("left justified %d ", p->ct);
if (p->flags & PM_RIGHT_B)
printf("right justified %d ", p->ct);
if (p->flags & PM_RIGHT_Z)
printf("zero filled %d ", p->ct);
if (p->flags & PM_LOWER)
printf("lowercase ");
if (p->flags & PM_UPPER)
printf("uppercase ");
if (p->flags & PM_READONLY)
printf("readonly ");
if (p->flags & PM_TAGGED)
printf("tagged ");
if (p->flags & PM_EXPORTED)
printf("exported ");
}
if (printflags & PRINT_NAMEONLY) {
zputs(p->nam, stdout);
putchar('\n');
return;
}
/* How the value is displayed depends *
* on the type of the parameter */
quotedzputs(p->nam, stdout);
putchar('=');
switch (PM_TYPE(p->flags)) {
case PM_SCALAR:
/* string: simple output */
if (p->gets.cfn && (t = p->gets.cfn(p)))
quotedzputs(t, stdout);
putchar('\n');
break;
case PM_INTEGER:
/* integer */
printf("%ld\n", p->gets.ifn(p));
break;
case PM_ARRAY:
/* array */
putchar('(');
u = p->gets.afn(p);
if(*u) {
quotedzputs(*u++, stdout);
while (*u) {
putchar(' ');
quotedzputs(*u++, stdout);
}
}
printf(")\n");
break;
}
}
/****************************************/ /****************************************/
/* Named Directory Hash Table Functions */ /* Named Directory Hash Table Functions */
/****************************************/ /****************************************/
#ifdef HAVE_NIS_PLUS
# include <rpcsvc/nis.h>
#else
# ifdef HAVE_NIS
# include <rpc/types.h>
# include <rpc/rpc.h>
# include <rpcsvc/ypclnt.h>
# include <rpcsvc/yp_prot.h>
# endif
#endif
/* hash table containing named directories */ /* hash table containing named directories */
/**/ /**/
HashTable nameddirtab; mod_export HashTable nameddirtab;
/* != 0 if all the usernames have already been * /* != 0 if all the usernames have already been *
* added to the named directory hash table. */ * added to the named directory hash table. */
@ -1173,6 +1156,7 @@ createnameddirtable(void)
nameddirtab->hash = hasher; nameddirtab->hash = hasher;
nameddirtab->emptytable = emptynameddirtable; nameddirtab->emptytable = emptynameddirtable;
nameddirtab->filltable = fillnameddirtable; nameddirtab->filltable = fillnameddirtable;
nameddirtab->cmpnodes = strcmp;
nameddirtab->addnode = addnameddirnode; nameddirtab->addnode = addnameddirnode;
nameddirtab->getnode = gethashnode; nameddirtab->getnode = gethashnode;
nameddirtab->getnode2 = gethashnode2; nameddirtab->getnode2 = gethashnode2;
@ -1200,12 +1184,122 @@ emptynameddirtable(HashTable ht)
/* Add all the usernames in the password file/database * /* Add all the usernames in the password file/database *
* to the named directories table. */ * to the named directories table. */
#ifdef HAVE_NIS_PLUS
static int
add_userdir(nis_name table, nis_object *object, void *userdata)
{
if (object->zo_data.objdata_u.en_data.en_cols.en_cols >= 6) {
static char name[40], dir[PATH_MAX + 1];
register entry_col *ec =
object->zo_data.objdata_u.en_data.en_cols.en_cols_val;
register int nl = minimum(ec[0].ec_value.ec_value_len, 39);
register int dl = minimum(ec[5].ec_value.ec_value_len, PATH_MAX);
memcpy(name, ec[0].ec_value.ec_value_val, nl);
name[nl] = '\0';
memcpy(dir, ec[5].ec_value.ec_value_val, dl);
dir[dl] = '\0';
adduserdir(name, dir, ND_USERNAME, 1);
}
return 0;
}
#else
# ifdef HAVE_NIS
static int
add_userdir(int status, char *key, int keylen, char *val, int vallen, char *dummy)
{
char *p, *d, *de;
if (status != YP_TRUE)
return 1;
if (vallen > keylen && *(p = val + keylen) == ':') {
*p++ = '\0';
if ((de = strrchr(p, ':'))) {
*de = '\0';
if ((d = strrchr(p, ':'))) {
if (*++d && val[0])
adduserdir(val, d, ND_USERNAME, 1);
}
}
}
return 0;
}
# endif /* HAVE_NIS */
#endif /* HAVE_NIS_PLUS */
/**/ /**/
static void static void
fillnameddirtable(HashTable ht) fillnameddirtable(HashTable ht)
{ {
#ifdef HAVE_GETPWENT
if (!allusersadded) { if (!allusersadded) {
#if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS)
FILE *pwf;
char buf[BUFSIZ], *p, *d, *de;
int skipping, oldct = nameddirtab->ct, usepwf = 1;
# ifndef HAVE_NIS_PLUS
char domain[YPMAXDOMAIN];
struct ypall_callback cb;
/* Get potential matches from NIS and cull those without local accounts */
if (getdomainname(domain, YPMAXDOMAIN) == 0) {
cb.foreach = (int (*)()) add_userdir;
cb.data = NULL;
yp_all(domain, PASSWD_MAP, &cb);
}
# else /* HAVE_NIS_PLUS */
/* Maybe we should turn this string into a #define'd constant...? */
nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH,
add_userdir, 0);
# endif
if (nameddirtab->ct == oldct) {
/* Using NIS or NIS+ didn't add any user directories. This seems
* fishy, so we fall back to using getpwent(). If we don't have
* that, we only use the passwd file. */
#ifdef HAVE_GETPWENT
struct passwd *pw;
setpwent();
/* loop through the password file/database *
* and add all entries returned. */
while ((pw = getpwent()) && !errflag)
adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1);
endpwent();
usepwf = 0;
#endif /* HAVE_GETPWENT */
}
if (usepwf) {
/* Don't forget the non-NIS matches from the flat passwd file */
if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) {
skipping = 0;
while (fgets(buf, BUFSIZ, pwf) != NULL) {
if (strchr(buf, '\n') != NULL) {
if (!skipping) {
if ((p = strchr(buf, ':')) != NULL) {
*p++ = '\0';
if ((de = strrchr(p, ':'))) {
*de = '\0';
if ((d = strrchr(p, ':'))) {
if (*++d && buf[0])
adduserdir(buf, d, ND_USERNAME, 1);
}
}
}
} else
skipping = 0;
} else
skipping = 1;
}
fclose(pwf);
}
}
#else /* no NIS or NIS_PLUS */
#ifdef HAVE_GETPWENT
struct passwd *pw; struct passwd *pw;
setpwent(); setpwent();
@ -1213,13 +1307,13 @@ fillnameddirtable(HashTable ht)
/* loop through the password file/database * /* loop through the password file/database *
* and add all entries returned. */ * and add all entries returned. */
while ((pw = getpwent()) && !errflag) while ((pw = getpwent()) && !errflag)
adduserdir(ztrdup(pw->pw_name), pw->pw_dir, ND_USERNAME, 1); adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1);
endpwent(); endpwent();
#endif /* HAVE_GETPWENT */
#endif
allusersadded = 1; allusersadded = 1;
} }
return;
#endif /* HAVE_GETPWENT */
} }
/* Add an entry to the named directory hash * /* Add an entry to the named directory hash *
@ -1283,3 +1377,137 @@ printnameddirnode(HashNode hn, int printflags)
quotedzputs(nd->dir, stdout); quotedzputs(nd->dir, stdout);
putchar('\n'); putchar('\n');
} }
/*************************************/
/* History Line Hash Table Functions */
/*************************************/
/**/
void
createhisttable(void)
{
histtab = newhashtable(599, "histtab", NULL);
histtab->hash = histhasher;
histtab->emptytable = emptyhisttable;
histtab->filltable = NULL;
histtab->cmpnodes = histstrcmp;
histtab->addnode = addhistnode;
histtab->getnode = gethashnode2;
histtab->getnode2 = gethashnode2;
histtab->removenode = removehashnode;
histtab->disablenode = NULL;
histtab->enablenode = NULL;
histtab->freenode = freehistnode;
histtab->printnode = NULL;
}
/**/
unsigned
histhasher(char *str)
{
unsigned hashval = 0;
while (inblank(*str)) str++;
while (*str) {
if (inblank(*str)) {
do str++; while (inblank(*str));
if (*str)
hashval += (hashval << 5) + ' ';
}
else
hashval += (hashval << 5) + *(unsigned char *)str++;
}
return hashval;
}
/**/
void
emptyhisttable(HashTable ht)
{
emptyhashtable(ht);
if (hist_ring)
histremovedups();
}
/* Compare two strings with normalized white-space */
/**/
int
histstrcmp(const char *str1, const char *str2)
{
while (inblank(*str1)) str1++;
while (inblank(*str2)) str2++;
while (*str1 && *str2) {
if (inblank(*str1)) {
if (!inblank(*str2))
break;
do str1++; while (inblank(*str1));
do str2++; while (inblank(*str2));
}
else {
if (*str1 != *str2)
break;
str1++;
str2++;
}
}
return *str1 - *str2;
}
/**/
void
addhistnode(HashTable ht, char *nam, void *nodeptr)
{
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
Histent he = (Histent)nodeptr;
if (oldnode && oldnode != (HashNode)nodeptr) {
if (he->flags & HIST_MAKEUNIQUE
|| (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
he->flags |= HIST_DUP;
addhashnode(ht, oldnode->nam, oldnode); /* Remove the new dup */
}
else {
oldnode->flags |= HIST_DUP;
if (hist_ignore_all_dups)
freehistnode(oldnode); /* Remove the old dup */
}
}
else
he->flags &= ~HIST_MAKEUNIQUE;
}
/**/
void
freehistnode(HashNode nodeptr)
{
freehistdata((Histent)nodeptr, 1);
zfree(nodeptr, sizeof (struct histent));
}
/**/
void
freehistdata(Histent he, int unlink)
{
if (!he)
return;
if (!(he->flags & HIST_DUP))
removehashnode(histtab, he->text);
zsfree(he->text);
if (he->nwords)
zfree(he->words, he->nwords*2*sizeof(short));
if (unlink) {
if (!--histlinect)
hist_ring = NULL;
else {
if (he == hist_ring)
hist_ring = hist_ring->up;
he->up->down = he->down;
he->down->up = he->up;
}
}
}

View file

@ -33,12 +33,12 @@
/* the process group of the shell */ /* the process group of the shell */
/**/ /**/
pid_t mypgrp; mod_export pid_t mypgrp;
/* the job we are working on */ /* the job we are working on */
/**/ /**/
int thisjob; mod_export int thisjob;
/* the current job (+) */ /* the current job (+) */
@ -53,8 +53,8 @@ int prevjob;
/* the job table */ /* the job table */
/**/ /**/
struct job jobtab[MAXJOB]; mod_export struct job jobtab[MAXJOB];
/* shell timings */ /* shell timings */
/**/ /**/
@ -64,13 +64,18 @@ struct tms shtms;
/**/ /**/
int ttyfrozen; int ttyfrozen;
/* empty job structure for quick clearing of jobtab entries */
static struct job zero; /* static variables are initialized to zero */ /* Previous values of errflag and breaks if the signal handler had to
* change them. And a flag saying if it did that. */
/**/
int prev_errflag, prev_breaks, errbrk_saved;
static struct timeval dtimeval, now; static struct timeval dtimeval, now;
/**/
int numpipestats, pipestats[MAX_PIPESTATS];
/* Diff two timevals for elapsed-time computations */ /* Diff two timevals for elapsed-time computations */
/**/ /**/
@ -96,9 +101,13 @@ makerunning(Job jn)
jn->stat &= ~STAT_STOPPED; jn->stat &= ~STAT_STOPPED;
for (pn = jn->procs; pn; pn = pn->next) for (pn = jn->procs; pn; pn = pn->next)
#if 0
if (WIFSTOPPED(pn->status) && if (WIFSTOPPED(pn->status) &&
(!(jn->stat & STAT_SUPERJOB) || pn->next)) (!(jn->stat & STAT_SUPERJOB) || pn->next))
pn->status = SP_RUNNING; pn->status = SP_RUNNING;
#endif
if (WIFSTOPPED(pn->status))
pn->status = SP_RUNNING;
if (jn->stat & STAT_SUPERJOB) if (jn->stat & STAT_SUPERJOB)
makerunning(jobtab + jn->other); makerunning(jobtab + jn->other);
@ -125,6 +134,86 @@ findproc(pid_t pid, Job *jptr, Process *pptr)
return 0; return 0;
} }
/* Find the super-job of a sub-job. */
/**/
static int
super_job(int sub)
{
int i;
for (i = 1; i < MAXJOB; i++)
if ((jobtab[i].stat & STAT_SUPERJOB) &&
jobtab[i].other == sub &&
jobtab[i].gleader)
return i;
return 0;
}
/**/
static int
handle_sub(int job, int fg)
{
Job jn = jobtab + job, sj = jobtab + jn->other;
if ((sj->stat & STAT_DONE) || !sj->procs) {
struct process *p;
for (p = sj->procs; p; p = p->next)
if (WIFSIGNALED(p->status)) {
if (jn->gleader != mypgrp && jn->procs->next)
killpg(jn->gleader, WTERMSIG(p->status));
else
kill(jn->procs->pid, WTERMSIG(p->status));
kill(sj->other, SIGCONT);
kill(sj->other, WTERMSIG(p->status));
break;
}
if (!p) {
int cp;
jn->stat &= ~STAT_SUPERJOB;
jn->stat |= STAT_WASSUPER;
if ((cp = ((WIFEXITED(jn->procs->status) ||
WIFSIGNALED(jn->procs->status)) &&
killpg(jn->gleader, 0) == -1))) {
Process p;
for (p = jn->procs; p->next; p = p->next);
jn->gleader = p->pid;
}
/* This deleted the job too early if the parent
shell waited for a command in a list that will
be executed by the sub-shell (e.g.: if we have
`ls|if true;then sleep 20;cat;fi' and ^Z the
sleep, the rest will be executed by a sub-shell,
but the parent shell gets notified for the
sleep.
deletejob(sj); */
/* If this super-job contains only the sub-shell,
we have to attach the tty to its process group
now. */
if ((fg || thisjob == job) &&
(!jn->procs->next || cp || jn->procs->pid != jn->gleader))
attachtty(jn->gleader);
kill(sj->other, SIGCONT);
}
curjob = jn - jobtab;
} else if (sj->stat & STAT_STOPPED) {
struct process *p;
jn->stat |= STAT_STOPPED;
for (p = jn->procs; p; p = p->next)
if (p->status == SP_RUNNING ||
(!WIFEXITED(p->status) && !WIFSIGNALED(p->status)))
p->status = sj->procs->status;
curjob = jn - jobtab;
printjob(jn, !!isset(LONGLISTJOBS), 1);
return 1;
}
return 0;
}
/* Update status of process that we have just WAIT'ed for */ /* Update status of process that we have just WAIT'ed for */
/**/ /**/
@ -175,16 +264,31 @@ update_job(Job jn)
jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo)); jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
gettyinfo(jn->ty); gettyinfo(jn->ty);
} }
if (jn->stat & STAT_STOPPED) if (jn->stat & STAT_STOPPED) {
if (jn->stat & STAT_SUBJOB) {
/* If we have `cat foo|while read a; grep $a bar;done'
* and have hit ^Z, the sub-job is stopped, but the
* super-job may still be running, waiting to be stopped
* or to exit. So we have to send it a SIGTSTP. */
int i;
if ((i = super_job(job)))
killpg(jobtab[i].gleader, SIGTSTP);
}
return; return;
} else { /* job is done, so remember return value */ }
}
{ /* job is done or stopped, remember return value */
lastval2 = val; lastval2 = val;
/* If last process was run in the current shell, keep old status /* If last process was run in the current shell, keep old status
* and let it handle its own traps * and let it handle its own traps, but always allow the test
* for the pgrp.
*/ */
if (job == thisjob && !(jn->stat & STAT_CURSH)) { if (jn->stat & STAT_CURSH)
lastval = val; inforeground = 1;
inforeground = 1; else if (job == thisjob) {
lastval = val;
inforeground = 2;
} }
} }
@ -198,15 +302,72 @@ update_job(Job jn)
/* is this job in the foreground of an interactive shell? */ /* is this job in the foreground of an interactive shell? */
if (mypgrp != pgrp && inforeground && if (mypgrp != pgrp && inforeground &&
(jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) { (jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
attachtty(mypgrp); if (list_pipe) {
adjustwinsize(); /* check window size and adjust if necessary */ if (somestopped || (pgrp > 1 && kill(-pgrp, 0) == -1)) {
attachtty(mypgrp);
/* check window size and adjust if necessary */
adjustwinsize(0);
} else {
/*
* Oh, dear, we're right in the middle of some confusion
* of shell jobs on the righthand side of a pipeline, so
* it's death to call attachtty() just yet. Mark the
* fact in the job, so that the attachtty() will be called
* when the job is finally deleted.
*/
jn->stat |= STAT_ATTACH;
}
/* If we have `foo|while true; (( x++ )); done', and hit
* ^C, we have to stop the loop, too. */
if ((val & 0200) && inforeground == 1) {
if (!errbrk_saved) {
errbrk_saved = 1;
prev_breaks = breaks;
prev_errflag = errflag;
}
breaks = loops;
errflag = 1;
inerrflush();
}
} else {
attachtty(mypgrp);
/* check window size and adjust if necessary */
adjustwinsize(0);
}
} }
} else if (list_pipe && (val & 0200) && inforeground == 1) {
if (!errbrk_saved) {
errbrk_saved = 1;
prev_breaks = breaks;
prev_errflag = errflag;
}
breaks = loops;
errflag = 1;
inerrflush();
} }
if (somestopped && jn->stat & STAT_SUPERJOB) if (somestopped && jn->stat & STAT_SUPERJOB)
return; return;
jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED : jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
STAT_CHANGED | STAT_DONE; STAT_CHANGED | STAT_DONE;
if (job == thisjob && (jn->stat & STAT_DONE)) {
int i;
Process p;
for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++)
pipestats[i] = ((WIFSIGNALED(p->status)) ?
0200 | WTERMSIG(p->status) :
WEXITSTATUS(p->status));
if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS)
pipestats[i++] = lastval;
numpipestats = i;
}
if (!inforeground &&
(jn->stat & (STAT_SUBJOB | STAT_DONE)) == (STAT_SUBJOB | STAT_DONE)) {
int su;
if ((su = super_job(jn - jobtab)))
handle_sub(su, 0);
}
if ((jn->stat & (STAT_DONE | STAT_STOPPED)) == STAT_STOPPED) { if ((jn->stat & (STAT_DONE | STAT_STOPPED)) == STAT_STOPPED) {
prevjob = curjob; prevjob = curjob;
curjob = job; curjob = job;
@ -214,7 +375,7 @@ update_job(Job jn)
if ((isset(NOTIFY) || job == thisjob) && (jn->stat & STAT_LOCKED)) { if ((isset(NOTIFY) || job == thisjob) && (jn->stat & STAT_LOCKED)) {
printjob(jn, !!isset(LONGLISTJOBS), 0); printjob(jn, !!isset(LONGLISTJOBS), 0);
if (zleactive) if (zleactive)
refresh(); zrefresh();
} }
if (sigtrapped[SIGCHLD] && job != thisjob) if (sigtrapped[SIGCHLD] && job != thisjob)
dotrap(SIGCHLD); dotrap(SIGCHLD);
@ -223,7 +384,7 @@ update_job(Job jn)
* process group from the shell, so the shell will not receive * * process group from the shell, so the shell will not receive *
* terminal signals, therefore we we pretend that the shell got * * terminal signals, therefore we we pretend that the shell got *
* the signal too. */ * the signal too. */
if (inforeground && isset(MONITOR) && WIFSIGNALED(status)) { if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) {
int sig = WTERMSIG(status); int sig = WTERMSIG(status);
if (sig == SIGINT || sig == SIGQUIT) { if (sig == SIGINT || sig == SIGQUIT) {
@ -256,13 +417,14 @@ setprevjob(void)
for (i = MAXJOB - 1; i; i--) for (i = MAXJOB - 1; i; i--)
if ((jobtab[i].stat & STAT_INUSE) && (jobtab[i].stat & STAT_STOPPED) && if ((jobtab[i].stat & STAT_INUSE) && (jobtab[i].stat & STAT_STOPPED) &&
i != curjob && i != thisjob) { !(jobtab[i].stat & STAT_SUBJOB) && i != curjob && i != thisjob) {
prevjob = i; prevjob = i;
return; return;
} }
for (i = MAXJOB - 1; i; i--) for (i = MAXJOB - 1; i; i--)
if ((jobtab[i].stat & STAT_INUSE) && i != curjob && i != thisjob) { if ((jobtab[i].stat & STAT_INUSE) && !(jobtab[i].stat & STAT_SUBJOB) &&
i != curjob && i != thisjob) {
prevjob = i; prevjob = i;
return; return;
} }
@ -409,6 +571,7 @@ dumptime(Job jn)
static int static int
should_report_time(Job j) should_report_time(Job j)
{ {
struct value vbuf;
Value v; Value v;
char *s = "REPORTTIME"; char *s = "REPORTTIME";
int reporttime; int reporttime;
@ -417,9 +580,10 @@ should_report_time(Job j)
if (j->stat & STAT_TIMED) if (j->stat & STAT_TIMED)
return 1; return 1;
if (!(v = getvalue(&s, 0)) || (reporttime = getintvalue(v)) < 0) if (!(v = getvalue(&vbuf, &s, 0)) ||
(reporttime = getintvalue(v)) < 0) {
return 0; return 0;
}
/* can this ever happen? */ /* can this ever happen? */
if (!j->procs) if (!j->procs)
return 0; return 0;
@ -462,10 +626,10 @@ printjob(Job jn, int lng, int synch)
if (jn->stat & STAT_SUPERJOB && if (jn->stat & STAT_SUPERJOB &&
jn->procs->status == SP_RUNNING && !pn->next) jn->procs->status == SP_RUNNING && !pn->next)
pn->status = SP_RUNNING; pn->status = SP_RUNNING;
if (pn->status != SP_RUNNING) if (pn->status != SP_RUNNING) {
if (WIFSIGNALED(pn->status)) { if (WIFSIGNALED(pn->status)) {
sig = WTERMSIG(pn->status); sig = WTERMSIG(pn->status);
llen = strlen(sigmsg[sig]); llen = strlen(sigmsg(sig));
if (WCOREDUMP(pn->status)) if (WCOREDUMP(pn->status))
llen += 14; llen += 14;
if (llen > len) if (llen > len)
@ -476,13 +640,14 @@ printjob(Job jn, int lng, int synch)
doputnl = 1; doputnl = 1;
} else if (WIFSTOPPED(pn->status)) { } else if (WIFSTOPPED(pn->status)) {
sig = WSTOPSIG(pn->status); sig = WSTOPSIG(pn->status);
if ((int)strlen(sigmsg[sig]) > len) if ((int)strlen(sigmsg(sig)) > len)
len = strlen(sigmsg[sig]); len = strlen(sigmsg(sig));
if (job == thisjob && sig == SIGTSTP) if (job == thisjob && sig == SIGTSTP)
doputnl = 1; doputnl = 1;
} else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) && } else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
WEXITSTATUS(pn->status)) WEXITSTATUS(pn->status))
sflag = 1; sflag = 1;
}
} }
/* print if necessary */ /* print if necessary */
@ -508,7 +673,7 @@ printjob(Job jn, int lng, int synch)
break; break;
len2 += strlen(qn->text) + 2; len2 += strlen(qn->text) + 2;
} }
if (job != thisjob) if (job != thisjob) {
if (fline) if (fline)
fprintf(fout, "[%ld] %c ", fprintf(fout, "[%ld] %c ",
(long)(jn - jobtab), (long)(jn - jobtab),
@ -516,7 +681,7 @@ printjob(Job jn, int lng, int synch)
: (job == prevjob) ? '-' : ' '); : (job == prevjob) ? '-' : ' ');
else else
fprintf(fout, (job > 9) ? " " : " "); fprintf(fout, (job > 9) ? " " : " ");
else } else
fprintf(fout, "zsh: "); fprintf(fout, "zsh: ");
if (lng & 1) if (lng & 1)
fprintf(fout, "%ld ", (long) pn->pid); fprintf(fout, "%ld ", (long) pn->pid);
@ -531,25 +696,26 @@ printjob(Job jn, int lng, int synch)
lng &= ~3; lng &= ~3;
} else } else
fprintf(fout, "%*s", skip, ""); fprintf(fout, "%*s", skip, "");
if (pn->status == SP_RUNNING) if (pn->status == SP_RUNNING) {
if (!conted) if (!conted)
fprintf(fout, "running%*s", len - 7 + 2, ""); fprintf(fout, "running%*s", len - 7 + 2, "");
else else
fprintf(fout, "continued%*s", len - 9 + 2, ""); fprintf(fout, "continued%*s", len - 9 + 2, "");
else if (WIFEXITED(pn->status)) }
else if (WIFEXITED(pn->status)) {
if (WEXITSTATUS(pn->status)) if (WEXITSTATUS(pn->status))
fprintf(fout, "exit %-4d%*s", WEXITSTATUS(pn->status), fprintf(fout, "exit %-4d%*s", WEXITSTATUS(pn->status),
len - 9 + 2, ""); len - 9 + 2, "");
else else
fprintf(fout, "done%*s", len - 4 + 2, ""); fprintf(fout, "done%*s", len - 4 + 2, "");
else if (WIFSTOPPED(pn->status)) } else if (WIFSTOPPED(pn->status))
fprintf(fout, "%-*s", len + 2, sigmsg[WSTOPSIG(pn->status)]); fprintf(fout, "%-*s", len + 2, sigmsg(WSTOPSIG(pn->status)));
else if (WCOREDUMP(pn->status)) else if (WCOREDUMP(pn->status))
fprintf(fout, "%s (core dumped)%*s", fprintf(fout, "%s (core dumped)%*s",
sigmsg[WTERMSIG(pn->status)], sigmsg(WTERMSIG(pn->status)),
(int)(len - 14 + 2 - strlen(sigmsg[WTERMSIG(pn->status)])), ""); (int)(len - 14 + 2 - strlen(sigmsg(WTERMSIG(pn->status)))), "");
else else
fprintf(fout, "%-*s", len + 2, sigmsg[WTERMSIG(pn->status)]); fprintf(fout, "%-*s", len + 2, sigmsg(WTERMSIG(pn->status)));
for (; pn != qn; pn = pn->next) for (; pn != qn; pn = pn->next)
fprintf(fout, (pn->next) ? "%s | " : "%s", pn->text); fprintf(fout, (pn->next) ? "%s | " : "%s", pn->text);
putc('\n', fout); putc('\n', fout);
@ -565,7 +731,8 @@ printjob(Job jn, int lng, int synch)
* the directory where the job is running, otherwise the current directory * the directory where the job is running, otherwise the current directory
*/ */
if ((lng & 4) || (interact && job == thisjob && strcmp(jn->pwd, pwd))) { if ((lng & 4) || (interact && job == thisjob &&
jn->pwd && strcmp(jn->pwd, pwd))) {
fprintf(shout, "(pwd %s: ", (lng & 4) ? "" : "now"); fprintf(shout, "(pwd %s: ", (lng & 4) ? "" : "now");
fprintdir((lng & 4) ? jn->pwd : pwd, shout); fprintdir((lng & 4) ? jn->pwd : pwd, shout);
fprintf(shout, ")\n"); fprintf(shout, ")\n");
@ -607,20 +774,31 @@ deletejob(Job jn)
{ {
struct process *pn, *nx; struct process *pn, *nx;
if (jn->stat & STAT_ATTACH) {
attachtty(mypgrp);
adjustwinsize(0);
}
pn = jn->procs; pn = jn->procs;
jn->procs = NULL; jn->procs = NULL;
for (; pn; pn = nx) { for (; pn; pn = nx) {
nx = pn->next; nx = pn->next;
zfree(pn, sizeof(struct process)); zfree(pn, sizeof(struct process));
} }
zsfree(jn->pwd);
deletefilelist(jn->filelist); deletefilelist(jn->filelist);
if (jn->ty) if (jn->ty)
zfree(jn->ty, sizeof(struct ttyinfo)); zfree(jn->ty, sizeof(struct ttyinfo));
if (jn->pwd)
*jn = zero; zsfree(jn->pwd);
jn->pwd = NULL;
if (jn->stat & STAT_WASSUPER)
deletejob(jobtab + jn->other);
jn->gleader = jn->other = 0;
jn->stat = jn->stty_in_env = 0;
jn->procs = NULL;
jn->filelist = NULL;
jn->ty = NULL;
} }
/* add a process to the current job */ /* add a process to the current job */
@ -729,40 +907,20 @@ waitjob(int job, int sig)
what this might be. --oberon what this might be. --oberon
errflag = 0; */ errflag = 0; */
if (jn->stat & STAT_SUPERJOB) { if (subsh) {
Job sj = jobtab + jn->other; killjb(jn, SIGCONT);
if (sj->stat & STAT_DONE) { jn->stat &= ~STAT_STOPPED;
struct process *p;
for (p = sj->procs; p; p = p->next)
if (WIFSIGNALED(p->status)) {
killpg(jn->gleader, WTERMSIG(p->status));
kill(sj->other, SIGCONT);
kill(sj->other, WTERMSIG(p->status));
break;
}
if (!p) {
jn->stat &= ~STAT_SUPERJOB;
kill(sj->other, SIGCONT);
deletejob(sj);
}
curjob = jn - jobtab;
}
else if (sj->stat & STAT_STOPPED) {
struct process *p;
jn->stat |= STAT_STOPPED;
for (p = jn->procs; p; p = p->next)
p->status = sj->procs->status;
curjob = jn - jobtab;
printjob(jn, !!isset(LONGLISTJOBS), 1);
break;
}
} }
if (jn->stat & STAT_SUPERJOB)
if (handle_sub(jn - jobtab, 1))
break;
child_block(); child_block();
} }
} else } else {
deletejob(jn); deletejob(jn);
pipestats[0] = lastval;
numpipestats = 1;
}
child_unblock(); child_unblock();
} }
@ -772,24 +930,29 @@ waitjob(int job, int sig)
void void
waitjobs(void) waitjobs(void)
{ {
waitjob(thisjob, 0); Job jn = jobtab + thisjob;
if (jn->procs)
waitjob(thisjob, 0);
else {
deletejob(jn);
pipestats[0] = lastval;
numpipestats = 1;
}
thisjob = -1; thisjob = -1;
} }
/* clear job table when entering subshells */ /* clear job table when entering subshells */
/**/ /**/
void mod_export void
clearjobtab(void) clearjobtab(void)
{ {
int i; int i;
for (i = 1; i < MAXJOB; i++) { for (i = 1; i < MAXJOB; i++)
if (jobtab[i].pwd)
zsfree(jobtab[i].pwd);
if (jobtab[i].ty) if (jobtab[i].ty)
zfree(jobtab[i].ty, sizeof(struct ttyinfo)); zfree(jobtab[i].ty, sizeof(struct ttyinfo));
}
memset(jobtab, 0, sizeof(jobtab)); /* zero out table */ memset(jobtab, 0, sizeof(jobtab)); /* zero out table */
} }
@ -805,7 +968,8 @@ initjob(void)
for (i = 1; i < MAXJOB; i++) for (i = 1; i < MAXJOB; i++)
if (!jobtab[i].stat) { if (!jobtab[i].stat) {
jobtab[i].stat = STAT_INUSE; jobtab[i].stat = STAT_INUSE;
jobtab[i].pwd = ztrdup(pwd); if (jobtab[i].pwd)
zsfree(jobtab[i].pwd);
jobtab[i].gleader = 0; jobtab[i].gleader = 0;
return i; return i;
} }
@ -814,6 +978,21 @@ initjob(void)
return -1; return -1;
} }
/**/
void
setjobpwd(void)
{
int i, l;
for (i = 1; i < MAXJOB; i++)
if (jobtab[i].stat && !jobtab[i].pwd) {
if ((l = strlen(pwd)) >= PATH_MAX)
jobtab[i].pwd = ztrdup(pwd + l - PATH_MAX);
else
jobtab[i].pwd = ztrdup(pwd);
}
}
/* print pids for & */ /* print pids for & */
/**/ /**/
@ -1071,7 +1250,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
/* If you immediately type "exit" after "jobs", this * /* If you immediately type "exit" after "jobs", this *
* will prevent zexit from complaining about stopped jobs */ * will prevent zexit from complaining about stopped jobs */
stopmsg = 2; stopmsg = 2;
if (!*argv) if (!*argv) {
/* This block handles all of the default cases (no arguments). bg, /* This block handles all of the default cases (no arguments). bg,
fg and disown act on the current job, and jobs and wait act on all the fg and disown act on the current job, and jobs and wait act on all the
jobs. */ jobs. */
@ -1100,6 +1279,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
waitjob(job, SIGINT); waitjob(job, SIGINT);
return 0; return 0;
} }
}
/* Defaults have been handled. We now have an argument or two, or three... /* Defaults have been handled. We now have an argument or two, or three...
In the default case for bg, fg and disown, the argument will be provided by In the default case for bg, fg and disown, the argument will be provided by
@ -1157,7 +1337,7 @@ bin_fg(char *name, char **argv, char *ops, int func)
/* for bg and fg -- show the job we are operating on */ /* for bg and fg -- show the job we are operating on */
printjob(jobtab + job, (stopped) ? -1 : 0, 1); printjob(jobtab + job, (stopped) ? -1 : 0, 1);
if (func != BIN_BG) { /* fg or wait */ if (func != BIN_BG) { /* fg or wait */
if (strcmp(jobtab[job].pwd, pwd)) { if (jobtab[job].pwd && strcmp(jobtab[job].pwd, pwd)) {
fprintf(shout, "(pwd : "); fprintf(shout, "(pwd : ");
fprintdir(jobtab[job].pwd, shout); fprintdir(jobtab[job].pwd, shout);
fprintf(shout, ")\n"); fprintf(shout, ")\n");
@ -1165,7 +1345,14 @@ bin_fg(char *name, char **argv, char *ops, int func)
fflush(shout); fflush(shout);
if (func != BIN_WAIT) { /* fg */ if (func != BIN_WAIT) { /* fg */
thisjob = job; thisjob = job;
attachtty(jobtab[job].gleader); if ((jobtab[job].stat & STAT_SUPERJOB) &&
((!jobtab[job].procs->next ||
(jobtab[job].stat & STAT_SUBLEADER) ||
killpg(jobtab[job].gleader, 0) == -1)) &&
jobtab[jobtab[job].other].gleader)
attachtty(jobtab[jobtab[job].other].gleader);
else
attachtty(jobtab[job].gleader);
} }
} }
if (stopped) { if (stopped) {

View file

@ -43,47 +43,79 @@ int contflag;
/* # of break levels */ /* # of break levels */
/**/ /**/
int breaks; mod_export int breaks;
/**/ /**/
int int
execfor(Cmd cmd) execfor(Estate state, int do_exec)
{ {
List list; Wordcode end, loop;
Forcmd node; wordcode code = state->pc[-1];
char *str; int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0;
int val; char *name, *str, *cond = NULL, *advance = NULL;
LinkList args; zlong val = 0;
LinkList args = NULL;
node = cmd->u.forcmd; name = ecgetstr(state, EC_NODUP, NULL);
args = cmd->args; end = state->pc + WC_FOR_SKIP(code);
if (node->condition) {
str = node->name; if (iscond) {
str = dupstring(name);
singsub(&str); singsub(&str);
if (isset(XTRACE)) {
char *str2 = dupstring(str);
untokenize(str2);
printprompt4();
fprintf(xtrerr, "%s\n", str2);
fflush(xtrerr);
}
if (!errflag) if (!errflag)
matheval(str); matheval(str);
if (errflag) if (errflag) {
state->pc = end;
return lastval = errflag; return lastval = errflag;
} else if (!node->inflag) { }
cond = ecgetstr(state, EC_NODUP, &ctok);
advance = ecgetstr(state, EC_NODUP, &atok);
} else if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
int htok = 0;
if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
state->pc = end;
return 0;
}
if (htok)
execsubst(args);
} else {
char **x; char **x;
args = newlinklist(); args = newlinklist();
for (x = pparams; *x; x++) for (x = pparams; *x; x++)
addlinknode(args, ztrdup(*x)); addlinknode(args, dupstring(*x));
} }
lastval = 0; lastval = 0;
loops++; loops++;
pushheap(); pushheap();
cmdpush(CS_FOR);
loop = state->pc;
for (;;) { for (;;) {
if (node->condition) { if (iscond) {
str = dupstring(node->condition); if (ctok) {
singsub(&str); str = dupstring(cond);
singsub(&str);
} else
str = cond;
if (!errflag) { if (!errflag) {
while (iblank(*str)) while (iblank(*str))
str++; str++;
if (*str) if (*str) {
val = matheval(str); if (isset(XTRACE)) {
else printprompt4();
fprintf(xtrerr, "%s\n", str);
fflush(xtrerr);
}
val = mathevali(str);
} else
val = 1; val = 1;
} }
if (errflag) { if (errflag) {
@ -95,22 +127,36 @@ execfor(Cmd cmd)
if (!val) if (!val)
break; break;
} else { } else {
str = (char *) ugetnode(args); if (!args || !(str = (char *) ugetnode(args)))
if (!str)
break; break;
setsparam(node->name, ztrdup(str)); if (isset(XTRACE)) {
printprompt4();
fprintf(xtrerr, "%s=%s\n", name, str);
fflush(xtrerr);
}
setsparam(name, ztrdup(str));
} }
list = (List) dupstruct(node->list); state->pc = loop;
execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args)); execlist(state, 1, do_exec && args && empty(args));
if (breaks) { if (breaks) {
breaks--; breaks--;
if (breaks || !contflag) if (breaks || !contflag)
break; break;
contflag = 0; contflag = 0;
} }
if (node->condition && !errflag) { if (retflag)
str = dupstring(node->advance); break;
singsub(&str); if (iscond && !errflag) {
if (atok) {
str = dupstring(advance);
singsub(&str);
} else
str = advance;
if (isset(XTRACE)) {
printprompt4();
fprintf(xtrerr, "%s\n", str);
fflush(xtrerr);
}
if (!errflag) if (!errflag)
matheval(str); matheval(str);
} }
@ -123,44 +169,67 @@ execfor(Cmd cmd)
freeheap(); freeheap();
} }
popheap(); popheap();
cmdpop();
loops--; loops--;
state->pc = end;
return lastval; return lastval;
} }
/**/ /**/
int int
execselect(Cmd cmd) execselect(Estate state, int do_exec)
{ {
List list; Wordcode end, loop;
Forcmd node; wordcode code = state->pc[-1];
char *str, *s; char *str, *s, *name;
LinkList args;
LinkNode n; LinkNode n;
int i; int i, usezle;
FILE *inp; FILE *inp;
size_t more;
LinkList args;
node = cmd->u.forcmd; end = state->pc + WC_FOR_SKIP(code);
args = cmd->args; name = ecgetstr(state, EC_NODUP, NULL);
if (!node->inflag) {
if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) {
char **x; char **x;
args = newlinklist(); args = newlinklist();
for (x = pparams; *x; x++) for (x = pparams; *x; x++)
addlinknode(args, ztrdup(*x)); addlinknode(args, dupstring(*x));
} else {
int htok = 0;
if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
state->pc = end;
return 0;
}
if (htok)
execsubst(args);
} }
if (empty(args)) if (!args || empty(args)) {
state->pc = end;
return 1; return 1;
}
loops++; loops++;
lastval = 0; lastval = 0;
pushheap(); pushheap();
inp = fdopen(dup((SHTTY == -1) ? 0 : SHTTY), "r"); cmdpush(CS_SELECT);
selectlist(args); usezle = interact && SHTTY != -1 && isset(USEZLE);
inp = fdopen(dup(usezle ? SHTTY : 0), "r");
more = selectlist(args, 0);
loop = state->pc;
for (;;) { for (;;) {
for (;;) { for (;;) {
if (empty(bufstack)) { if (empty(bufstack)) {
if (interact && SHTTY != -1 && isset(USEZLE)) { if (usezle) {
int oef = errflag;
isfirstln = 1; isfirstln = 1;
str = (char *)zleread(prompt3, NULL, 0); str = (char *)zleread(prompt3, NULL, 0);
if (errflag)
str = NULL;
errflag = oef;
} else { } else {
str = promptexpand(prompt3, 0, NULL, NULL); str = promptexpand(prompt3, 0, NULL, NULL);
zputs(str, stderr); zputs(str, stderr);
@ -181,7 +250,7 @@ execselect(Cmd cmd)
*s = '\0'; *s = '\0';
if (*str) if (*str)
break; break;
selectlist(args); more = selectlist(args, more);
} }
setsparam("REPLY", ztrdup(str)); setsparam("REPLY", ztrdup(str));
i = atoi(str); i = atoi(str);
@ -194,9 +263,9 @@ execselect(Cmd cmd)
else else
str = ""; str = "";
} }
setsparam(node->name, ztrdup(str)); setsparam(name, ztrdup(str));
list = (List) dupstruct(node->list); state->pc = loop;
execlist(list, 1, 0); execlist(state, 1, 0);
freeheap(); freeheap();
if (breaks) { if (breaks) {
breaks--; breaks--;
@ -204,21 +273,23 @@ execselect(Cmd cmd)
break; break;
contflag = 0; contflag = 0;
} }
if (errflag) if (retflag || errflag)
break; break;
} }
done: done:
cmdpop();
popheap(); popheap();
fclose(inp); fclose(inp);
loops--; loops--;
state->pc = end;
return lastval; return lastval;
} }
/* And this is used to print select lists. */ /* And this is used to print select lists. */
/**/ /**/
static void size_t
selectlist(LinkList l) selectlist(LinkList l, size_t start)
{ {
size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct; size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
LinkNode n; LinkNode n;
@ -226,7 +297,7 @@ selectlist(LinkList l)
trashzle(); trashzle();
ct = countlinknodes(l); ct = countlinknodes(l);
ap = arr = (char **)alloc((countlinknodes(l) + 1) * sizeof(char **)); ap = arr = (char **) zhalloc((countlinknodes(l) + 1) * sizeof(char **));
for (n = (LinkNode) firstnode(l); n; incnode(n)) for (n = (LinkNode) firstnode(l); n; incnode(n))
*ap++ = (char *)getdata(n); *ap++ = (char *)getdata(n);
@ -245,7 +316,7 @@ selectlist(LinkList l)
else else
fw = (columns - 1) / fct; fw = (columns - 1) / fct;
colsz = (ct + fct - 1) / fct; colsz = (ct + fct - 1) / fct;
for (t1 = 0; t1 != colsz; t1++) { for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) {
ap = arr + t1; ap = arr + t1;
do { do {
int t2 = strlen(*ap) + 2, t3; int t2 = strlen(*ap) + 2, t3;
@ -271,70 +342,86 @@ selectlist(LinkList l)
} }
while (*ap);*/ while (*ap);*/
fflush(stderr); fflush(stderr);
return t1 < colsz ? t1 : 0;
} }
/**/ /**/
int int
execwhile(Cmd cmd) execwhile(Estate state, int do_exec)
{ {
List list; Wordcode end, loop;
struct whilecmd *node; wordcode code = state->pc[-1];
int olderrexit, oldval; int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL);
end = state->pc + WC_WHILE_SKIP(code);
olderrexit = noerrexit; olderrexit = noerrexit;
node = cmd->u.whilecmd;
oldval = 0; oldval = 0;
pushheap(); pushheap();
cmdpush(isuntil ? CS_UNTIL : CS_WHILE);
loops++; loops++;
loop = state->pc;
for (;;) { for (;;) {
list = (List) dupstruct(node->cont); state->pc = loop;
noerrexit = 1; noerrexit = 1;
execlist(list, 1, 0); execlist(state, 1, 0);
noerrexit = olderrexit; noerrexit = olderrexit;
if (!((lastval == 0) ^ node->cond)) { if (!((lastval == 0) ^ isuntil)) {
if (breaks) if (breaks)
breaks--; breaks--;
lastval = oldval; lastval = oldval;
break; break;
} }
list = (List) dupstruct(node->loop); if (retflag) {
execlist(list, 1, 0); lastval = oldval;
break;
}
execlist(state, 1, 0);
if (breaks) { if (breaks) {
breaks--; breaks--;
if (breaks || !contflag) if (breaks || !contflag)
break; break;
contflag = 0; contflag = 0;
} }
freeheap();
if (errflag) { if (errflag) {
lastval = 1; lastval = 1;
break; break;
} }
if (retflag)
break;
freeheap();
oldval = lastval; oldval = lastval;
} }
cmdpop();
popheap(); popheap();
loops--; loops--;
state->pc = end;
return lastval; return lastval;
} }
/**/ /**/
int int
execrepeat(Cmd cmd) execrepeat(Estate state, int do_exec)
{ {
List list; Wordcode end, loop;
int count; wordcode code = state->pc[-1];
int count, htok = 0;
char *tmp;
end = state->pc + WC_REPEAT_SKIP(code);
lastval = 0; lastval = 0;
if (empty(cmd->args) || nextnode(firstnode(cmd->args))) { tmp = ecgetstr(state, EC_DUPTOK, &htok);
zerr("bad argument for repeat", NULL, 0); if (htok)
return 1; singsub(&tmp);
} count = atoi(tmp);
count = atoi(peekfirst(cmd->args));
pushheap(); pushheap();
cmdpush(CS_REPEAT);
loops++; loops++;
while (count--) { loop = state->pc;
list = (List) dupstruct(cmd->u.list); while (count-- > 0) {
execlist(list, 1, 0); state->pc = loop;
execlist(state, 1, 0);
freeheap(); freeheap();
if (breaks) { if (breaks) {
breaks--; breaks--;
@ -346,76 +433,151 @@ execrepeat(Cmd cmd)
lastval = 1; lastval = 1;
break; break;
} }
if (retflag)
break;
} }
cmdpop();
popheap(); popheap();
loops--; loops--;
state->pc = end;
return lastval; return lastval;
} }
/**/ /**/
int int
execif(Cmd cmd) execif(Estate state, int do_exec)
{ {
struct ifcmd *node; Wordcode end, next;
int olderrexit; wordcode code = state->pc[-1];
List *i, *t; int olderrexit, s = 0, run = 0;
olderrexit = noerrexit; olderrexit = noerrexit;
node = cmd->u.ifcmd; end = state->pc + WC_IF_SKIP(code);
i = node->ifls;
t = node->thenls;
if (!noerrexit) if (!noerrexit)
noerrexit = 1; noerrexit = 1;
while (*i) { while (state->pc < end) {
execlist(*i, 1, 0); code = *state->pc++;
if (!lastval) if (wc_code(code) != WC_IF ||
(run = (WC_IF_TYPE(code) == WC_IF_ELSE))) {
if (run)
run = 2;
break; break;
i++; }
t++; next = state->pc + WC_IF_SKIP(code);
cmdpush(s ? CS_ELIF : CS_IF);
execlist(state, 1, 0);
cmdpop();
if (!lastval) {
run = 1;
break;
}
if (retflag)
break;
s = 1;
state->pc = next;
} }
noerrexit = olderrexit; noerrexit = olderrexit;
if (*t) if (run) {
execlist(*t, 1, cmd->flags & CFLAG_EXEC); cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN));
else execlist(state, 1, do_exec);
cmdpop();
} else
lastval = 0; lastval = 0;
state->pc = end;
return lastval; return lastval;
} }
/**/ /**/
int int
execcase(Cmd cmd) execcase(Estate state, int do_exec)
{ {
struct casecmd *node; Wordcode end, next;
char *word; wordcode code = state->pc[-1];
List *l; char *word, *pat;
char **p; int npat, save;
Patprog *spprog, pprog;
node = cmd->u.casecmd; end = state->pc + WC_CASE_SKIP(code);
l = node->lists;
p = node->pats;
word = *p++; word = ecgetstr(state, EC_DUP, NULL);
singsub(&word); singsub(&word);
untokenize(word); untokenize(word);
lastval = 0; lastval = 0;
if (node) { cmdpush(CS_CASE);
while (*p) { while (state->pc < end) {
char *pat = *p + 1; code = *state->pc++;
if (wc_code(code) != WC_CASE)
break;
pat = NULL;
pprog = NULL;
save = 0;
npat = state->pc[1];
spprog = state->prog->pats + npat;
next = state->pc + WC_CASE_SKIP(code);
if (isset(XTRACE)) {
char *pat2, *opat;
opat = pat = ecgetstr(state, EC_DUP, NULL);
singsub(&pat); singsub(&pat);
if (matchpat(word, pat)) { save = (!(state->prog->flags & EF_HEAP) &&
do { !strcmp(pat, opat) && *spprog != dummy_patprog2);
execlist(*l++, 1, **p == ';' && (cmd->flags & CFLAG_EXEC));
} while(**p++ == '&' && *p); pat2 = dupstring(pat);
break; untokenize(pat2);
printprompt4();
fprintf(xtrerr, "case %s (%s)\n", word, pat2);
fflush(xtrerr);
state->pc++;
} else
state->pc += 2;
if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
pprog = *spprog;
if (!pprog) {
if (!pat) {
char *opat;
int htok = 0;
opat = pat = dupstring(ecrawstr(state->prog,
state->pc - 2, &htok));
if (htok)
singsub(&pat);
save = (!(state->prog->flags & EF_HEAP) &&
!strcmp(pat, opat) && *spprog != dummy_patprog2);
} }
p++; if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
l++; NULL)))
zerr("bad pattern: %s", pat, 0);
else if (save)
*spprog = pprog;
} }
if (pprog && pattry(pprog, word)) {
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
do_exec));
while (!retflag && wc_code(code) == WC_CASE &&
WC_CASE_TYPE(code) == WC_CASE_AND) {
state->pc = next;
code = *state->pc;
state->pc += 3;
next = state->pc + WC_CASE_SKIP(code) - 1;
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
do_exec));
}
break;
} else
state->pc = next;
} }
cmdpop();
state->pc = end;
return lastval; return lastval;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -31,7 +31,7 @@
#include "text.pro" #include "text.pro"
static char *tptr, *tbuf, *tlim; static char *tptr, *tbuf, *tlim;
static int tsiz, tindent, tnewlins; static int tsiz, tindent, tnewlins, tjob;
/* add a character to the text buffer */ /* add a character to the text buffer */
@ -72,19 +72,18 @@ taddstr(char *s)
tptr += sl; tptr += sl;
} }
#if 0
/* add an integer to the text buffer */
/**/ /**/
void static void
taddint(int x) taddlist(Estate state, int num)
{ {
char buf[DIGBUFSIZE]; if (num) {
while (num--) {
sprintf(buf, "%d", x); taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr(buf); taddchr(' ');
}
tptr--;
}
} }
#endif
/* add a newline, or something equivalent, to the text buffer */ /* add a newline, or something equivalent, to the text buffer */
@ -105,15 +104,26 @@ taddnl(void)
/* get a permanent textual representation of n */ /* get a permanent textual representation of n */
/**/ /**/
char * mod_export char *
getpermtext(struct node *n) getpermtext(Eprog prog, Wordcode c)
{ {
struct estate s;
if (!c)
c = prog->prog;
s.prog = prog;
s.pc = c;
s.strs = prog->strs;
tnewlins = 1; tnewlins = 1;
tbuf = (char *)zalloc(tsiz = 32); tbuf = (char *)zalloc(tsiz = 32);
tptr = tbuf; tptr = tbuf;
tlim = tbuf + tsiz; tlim = tbuf + tsiz;
tindent = 1; tindent = 1;
gettext2(n); tjob = 0;
if (prog->len)
gettext2(&s);
*tptr = '\0'; *tptr = '\0';
untokenize(tbuf); untokenize(tbuf);
return tbuf; return tbuf;
@ -123,344 +133,587 @@ getpermtext(struct node *n)
/**/ /**/
char * char *
getjobtext(struct node *n) getjobtext(Eprog prog, Wordcode c)
{ {
static char jbuf[JOBTEXTSIZE]; static char jbuf[JOBTEXTSIZE];
struct estate s;
if (!c)
c = prog->prog;
s.prog = prog;
s.pc = c;
s.strs = prog->strs;
tnewlins = 0; tnewlins = 0;
tbuf = NULL; tbuf = NULL;
tptr = jbuf; tptr = jbuf;
tlim = tptr + JOBTEXTSIZE - 1; tlim = tptr + JOBTEXTSIZE - 1;
tindent = 1; tindent = 1;
gettext2(n); tjob = 1;
gettext2(&s);
*tptr = '\0'; *tptr = '\0';
untokenize(jbuf); untokenize(jbuf);
return jbuf; return jbuf;
} }
#define gt2(X) gettext2((struct node *) (X))
/* /*
"gettext2" or "type checking and how to avoid it" * gettext2() shows one way to walk through the word code without
an epic function by Paul Falstad * recursion. We start by reading a word code and executing the
*/ * action for it. Some codes have sub-structures (like, e.g. WC_FOR)
* and require something to be done after the sub-structure has been
* handled. For these codes a tstack structure which describes what
* has to be done is pushed onto a stack. Codes without sub-structures
* arrange for the next structure being taken from the stack so that
* the action for it is executed instead of the one for the next
* word code. If the stack is empty at this point, we have handled
* the whole structure we were called for.
*/
#define _Cond(X) ((Cond) (X)) typedef struct tstack *Tstack;
#define _Cmd(X) ((Cmd) (X))
#define _Pline(X) ((Pline) (X)) struct tstack {
#define _Sublist(X) ((Sublist) (X)) Tstack prev;
#define _List(X) ((List) (X)) wordcode code;
#define _casecmd(X) ((struct casecmd *) (X)) int pop;
#define _ifcmd(X) ((struct ifcmd *) (X)) union {
#define _whilecmd(X) ((struct whilecmd *) (X)) struct {
LinkList list;
} _redir;
struct {
char *strs;
Wordcode end;
} _funcdef;
struct {
Wordcode end;
} _case;
struct {
int cond;
Wordcode end;
} _if;
struct {
int par;
} _cond;
struct {
Wordcode end;
} _subsh;
} u;
};
static Tstack tstack, tfree;
static Tstack
tpush(wordcode code, int pop)
{
Tstack s;
if ((s = tfree))
tfree = s->prev;
else
s = (Tstack) zalloc(sizeof(*s));
s->prev = tstack;
tstack = s;
s->code = code;
s->pop = pop;
return s;
}
/**/ /**/
static void static void
gettext2(struct node *n) gettext2(Estate state)
{ {
Cmd nn; Tstack s, n;
int stack = 0;
wordcode code;
if (!n || ((List) n) == &dummy_list) while (1) {
return; if (stack) {
switch (NT_TYPE(n->ntype)) { if (!(s = tstack))
case N_LIST: return;
gt2(_List(n)->left); if (s->pop) {
if (_List(n)->type & Z_ASYNC) { tstack = s->prev;
taddstr(" &"); s->prev = tfree;
if (_List(n)->type & Z_DISOWN) tfree = s;
taddstr("|"); }
code = s->code;
stack = 0;
} else {
s = NULL;
code = *state->pc++;
} }
simplifyright(_List(n)); switch (wc_code(code)) {
if (_List(n)->right) { case WC_LIST:
if (tnewlins) if (!s) {
taddnl(); s = tpush(code, (WC_LIST_TYPE(code) & Z_END));
else stack = 0;
taddstr((_List(n)->type & Z_ASYNC) ? " " : "; ");
gt2(_List(n)->right);
}
break;
case N_SUBLIST:
if (_Sublist(n)->flags & PFLAG_NOT)
taddstr("! ");
if (_Sublist(n)->flags & PFLAG_COPROC)
taddstr("coproc ");
gt2(_Sublist(n)->left);
if (_Sublist(n)->right) {
taddstr((_Sublist(n)->type == ORNEXT) ? " || " : " && ");
gt2(_Sublist(n)->right);
}
break;
case N_PLINE:
gt2(_Pline(n)->left);
if (_Pline(n)->type == PIPE) {
taddstr(" | ");
gt2(_Pline(n)->right);
}
break;
case N_CMD:
nn = _Cmd(n);
switch (nn->type) {
case SIMPLE:
getsimptext(nn);
break;
case SUBSH:
taddstr("( ");
tindent++;
gt2(nn->u.list);
tindent--;
taddstr(" )");
break;
case ZCTIME:
taddstr("time ");
tindent++;
gt2(nn->u.pline);
tindent--;
break;
case FUNCDEF:
taddlist(nn->args);
taddstr(" () {");
tindent++;
taddnl();
gt2(nn->u.list);
tindent--;
taddnl();
taddstr("}");
break;
case CURSH:
taddstr("{ ");
tindent++;
gt2(nn->u.list);
tindent--;
taddstr(" }");
break;
case CFOR:
case CSELECT:
taddstr((nn->type == CFOR) ? "for " : "select ");
if (nn->u.forcmd->condition) {
taddstr("((");
taddstr(nn->u.forcmd->name);
taddstr("; ");
taddstr(nn->u.forcmd->condition);
taddstr("; ");
taddstr(nn->u.forcmd->advance);
taddstr(")) do");
} else { } else {
taddstr(nn->u.forcmd->name); if (WC_LIST_TYPE(code) & Z_ASYNC) {
if (nn->u.forcmd->inflag) { taddstr(" &");
taddstr(" in "); if (WC_LIST_TYPE(code) & Z_DISOWN)
taddlist(nn->args); taddstr("|");
} }
if (!(stack = (WC_LIST_TYPE(code) & Z_END))) {
if (tnewlins)
taddnl();
else
taddstr((WC_LIST_TYPE(code) & Z_ASYNC) ? " " : "; ");
s->code = *state->pc++;
s->pop = (WC_LIST_TYPE(s->code) & Z_END);
}
}
if (!stack && (WC_LIST_TYPE(s->code) & Z_SIMPLE))
state->pc++;
break;
case WC_SUBLIST:
if (!s) {
if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT)
taddstr("! ");
if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_COPROC)
taddstr("coproc ");
s = tpush(code, (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END));
} else {
if (!(stack = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END))) {
taddstr((WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) ?
" || " : " && ");
s->code = *state->pc++;
s->pop = (WC_SUBLIST_TYPE(s->code) == WC_SUBLIST_END);
if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT)
taddstr("! ");
if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_COPROC)
taddstr("coproc ");
}
}
if (!stack && (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_SIMPLE))
state->pc++;
break;
case WC_PIPE:
if (!s) {
tpush(code, (WC_PIPE_TYPE(code) == WC_PIPE_END));
if (WC_PIPE_TYPE(code) == WC_PIPE_MID)
state->pc++;
} else {
if (!(stack = (WC_PIPE_TYPE(code) == WC_PIPE_END))) {
taddstr(" | ");
s->code = *state->pc++;
if (!(s->pop = (WC_PIPE_TYPE(s->code) == WC_PIPE_END)))
state->pc++;
}
}
break;
case WC_REDIR:
if (!s) {
state->pc--;
n = tpush(code, 1);
n->u._redir.list = ecgetredirs(state);
} else {
getredirs(s->u._redir.list);
stack = 1;
}
break;
case WC_ASSIGN:
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddchr('=');
if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) {
taddchr('(');
taddlist(state, WC_ASSIGN_NUM(code));
taddstr(") ");
} else {
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddchr(' ');
}
break;
case WC_SIMPLE:
taddlist(state, WC_SIMPLE_ARGC(code));
stack = 1;
break;
case WC_SUBSH:
if (!s) {
taddstr("( ");
tindent++;
n = tpush(code, 1);
n->u._subsh.end = state->pc + WC_SUBSH_SKIP(code);
} else {
state->pc = s->u._subsh.end;
tindent--;
taddstr(" )");
stack = 1;
}
break;
case WC_CURSH:
if (!s) {
taddstr("{ ");
tindent++;
n = tpush(code, 1);
n->u._subsh.end = state->pc + WC_CURSH_SKIP(code);
} else {
state->pc = s->u._subsh.end;
tindent--;
taddstr(" }");
stack = 1;
}
break;
case WC_TIMED:
if (!s) {
taddstr("time");
if (WC_TIMED_TYPE(code) == WC_TIMED_PIPE) {
taddchr(' ');
tindent++;
tpush(code, 1);
} else
stack = 1;
} else {
tindent--;
stack = 1;
}
break;
case WC_FUNCDEF:
if (!s) {
Wordcode p = state->pc;
Wordcode end = p + WC_FUNCDEF_SKIP(code);
taddlist(state, *state->pc++);
if (tjob) {
taddstr(" () { ... }");
state->pc = end;
stack = 1;
} else {
taddstr(" () {");
tindent++;
taddnl();
n = tpush(code, 1);
n->u._funcdef.strs = state->strs;
n->u._funcdef.end = end;
state->strs += *state->pc;
state->pc += 3;
}
} else {
state->strs = s->u._funcdef.strs;
state->pc = s->u._funcdef.end;
tindent--;
taddnl();
taddstr("}");
stack = 1;
}
break;
case WC_FOR:
if (!s) {
taddstr("for ");
if (WC_FOR_TYPE(code) == WC_FOR_COND) {
taddstr("((");
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr("; ");
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr("; ");
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr(")) do");
} else {
taddstr(ecgetstr(state, EC_NODUP, NULL));
if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
taddstr(" in ");
taddlist(state, *state->pc++);
}
taddnl();
taddstr("do");
}
tindent++;
taddnl();
tpush(code, 1);
} else {
tindent--;
taddnl();
taddstr("done");
stack = 1;
}
break;
case WC_SELECT:
if (!s) {
taddstr("select ");
taddstr(ecgetstr(state, EC_NODUP, NULL));
if (WC_SELECT_TYPE(code) == WC_SELECT_LIST) {
taddstr(" in ");
taddlist(state, *state->pc++);
}
tindent++;
taddnl();
tpush(code, 1);
} else {
tindent--;
taddnl();
taddstr("done");
stack = 1;
}
break;
case WC_WHILE:
if (!s) {
taddstr(WC_WHILE_TYPE(code) == WC_WHILE_UNTIL ?
"until " : "while ");
tindent++;
tpush(code, 0);
} else if (!s->pop) {
tindent--;
taddnl(); taddnl();
taddstr("do"); taddstr("do");
tindent++;
taddnl();
s->pop = 1;
} else {
tindent--;
taddnl();
taddstr("done");
stack = 1;
} }
tindent++;
taddnl();
gt2(nn->u.forcmd->list);
tindent--;
taddnl();
taddstr("done");
break; break;
case CIF: case WC_REPEAT:
gt2(nn->u.ifcmd); if (!s) {
taddstr("fi"); taddstr("repeat ");
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddnl();
taddstr("do");
tindent++;
taddnl();
tpush(code, 1);
} else {
tindent--;
taddnl();
taddstr("done");
stack = 1;
}
break; break;
case CCASE: case WC_CASE:
gt2(nn->u.casecmd); if (!s) {
break; Wordcode end = state->pc + WC_CASE_SKIP(code);
case COND:
taddstr("[[ ");
gt2(nn->u.cond);
taddstr(" ]]");
break;
case CARITH:
taddstr("((");
taddlist(nn->args);
taddstr("))");
break;
case CREPEAT:
taddstr("repeat ");
taddlist(nn->args);
taddnl();
taddstr("do");
tindent++;
taddnl();
gt2(nn->u.list);
tindent--;
taddnl();
taddstr("done");
break;
case CWHILE:
gt2(nn->u.whilecmd);
break;
}
getredirs(nn);
break;
case N_COND:
getcond(_Cond(n), 0);
break;
case N_CASE:
{
List *l;
char **p;
l = _casecmd(n)->lists; taddstr("case ");
p = _casecmd(n)->pats; taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr(" in");
taddstr("case "); if (state->pc >= end) {
taddstr(*p++); if (tnewlins)
taddstr(" in"); taddnl();
tindent++; else
for (; *l; p++, l++) { taddchr(' ');
taddstr("esac");
stack = 1;
} else {
tindent++;
if (tnewlins)
taddnl();
else
taddchr(' ');
code = *state->pc++;
taddstr(ecgetstr(state, EC_NODUP, NULL));
state->pc++;
taddstr(") ");
tindent++;
n = tpush(code, 0);
n->u._case.end = end;
n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end);
}
} else if (state->pc < s->u._case.end) {
tindent--;
taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
if (tnewlins) if (tnewlins)
taddnl(); taddnl();
else else
taddchr(' '); taddchr(' ');
taddstr(*p + 1); code = *state->pc++;
taddstr(ecgetstr(state, EC_NODUP, NULL));
state->pc++;
taddstr(") "); taddstr(") ");
tindent++; tindent++;
gt2(*l); s->code = code;
s->pop = ((state->pc - 2 + WC_CASE_SKIP(code)) >=
s->u._case.end);
} else {
tindent--; tindent--;
taddstr(" ;"); taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
taddchr(**p); tindent--;
if (tnewlins)
taddnl();
else
taddchr(' ');
taddstr("esac");
stack = 1;
} }
tindent--;
if (tnewlins)
taddnl();
else
taddchr(' ');
taddstr("esac");
break; break;
} case WC_IF:
case N_IF: if (!s) {
{ Wordcode end = state->pc + WC_IF_SKIP(code);
List *i, *t;
taddstr("if "); taddstr("if ");
for (i = _ifcmd(n)->ifls, t = _ifcmd(n)->thenls; *i; i++, t++) {
tindent++; tindent++;
gt2(*i); state->pc++;
n = tpush(code, 0);
n->u._if.end = end;
n->u._if.cond = 1;
} else if (s->pop) {
stack = 1;
} else if (s->u._if.cond) {
tindent--; tindent--;
taddnl(); taddnl();
taddstr("then"); taddstr("then");
tindent++; tindent++;
taddnl(); taddnl();
gt2(*t); s->u._if.cond = 0;
} else if (state->pc < s->u._if.end) {
tindent--; tindent--;
taddnl(); taddnl();
if (i[1]) { code = *state->pc++;
if (WC_IF_TYPE(code) == WC_IF_ELIF) {
taddstr("elif "); taddstr("elif ");
tindent++;
s->u._if.cond = 1;
} else {
taddstr("else");
tindent++;
taddnl();
} }
} } else {
if (*t) { s->pop = 1;
taddstr("else");
tindent++;
taddnl();
gt2(*t);
tindent--; tindent--;
taddnl(); taddnl();
taddstr("fi");
stack = 1;
} }
break; break;
} case WC_COND:
case N_WHILE: {
taddstr((_whilecmd(n)->cond) ? "until " : "while "); static char *c1[] = {
tindent++; "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
gt2(_whilecmd(n)->cont); "-ne", "-lt", "-gt", "-le", "-ge"
tindent--; };
taddnl();
taddstr("do");
tindent++;
taddnl();
gt2(_whilecmd(n)->loop);
tindent--;
taddnl();
taddstr("done");
break;
}
}
/* Print a condition bracketed by [[ ... ]]. * int ctype;
* With addpar non-zero, parenthesise the subexpression. */
/**/ if (!s) {
static void taddstr("[[ ");
getcond(Cond nm, int addpar) n = tpush(code, 1);
{ n->u._cond.par = 2;
static char *c1[] = } else if (s->u._cond.par == 2) {
{ taddstr(" ]]");
"=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq", stack = 1;
"-ne", "-lt", "-gt", "-le", "-ge" break;
}; } else if (s->u._cond.par == 1) {
taddstr(" )");
stack = 1;
break;
} else if (WC_COND_TYPE(s->code) == COND_AND) {
taddstr(" && ");
code = *state->pc++;
if (WC_COND_TYPE(code) == COND_OR) {
taddstr("( ");
n = tpush(code, 1);
n->u._cond.par = 1;
}
} else if (WC_COND_TYPE(s->code) == COND_OR) {
taddstr(" || ");
code = *state->pc++;
if (WC_COND_TYPE(code) == COND_AND) {
taddstr("( ");
n = tpush(code, 1);
n->u._cond.par = 1;
}
}
while (!stack) {
switch ((ctype = WC_COND_TYPE(code))) {
case COND_NOT:
taddstr("! ");
code = *state->pc++;
if (WC_COND_TYPE(code) <= COND_OR) {
taddstr("( ");
n = tpush(code, 1);
n->u._cond.par = 1;
}
break;
case COND_AND:
n = tpush(code, 1);
n->u._cond.par = 0;
code = *state->pc++;
if (WC_COND_TYPE(code) == COND_OR) {
taddstr("( ");
n = tpush(code, 1);
n->u._cond.par = 1;
}
break;
case COND_OR:
n = tpush(code, 1);
n->u._cond.par = 0;
code = *state->pc++;
if (WC_COND_TYPE(code) == COND_AND) {
taddstr("( ");
n = tpush(code, 1);
n->u._cond.par = 1;
}
break;
case COND_MOD:
taddstr(ecgetstr(state, EC_NODUP, NULL));
taddchr(' ');
taddlist(state, WC_COND_SKIP(code));
stack = 1;
break;
case COND_MODI:
{
char *name = ecgetstr(state, EC_NODUP, NULL);
if (addpar) taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr("( "); taddchr(' ');
switch (nm->type) { taddstr(name);
case COND_NOT: taddchr(' ');
taddstr("! "); taddstr(ecgetstr(state, EC_NODUP, NULL));
getcond(nm->left, _Cond(nm->left)->type <= COND_OR); stack = 1;
break; }
case COND_AND: break;
getcond(nm->left, _Cond(nm->left)->type == COND_OR); default:
taddstr(" && "); if (ctype <= COND_GE) {
getcond(nm->right, _Cond(nm->right)->type == COND_OR); /* Binary test: `a = b' etc. */
break; taddstr(ecgetstr(state, EC_NODUP, NULL));
case COND_OR: taddstr(" ");
/* This is deliberately over-generous with parentheses: * taddstr(c1[ctype - COND_STREQ]);
* in fact omitting them gives correct precedence. */ taddstr(" ");
getcond(nm->left, _Cond(nm->left)->type == COND_AND); taddstr(ecgetstr(state, EC_NODUP, NULL));
taddstr(" || "); if (ctype == COND_STREQ ||
getcond(nm->right, _Cond(nm->right)->type == COND_AND); ctype == COND_STRNEQ)
break; state->pc++;
default: } else {
if (nm->type <= COND_GE) { /* Unary test: `-f foo' etc. */
/* Binary test: `a = b' etc. */ char c2[4];
taddstr(nm->left);
taddstr(" ");
taddstr(c1[nm->type - COND_STREQ]);
taddstr(" ");
taddstr(nm->right);
} else {
/* Unary test: `-f foo' etc. */
char c2[4];
c2[0] = '-'; c2[0] = '-';
c2[1] = nm->type; c2[1] = ctype;
c2[2] = ' '; c2[2] = ' ';
c2[3] = '\0'; c2[3] = '\0';
taddstr(c2); taddstr(c2);
taddstr(nm->left); taddstr(ecgetstr(state, EC_NODUP, NULL));
} }
break; stack = 1;
} break;
if (addpar) }
taddstr(" )"); }
} }
break;
/**/ case WC_ARITH:
static void taddstr("((");
getsimptext(Cmd cmd) taddstr(ecgetstr(state, EC_NODUP, NULL));
{ taddstr("))");
LinkNode n; stack = 1;
break;
for (n = firstnode(cmd->vars); n; incnode(n)) { case WC_END:
struct varasg *v = (struct varasg *)getdata(n); stack = 1;
break;
taddstr(v->name); default:
taddchr('='); DPUTS(1, "unknown word code in gettext2()");
if (PM_TYPE(v->type) == PM_ARRAY) { return;
taddchr('(');
taddlist(v->arr);
taddstr(") ");
} else {
taddstr(v->str);
taddchr(' ');
} }
} }
taddlist(cmd->args);
} }
/**/ /**/
void void
getredirs(Cmd cmd) getredirs(LinkList redirs)
{ {
LinkNode n; LinkNode n;
static char *fstr[] = static char *fstr[] =
@ -468,10 +721,9 @@ getredirs(Cmd cmd)
">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<", ">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">" "<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
}; };
taddchr(' '); taddchr(' ');
for (n = firstnode(cmd->redir); n; incnode(n)) { for (n = firstnode(redirs); n; incnode(n)) {
struct redir *f = (struct redir *)getdata(n); Redir f = (Redir) getdata(n);
switch (f->type) { switch (f->type) {
case WRITE: case WRITE:
@ -493,7 +745,12 @@ getredirs(Cmd cmd)
taddchr('0' + f->fd1); taddchr('0' + f->fd1);
taddstr(fstr[f->type]); taddstr(fstr[f->type]);
taddchr(' '); taddchr(' ');
taddstr(f->name); if (f->type == HERESTR) {
taddchr('\'');
taddstr(bslashquote(f->name, NULL, 1));
taddchr('\'');
} else
taddstr(f->name);
taddchr(' '); taddchr(' ');
break; break;
#ifdef DEBUG #ifdef DEBUG
@ -509,18 +766,3 @@ getredirs(Cmd cmd)
} }
tptr--; tptr--;
} }
/**/
static void
taddlist(LinkList l)
{
LinkNode n;
if (!(n = firstnode(l)))
return;
for (; n; incnode(n)) {
taddstr(getdata(n));
taddchr(' ');
}
tptr--;
}

964
Src/zsh.h

File diff suppressed because it is too large Load diff

View file

@ -11,10 +11,11 @@
touch unmodified touch unmodified
touch zerolength touch zerolength
chgrp $EGID zerolength
print 'Garbuglio' >nonzerolength print 'Garbuglio' >nonzerolength
touch modish mkdir modish
chmod g+s modish chmod g+xs modish
chmod u+s modish chmod u+s modish
chmod +t modish chmod +t modish
@ -26,7 +27,11 @@
0:-a cond 0:-a cond
# Find a block special file system. This is a little tricky. # Find a block special file system. This is a little tricky.
block=$(df / | tail -1 | awk '{ print $1 }') && block=$(df / | awk '
$NF == "/" {print $1}
$1 == "/" && substr($2,0,1) == "(" {
if((l = index($2,")") - 2) < 0) l = length($2) - 1;
print substr($2,2,l)}') &&
[[ -b $block && ! -b zerolength ]] [[ -b $block && ! -b zerolength ]]
0:-b cond 0:-b cond
@ -61,7 +66,11 @@
[[ -o rcs && ! -o norcs && -o noerrexit && ! -o errexit ]] [[ -o rcs && ! -o norcs && -o noerrexit && ! -o errexit ]]
0:-o cond 0:-o cond
mknod pipe p if whence mkfifo >/dev/null; then
mkfifo pipe
else
mknod pipe p
fi
[[ -p pipe && ! -p zerolength ]] [[ -p pipe && ! -p zerolength ]]
0:-p cond 0:-p cond
@ -76,7 +85,7 @@
[[ -u modish && ! -u zerolength ]] [[ -u modish && ! -u zerolength ]]
0:-u cond 0:-u cond
[[ -x $ZTST_testdir/ztst.zsh && ! -x zerolength ]] [[ -x $ZTST_srcdir/ztst.zsh && ! -x zerolength ]]
0:-x cond 0:-x cond
[[ -z $bar && -z '' && ! -z $foo ]] [[ -z $bar && -z '' && ! -z $foo ]]
@ -89,8 +98,6 @@
[[ -O zerolength ]] [[ -O zerolength ]]
0:-O cond 0:-O cond
# there may be strange cases where this doesn't work, e.g.
# inherited funny groups for directories via setgid.
[[ -G zerolength ]] [[ -G zerolength ]]
0:-G cond 0:-G cond
@ -132,4 +139,16 @@
0:|| and && in conds 0:|| and && in conds
[[ -e /dev/fd/0 ]] [[ -e /dev/fd/0 ]]
0:/dev/fd support in conds 0:/dev/fd support in conds handled by access
[[ -O /dev/fd/0 ]]
0:/dev/fd support in conds handled by stat
[[ ( -z foo && -z foo ) || -z foo ]]
1:complex conds with skipping
[ '' != bar -a '' = '' ]
0:strings with `[' builtin
[ `echo 0` -lt `echo 1` ]
0:substituion in `[' builtin

View file

@ -1,8 +1,22 @@
# Tests for globbing # Tests for globbing
%prep %prep
mkdir glob.tmp
mkdir glob.tmp/dir1
mkdir glob.tmp/dir2
: >glob.tmp/{,{dir1,dir2}/}{a,b,c}
globtest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/../Misc/$1 } globtest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/../Misc/$1 }
regress_absolute_path_and_core_dump() {
local absolute_dir=$(cd glob.tmp && pwd -P)
[[ -n $absolute_dir ]] || return 1
setopt localoptions extendedglob nullglob
print $absolute_dir/**/*~/*
setopt nonullglob nomatch
print glob.tmp/**/*~(.)#
}
%test %test
globtest globtests globtest globtests
@ -234,3 +248,8 @@
>0: [[ FOO = @(bar|(#i)foo) ]] >0: [[ FOO = @(bar|(#i)foo) ]]
>0: [[ Modules = (#i)*m* ]] >0: [[ Modules = (#i)*m* ]]
>0 tests failed. >0 tests failed.
( regress_absolute_path_and_core_dump )
0:exclusions regression test
>
>glob.tmp/a glob.tmp/b glob.tmp/c glob.tmp/dir1 glob.tmp/dir1/a glob.tmp/dir1/b glob.tmp/dir1/c glob.tmp/dir2 glob.tmp/dir2/a glob.tmp/dir2/b glob.tmp/dir2/c

View file

@ -1,7 +1,10 @@
# Tests for completion system. # Tests for completion system.
%prep %prep
zmodload -i zsh/zpty
TERM=vt100
export ZTST_testdir ZTST_srcdir TERM
comptest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/comptest -z $ZTST_testdir/../Src/zsh -d $ZTST_testdir/compdump.tmp "$@" } comptest () { $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/comptest -z $ZTST_testdir/../Src/zsh -d $ZTST_testdir/compdump.tmp "$@" }
mkdir comp.tmp mkdir comp.tmp
@ -104,11 +107,11 @@
>DESCRIPTION:{desc1} >DESCRIPTION:{desc1}
>NO:{arg1} >NO:{arg1}
# code='compdef _tst tst; _tst () { _arguments "-\+[opt]" }' code='compdef _tst tst; _tst () { _arguments "-\+[opt]" }'
# comptest -c "$code" $'tst -\C-D' comptest -c "$code" $'tst -\C-D'
#0:_arguments 0:_arguments
#>DESCRIPTION:{option} >DESCRIPTION:{option}
#>NO:{-+ -- opt} >NO:{-+ -- opt}
code='compdef _tst tst; _tst () { _arguments "1:desc1:(arg1)" }' code='compdef _tst tst; _tst () { _arguments "1:desc1:(arg1)" }'
comptest -c "$code" $'tst \t' comptest -c "$code" $'tst \t'