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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

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

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

View File

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

View File

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

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

1868
Src/exec.c

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

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

964
Src/zsh.h

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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