1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-06-16 20:58:05 +02:00

zsh-3.1.5-pws-1

This commit is contained in:
Tanaka Akira 1999-04-15 18:06:33 +00:00
parent 32c2ebbaa5
commit a61dc2074a
44 changed files with 4986 additions and 1444 deletions

View file

@ -56,6 +56,8 @@ EXELDFLAGS = @EXELDFLAGS@
LIBS = @LIBS@
DL_EXT = @DL_EXT@
DLLD = @DLLD@
EXPOPT = @EXPOPT@
IMPOPT = @IMPOPT@
# utilities
AWK = @AWK@

View file

@ -10,6 +10,7 @@ list(tt(compctl) [ tt(-CDT) ] var(options) \
[ tt(-x) var(pattern) var(options) tt(-) ... tt(--) ] \
[ tt(PLUS()) var(options) [ tt(-x) ... tt(--) ] ... [tt(PLUS())] ] \
[ var(command) ... ])
list(tt(compctl) tt(-M) var(match-specs) ...)
list(tt(compctl) tt(-L) [ tt(-CDT) ] [ var(command) ... ])
list(tt(compctl) tt(PLUS()) var(command) ...)
endlist()
@ -28,6 +29,7 @@ menu(Command Flags)
menu(Option Flags)
menu(Alternative Completion)
menu(Extended Completion)
menu(Matching Control)
menu(Example)
endmenu()
texinode(Command Flags)(Option Flags)()(Programmable Completion)
@ -44,7 +46,19 @@ item(var(command) ...)(
controls completion for the named commands, which must be listed last
on the command line. If completion is attempted for a command with a
pathname containing slashes and no completion definition is found, the
search is retried with the last pathname component. Note that aliases
search is retried with the last pathname component. If the command starts
with a tt(=), completion is tried with the pathname of the command.
The strings may also be patterns (i.e. they may contain an unquoted
occurrence of characters used to form patterns in the shell). When
completion is attempted, the shell first tries all such pattern compctls.
If one matches the command name on the line or if the pathname of the
command on the line matches a pattern, it is used. The patterns are tested
in reverse order, i.e. the pattern compctl defined last overrides all
previously defined pattern compctls. Unless the option list of that compctl
contains an tt(-t) flag with a \tt(c) character, no more compctls are tried.
Note that aliases
are expanded before the command name is determined unless the
tt(COMPLETE_ALIASES) option is set. Commands should not be combined
with the tt(-C), tt(-D) or tt(-T) flags.
@ -63,7 +77,7 @@ been issued, filenames are completed.
item(tt(-T))(
supplies completion flags to be used before any other processing is
done, even those given to specific commands with other compctl
definitions. This is only useful when combined with extended
definitions. This is especially useful when combined with extended
completion (the tt(-x) flag, see noderef(Extended Completion) below).
Using this flag you can define default behavior
which will apply to all commands without exception, or you can alter
@ -95,6 +109,9 @@ If the tt(PLUS()) flag is alone and followed immediately by the var(command)
list, the completion behavior for all the commands in the list is reset to
the default. In other words, completion will subsequently use the
options specified by the tt(-D) flag.
The form with tt(-M) as the first and only option defines global
matching specifications described below in noderef(Matching Control).
texinode(Option Flags)(Alternative Completion)(Command Flags)(Programmable Completion)
sect(Option Flags)
startlist()
@ -106,6 +123,8 @@ list([ tt(-Q) ] [ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ])
list([ tt(-W) var(file-prefix) ])
list([ tt(-q) ] [ tt(-X) var(explanation) ] [ tt(-Y) var(explanation) ])
list([ tt(-y) var(func-or-var) ] [ tt(-l) var(cmd) ] [ tt(-U) ])
list([ tt(-t) var(continue) ] [ tt(-J) var(name) ] [ tt(-V) var(name) ])
list([ tt(-M) var(match-spec) ])
endlist()
The remaining var(options) specify the type of command arguments
@ -256,7 +275,7 @@ passed two arguments: the prefix and the suffix of the word on which
completion is to be attempted, in other words those characters before
the cursor position, and those from the cursor position onwards. The
whole command line can be accessed with the tt(-c) and tt(-l) flags
of the tt(read) builtin. The
of the tt(read) builtin. The
function should set the variable tt(reply) to an array containing
the completions (one completion per element); note that tt(reply)
should not be made local to the function. From such a function the
@ -322,6 +341,9 @@ nofill(tt(compctl -/ -W ~/Mail maildirs))
completes any subdirectories to any depth beneath the directory
tt(~/Mail), although that prefix does not appear on the command line.
The var(suffix) may also be of the form accepted by the tt(-k) flag, i.e.
the name of an array or a literal list in parenthesis. In this cases all
words are used as prefixes.
)
item(tt(-q))(
If used with a suffix as specified by the tt(-S) option, this
@ -331,7 +353,7 @@ tt(AUTO_REMOVE_SLASH) option). The option is most useful for list
separators (comma, colon, etc.).
)
item(tt(-l) var(cmd))(
This option cannot be combined with any other. It restricts the range
This option restricts the range
of command line words that are considered to be arguments. If
combined with one of the extended completion patterns `tt(p[)...tt(])',
`tt(r[)...tt(])', or `tt(R[)...tt(])' (see noderef(Extended Completion)
@ -355,7 +377,10 @@ will be deleted. This is most useful with a function (given by the
tt(-K) option) which can examine the word components passed to it
(or via the tt(read) builtin's tt(-c) and tt(-l) flags) and
use its own criteria to decide what matches. If there is no
completion, the original word is retained.
completion, the original word is retained. Since the produced
possible completions seldom seldom have interesting common prefixes
and suffixes, menucompletion is started immediatly if tt(AUTO_MENU) is
set and this flag is used.
)
item(tt(-y) var(func-or-var))(
The list provided by var(func-or-var) is displayed instead of the list
@ -382,6 +407,8 @@ Print var(explanation) when trying completion on the current set of
options. A `tt(%n)' in this string is replaced by the number of matches.
The explanation only appears if completion was tried and there was
no unique match, or when listing completions.
The sequences tt(%B), tt(%b), tt(%S), tt(%s), tt(%U), and tt(%u) specify
output attributes (bold, standout, and underline) as in prompts.
)
item(tt(-Y) var(explanation))(
Identical to tt(-X), except that the var(explanation) first undergoes
@ -389,6 +416,37 @@ expansion following the usual rules for strings in double quotes.
The expansion will be carried out after any functions are called for
the tt(-K) or tt(-y) options, allowing them to set variables.
)
item(tt(-J))(
This gives the name of the group the matches should be placed in. Groups
are listed and sorted separately. Also, menucompletion will offer the matches
in the groups in the order, in which the groups were defined. If no group
name is explicitly given, the matches are stored in a group named var(default).
The first time a group name is encountered, a group with that name is created.
After that all matches with the same group name are stored in that group.
)
item(tt(-V))(
Like tt(-J), but the matches in the group will not be sorted in the listing and
with menucompletion. These unsorted groups are in a different name space than
the sorted ones. I.e. it is possible to have a sorted and a unsorted group
with the same name and the matches in those groups will not be mixed.
)
item(tt(-t) var(continue))(
The var(continue)-string contains a set of characters that specify if
and when completion should continue to produce matches where it normally
would not do that. The character tt(c) means that completion continues
with the next suitable compctl (i.e. if you don't specify this in a
tt(compctl -T), compctls for commands are never used). The character
tt(PLUS()) is used to continue with the matches for the next alternative
completion (see below). The characters tt(-) and tt(x) may be used in
sub-lists for extended completion (see below). They will make the completion
code use the flag list after the next tt(-) (if the corresponding pattern
matches) and the default flag list (those before the tt(-x)), respectively.
)
item(tt(-M) var(match-spec))(
This defines additional matching control specifications that should be used
only when testing words for the list of flags this flag appears in. The format
of the var(match-spec) string is described below in noderef(Matching Control).
)
enditem()
texinode(Alternative Completion)(Extended Completion)(Option Flags)(Programmable Completion)
sect(Alternative Completion)
@ -402,7 +460,9 @@ tried with the options before the first `tt(PLUS())'. If this produces no
matches completion is tried with the flags after the `tt(PLUS())' and so on. If
there are no flags after the last `tt(PLUS())' and a match has not been found
up to that point, default completion is tried.
texinode(Extended Completion)(Example)(Alternative Completion)(Programmable Completion)
If the list of flags contains a tt(-t) with a tt(PLUS()) character, the next
list of flags is used even if the current list produced matches.
texinode(Extended Completion)(Matching Control)(Alternative Completion)(Programmable Completion)
sect(Extended Completion)
startlist()
list(tt(compctl) [ tt(-CDT) ] var(options) \
@ -498,13 +558,187 @@ var(max) inclusive.
item(tt(r[)var(str1)tt(,)var(str2)tt(])...)(
Matches if the cursor is after a word with prefix var(str1). If there
is also a word with prefix var(str2) on the command line it matches
only if the cursor is before this word.
only if the cursor is before this word. If the comma and var(str2) are
omitted, it matches if the cursor is after a word with prefix var(str1).
)
item(tt(R[)var(str1)tt(,)var(str2)tt(])...)(
Like tt(r) but using pattern matching instead.
)
enditem()
texinode(Example)()(Extended Completion)(Programmable Completion)
texinode(Matching Control)(Example)(Extended Completion)(Programmable Completion)
sect(Matching Control)
Matching specifications are used to describe that certain strings
on the command line match possibly different strings in the words produced
by the completion code.
Matching specification strings consist of one or more matching
descriptions separated by whitespace. Each description consists of
a letter followed by a colon and the patterns describing which character
sequences on the line match which character sequences in the words.
The letters understood are: tt(l), tt(r), tt(m), tt(L), tt(R), and tt(M).
startitem()
item(tt(m) and tt(M))(
These describe patterns that match anywhere in the words. The colon should
be followed by two patterns separated by an equal sign. The pattern on the
left side describes the substrings that are to be matched on the command line,
the pattern on the right side describes the substrings matched in the word.
)
item(tt(l) and tt(L))(
These letters are for patterns that are anchored by another pattern on
the left side. In this case the colon has to be followed by the pattern
for the anchor, a pipe symbol, the pattern for the command line, an equal
sign, and the pattern for the word. Patterns anchored on the left side match
only if the anchor-pattern matches directly before the line pattern and if
the string in the word before the word pattern matches the string before
the line pattern in the line string.
)
item(tt(r) and tt(R))(
Like tt(l) and tt(L) with the difference that the line and word patterns
are anchored on the right side. Also, here the pattern for the anchor has
to come after the pattern for the line, again separated by a pipe symbol.
)
enditem()
Each pattern is either an empty string or consists of a sequence of
character (possibly quoted), question marks, character classes, and
correspondence classes. Normal characters match only themselves, question
marks match any character, and character classes are formed as for
globbing and match the same characters as there.
Correspondence classes are formed like character classes with two
differences: they are delimited by a pair of braces and negated
classes are not allowed (i.e. the characters tt(!) and tt(^) have no
special meaning directly after the opening brace).
Correspondence classes are used to conveniently describe that several
characters on the line match several other characters in the word. For
example, if you want to define the any lowercase letter on the line
matches the corresponding uppercase letter in the word all you need to
write down is: `tt(m:{a-z}={A-Z})'. More than one correspondence class
may be given on either side of the equal sign, in this case the first
class on the left says which character matches for the first class on
the right, the second class on either side work together, and so on.
If one side has more such classes than the other side, the superfluous
classes behave like normal character classes. In anchor patterns
correspondence classes always behave like normal character classes.
The word pattern may also be a single star (tt(*)). This means that
the line pattern matches any number of characters in the word. In this
case the pattern has to be anchored (on any side) and the line pattern
matches all characters in the word up to a character sequence that
matches the anchor.
For anchors the empty string as a pattern has a special meaning. Such
empty anchors match only the beginning (in the case of an left side
anchor) or end (for right side anchors) of the command line string or
word.
The distinction between the lowercase and the uppercase forms of the
specification characters is used to define which matched substring
should be put in the match and the generated command line. The
lowercase forms use the substring from the word, so this should be
used if the exact words produced by the completion code need to be
used. The uppercase forms use the substring from the command line and
should be used if the typed string need to be retained.
Examples:
startitem()
The option tt(-o) produces option names in all-lowercase form, without
underscores, and without the optional tt(no) at the beginning even
though the buitlins tt(setopt) and tt(unsetopt) understand opotion
names with uppercase letters, underscores, and the optional tt(no).
So we want to be able to say, that in this case an prefix tt(no) and
any underscore may be ignored when trying to match the produced words,
and that uppercase letters on the line match the corresponding
lowercase letters in the words. This can be done with:
indent(
tt(compctl -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o setopt unsetopt)
)
The first part says that the pattern `tt([nN][oO])' at the beginning
(note the empty anchor before the pipe symbol) of the string on the
line matches the the empty string in the produced words, i.e. it need
not be there. The second part says that an underscore anywhere on the
line need not be present in the word, and the third part uses
correspondence classes as in the example above to say that any
uppercase letter on the line matches the corresponding lowercase
letter in the word. The use of the uppercase forms of the
specification characters (tt(L) and tt(M)) guarantees that the special
wrinting on the command line (and especially the option tt(no)) will
not be erased.
As a second example we will make completion case insensitive. For this
we use the form of tt(compctl) that defines matching specification that
are to be used everywhere, i.e. a tt(compctl) with tt(-M) as the only
option given.
The pattern needed was already explained above, this gives us:
indent(
tt(compctl -M 'm:{a-z}={A-Z}')
)
This makes lowercase letters match their uppercase counterparts. If we
want to make uppercase letters match the lowercase forms, we would
have to use:
indent(
tt(compctl -M 'm:{a-z}={A-Z} m:{A-Z}={a-z}')
)
A nice example for the use of tt(*) patterns is partial word
completion. Sometimes you would like to make strings like tt(c.s.u)
complete to strings like tt(comp.source.unix), i.e. you consider the
word to consist of multiple parts (separated by the dot in the
example) and each part should be completed separately. Defining such
forms of matching is simple, for example if we want to separately
complete word parts separated by dots, commas, underscores, and
hyphens, we can do this by saying:
indent(
tt(compctl -M 'r:|[.,_-]=* r:|=*')
)
The first specification says that an empty string on the line before
one of our special characters matches any number of characters in the
word which has the effect we wanted. The second specification is
needed to make this work when the cursor is in the middle of the word
and the option tt(COMPLETE_IN_WORD) is set. In this case the
completion code would normally try to match word that end with the
string that is already on the command line, but in our example we
would like the code to match words even if they contain extra
characters after the string on the line. Hence we say that the empty
string at the end of the string on the line matches any characters at
the end of the word.
The form of tt(compctl) that defines the global matching
specifications is a bit more powerful than described until now. It
accepts not only one specification strin, but any number of them. When
completion is attempted, the code first uses the definitions from the
first string. If no words could be matched with these specifications,
it tries the whole thing again with the specifications from the second
string, and so on. This allows one to define simple and fast matches
to be used first, more powerful matchers as a second choice, and so on.
As an example we would like to make the code match words that contain
the string on the line as a substring (anywhere, not just at the
beginning). But since this could produce more matches than we want,
this should be tried only if the matchers described above don't
produce any matches. E.g.:
indent(
tt(compctl -M 'r:|[.,_-]=* r:|=*' 'l:|=* r:|=*')
)
If using the first specification string does not produce matches, the
second one is tried. The two descriptions it this string say that the
empty string at the beginning and end of the string on the line
matches any characters at the beginning or end of the word.
enditem()
texinode(Example)()(Matching Control)(Programmable Completion)
sect(Example)
nofill(tt(compctl -u -x 's[tt(PLUS())] c[-1,-f],s[-f+PLUS()]' -g '~/Mail/*(:t)' \
- 's[-f],c[-1,-f]' -f -- mail))

View file

@ -777,6 +777,9 @@ Matches the enclosed pattern. This is used for grouping.
If the tt(KSH_GLOB) option is set, then a
`tt(@)', `tt(*)', `tt(+)', `tt(?)' or `tt(!)' immediately preceding
the `tt(LPAR())' is treated specially, as detailed below.
Note that grouping cannot currently extend over multiple directories:
a `tt(/)' separating a directory terminates processing of the current
group; processing resumes after the end of the group.
)
item(var(x)tt(|)var(y))(
Matches either var(x) or var(y).
@ -840,6 +843,43 @@ Match anything but the expression in parentheses.
(Like `tt(LPAR()^LPAR())...tt(RPAR()RPAR())'.)
)
enditem()
subsect(Globbing Flags)
There are various flags which affect any text to their right up to the
end of the enclosing group or to the end of the pattern; they require
the tt(EXTENDED_GLOB) option. All take the form
tt(LPAR()#)var(X)tt(RPAR()) where var(X) may be one of the following
characters:
startitem()
item(i)(
Case insensitive: upper or lower case characters in the pattern match
upper or lower case characters.
)
item(l)(
Lower case characters in the pattern match upper or lower case
characters; upper case characters in the pattern still only match
upper case characters.
)
item(I)(
Case sensitive: locally negates the effect of tt(i) or tt(l) from
that point on.
)
enditem()
For example, the test string tt(fooxx) can be matched by the pattern
tt(LPAR()#i)tt(RPAR()FOOXX), but not by tt(LPAR()#l)tt(RPAR()FOOXX),
tt(LPAR()#i)tt(RPAR()FOO)tt(LPAR()#I)tt(RPAR()XX) or
tt(LPAR()LPAR()#i)tt(RPAR()FOOX)tt(RPAR()X).
When using the ksh syntax for grouping both tt(KSH_GLOB) and
tt(EXTENDED_GLOB) must be set and the left parenthesis should be
preceded by tt(@). Note also that the flags do not affect letters
inside tt([...]) groups, in other words tt(LPAR()#i)tt(RPAR()[a-z])
still matches only lowercase letters. Finally, note that when
examining whole paths case-insensitively every directory must be
searched for all files which match, so that a pattern of the form
tt(LPAR()#i)tt(RPAR()/foo/bar/...) is potentially slow.
subsect(Recursive Globbing)
A pathname component of the form `tt(LPAR())var(foo)tt(/RPAR()#)'
matches a path consisting of zero or more directories

View file

@ -157,6 +157,7 @@ xitem(tt(zle) tt(-l) [ tt(-L) ])
xitem(tt(zle) tt(-D) var(widget) ...)
xitem(tt(zle) tt(-A) var(old-widget) var(new-widget))
xitem(tt(zle) tt(-N) var(widget) [ var(function) ])
xitem(tt(zle) tt(-C) [ tt(-mMgG) ] var(widget) [ var(compctl-options) ])
item(tt(zle) var(widget))(
The tt(zle) builtin performs a number of different actions concerning
ZLE. Which operation it performs depends on its options:
@ -184,6 +185,23 @@ widget is invoked from within the editor, the specified shell var(function)
is called. If no function name is specified, it defaults to
the same name as the widget.
)
item(tt(-C) [ tt(-mMgG) ] var(widget) [ var(compctl-options) ])(
Create a user-defined widget which will perform completion according
to var(compctl-options). These are passed directly to the
tt(compctl) command, see
ifzman(zmanref(zshcompctl))\
ifnzman(noderef(Programmable Completion))\
; no command names or special options (tt(-LDCT)) may be used. If the
var(compctl-options) are missing the widget will have normal
completion behaviour as modified by the tt(zle) options.
There are four additional tt(zle) options, which must precede the
widget name: tt(-m) and tt(-M) force the widget to use or not to use
menu completion, respectively, while tt(-g) and tt(-G) likewise force
the widget to use or not to use glob completion. The defaults are to
use the current settings of tt(MENU_COMPLETE) and tt(GLOB_COMPLETE)
as with normal completion.
)
item(var(widget))(
Invoke the specified widget. This can only be done when ZLE is
active; normally this will be within a user-defined widget.

View file

@ -103,5 +103,14 @@ t :] [:]]#
t [ [[]
t ] []]
t [] [^]]]
t fooxx (#i)FOOXX
f fooxx (#l)FOOXX
t FOOXX (#l)fooxx
f fooxx (#i)FOO(#I)X(#i)X
t fooXx (#i)FOO(#I)X(#i)X
t fooxx ((#i)FOOX)x
f fooxx ((#i)FOOX)X
f BAR (bar|(#i)foo)
t FOO (bar|(#i)foo)
EOT
print "$failed tests failed."

View file

@ -1,6 +1,6 @@
#!/usr/local/bin/zsh -f
setopt kshglob
setopt kshglob extendedglob
failed=0
while read res str pat; do
@ -87,5 +87,14 @@ t zoox @(!(z*)|*x)
t foo *(!(foo))
f foob !(foo)b*
t foobb !(foo)b*
t fooxx (#i)FOOXX
f fooxx (#l)FOOXX
t FOOXX (#l)fooxx
f fooxx (#i)FOO@(#I)X@(#i)X
t fooXx (#i)FOO@(#I)X@(#i)X
t fooxx @((#i)FOOX)x
f fooxx @((#i)FOOX)X
f BAR @(bar|(#i)foo)
t FOO @(bar|(#i)foo)
EOT
print "$failed tests failed."

View file

@ -9,6 +9,7 @@
# Runs as a filter. Should ignore anything which isn't a "complete".
# It expects each "complete" statement to be the first thing on a line.
# All the examples in the tcsh manual give sensible results.
# Author: Peter Stephenson <pws@ibmth.df.unipi.it>
#
# Option:
# -x (exact): only applies in the case of command disambiguation (is
@ -38,6 +39,11 @@
# (5) Make sure all command names with wildcards are processed together --
# they need to be lumped into one "compctl -C" or "compctl -D"
# statement for zsh.
# (6) Group completion (complete's g flag) is not built into zsh, so
# you need perl to be available to generate the groups. If this
# script is useful, I assume that's not a problem.
# (7) I don't know what `completing completions' means, so the X
# flag to complete is not handled.
# Handle options
if (@ARGV) {
@ -113,6 +119,13 @@ sub gettype {
# Nothing (n) can be handled by returning nothing. (C.f. King Lear, I.i.)
if ($c =~ /[abcjuv]/) {
$ret = "-$c";
} elsif ($c eq 'C') {
if (defined($glob)) {
$ret = "-W $glob -/g '*(.*)'";
undef($glob);
} else {
$ret = '-c';
}
} elsif ($c eq 'S') {
$ret = '-k signals';
} elsif ($c eq 'd') {
@ -121,18 +134,42 @@ sub gettype {
} else {
$ret = '-/';
}
} elsif ($c eq 'D') {
if (defined($glob)) {
$ret = "-W $glob -/";
undef($glob);
} else {
$ret = '-/';
}
} elsif ($c eq 'e') {
$ret = '-E';
} elsif ($c eq 'f' && !$glob) {
$ret = '-f';
} elsif ($c eq 'F') {
if (defined($glob)) {
$ret = "-W $glob -f";
undef($glob);
} else {
$ret = '-f';
}
} elsif ($c eq 'g') {
$ret = "-s '\$(perl -e '\\''while ((\$name) = getgrent)\n" .
"{ print \$name, \"\\n\"; }'\\'')'";
} elsif ($c eq 'l') {
$ret = q!-k "(`limit | awk '{print $1}'`)"!;
} elsif ($c eq 'p') {
$ret = "-W $glob -f", undef($glob) if defined($glob);
$ret = "-W $glob -f", undef($glob) if defined($glob);
} elsif ($c eq 's') {
$ret = '-p';
$ret = '-p';
} elsif ($c eq 't') {
$qual = '.';
} elsif ($c eq 'T') {
if (defined($glob)) {
$ret = "-W $glob -g '*(.)'";
undef($glob);
} else {
$ret = "-g '*(.)'";
}
} elsif ($c eq 'x') {
$glob =~ s/'/'\\''/g;
$ret = "-X '$glob'";
@ -190,7 +227,7 @@ $" = " - ";
while (<>) {
if (/^\s*complete\s/) {
undef(@stuff);
undef(@stuff);
$default = '';
$_ = $';
while (/\\$/) {
@ -211,7 +248,7 @@ while (<>) {
# Loop over remaining arguments to "complete".
$sep = substr($word,1,1);
$sep =~ s/(\W)/\\$1/g;
@split = split(/$sep/,$word);
@split = split(/$sep/,$word,4);
for ($i = 0; $i < 3; $i++) {
while ($split[$i] =~ /\\$/) {
substr($split[$i],-1,1) = "";
@ -225,7 +262,9 @@ while (<>) {
# The "complete" catch-all: treat this as compctl\'s
# default (requiring no pattern matching).
$default .= &gettype($type) . ' ';
defined($suffix) && ($defsuf .= $suffix);
defined($suffix) &&
(defined($defsuf) ? ($defsuf .= $suffix)
: ($defsuf = $suffix));
} else {
$pat = &getpat($pat,$arg);
$type = &gettype($type);

5
Src/.lastloc Normal file
View file

@ -0,0 +1,5 @@
(("/home/user2/pws/src/zsh-3.1.5/Src/glob.c" . 15475)
("/home/user2/pws/src/zsh-3.1.5/Src/zsh.export" . 794)
("/home/user2/pws/src/zsh-3.1.5/Src/utils.c" . 10946)
("/home/user2/pws/src/zsh-3.1.5/Src/Makefile" . 4282)
("/home/user2/pws/src/zsh-3.1.5/Src/mkmakemod.sh" . 6832))

View file

@ -55,12 +55,17 @@ NLIST = `cat stamp-modobjs`
LIBZSH = libzsh-$(VERSION).$(DL_EXT)
NIBZSH =
ZSH_EXPORT = $(EXPOPT)$(sdir)/zsh.export
ZSH_NXPORT =
ENTRYOBJ = modentry..o
NNTRYOBJ =
LDRUNPATH = LD_RUN_PATH=$(libdir)/zsh
NDRUNPATH =
zsh: $(@L@IBZSH) $(@L@STMP) $(MAIN_OBJS)
rm -f $@
$(@L@DRUNPATH) $(LINK) $(MAIN_OBJS) $(@L@LIST) $(@L@IBZSH) $(LIBS)
$(@L@DRUNPATH) $(LINK) $(MAIN_OBJS) $(@L@LIST) $(ZSH_@E@XPORT) $(@L@IBZSH) $(LIBS)
$(LIBZSH): $(LIBOBJS) $(NSTMP)
rm -f $@
@ -114,6 +119,11 @@ modules-bltin:
echo > $@; \
fi
modules: $(@E@NTRYOBJ)
$(ENTRYOBJ): FORCE
@$(MAKE) -f Makemod $(MAKEDEFS) $@
# ========== ANSI TO K&R CONVERSION ==========
ANSI_KNR = ansi2knr

View file

@ -85,6 +85,7 @@ statmodeprint(mode_t mode, char *outbuf, int flags)
for (i = 1; i <= 9; i++)
pm[i] = (mode & *mfp++) ? modes[i] : '-';
pm[10] = '\0';
if (mode & S_ISUID)
pm[3] = (mode & S_IXUSR) ? 's' : 'S';

10
Src/Zle/.lastloc Normal file
View file

@ -0,0 +1,10 @@
(("/home/user2/pws/src/zsh-3.1.5/Src/Zle/zle.h" . 2619)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/zle.export" . 35)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/zle_main.c" . 13806)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/iwidgets.list" . 7831)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/comp.h" . 8512)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/zle_tricky.c" . 72920)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/comp1.c" . 9640)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/zle_vi.c" . 16035)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/zle_utils.c" . 8406)
("/home/user2/pws/src/zsh-3.1.5/Src/Zle/comp1.export" . 81))

View file

@ -32,6 +32,11 @@
typedef struct compctlp *Compctlp;
typedef struct compctl *Compctl;
typedef struct compcond *Compcond;
typedef struct patcomp *Patcomp;
typedef struct cmatcher *Cmatcher;
typedef struct cmlist *Cmlist;
typedef struct cpattern *Cpattern;
typedef struct cline *Cline;
/* node for compctl hash table (compctltab) */
@ -42,6 +47,14 @@ struct compctlp {
Compctl cc; /* pointer to the compctl desc. */
};
/* for the list of pattern compctls */
struct patcomp {
Patcomp next;
char *pat;
Compctl cc;
};
/* compctl -x condition */
struct compcond {
@ -85,7 +98,7 @@ struct compcond {
struct compctl {
int refc; /* reference count */
Compctl next; /* next compctl for -x */
unsigned long mask; /* mask of things to complete (CC_*) */
unsigned long mask, mask2; /* mask of things to complete (CC_*) */
char *keyvar; /* for -k (variable) */
char *glob; /* for -g (globbing) */
char *str; /* for -s (expansion) */
@ -97,12 +110,15 @@ struct compctl {
char *withd; /* for -w (with directory */
char *hpat; /* for -H (history pattern) */
int hnum; /* for -H (number of events to search) */
char *gname;
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) */
Cmatcher matcher; /* matcher control (-M) */
char *mstr; /* matcher string */
};
/* objects to complete */
/* objects to complete (mask) */
#define CC_FILES (1<<0)
#define CC_COMMPATH (1<<1)
#define CC_REMOVE (1<<2)
@ -135,3 +151,120 @@ struct compctl {
#define CC_EXPANDEXPL (1<<30)
#define CC_RESERVED (1<<31)
/* objects to complete (mask2) */
#define CC_NOSORT (1<<0)
#define CC_XORCONT (1<<1)
#define CC_CCCONT (1<<2)
#define CC_PATCONT (1<<3)
#define CC_DEFCONT (1<<4)
typedef struct cexpl *Cexpl;
typedef struct cmgroup *Cmgroup;
typedef struct cmatch *Cmatch;
/* This is for explantion strings. */
struct cexpl {
char *str; /* the string */
int count; /* the number of matches */
int fcount; /* number of matches with fignore ignored */
};
/* This describes a group of matches. */
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 */
char **ylist; /* things to list */
int ecount; /* number of explanation string */
Cexpl *expls; /* explanation strings */
int ccount; /* number of compctls used */
Compctl *ccs; /* the 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 */
};
#define CGF_NOSORT 1 /* don't sort this group */
#define CGF_LINES 2 /* these are to be printed on different lines */
/* 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 *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 */
int flags; /* see CMF_* below */
int brpl; /* the place where to put the brace prefix */
int brsl; /* ...and the suffix */
};
#define CMF_FILE 1 /* this is a file */
#define CMF_REMOVE 2 /* remove the suffix */
#define CMF_PARBR 4 /* paramter expansion with a brace */
#define CMF_NOLIST 8 /* should not be listed */
/* 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 {
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 */
};
struct cline {
Cline next; /* next chunk */
char *line; /* string to insert if !word */
int llen; /* length of line */
char *word; /* prefered string to insert */
int wlen; /* length of word */
Cmatcher matcher; /* which matcher was used */
int flags; /* see CLF_* below */
};
#define CLF_END 1
#define CLF_MID 2
#define CLF_MISS 4
#define CLF_DIFF 8
#define CLF_SUF 16

View file

@ -31,16 +31,34 @@
#include "comp1.pro"
/* default completion infos */
/* Default completion infos */
/**/
struct compctl cc_compos, cc_default, cc_first, cc_dummy;
/* hash table for completion info for commands */
/* Global matcher. */
/**/
Cmlist cmatcher;
/* pointers to functions required by zle */
/**/
void (*printcompctlptr) _((char *, Compctl, int));
/**/
Compctl (*compctl_widgetptr) _((char *, char **));
/* Hash table for completion info for commands */
/**/
HashTable compctltab;
/* List of pattern compctls */
/**/
Patcomp patcomps;
/* Words on the command line, for use in completion */
/**/
@ -54,6 +72,16 @@ char **clwords;
/**/
int incompctlfunc;
/* This variable and the functions rembslash() and quotename() came from *
* zle_tricky.c, but are now used in compctl.c, too. */
/* 1 if we are completing in a string */
/**/
int instring;
/**/
static void
createcompctltable(void)
@ -71,6 +99,8 @@ createcompctltable(void)
compctltab->enablenode = NULL;
compctltab->freenode = freecompctlp;
compctltab->printnode = NULL;
patcomps = NULL;
}
/**/
@ -103,6 +133,7 @@ freecompctl(Compctl cc)
zsfree(cc->prefix);
zsfree(cc->suffix);
zsfree(cc->hpat);
zsfree(cc->gname);
zsfree(cc->subcmd);
if (cc->cond)
freecompcond(cc->cond);
@ -119,6 +150,9 @@ freecompctl(Compctl cc)
}
if (cc->xor && cc->xor != &cc_default)
freecompctl(cc->xor);
if (cc->matcher)
freecmatcher(cc->matcher);
zsfree(cc->mstr);
zfree(cc, sizeof(struct compctl));
}
@ -166,6 +200,56 @@ freecompcond(void *a)
}
}
/**/
void
freecmlist(Cmlist l)
{
Cmlist n;
while (l) {
n = l->next;
freecmatcher(l->matcher);
zsfree(l->str);
zfree(l, sizeof(struct cmlist));
l = n;
}
}
/**/
void
freecmatcher(Cmatcher m)
{
Cmatcher n;
while (m) {
n = m->next;
freecpattern(m->line);
freecpattern(m->word);
freecpattern(m->left);
freecpattern(m->right);
zfree(m, sizeof(struct cmatcher));
m = n;
}
}
/**/
void
freecpattern(Cpattern p)
{
Cpattern n;
while (p) {
n = p->next;
zfree(p, sizeof(struct cpattern));
p = n;
}
}
/**/
int
compctlread(char *name, char **args, char *ops, char *reply)
@ -261,6 +345,89 @@ compctlread(char *name, char **args, char *ops, char *reply)
return 0;
}
/* Copy the given string and remove backslashes from the copy and return it. */
/**/
char *
rembslash(char *s)
{
char *t = s = dupstring(s);
while (*s)
if (*s == '\\') {
chuck(s);
if (*s)
s++;
} else
s++;
return t;
}
/* Quote the string s and return the result. If e is non-zero, the *
* pointer it points to may point to a position in s and in e the position *
* of the corresponding character in the quoted string is returned. Like *
* e, te may point to a position in the string and pl is used to return *
* the position of the character pointed to by te in the quoted string. *
* The string is metafied and may contain tokens. */
/**/
char *
quotename(const char *s, char **e, char *te, int *pl)
{
const char *u, *tt;
char *v, buf[PATH_MAX * 2];
int sf = 0;
tt = v = buf;
u = s;
for (; *u; u++) {
if (e && *e == u)
*e = v, sf |= 1;
if (te == u)
*pl = v - tt, sf |= 2;
if (ispecial(*u) &&
(!instring || (isset(BANGHIST) &&
*u == (char)bangchar) ||
(instring == 2 &&
(*u == '$' || *u == '`' || *u == '\"')) ||
(instring == 1 && *u == '\''))) {
if (*u == '\n' || (instring == 1 && *u == '\'')) {
if (unset(RCQUOTES)) {
*v++ = '\'';
if (*u == '\'')
*v++ = '\\';
*v++ = *u;
*v++ = '\'';
} else if (*u == '\n')
*v++ = '"', *v++ = '\n', *v++ = '"';
else
*v++ = '\'', *v++ = '\'';
continue;
} else
*v++ = '\\';
}
if(*u == Meta)
*v++ = *u++;
*v++ = *u;
}
*v = '\0';
if (strcmp(buf, s))
tt = dupstring(buf);
else
tt = s;
v += tt - buf;
if (e && (sf & 1))
*e += tt - buf;
if (e && *e == u)
*e = v;
if (te == u)
*pl = v - tt;
return (char *) tt;
}
/**/
int
boot_comp1(Module m)
@ -269,10 +436,13 @@ boot_comp1(Module m)
clwords = (char **) zcalloc((clwsize = 16) * sizeof(char *));
createcompctltable();
cc_compos.mask = CC_COMMPATH;
cc_compos.mask2 = 0;
cc_default.refc = 10000;
cc_default.mask = CC_FILES;
cc_default.mask2 = 0;
cc_first.refc = 10000;
cc_first.mask = 0;
cc_first.mask2 = CC_CCCONT;
return 0;
}

22
Src/Zle/comp1.export Normal file
View file

@ -0,0 +1,22 @@
#!
cc_compos
cc_default
cc_dummy
cc_first
clwnum
clwords
clwpos
clwsize
cmatcher
compctl_widgetptr
compctltab
freecmatcher
freecmlist
freecompcond
freecompctl
incompctlfunc
instring
patcomps
printcompctlptr
quotename
rembslash

View file

@ -1,3 +1,5 @@
hasexport=1
objects="comp1.o"
headers="comp.h"

View file

@ -29,6 +29,9 @@
#include "compctl.mdh"
#include "compctl.pro"
#define GLOBAL_PROTOTYPES
#include "zle_tricky.pro"
#undef GLOBAL_PROTOTYPES
#define COMP_LIST (1<<0) /* -L */
#define COMP_COMMAND (1<<1) /* -C */
@ -44,6 +47,328 @@ static int cclist;
/* Mask for determining what to print */
static unsigned long showmask = 0;
/* This is a special return value for parse_cmatcher(), *
* signalling an error. */
#define pcm_err ((Cmatcher) 1)
/* 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. */
/**/
static Cmatcher
cpcmatcher(Cmatcher m)
{
Cmatcher r = NULL, *p = &r, n;
while (m) {
*p = n = (Cmatcher) zalloc(sizeof(struct cmatcher));
n->next = NULL;
n->flags = m->flags;
n->line = cpcpattern(m->line);
n->llen = m->llen;
n->word = cpcpattern(m->word);
n->wlen = m->wlen;
n->left = cpcpattern(m->left);
n->lalen = m->lalen;
n->right = cpcpattern(m->right);
n->ralen = m->ralen;
p = &(n->next);
m = m->next;
}
return r;
}
/* Copy a completion matcher pattern. */
/**/
static Cpattern
cpcpattern(Cpattern o)
{
Cpattern r = NULL, *p = &r, n;
while (o) {
*p = n = (Cpattern) zalloc(sizeof(struct cpattern));
n->next = NULL;
memcpy(n->tab, o->tab, 256);
n->equiv = o->equiv;
p = &(n->next);
o = o->next;
}
return r;
}
/* Try to get the global matcher from the given compctl. */
/**/
static int
get_gmatcher(char *name, char **argv)
{
if (!strcmp(*argv, "-M")) {
char **p = ++argv;
Cmlist l = NULL, *q = &l, n;
Cmatcher m;
while (*p) {
if (**p++ == '-')
return 0;
}
while (*argv) {
if ((m = parse_cmatcher(name, *argv)) == pcm_err)
return 2;
*q = n = (Cmlist) halloc(sizeof(struct cmlist));
n->next = NULL;
n->matcher = m;
n->str = *argv++;
q = &(n->next);
}
freecmlist(cmatcher);
PERMALLOC {
cmatcher = cpcmlist(l);
} LASTALLOC;
return 1;
}
return 0;
}
/* This prints the global matcher definitions. */
/**/
static void
print_gmatcher(int ac)
{
Cmlist p;
if ((p = cmatcher)) {
printf((ac ? "compctl -M" : "MATCH"));
while (p) {
printf(" \'%s\'", p->str);
p = p->next;
}
putchar('\n');
}
}
/* Parse a string for matcher control, containing multiple matchers. */
/**/
static Cmatcher
parse_cmatcher(char *name, char *s)
{
Cmatcher ret = NULL, r, n;
Cpattern line, word, left, right;
int fl, ll, wl, lal, ral, err;
if (!*s)
return NULL;
while (*s) {
while (*s && inblank(*s)) s++;
if (!*s) break;
switch (*s) {
case 'l': fl = CMF_LEFT; break;
case 'r': fl = CMF_RIGHT; break;
case 'm': fl = 0; break;
case 'L': fl = CMF_LEFT | CMF_LINE; break;
case 'R': fl = CMF_RIGHT | CMF_LINE; break;
case 'M': fl = CMF_LINE; break;
default:
zwarnnam(name, "unknown match specification character `%c'", NULL, *s);
return pcm_err;
}
if (s[1] != ':') {
zwarnnam(name, "missing `:'", NULL, 0);
return pcm_err;
}
s += 2;
if (!*s) {
zwarnnam(name, "missing patterns", NULL, 0);
return pcm_err;
}
if (fl & CMF_LEFT) {
left = parse_pattern(name, &s, &lal, '|', &err);
if (err)
return pcm_err;
if (!*s || !*++s) {
zwarnnam(name, "missing line pattern", NULL, 0);
return pcm_err;
}
} else
left = NULL;
line = parse_pattern(name, &s, &ll, ((fl & CMF_RIGHT) ? '|' : '='),
&err);
if (err)
return pcm_err;
if (!*s || !*++s) {
zwarnnam(name, ((fl & CMF_RIGHT) ? "missing right anchor" : "missing word pattern"), NULL, 0);
return pcm_err;
}
if (fl & CMF_RIGHT) {
right = parse_pattern(name, &s, &ral, '=', &err);
if (err)
return pcm_err;
if (!*s || !*++s) {
zwarnnam(name, "missing word pattern", NULL, 0);
return pcm_err;
}
} else
right = NULL;
if (*s == '*') {
if (!(fl & (CMF_LEFT | CMF_RIGHT))) {
zwarnnam(name, "need anchor for `*'", NULL, 0);
return pcm_err;
}
word = NULL;
wl = -1;
s++;
} else {
word = parse_pattern(name, &s, &wl, 0, &err);
if (!word && !line) {
zwarnnam(name, "need non-empty word or line pattern", NULL, 0);
return pcm_err;
}
}
if (err)
return pcm_err;
n = (Cmatcher) zcalloc(sizeof(*ret));
n->next = NULL;
n->flags = fl;
n->line = line;
n->llen = ll;
n->word = word;
n->wlen = wl;
n->left = left;
n->lalen = lal;
n->right = right;
n->ralen = ral;
if (ret) r->next = n;
else ret = n;
r = n;
}
return ret;
}
/* Parse a pattern for matcher control. */
/**/
static Cpattern
parse_pattern(char *name, char **sp, int *lp, char e, int *err)
{
Cpattern ret = NULL, r, n;
unsigned char *s = (unsigned char *) *sp;
int l = 0;
*err = 0;
while (*s && (e ? (*s != e) : !inblank(*s))) {
n = (Cpattern) hcalloc(sizeof(*n));
n->next = NULL;
n->equiv = 0;
if (*s == '[') {
s = parse_class(n, s + 1, ']');
if (!*s) {
*err = 1;
zwarnnam(name, "unterminated character class", NULL, 0);
return NULL;
}
} else if (*s == '{') {
n->equiv = 1;
s = parse_class(n, s + 1, '}');
if (!*s) {
*err = 1;
zwarnnam(name, "unterminated character class", NULL, 0);
return NULL;
}
} else if (*s == '?') {
memset(n->tab, 1, 256);
} else if (*s == '*' || *s == '(' || *s == ')' || *s == '=') {
*err = 1;
zwarnnam(name, "invalid pattern character `%c'", NULL, *s);
return NULL;
} else {
if (*s == '\\' && s[1])
s++;
memset(n->tab, 0, 256);
n->tab[*s] = 1;
}
if (ret)
r->next = n;
else
ret = n;
r = n;
l++;
s++;
}
*sp = (char *) s;
*lp = l;
return ret;
}
/* Parse a character class for matcher control. */
/**/
static unsigned char *
parse_class(Cpattern p, unsigned char *s, unsigned char e)
{
int n = 0, i = 1, j, eq = (e == '}'), k = 1;
if (!eq && (*s == '!' || *s == '^') && s[1] != e) { n = 1; s++; }
memset(p->tab, n, 256);
n = !n;
while (*s && (k || *s != e)) {
if (s[1] == '-' && s[2] != e) {
/* a run of characters */
for (j = (int) *s; j <= (int) s[2]; j++)
p->tab[j] = (eq ? i++ : n);
s += 3;
} else
p->tab[*s++] = (eq ? i++ : n);
k = 0;
}
return s;
}
/* Parse the basic flags for `compctl' */
/**/
@ -176,6 +501,44 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
case '/':
cct.mask |= CC_DIRS;
break;
case 't':
{
char *p;
if ((*argv)[1]) {
p = (*argv) + 1;
*argv = "" - 1;
} else if (!argv[1]) {
zwarnnam(name, "retry specification expected after -%c", NULL,
**argv);
return 1;
} else {
p = *++argv;
*argv = "" - 1;
}
while (*p) {
switch (*p) {
case '+':
cct.mask2 |= CC_XORCONT;
break;
case 'c':
cct.mask2 |= CC_CCCONT;
break;
case '-':
cct.mask2 |= CC_PATCONT;
break;
case 'x':
cct.mask2 |= CC_DEFCONT;
break;
default:
zwarnnam(name, "invalid retry specification character `%c'",
NULL, *p);
return 1;
}
p++;
}
}
break;
case 'k':
if ((*argv)[1]) {
cct.keyvar = (*argv) + 1;
@ -307,6 +670,58 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef)
*argv = "" - 1;
}
break;
case 'J':
if ((*argv)[1]) {
cct.gname = (*argv) + 1;
*argv = "" - 1;
} else if (!argv[1]) {
zwarnnam(name, "group name expected after -%c", NULL,
**argv);
return 1;
} else {
cct.gname = *++argv;
*argv = "" - 1;
}
break;
case 'V':
if ((*argv)[1]) {
cct.gname = (*argv) + 1;
*argv = "" - 1;
} else if (!argv[1]) {
zwarnnam(name, "group name expected after -%c", NULL,
**argv);
return 1;
} else {
cct.gname = *++argv;
*argv = "" - 1;
}
cct.mask2 |= CC_NOSORT;
break;
case 'M':
if ((*argv)[1]) {
if ((cct.matcher =
parse_cmatcher(name, (cct.mstr = (*argv) + 1))) ==
pcm_err) {
cct.matcher = NULL;
cct.mstr = NULL;
return 1;
}
*argv = "" - 1;
} else if (!argv[1]) {
zwarnnam(name, "matching specification expected after -%c", NULL,
**argv);
return 1;
} else {
if ((cct.matcher =
parse_cmatcher(name, (cct.mstr = *++argv))) ==
pcm_err) {
cct.matcher = NULL;
cct.mstr = NULL;
return 1;
}
*argv = "" - 1;
}
break;
case 'H':
if ((*argv)[1])
cct.hnum = atoi((*argv) + 1);
@ -600,27 +1015,34 @@ get_xcompctl(char *name, char ***av, Compctl cc, int isdef)
c->u.s.s[l] = ztrdup(tt);
} else if (c->type == CCT_RANGESTR ||
c->type == CCT_RANGEPAT) {
int hc;
/* -r[..,..] or -R[..,..]: two strings expected */
for (; *t && *t != '\201'; t++);
for (; *t && *t != '\201' && *t != '\200'; t++);
if (!*t) {
zwarnnam(name, "error in condition", NULL, 0);
freecompcond(m);
return 1;
}
hc = (*t == '\201');
*t = '\0';
c->u.l.a[l] = ztrdup(tt);
tt = ++t;
/* any more commas are text, not active */
for (; *t && *t != '\200'; t++)
if (*t == '\201')
*t = ',';
if (!*t) {
zwarnnam(name, "error in condition", NULL, 0);
freecompcond(m);
return 1;
if (hc) {
tt = ++t;
/* any more commas are text, not active */
for (; *t && *t != '\200'; t++)
if (*t == '\201')
*t = ',';
if (!*t) {
zwarnnam(name, "error in condition", NULL, 0);
freecompcond(m);
return 1;
}
*t = '\0';
c->u.l.b[l] = ztrdup(tt);
}
*t = '\0';
c->u.l.b[l] = ztrdup(tt);
else
c->u.l.b[l] = NULL;
} else {
/* remaining patterns are number followed by string */
for (; *t && *t != '\200' && *t != '\201'; t++);
@ -700,13 +1122,6 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
/* Copy over the details from the values in cct to those in *ccptr */
Compctl cc;
if (cct->subcmd && (cct->keyvar || cct->glob || cct->str ||
cct->func || cct->explain || cct->ylist ||
cct->prefix)) {
zwarnnam(name, "illegal combination of options", NULL, 0);
return 1;
}
/* Handle assignment of new default or command completion */
if (reass && !(cclist & COMP_LIST)) {
/* if not listing */
@ -746,11 +1161,15 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
zsfree(cc->subcmd);
zsfree(cc->withd);
zsfree(cc->hpat);
zsfree(cc->gname);
zsfree(cc->mstr);
freecmatcher(cc->matcher);
/* and copy over the new stuff, (permanently) allocating
* space for strings.
*/
cc->mask = cct->mask;
cc->mask2 = cct->mask2;
cc->keyvar = ztrdup(cct->keyvar);
cc->glob = ztrdup(cct->glob);
cc->str = ztrdup(cct->str);
@ -761,8 +1180,13 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
cc->suffix = ztrdup(cct->suffix);
cc->subcmd = ztrdup(cct->subcmd);
cc->withd = ztrdup(cct->withd);
cc->gname = ztrdup(cct->gname);
cc->hpat = ztrdup(cct->hpat);
cc->hnum = cct->hnum;
PERMALLOC {
cc->matcher = cpcmatcher(cct->matcher);
} LASTALLOC;
cc->mstr = ztrdup(cct->mstr);
/* careful with extended completion: it's already allocated */
cc->ext = cct->ext;
@ -790,16 +1214,62 @@ cc_reassign(Compctl cc)
cc->ext = cc->xor = NULL;
}
/* Check if the given string is a pattern. If so, return one and tokenize *
* it. If not, we just remove the backslashes. */
static int
compctl_name_pat(char **p)
{
char *s = *p;
tokenize(s = dupstring(s));
remnulargs(s);
if (haswilds(s)) {
*p = s;
return 1;
} else
*p = rembslash(*p);
return 0;
}
/* Delete the pattern compctl with the given name. */
static void
delpatcomp(char *n)
{
Patcomp p, q;
for (q = 0, p = patcomps; p; q = p, p = p->next) {
if (!strcmp(n, p->pat)) {
if (q)
q->next = p->next;
else
patcomps = p->next;
zsfree(p->pat);
freecompctl(p->cc);
free(p);
break;
}
}
}
/**/
static void
compctl_process_cc(char **s, Compctl cc)
{
Compctlp ccp;
char *n;
if (cclist & COMP_REMOVE) {
/* Delete entries for the commands listed */
for (; *s; s++) {
if ((ccp = (Compctlp) compctltab->removenode(compctltab, *s)))
n = *s;
if (compctl_name_pat(&n))
delpatcomp(n);
else if ((ccp = (Compctlp) compctltab->removenode(compctltab, n)))
compctltab->freenode((HashNode) ccp);
}
} else {
@ -807,10 +1277,23 @@ compctl_process_cc(char **s, Compctl cc)
cc->refc = 0;
for (; *s; s++) {
n = *s;
cc->refc++;
ccp = (Compctlp) zalloc(sizeof *ccp);
ccp->cc = cc;
compctltab->addnode(compctltab, ztrdup(*s), ccp);
if (compctl_name_pat(&n)) {
Patcomp pc;
delpatcomp(n);
pc = zalloc(sizeof *pc);
pc->pat = ztrdup(n);
pc->cc = cc;
pc->next = patcomps;
patcomps = pc;
} else {
ccp = (Compctlp) zalloc(sizeof *ccp);
ccp->cc = cc;
compctltab->addnode(compctltab, ztrdup(n), ccp);
}
}
}
}
@ -819,15 +1302,21 @@ compctl_process_cc(char **s, Compctl cc)
/**/
static void
printcompctl(char *s, Compctl cc, int printflags)
printcompctl(char *s, Compctl cc, int printflags, int ispat)
{
Compctl cc2;
char *css = "fcqovbAIFpEjrzBRGudeNOZUnQmw/";
char *mss = " pcCwWsSnNmrR";
unsigned long t = 0x7fffffff;
unsigned long flags = cc->mask;
unsigned long flags = cc->mask, flags2 = cc->mask2;
unsigned long oldshowmask;
/* Printflags is used outside the standard compctl commands*/
if (printflags & PRINT_LIST)
cclist |= COMP_LIST;
else if (printflags & PRINT_TYPE)
cclist &= ~COMP_LIST;
if ((flags & CC_EXCMDS) && !(flags & CC_DISCMDS))
flags &= ~CC_EXCMDS;
@ -851,8 +1340,13 @@ printcompctl(char *s, Compctl cc, int printflags)
printf(" -D");
if (cc == &cc_first)
printf(" -T");
} else if (ispat) {
char *p = dupstring(s);
untokenize(p);
quotedzputs(p, stdout);
} else
quotedzputs(s, stdout);
quotedzputs(quotename(s, NULL, NULL, NULL), stdout);
}
/* loop through flags w/o args that are set, printing them if so */
@ -868,9 +1362,23 @@ printcompctl(char *s, Compctl cc, int printflags)
t >>= 1;
}
}
if (flags2 & (CC_XORCONT | CC_CCCONT | CC_PATCONT | CC_DEFCONT)) {
printf(" -t");
if (flags2 & CC_XORCONT)
putchar('+');
if (flags2 & CC_CCCONT)
putchar('c');
if (flags2 & CC_PATCONT)
putchar('-');
if (flags2 & CC_DEFCONT)
putchar('x');
}
/* now flags with arguments */
flags = cc->mask;
printif(cc->mstr, 'M');
if (flags2 & CC_NOSORT)
printif(cc->gname, 'V');
else
printif(cc->gname, 'J');
printif(cc->keyvar, 'k');
printif(cc->func, 'K');
printif(cc->explain, (cc->mask & CC_EXPANDEXPL) ? 'Y' : 'X');
@ -940,7 +1448,7 @@ printcompctl(char *s, Compctl cc, int printflags)
c = cc2->cond;
cc2->cond = NULL;
/* now print the flags for the current condition */
printcompctl(NULL, cc2, 0);
printcompctl(NULL, cc2, 0, 0);
cc2->cond = c;
if ((cc2 = (Compctl) (cc2->next)))
printf(" -");
@ -952,7 +1460,7 @@ printcompctl(char *s, Compctl cc, int printflags)
/* print xor'd (+) completions */
printf(" +");
if (cc->xor != &cc_default)
printcompctl(NULL, cc->xor, 0);
printcompctl(NULL, cc->xor, 0, 0);
}
if (s) {
if ((cclist & COMP_LIST) && (cc != &cc_compos)
@ -960,7 +1468,17 @@ printcompctl(char *s, Compctl cc, int printflags)
if(s[0] == '-' || s[0] == '+')
printf(" -");
putchar(' ');
quotedzputs(s, stdout);
if (ispat) {
char *p = dupstring(s);
untokenize(p);
quotedzputs(p, stdout);
} else {
char *p = dupstring(s);
untokenize(p);
quotedzputs(quotename(p, NULL, NULL, NULL), stdout);
}
}
putchar('\n');
}
@ -975,7 +1493,7 @@ printcompctlp(HashNode hn, int printflags)
Compctlp ccp = (Compctlp) hn;
/* Function needed for use by scanhashtable() */
printcompctl(ccp->nam, ccp->cc, printflags);
printcompctl(ccp->nam, ccp->cc, printflags, 0);
}
/* Main entry point for the `compctl' builtin */
@ -991,8 +1509,14 @@ bin_compctl(char *name, char **argv, char *ops, int func)
cclist = 0;
showmask = 0;
instring = 0;
/* Parse all the arguments */
if (*argv) {
/* Let's see if this is a global matcher definition. */
if ((ret = get_gmatcher(name, argv)))
return ret - 1;
cc = (Compctl) zcalloc(sizeof(*cc));
if (get_compctl(name, &argv, cc, 1, 0)) {
freecompctl(cc);
@ -1013,10 +1537,16 @@ bin_compctl(char *name, char **argv, char *ops, int func)
* If some flags (other than -C, -T, or -D) were given, then *
* only print compctl containing those flags. */
if (!*argv && !(cclist & COMP_SPECIAL)) {
Patcomp pc;
for (pc = patcomps; pc; pc = pc->next)
printcompctl(pc->pat, pc->cc, 0, 1);
scanhashtable(compctltab, 1, 0, 0, compctltab->printnode, 0);
printcompctl((cclist & COMP_LIST) ? "" : "COMMAND", &cc_compos, 0);
printcompctl((cclist & COMP_LIST) ? "" : "DEFAULT", &cc_default, 0);
printcompctl((cclist & COMP_LIST) ? "" : "FIRST", &cc_first, 0);
printcompctl((cclist & COMP_LIST) ? "" : "COMMAND", &cc_compos, 0, 0);
printcompctl((cclist & COMP_LIST) ? "" : "DEFAULT", &cc_default, 0, 0);
printcompctl((cclist & COMP_LIST) ? "" : "FIRST", &cc_first, 0, 0);
print_gmatcher((cclist & COMP_LIST));
return ret;
}
@ -1024,23 +1554,35 @@ bin_compctl(char *name, char **argv, char *ops, int func)
* or a COMP_SPECIAL flag (-D, -C, -T), so print only those. */
if (cclist & COMP_LIST) {
HashNode hn;
char **ptr;
char **ptr, *n;
showmask = 0;
for (ptr = argv; *ptr; ptr++) {
if ((hn = compctltab->getnode(compctltab, *ptr))) {
n = *ptr;
if (compctl_name_pat(&n)) {
Patcomp pc;
for (pc = patcomps; pc; pc = pc->next)
if (!strcmp(n, pc->pat)) {
printcompctl(pc->pat, pc->cc, 0, 1);
n = NULL;
break;
}
} else if ((hn = compctltab->getnode(compctltab, n))) {
compctltab->printnode(hn, 0);
} else {
zwarnnam(name, "no compctl defined for %s", *ptr, 0);
n = NULL;
}
if (n) {
zwarnnam(name, "no compctl defined for %s", n, 0);
ret = 1;
}
}
if (cclist & COMP_COMMAND)
printcompctl("", &cc_compos, 0);
printcompctl("", &cc_compos, 0, 0);
if (cclist & COMP_DEFAULT)
printcompctl("", &cc_default, 0);
printcompctl("", &cc_default, 0, 0);
if (cclist & COMP_FIRST)
printcompctl("", &cc_first, 0);
printcompctl("", &cc_first, 0, 0);
return ret;
}
@ -1058,6 +1600,38 @@ bin_compctl(char *name, char **argv, char *ops, int func)
return ret;
}
/* Externally callable version of get_compctl. Used for completion widgets */
/**/
static Compctl
compctl_widget(char *name, char **argv)
{
Compctl cc = (Compctl) zcalloc(sizeof(*cc));
cclist = 0;
showmask = 0;
if (get_compctl(name, &argv, cc, 1, 0)) {
freecompctl(cc);
return NULL;
}
if (cclist & COMP_REMOVE) {
zwarnnam(name, "use -D to delete widget", NULL, 0);
return NULL;
} else if (cclist) {
zwarnnam(name, "special options illegal in widget", NULL, 0);
freecompctl(cc);
return NULL;
} else if (*argv) {
zwarnnam(name, "command names illegal in widget", NULL, 0);
freecompctl(cc);
return NULL;
}
cc->refc++;
return cc;
}
static struct builtin bintab[] = {
BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL),
};
@ -1069,6 +1643,8 @@ boot_compctl(Module m)
if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)))
return 1;
compctltab->printnode = printcompctlp;
printcompctlptr = printcompctl;
compctl_widgetptr = compctl_widget;
return 0;
}
@ -1080,6 +1656,8 @@ cleanup_compctl(Module m)
{
compctltab->printnode = NULL;
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
printcompctlptr = NULL;
compctl_widgetptr = NULL;
return 0;
}
#endif

View file

@ -45,7 +45,7 @@ deltochar(void)
if (dest != ll) {
dest++;
if (!n) {
foredel(dest - cs);
forekill(dest - cs, 0);
ok++;
}
}
@ -57,9 +57,13 @@ deltochar(void)
while (n++ && dest != 0) {
while (dest != 0 && line[dest] != c)
dest--;
if (line[dest] == c && !n) {
backdel(cs - dest);
ok++;
if (line[dest] == c) {
if (!n) {
backkill(cs - dest, 1);
ok++;
}
if (dest)
dest--;
}
}
}
@ -71,7 +75,8 @@ deltochar(void)
int
boot_deltochar(Module m)
{
w_deletetochar = addzlefunction("delete-to-char", deltochar, ZLE_KEEPSUFFIX);
w_deletetochar = addzlefunction("delete-to-char", deltochar,
ZLE_KILL | ZLE_KEEPSUFFIX);
if (w_deletetochar)
return 0;
zwarnnam(m->nam, "name clash when adding ZLE function `delete-to-char'",

View file

@ -24,7 +24,7 @@
"beginning-of-line", beginningofline, 0
"beginning-of-line-hist", beginningoflinehist, 0
"capitalize-word", capitalizeword, 0
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"copy-prev-word", copyprevword, 0
"copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX
@ -32,7 +32,7 @@
"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"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
@ -73,7 +73,7 @@
"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
"neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"overwrite-mode", overwritemode, 0
"pound-insert", poundinsert, 0
"push-input", pushinput, 0
@ -95,7 +95,7 @@
"transpose-words", transposewords, 0
"undefined-key", undefinedkey, 0
"undo", undo, 0
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"up-case-word", upcaseword, 0
"up-history", uphistory, 0
"up-line-or-history", uplineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
@ -145,8 +145,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
@ -168,5 +168,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

10
Src/Zle/zle.export Normal file
View file

@ -0,0 +1,10 @@
#!
addzlefunction
backdel
backkill
deletezlefunction
feep
foredel
forekill
getkey
zmod

View file

@ -31,7 +31,7 @@
#undef zleread
#undef spaceinline
#undef gotword
#undef refresh
#undef zrefresh
typedef struct widget *Widget;
typedef struct thingy *Thingy;
@ -46,16 +46,23 @@ struct widget {
union {
ZleIntFunc fn; /* pointer to internally implemented widget */
char *fnnam; /* name of the shell function for user-defined widget */
Compctl cc; /* for use with a WIDGET_COMP widget */
} u;
};
#define WIDGET_INT (1<<0) /* widget is internally implemented */
#define ZLE_MENUCMP (1<<1) /* DON'T invalidate completion list */
#define WIDGET_COMP (1<<1) /* Special completion widget */
#define ZLE_MENUCMP (1<<2) /* DON'T invalidate completion list */
#define ZLE_YANK (1<<3)
#define ZLE_LINEMOVE (1<<4) /* command is a line-oriented movement */
#define ZLE_LASTCOL (1<<5) /* command maintains lastcol correctly */
#define ZLE_KILL (1<<6)
#define ZLE_KEEPSUFFIX (1<<9) /* DON'T remove added suffix */
#define ZLE_USEMENU (1<<10) /* Do ) use menu completion for */
#define ZLE_NOMENU (1<<11) /* Don't ) widget, else use default */
#define ZLE_USEGLOB (1<<12) /* Do ) use glob completion for */
#define ZLE_NOGLOB (1<<13) /* Don't ) widget, else use default */
#define ZLE_NOTCOMMAND (1<<14) /* widget should not alter lastcmd */
/* thingies */

View file

@ -1,3 +1,5 @@
hasexport=1
moddeps="comp1"
autobins="bindkey vared zle"

View file

@ -291,73 +291,86 @@ downhistory(void)
feep();
}
static int histpos, srch_hl, srch_cs = -1;
static char *srch_str;
/**/
void
historysearchbackward(void)
{
int histpos, histmpos, hl = histline;
int hl = histline;
int n = zmult;
char *s;
if (!n)
return;
if (n < 0) {
if (zmult < 0) {
zmult = -n;
historysearchforward();
zmult = n;
return;
}
for (histpos = histmpos = 0; histpos < ll && !iblank(line[histpos]);
histpos++, histmpos++)
if(imeta(line[histpos]))
histmpos++;
if (hl == curhist || hl != srch_hl || cs != srch_cs || mark != 0
|| memcmp(srch_str, line, histpos) != 0) {
zfree(srch_str, histpos);
for (histpos = 0; histpos < ll && !iblank(line[histpos]); histpos++) ;
if (histpos < ll)
histpos++;
srch_str = zalloc(histpos);
memcpy(srch_str, line, histpos);
}
for (;;) {
hl--;
if (!(s = zle_get_event(hl))) {
feep();
return;
}
if (metadiffer(s, (char *) line, histpos) < 0 &&
iblank(s[histmpos] == Meta ? s[histmpos+1]^32 : s[histmpos]) &&
metadiffer(s, (char *) line, ll) && !--n)
break;
if (metadiffer(s, srch_str, histpos) < 0 &&
metadiffer(s, srch_str, ll)) {
if (--n <= 0)
break;
}
}
zle_goto_hist(hl);
srch_hl = hl;
srch_cs = cs;
}
/**/
void
historysearchforward(void)
{
int histpos, histmpos, hl = histline;
int hl = histline;
int n = zmult;
char *s;
if (!n)
return;
if (n < 0) {
if (zmult < 0) {
zmult = -n;
historysearchbackward();
zmult = n;
return;
}
for (histpos = histmpos = 0; histpos < ll && !iblank(line[histpos]);
histpos++, histmpos++)
if(imeta(line[histpos]))
histmpos++;
if (hl == curhist || hl != srch_hl || cs != srch_cs || mark != 0
|| memcmp(srch_str, line, histpos) != 0) {
zfree(srch_str, histpos);
for (histpos = 0; histpos < ll && !iblank(line[histpos]); histpos++) ;
if (histpos < ll)
histpos++;
srch_str = zalloc(histpos);
memcpy(srch_str, line, histpos);
}
for (;;) {
hl++;
if (!(s = zle_get_event(hl))) {
feep();
return;
}
if (metadiffer(s, (char *) line, histpos) < (histline == curhist) &&
(!s[histmpos] ||
iblank(s[histmpos] == Meta ? s[histmpos+1]^32 : s[histmpos])) &&
metadiffer(s, (char *) line, ll) && !--n)
break;
if (metadiffer(s, srch_str, histpos) < (hl == curhist) &&
metadiffer(s, srch_str, ll))
if (--n <= 0)
break;
}
zle_goto_hist(hl);
srch_hl = hl;
srch_cs = cs;
}
/**/
@ -721,7 +734,7 @@ doisearch(int dir)
sbuf[sbptr] = '_';
statusll = sbuf - statusline + sbptr + 1;
ref:
refresh();
zrefresh();
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
int i;
get_isrch_spot(0, &hl, &pos, &i, &sbptr, &dir, &nomatch);
@ -809,7 +822,7 @@ doisearch(int dir)
cmd == Th(z_quotedinsert)) {
if(cmd == Th(z_viquotedinsert)) {
sbuf[sbptr] = '^';
refresh();
zrefresh();
}
if ((c = getkey(0)) == EOF)
feep();
@ -936,7 +949,7 @@ getvisrchstr(void)
while (sptr) {
sbuf[sptr] = '_';
statusll = sptr + 1;
refresh();
zrefresh();
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
ret = 0;
break;
@ -971,7 +984,7 @@ getvisrchstr(void)
} else if(cmd == Th(z_viquotedinsert) || cmd == Th(z_quotedinsert)) {
if(cmd == Th(z_viquotedinsert)) {
sbuf[sptr] = '^';
refresh();
zrefresh();
}
if ((c = getkey(0)) == EOF)
feep();
@ -1030,9 +1043,7 @@ virepeatsearch(void)
feep();
return;
}
if (!n)
return;
if (n < 0) {
if (zmult < 0) {
n = -n;
visrchsense = -visrchsense;
}
@ -1078,9 +1089,7 @@ historybeginningsearchbackward(void)
int n = zmult;
char *s;
if (!n)
return;
if (n < 0) {
if (zmult < 0) {
zmult = -n;
historybeginningsearchforward();
zmult = n;
@ -1114,9 +1123,7 @@ historybeginningsearchforward(void)
int n = zmult;
char *s;
if (!n)
return;
if (n < 0) {
if (zmult < 0) {
zmult = -n;
historybeginningsearchbackward();
zmult = n;

View file

@ -69,6 +69,9 @@ static int baud;
/**/
int lastcmd;
/**/
Widget compwidget;
/* the status line, and its length */
/**/
@ -112,7 +115,7 @@ int feepflag;
/**/
void
setterm(void)
zsetterm(void)
{
struct ttyinfo ti;
@ -362,7 +365,7 @@ getkey(int keytmout)
ret = opts[MONITOR];
opts[MONITOR] = 1;
attachtty(mypgrp);
refresh(); /* kludge! */
zrefresh(); /* kludge! */
opts[MONITOR] = ret;
die = 1;
} else if (errno != 0) {
@ -372,7 +375,7 @@ getkey(int keytmout)
}
}
if (cc == '\r') /* undo the exchange of \n and \r determined by */
cc = '\n'; /* setterm() */
cc = '\n'; /* zsetterm() */
else if (cc == '\n')
cc = '\r';
@ -485,7 +488,7 @@ zleread(char *lp, char *rp, int ha)
initmodifier(&zmod);
prefixflag = 0;
feepflag = 0;
refresh();
zrefresh();
while (!done && !errflag) {
statusline = NULL;
@ -516,11 +519,11 @@ zleread(char *lp, char *rp, int ha)
tv.tv_usec = 500000;
if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
NULL, NULL, &tv) <= 0)
refresh();
zrefresh();
} else
#endif
if (!kungetct)
refresh();
zrefresh();
handlefeep();
}
statusline = NULL;
@ -562,12 +565,17 @@ execzlefunc(Thingy func)
showmsg(msg);
zsfree(msg);
feep();
} else if((w = func->widget)->flags & WIDGET_INT) {
} else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_COMP)) {
int wflags = w->flags;
if(!(wflags & ZLE_KEEPSUFFIX))
removesuffix();
if(!(wflags & ZLE_MENUCMP)) {
if(!(wflags & ZLE_MENUCMP) ||
((wflags & WIDGET_COMP) && compwidget != w)) {
/* If we are doing a special completion, and the widget
* is not the one currently in use for special completion,
* we are starting a new completion.
*/
fixsuffix();
invalidatelist();
}
@ -575,8 +583,13 @@ execzlefunc(Thingy func)
vilinerange = 1;
if(!(wflags & ZLE_LASTCOL))
lastcol = -1;
w->u.fn();
lastcmd = wflags;
if (wflags & WIDGET_COMP) {
compwidget = w;
completespecial();
} else
w->u.fn();
if (!(wflags & ZLE_NOTCOMMAND))
lastcmd = wflags;
} else {
List l = getshfunc(w->u.fnnam);
@ -743,7 +756,7 @@ describekeybriefly(void)
return;
statusline = "Describe key briefly: _";
statusll = strlen(statusline);
refresh();
zrefresh();
seq = getkeymapcmd(curkeymap, &func, &str);
statusline = NULL;
if(!*seq)
@ -811,14 +824,14 @@ void
trashzle(void)
{
if (zleactive) {
/* This refresh() is just to get the main editor display right and *
* get the cursor in the right place. For that reason, we disable *
* list display (which would otherwise result in infinite *
* recursion [at least, it would if refresh() didn't have its *
* extra `inlist' check]). */
/* This zrefresh() is just to get the main editor display right and *
* get the cursor in the right place. For that reason, we disable *
* list display (which would otherwise result in infinite *
* recursion [at least, it would if zrefresh() didn't have its *
* extra `inlist' check]). */
int sl = showinglist;
showinglist = 0;
refresh();
zrefresh();
showinglist = sl;
moveto(nlnct, 0);
if (clearflag && tccan(TCCLEAREOD)) {
@ -838,7 +851,7 @@ trashzle(void)
static struct builtin bintab[] = {
BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaMldDANmrsLR", NULL),
BUILTIN("vared", 0, bin_vared, 1, 7, 0, NULL, NULL),
BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANL", NULL),
BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgG", NULL),
};
/**/
@ -848,7 +861,7 @@ boot_zle(Module m)
/* Set up editor entry points */
trashzleptr = trashzle;
gotwordptr = gotword;
refreshptr = refresh;
refreshptr = zrefresh;
spaceinlineptr = spaceinline;
zlereadptr = zleread;

View file

@ -426,7 +426,7 @@ quotedinsert(void)
#endif
c = getkey(0);
#ifndef HAS_TIO
setterm();
zsetterm();
#endif
if (c < 0)
feep();
@ -621,7 +621,7 @@ executenamedcommand(char *prmt)
for (;;) {
*ptr = '_';
statusll = l + len + 1;
refresh();
zrefresh();
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
statusline = NULL;
selectkeymap(okeymap, 1);
@ -633,7 +633,7 @@ executenamedcommand(char *prmt)
redisplay();
} else if(cmd == Th(z_viquotedinsert)) {
*ptr = '^';
refresh();
zrefresh();
c = getkey(0);
if(c == EOF || !c || len == NAMLEN)
feep();

View file

@ -47,7 +47,7 @@ int nlnct;
/* Most lines of the buffer we've shown at once with the current list *
* showing. == 0 if there is no list. == -1 if a new list has just *
* been put on the screen. == -2 if refresh() needs to put up a new *
* been put on the screen. == -2 if zrefresh() needs to put up a new *
* list. */
/**/
@ -55,7 +55,7 @@ int showinglist;
/* Non-zero if ALWAYS_LAST_PROMPT has been used, meaning that the *
* screen below the buffer display should not be cleared by *
* refresh(), but should be by trashzle(). */
* zrefresh(), but should be by trashzle(). */
/**/
int clearflag;
@ -75,7 +75,7 @@ int cost;
#endif
/* Oct/Nov 94: <mason> some code savagely redesigned to fix several bugs -
refreshline() & tc_rightcurs() majorly rewritten; refresh() fixed -
refreshline() & tc_rightcurs() majorly rewritten; zrefresh() fixed -
I've put my fingers into just about every routine in here -
any queries about updates to mason@werple.net.au */
@ -224,7 +224,7 @@ static int cleareol, /* clear to end-of-line (if can't cleareod) */
/**/
void
refresh(void)
zrefresh(void)
{
static int inlist; /* avoiding recursion */
int canscroll = 0, /* number of lines we are allowed to scroll */
@ -240,7 +240,7 @@ refresh(void)
char **qbuf; /* tmp */
/* If this is called from listmatches() (indirectly via trashzle()), and *
* that was called from the end of refresh(), then we don't need to do *
* that was called from the end of zrefresh(), then we don't need to do *
* anything. All this `inlist' code is actually unnecessary, but it *
* improves speed a little in a common case. */
if (inlist)
@ -263,7 +263,7 @@ refresh(void)
termflags &= ~TERM_SHORT;
if (resetneeded) {
onumscrolls = 0;
setterm();
zsetterm();
#ifdef TIOCGWINSZ
if (winchanged) {
moveto(0, 0);
@ -547,7 +547,7 @@ individually */
inlist = 1;
listmatches();
inlist = 0;
refresh();
zrefresh();
}
if (showinglist == -1)
showinglist = nlnct;

View file

@ -244,7 +244,9 @@ unbindwidget(Thingy t, int override)
static void
freewidget(Widget w)
{
if(!(w->flags & WIDGET_INT))
if ((w->flags & WIDGET_COMP) && w->u.cc)
freecompctl(w->u.cc);
else if(!(w->flags & WIDGET_INT))
zsfree(w->u.fnnam);
zfree(w, sizeof(*w));
}
@ -334,6 +336,7 @@ bin_zle(char *name, char **args, char *ops, int func)
{ 'D', bin_zle_del, 1, -1 },
{ 'A', bin_zle_link, 2, 2 },
{ 'N', bin_zle_new, 1, 2 },
{ 'C', bin_zle_compctl, 1, -1},
{ 0, bin_zle_call, 0, -1 },
};
struct opn const *op, *opp;
@ -385,17 +388,24 @@ scanlistwidgets(HashNode hn, int list)
if(w->flags & WIDGET_INT)
return;
if(list) {
fputs("zle -N ", stdout);
fputs((w->flags & WIDGET_COMP) ? "zle -C " : "zle -N ", stdout);
if(t->nam[0] == '-')
fputs("-- ", stdout);
quotedzputs(t->nam, stdout);
if(strcmp(t->nam, w->u.fnnam)) {
if (w->flags & WIDGET_COMP) {
if (printcompctlptr && w->u.cc)
printcompctlptr(NULL, w->u.cc, PRINT_LIST);
} else if(strcmp(t->nam, w->u.fnnam)) {
fputc(' ', stdout);
quotedzputs(w->u.fnnam, stdout);
}
} else {
nicezputs(t->nam, stdout);
if(strcmp(t->nam, w->u.fnnam)) {
if (w->flags & WIDGET_COMP) {
fputs(" -C", stdout);
if (printcompctlptr && w->u.cc)
printcompctlptr(NULL, w->u.cc, PRINT_TYPE);
} else if(strcmp(t->nam, w->u.fnnam)) {
fputs(" (", stdout);
nicezputs(w->u.fnnam, stdout);
fputc(')', stdout);
@ -456,6 +466,44 @@ bin_zle_new(char *name, char **args, char *ops, char func)
return 1;
}
/**/
static int
bin_zle_compctl(char *name, char **args, char *ops, char func)
{
Compctl cc = NULL;
Widget w;
char *wname = args[0];
if (!compctl_widgetptr) {
zwarnnam(name, "compctl module is not loaded", NULL, 0);
return 1;
}
args++;
if (*args && !(cc = compctl_widgetptr(name, args)))
return 1;
w = zalloc(sizeof(*w));
w->flags = WIDGET_COMP|ZLE_MENUCMP|ZLE_KEEPSUFFIX;
w->first = NULL;
w->u.cc = cc;
if(bindwidget(w, rthingy(wname))) {
freewidget(w);
zerrnam(name, "widget name `%s' is protected", wname, 0);
return 1;
}
if (ops['m'])
w->flags |= ZLE_USEMENU;
else if (ops['M'])
w->flags |= ZLE_NOMENU;
if (ops['g'])
w->flags |= ZLE_USEGLOB;
else if (ops['G'])
w->flags |= ZLE_NOGLOB;
return 0;
}
/**/
static int
bin_zle_call(char *name, char **args, char *ops, char func)

File diff suppressed because it is too large Load diff

View file

@ -420,7 +420,7 @@ void
handlefeep(void)
{
if(feepflag)
beep();
zbeep();
feepflag = 0;
}

View file

@ -126,7 +126,7 @@ vigetkey(void)
char sav = line[cs];
line[cs] = '^';
refresh();
zrefresh();
c = getkey(0);
line[cs] = sav;
if(c == EOF) {
@ -814,10 +814,10 @@ viswapcase(void)
void
vicapslockpanic(void)
{
beep();
zbeep();
statusline = "press a lowercase key to continue";
statusll = strlen(statusline);
refresh();
zrefresh();
while (!islower(getkey(0)));
statusline = NULL;
}
@ -891,7 +891,7 @@ viquotedinsert(void)
spaceinline(1);
line[cs] = '^';
refresh();
zrefresh();
#ifndef HAS_TIO
sob = shttyinfo.sgttyb;
sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO;
@ -899,7 +899,7 @@ viquotedinsert(void)
#endif
c = getkey(0);
#ifndef HAS_TIO
setterm();
zsetterm();
#endif
foredel(1);
if(c < 0)

View file

@ -2627,14 +2627,14 @@ bin_getopts(char *name, char **argv, char *ops, int func)
if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) {
p = "?";
err:
zsfree(zoptarg);
zsfree(zoptarg);
if(quiet) {
setsparam(var, ztrdup(p));
zoptarg = metafy(optbuf, lenoptbuf, META_DUP);
} else {
zerr(*p == '?' ? "bad option: -%c" :
"argument expected after -%c option", NULL, opch);
zoptarg=ztrdup("");
zoptarg=ztrdup("");
errflag = 0;
}
return 0;

View file

@ -1992,8 +1992,8 @@ restore_params(LinkList restorelist, LinkList removelist)
}
} else
paramtab->addnode(paramtab, pm->nam, pm);
if (pm->flags & PM_EXPORTED)
pm->env = addenv(pm->nam, getsparam(pm->nam));
if ((pm->flags & PM_EXPORTED) && ((s = getsparam(pm->nam))))
pm->env = addenv(pm->nam, s);
}
}
}

View file

@ -110,6 +110,8 @@ struct comp {
#define C_CLOSURE (C_ONEHASH|C_TWOHASH|C_OPTIONAL|C_STAR)
#define C_LAST 16
#define C_PATHADD 32
#define C_LCMATCHUC 64
#define C_IGNCASE 128
/* Test macros for the above */
#define CLOSUREP(c) (c->stat & C_CLOSURE)
@ -305,15 +307,24 @@ scanner(Complist q)
if (!q)
return;
if ((closure = q->closure)) /* (foo/)# - match zero or more dirs */
if ((closure = q->closure)) {
/* (foo/)# - match zero or more dirs */
if (q->closure == 2) /* (foo/)## - match one or more dirs */
q->closure = 1;
else
scanner(q->next);
}
c = q->comp;
/* Now the actual matching for the current path section. */
if (!(c->next || c->left) && !haswilds(c->str)) {
/* It's a straight string to the end of the path section. */
if (!(c->next || c->left) && !haswilds(c->str)
&& (!(c->stat & (C_LCMATCHUC|C_IGNCASE))
|| !strcmp(".", c->str) || !strcmp("..", c->str))) {
/*
* We always need to match . and .. explicitly, even if we're
* checking other strings for case-insensitive matches.
*
* It's a straight string to the end of the path section.
*/
int l = strlen(c->str);
if (l + !l + pathpos - pathbufcwd >= PATH_MAX) {
@ -436,6 +447,52 @@ scanner(Complist q)
/* Parse a series of path components pointed to by pptr */
/* Flags to apply to current level of grourping */
static int addflags;
/**/
static Comp
compalloc(void)
{
Comp c = (Comp) alloc(sizeof *c);
c->stat |= addflags;
return c;
}
/**/
static int
getglobflags()
{
/* (#X): assumes we are still positioned on the initial '(' */
pptr++;
while (*++pptr && *pptr != Outpar) {
switch (*pptr) {
case 'l':
/* Lowercase in pattern matches lower or upper in target */
addflags |= C_LCMATCHUC;
break;
case 'i':
/* Fully case insensitive */
addflags |= C_IGNCASE;
break;
case 'I':
/* Restore case sensitivity */
addflags &= ~(C_LCMATCHUC|C_IGNCASE);
break;
default:
return 1;
}
}
if (*pptr != Outpar)
return 1;
pptr++;
return 0;
}
/* enum used with ksh-like patterns, @(...) etc. */
enum { KF_NONE, KF_AT, KF_QUEST, KF_STAR, KF_PLUS, KF_NOT };
@ -447,7 +504,7 @@ static Comp
parsecomp(int gflag)
{
int kshfunc;
Comp c = (Comp) alloc(sizeof *c), c1, c2;
Comp c = compalloc(), c1, c2;
char *cstr, *ls = NULL;
/* In case of alternatives, code coming up is stored in tail. */
@ -468,10 +525,10 @@ parsecomp(int gflag)
c->str = dupstrpfx(cstr, pptr - cstr);
pptr++;
c1 = (Comp) alloc(sizeof *c1);
c1 = compalloc();
c1->stat |= C_STAR;
c2 = (Comp) alloc(sizeof *c2);
c2 = compalloc();
if (!(c2->exclude = parsecomp(gflag)))
return NULL;
if (!*pptr || *pptr == '/')
@ -513,6 +570,39 @@ parsecomp(int gflag)
pptr++;
}
if (*pptr == Inpar && pptr[1] == Pound) {
/* Found some globbing flags */
char *eptr = pptr;
if (kshfunc != KF_NONE)
eptr--;
if (getglobflags())
return NULL;
if (eptr == cstr) {
/* if no string yet, carry on and get one. */
c->stat = addflags;
cstr = pptr;
continue;
}
c->str = dupstrpfx(cstr, eptr - cstr);
/*
* The next bit simply handles the case where . or ..
* is followed by a set of flags, but we need to force
* them to be handled as a string. Hardly worth it.
*/
if (!*pptr || (!mode && *pptr == '/') || *pptr == Bar ||
(isset(EXTENDEDGLOB) && *pptr == Tilde &&
pptr[1] && pptr[1] != Outpar && pptr[1] != Bar) ||
*pptr == Outpar) {
if (*pptr == '/' || !*pptr ||
(isset(EXTENDEDGLOB) && *pptr == Tilde &&
(gflag & GF_TOPLEV)))
c->stat |= C_LAST;
return c;
}
if (!(c->next = parsecomp(gflag)))
return NULL;
return c;
}
if (*pptr == Inpar) {
/* Found a group (...) */
char *startp = pptr, *endp;
@ -552,16 +642,16 @@ parsecomp(int gflag)
pptr = startp;
c->str = dupstrpfx(cstr, (pptr - cstr) - (kshfunc != KF_NONE));
pptr++;
c2 = (Comp) alloc(sizeof *c);
c2 = compalloc();
c->next = c2;
c2->next = (dpnd || kshfunc == KF_NOT) ?
c1 : (Comp) alloc(sizeof *c);
c1 : compalloc();
if (!(c2->left = parsecompsw(0)))
return NULL;
if (kshfunc == KF_NOT) {
/* we'd actually rather it didn't match. Instead, match *
* a star and put the parsed pattern into exclude. */
Comp c3 = (Comp) alloc(sizeof *c3);
Comp c3 = compalloc();
c3->stat |= C_STAR;
c2->exclude = c2->left;
@ -584,7 +674,7 @@ parsecomp(int gflag)
*/
c->str = dupstrpfx(cstr, pptr - cstr);
pptr++;
c1 = (Comp) alloc(sizeof *c1);
c1 = compalloc();
c1->stat |= C_STAR;
if (!(c2 = parsecomp(gflag)))
return NULL;
@ -596,13 +686,13 @@ parsecomp(int gflag)
/* repeat whatever we've just had (ls) zero or more times */
if (!ls)
return NULL;
c2 = (Comp) alloc(sizeof *c);
c2 = compalloc();
c2->str = dupstrpfx(ls, pptr - ls);
pptr++;
if (*pptr == Pound) {
/* need one or more matches: cheat by copying previous char */
pptr++;
c->next = c1 = (Comp) alloc(sizeof *c);
c->next = c1 = compalloc();
c1->str = c2->str;
} else
c1 = c;
@ -669,6 +759,7 @@ static Comp
parsecompsw(int gflag)
{
Comp c1, c2, c3, excl = NULL, stail = tail;
int oaddflags = addflags;
char *sptr;
/*
@ -709,7 +800,7 @@ parsecompsw(int gflag)
tail = stail;
if (*pptr == Bar || excl) {
/* found an alternative or something to exclude */
c2 = (Comp) alloc(sizeof *c2);
c2 = compalloc();
if (*pptr == Bar) {
/* get the next alternative after the | */
pptr++;
@ -728,8 +819,10 @@ parsecompsw(int gflag)
c2->next = stail;
if (gflag & GF_PATHADD)
c2->stat |= C_PATHADD;
return c2;
c1 = c2;
}
if (!(gflag & GF_TOPLEV))
addflags = oaddflags;
return c1;
}
@ -758,7 +851,7 @@ parsecomplist(void)
errflag = 1;
return NULL;
}
p1->comp = (Comp) alloc(sizeof *p1->comp);
p1->comp = compalloc();
p1->comp->stat |= C_LAST; /* end of path component */
p1->comp->str = dupstring("*");
*p1->comp->str = Star; /* match anything... */
@ -814,8 +907,28 @@ static Complist
parsepat(char *str)
{
mode = 0; /* path components present */
addflags = 0;
pptr = str;
tail = NULL;
/*
* Check for initial globbing flags, so that they don't form
* a bogus path component.
*/
if (*pptr == Inpar && pptr[1] == Pound && isset(EXTENDEDGLOB) &&
getglobflags())
return NULL;
/* Now there is no (#X) in front, we can check the path. */
if (!pathbuf)
pathbuf = zalloc(pathbufsz = PATH_MAX);
DPUTS(pathbufcwd, "BUG: glob changed directory");
if (*pptr == '/') { /* pattern has absolute path */
pptr++;
pathbuf[0] = '/';
pathbuf[pathpos = 1] = '\0';
} else /* pattern is relative to pwd */
pathbuf[pathpos = 0] = '\0';
return parsecomplist();
}
@ -897,7 +1010,7 @@ glob(LinkList list, LinkNode np)
if (*s == Bar || *s == Outpar ||
(isset(EXTENDEDGLOB) && *s == Tilde))
break;
if (*s == Inpar) {
if (*s == Inpar && (!isset(EXTENDEDGLOB) || s[1] != Pound)) {
/* Real qualifiers found. */
int sense = 0; /* bit 0 for match (0)/don't match (1) */
/* bit 1 for follow links (2), don't (0) */
@ -1234,15 +1347,6 @@ glob(LinkList list, LinkNode np)
}
}
}
if (!pathbuf)
pathbuf = zalloc(pathbufsz = PATH_MAX);
DPUTS(pathbufcwd, "BUG: glob changed directory");
if (*str == '/') { /* pattern has absolute path */
str++;
pathbuf[0] = '/';
pathbuf[pathpos = 1] = '\0';
} else /* pattern is relative to pwd */
pathbuf[pathpos = 0] = '\0';
q = parsepat(str);
if (!q || errflag) { /* if parsing failed */
if (unset(BADPATTERN)) {
@ -1267,7 +1371,7 @@ glob(LinkList list, LinkNode np)
/* Deal with failures to match depending on options */
if (matchct)
badcshglob |= 2; /* at least one cmd. line expansion O.K. */
else if (!gf_nullglob)
else if (!gf_nullglob) {
if (isset(CSHNULLGLOB)) {
badcshglob |= 1; /* at least one cmd. line expansion failed */
} else if (isset(NOMATCH)) {
@ -1279,6 +1383,7 @@ glob(LinkList list, LinkNode np)
untokenize(*matchptr++ = dupstring(ostr));
matchct = 1;
}
}
/* Sort arguments in to lexical (and possibly numeric) order. *
* This is reversed to facilitate insertion into the list. */
qsort((void *) & matchbuf[0], matchct, sizeof(char *),
@ -1373,11 +1478,12 @@ hasbraces(char *str)
*str++ = '{', *str = '}';
else
bc++;
} else if (*str == Outbrace)
} else if (*str == Outbrace) {
if (!bc)
*str = '}';
else if (!--bc)
return 1;
}
return 0;
}
/* Otherwise we need to look for... */
@ -1554,11 +1660,12 @@ xpandbraces(LinkList list, LinkNode *np)
else if (*str2 == Outbrace) {
if (--bc == 0)
break;
} else if (bc == 1)
} else if (bc == 1) {
if (*str2 == Comma)
++comma; /* we have {foo,bar} */
else if (*str2 == '.' && str2[1] == '.')
dotdot++; /* we have {num1..num2} */
}
DPUTS(bc, "BUG: unmatched brace in xpandbraces()");
if (!comma && dotdot) {
/* Expand range like 0..10 numerically: comma or recursive
@ -2489,7 +2596,10 @@ matchonce(Comp c)
}
continue;
}
if (*pptr == *pat) {
if (*pptr == *pat ||
(((c->stat & C_IGNCASE) ? (tulower(*pat) == tulower(*pptr)) :
(c->stat & C_LCMATCHUC) ?
(islower(*pat) && tuupper(*pat) == *pptr) : 0))) {
/* just plain old characters */
pptr++;
pat++;
@ -2508,6 +2618,7 @@ parsereg(char *str)
{
remnulargs(str);
mode = 1; /* no path components */
addflags = 0;
pptr = str;
tail = NULL;
return parsecompsw(GF_TOPLEV);

View file

@ -214,7 +214,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);

View file

@ -145,6 +145,11 @@ if $first_stage; then
echo "PROTOS =$all_proto"
echo "SUBDIRS =$all_subdirs"
echo
echo "ENTRYOBJ = \$(dir_src)/modentry..o"
echo "NNTRYOBJ ="
echo "ENTRYOPT = -emodentry"
echo "NNTRYOPT ="
echo
echo "##### ===== INCLUDING Makemod.in.in ===== #####"
echo
@ -161,7 +166,7 @@ if $first_stage; then
remote_mdhs=
for module in $here_modules; do
unset moddeps nozshdep alwayslink
unset moddeps nozshdep alwayslink hasexport
unset autobins
unset objects proto headers hdrdeps otherincs
. $top_srcdir/$the_subdir/${module}.mdd
@ -172,8 +177,10 @@ if $first_stage; then
dobjects=`echo $objects '' | sed 's,\.o ,..o ,g'`
modhdeps=
imports=
for dep in $moddeps; do
eval "loc=\$loc_$dep"
imports="$imports \$(IMPOPT)\$(sdir_top)/$loc/$dep.export"
case $the_subdir in
$loc)
mdh="${dep}.mdh"
@ -199,9 +206,11 @@ if $first_stage; then
echo "##### ===== DEPENDENCIES GENERATED FROM ${module}.mdd ===== #####"
echo
echo "MODOBJS_${module} = $objects"
echo "MODDOBJS_${module} = $dobjects"
echo "MODDOBJS_${module} = $dobjects \$(@E@NTRYOBJ)"
echo "PROTO_${module} = $proto"
echo "INCS_${module} = \$(PROTO_${module}) $otherincs"
echo "EXPIMP_${module} = $imports ${hasexport+\$(EXPOPT)\$(sdir)/$module.export}"
echo "NXPIMP_${module} ="
echo
echo "proto.${module}: \$(PROTO_${module})"
echo "\$(PROTO_${module}): \$(PROTODEPS)"
@ -212,7 +221,7 @@ if $first_stage; then
if test -z "$alwayslink"; then
echo "${module}.\$(DL_EXT): \$(MODDOBJS_${module})"
echo ' rm -f $@'
echo " \$(DLLINK) \$(MODDOBJS_${module}) \$(LIBS)"
echo " \$(DLLINK) \$(@E@XPIMP_$module) \$(@E@NTRYOPT) \$(MODDOBJS_${module}) \$(LIBS)"
echo
fi
echo "${module}.mdhi: ${module}.mdhs \$(INCS_${module})"

15
Src/modentry.c Normal file
View file

@ -0,0 +1,15 @@
#include "zsh.mdh"
int boot_ _((Module));
int cleanup_ _((Module));
int modentry _((int boot, Module m));
/**/
int
modentry(int boot, Module m)
{
if (boot)
return boot_(m);
else
return cleanup_(m);
}

View file

@ -161,6 +161,44 @@ deletebuiltins(char const *nam, Builtin binl, int size)
return hadf ? hads : 1;
}
#ifdef AIXDYNAMIC
#include <sys/ldr.h>
static char *dlerrstr[256];
/**/
static void *
load_and_bind(const char *fn)
{
void *ret = (void *) load((char *) fn, L_NOAUTODEFER, NULL);
if (ret) {
LinkNode node;
int err = loadbind(0, (void *) addbuiltin, ret);
for (node = firstnode(modules); !err && node; incnode(node)) {
Module m = (Module) getdata(node);
if (m->handle)
err |= loadbind(0, m->handle, ret);
}
if (err) {
loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr));
unload(ret);
ret = NULL;
}
} else
loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr));
return ret;
}
#define dlopen(X,Y) load_and_bind(X)
#define dlclose(X) unload(X)
#define dlerror() (dlerrstr[0])
#else
#ifdef HAVE_DLFCN_H
# include <dlfcn.h>
#else
@ -168,12 +206,6 @@ deletebuiltins(char const *nam, Builtin binl, int size)
# include <nlist.h>
# include <link.h>
#endif
#ifndef RTLD_LAZY
# define RTLD_LAZY 1
#endif
#ifndef RTLD_GLOBAL
# define RTLD_GLOBAL 0
#endif
#ifndef HAVE_DLCLOSE
# define dlclose(X) ((X), 0)
#endif
@ -189,6 +221,16 @@ deletebuiltins(char const *nam, Builtin binl, int size)
# define STR_CLEANUP "cleanup_"
# define STR_CLEANUP_S "cleanup_%s"
#endif /* !DLSYM_NEEDS_UNDERSCORE */
#endif /* !AIXDYNAMIC */
#ifndef RTLD_LAZY
# define RTLD_LAZY 1
#endif
#ifndef RTLD_GLOBAL
# define RTLD_GLOBAL 0
#endif
typedef int (*Module_func) _((Module));
/**/
@ -257,6 +299,24 @@ find_module(const char *name)
return NULL;
}
#ifdef AIXDYNAMIC
/**/
static int
init_module(Module m)
{
return ((int (*)_((int,Module))) m->handle)(1, m);
}
/**/
static int
cleanup_module(Module m)
{
return ((int (*)_((int,Module))) m->handle)(0, m);
}
#else
/**/
static int
init_module(Module m)
@ -288,6 +348,39 @@ init_module(Module m)
return 1;
}
/**/
static int
cleanup_module(Module m)
{
char *s, *t;
#ifndef DYNAMIC_NAME_CLASH_OK
char buf[PATH_MAX + 1];
#endif
Module_func fn;
s = strrchr(m->nam, '/');
if (s)
s = dupstring(++s);
else
s = m->nam;
if ((t = strrchr(s, '.')))
*t = '\0';
#ifdef DYNAMIC_NAME_CLASH_OK
fn = (Module_func) dlsym(m->handle, STR_CLEANUP);
#else /* !DYNAMIC_NAME_CLASH_OK */
if (strlen(s) + 9 > PATH_MAX)
return 1;
sprintf(buf, STR_CLEANUP_S, s);
fn = (Module_func) dlsym(m->handle, buf);
#endif /* !DYNAMIC_NAME_CLASH_OK */
if(fn)
return fn(m);
zwarnnam(m->nam, "no cleanup function", NULL, 0);
return 1;
}
#endif /* !AIXDYNAMIC */
/**/
Module
load_module(char const *name)
@ -337,37 +430,6 @@ load_module(char const *name)
return m;
}
/**/
static int
cleanup_module(Module m)
{
char *s, *t;
#ifndef DYNAMIC_NAME_CLASH_OK
char buf[PATH_MAX + 1];
#endif
Module_func fn;
s = strrchr(m->nam, '/');
if (s)
s = dupstring(++s);
else
s = m->nam;
if ((t = strrchr(s, '.')))
*t = '\0';
#ifdef DYNAMIC_NAME_CLASH_OK
fn = (Module_func) dlsym(m->handle, STR_CLEANUP);
#else /* !DYNAMIC_NAME_CLASH_OK */
if (strlen(s) + 9 > PATH_MAX)
return 1;
sprintf(buf, STR_CLEANUP_S, s);
fn = (Module_func) dlsym(m->handle, buf);
#endif /* !DYNAMIC_NAME_CLASH_OK */
if(fn)
return fn(m);
zwarnnam(m->nam, "no cleanup function", NULL, 0);
return 1;
}
/**/
void
add_dep(char *name, char *from)

View file

@ -593,6 +593,12 @@ extern char PC, *BC, *UP;
extern short ospeed;
#endif
/* Rename some global zsh variables to avoid *
* possible name clashes with libc */
#define cs zshcs
#define ll zshll
#ifndef O_NOCTTY
# define O_NOCTTY 0
#endif

View file

@ -510,6 +510,10 @@ adduserdir(char *s, char *t, int flags, int always)
if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s))
return;
/* Never hash PWD, because it's never useful */
if (!strcmp(s, "PWD"))
return;
/* Normal parameter assignments generate calls to this function, *
* with always==0. Unless the AUTO_NAME_DIRS option is set, we *
* don't let such assignments actually create directory names. *
@ -854,7 +858,7 @@ adjustwinsize(void)
setiparam("LINES", shttyinfo.winsize.ws_row);
if (zleactive && (oldcols != columns || oldrows != lines)) {
resetneeded = winchanged = 1;
refresh();
zrefresh();
}
#endif /* TIOCGWINSZ */
}
@ -1129,13 +1133,13 @@ checkrmall(char *s)
if(isset(RMSTARWAIT)) {
fputs("? (waiting ten seconds)", shout);
fflush(shout);
beep();
zbeep();
sleep(10);
fputc('\n', shout);
}
fputs(" [yn]? ", shout);
fflush(shout);
beep();
zbeep();
return (getquery("ny", 1) == 'y');
}
@ -1181,7 +1185,7 @@ getquery(char *valid_chars, int purge)
write(SHTTY, "\n", 1);
break;
}
beep();
zbeep();
if (icntrl(c))
write(SHTTY, "\b \b", 3);
write(SHTTY, "\b \b", 3);
@ -1327,7 +1331,7 @@ spckword(char **s, int hist, int cmd, int ask)
zputs(pptbuf, shout);
free(pptbuf);
fflush(shout);
beep();
zbeep();
x = getquery("nyae ", 0);
} else
x = 'y';
@ -2286,7 +2290,7 @@ mkarray(char *s)
/**/
void
beep(void)
zbeep(void)
{
if (isset(BEEP))
write(SHTTY, "\07", 1);

235
Src/zsh.export Normal file
View file

@ -0,0 +1,235 @@
#!
SHTTY
addbuiltins
addedx
addhashnode
aliastab
alloc_stackp
appstr
arrdup
arrlen
attachtty
bangchar
bin_notavail
breaks
bufstack
builtintab
chline
chuck
clearjobtab
closem
cmdnamtab
columns
compctlreadptr
coprocin
coprocout
countlinknodes
countprompt
createparam
ctxtlex
curhist
current_limits
deletebuiltins
deletehashtable
domatch
doshfunc
dputs
dquotedztrdup
dummy_list
dupstring
dupstrpfx
dyncat
emptyhashtable
endparamscope
errflag
excs
execstring
exlast
expanding
fallback_compctlread
fallback_zleread
fignore
file_type
filesub
filesubstr
findcmd
firsthist
freearray
freeheap
getaparam
gethashnode
gethashnode2
getiparam
getkeystring
getlinknode
getshfunc
getsparam
glob_pre
glob_suf
global_heapalloc
global_permalloc
globlist
gotwordptr
halloc
hasam
hashcmd
hasher
hasspecial
haswilds
hcalloc
hgetc
hgetline
histentarr
histentct
hptr
hrealloc
inbufct
incmdpos
incond
init_io
init_shout
init_term
inpop
inpush
inredir
insertlinknode
intr
inwhat
isfirstln
jobtab
lastpid
lastval
lchdir
lexrestore
lexsave
lexstop
limits
line
lines
locallevel
metadiffer
metafy
metalen
mode_to_octal
mypgrp
mypid
nameddirtab
ncalloc
newhashtable
newlinklist
nicechar
nicezputs
niceztrdup
niceztrlen
noaliases
noerrs
noop_function
noop_function_int
optiontab
opts
paramtab
parbegin
parend
parsereg
parsestr
path
pathchecked
popheap
postedit
ppid
prefork
prepromptfns
printif
printqt
promptexpand
pushheap
putshout
pwd
quietgetevent
quietgethist
quotedzputs
refreshptr
remlpaths
remnulargs
removehashnode
resetneeded
restoredir
reswdtab
retflag
scanhashtable
setaparam
setlimits
setsparam
settyinfo
shfunctab
shingetline
shout
shttyinfo
singsub
skipparens
spaceinlineptr
spacesplit
spckword
startparamscope
stdunsetfn
stophist
stopmsg
strinbeg
strinend
strpfx
strsfx
strucpy
struncpy
tclen
tcstr
termflags
tgoto
tok
tokenize
tokstr
tputs
trashzleptr
tricat
tsetcap
ttystrname
tulower
tuupper
txtchange
typtab
ugetnode
uinsertlinknode
unmeta
unmetafy
untokenize
uremnode
useheap
winchanged
wordbeg
zalloc
zbeep
zcalloc
zchdir
zerr
zerrnam
zexit
zfree
zgetdir
zgetenv
zjoin
zleactive
zleparse
zlereadptr
zputs
zreaddir
zsetlimit
zsfree
zshcs
zshll
zstrtol
ztokens
ztrdup
ztrduppfx
ztrftime
ztrlen
ztrsub
zwarnnam

View file

@ -31,7 +31,7 @@
#define zleread(X,Y,H) zlereadptr(X,Y,H)
#define spaceinline(X) spaceinlineptr(X)
#define gotword() gotwordptr()
#define refresh() refreshptr()
#define zrefresh() refreshptr()
#define compctlread(N,A,O,R) compctlreadptr(N,A,O,R)

View file

@ -12,7 +12,7 @@ headers="../config.h system.h zsh.h sigcount.h signals.h \
prototypes.h hashtable.h ztype.h"
:<<\Make
signames.c: signames.awk @SIGNAL_H@
signames.c: signames.awk ../config.h @SIGNAL_H@
$(AWK) -f $(sdir)/signames.awk @SIGNAL_H@ > $@
sigcount.h: signames.c

View file

@ -219,3 +219,6 @@
/* Define to 1 if you want to use dynamically loaded modules */
#undef DYNAMIC
/* Define to 1 if you want to use dynamically loaded modules on AIX */
#undef AIXDYNAMIC

View file

@ -207,6 +207,7 @@ main()
[zsh_cv_sys_dynamic_rtld_global=no],
[zsh_cv_sys_dynamic_rtld_global=no]
)
LDFLAGS=$save_ldflags
else
zsh_cv_sys_dynamic_rtld_global=no
fi

View file

@ -210,11 +210,11 @@ if test -n "$auto_cflags"; then
fi
fi
if test -n "$auto_ldflags"; then
if test "${enable_zsh_debug}" = yes; then
LDFLAGS=-g
else
LDFLAGS=-s
fi
case "${enable_zsh_debug}$host_os" in
yesaix*) ;; # AIX ld does not accept -g
yes*) LDFLAGS=-g ;;
*) LDFLAGS=-s ;;
esac
fi
dnl ----------
@ -401,12 +401,10 @@ AC_CHECK_LIB(c, printf)
dnl Prefer BSD termcap library to SysV curses library, except on certain
dnl versions of AIX and HP-UX.
if test `echo $host_os | sed 's/^.*\(aix\)[[1-9]]\.[[0-9]].*$/\1/'` = aix ||
test `echo $host_os | sed 's/^.*\(hpux\)10\..*$/\1/'` = hpux; then
termcap_curses_order="curses ncurses termcap"
else
termcap_curses_order="termcap curses ncurses"
fi
case "$host_os" in
aix*|hpux10.*) termcap_curses_order="curses ncurses termcap" ;;
*) termcap_curses_order="termcap curses ncurses" ;;
esac
for lib in $termcap_curses_order; do
AC_CHECK_LIB(${lib}, tgetent, [LIBS="-l$lib $LIBS"; break])
@ -617,8 +615,9 @@ AC_CHECK_FUNCS(memcpy memmove \
sigprocmask setuid seteuid setreuid setresuid setsid strerror \
nis_list initgroups fchdir cap_get_proc readlink nice \
getgrgid getgrnam getpwent getpwnam getpwuid)
if test $dynamic = yes; then
AC_CHECK_FUNCS(dlopen dlerror dlsym dlclose)
AC_CHECK_FUNCS(dlopen dlerror dlsym dlclose load loadquery loadbind unload)
fi
@ -900,14 +899,37 @@ dnl ---------------
dnl dynamic loading
dnl ---------------
L=N
if test "$ac_cv_func_dlopen" != yes; then
dynamic=no
elif test "$ac_cv_func_dlsym" != yes; then
dynamic=no
elif test "$ac_cv_func_dlerror" != yes; then
dynamic=no
aixdynamic=no
if test "$ac_cv_func_dlopen" != yes ||
test "$ac_cv_func_dlsym" != yes ||
test "$ac_cv_func_dlerror" != yes; then
if test "$ac_cv_func_load" != yes ||
test "$ac_cv_func_unload" != yes ||
test "$ac_cv_func_loadbind" != yes ||
test "$ac_cv_func_loadquery" != yes; then
dynamic=no
elif test "x$dynamic" = xyes; then
aixdynamic=yes
fi
fi
if test "x$dynamic" = xyes; then
test -n "$GCC" && LDARG=-Wl,
if test "x$aixdynamic" = xyes; then
DL_EXT="${DL_EXT=so}"
DLLD="${DLLD=$CC}"
zsh_cv_func_dlsym_needs_underscore=no
DLLDFLAGS=${DLLDFLAGS=}
EXTRA_LDFLAGS=${EXTRA_LDFLAGS=}
EXPOPT=${LDARG}-bE:
IMPOPT=${LDARG}-bI:
zsh_cv_sys_dynamic_clash_ok="${zsh_cv_sys_dynamic_clash_ok=yes}"
zsh_cv_sys_dynamic_rtld_global="${zsh_cv_sys_dynamic_rtld_global=yes}"
zsh_cv_sys_dynamic_execsyms="${zsh_cv_sys_dynamic_execsyms=yes}"
zsh_cv_sys_dynamic_strip_exe="${zsh_cv_sys_dynamic_strip_exe=yes}"
zsh_cv_sys_dynamic_strip_lib="${zsh_cv_sys_dynamic_strip_lib=yes}"
zsh_cv_sys_dynamic_broken="${zsh_cv_sys_dynamic_broken=no}"
elif test "x$dynamic" = xyes; then
AC_CACHE_CHECK(if your system use ELF binaries,
zsh_cv_sys_elf,
[AC_TRY_RUN([/* Test for whether ELF binaries are produced */
@ -947,10 +969,11 @@ char *argv[];
case "$host_os" in
hpux*) DLLDFLAGS="${DLLDFLAGS=-b}" ;;
linux*|irix*|osf*) DLLDFLAGS="${DLLDFLAGS=-shared}" ;;
solaris*) DLLDFLAGS="${DLLDFLAGS=-G}" ;;
sunos*) DLLDFLAGS="${DLLDFLAGS=-assert nodefinitions}" ;;
sysv4*|esix*) DLLDFLAGS="${DLLDFLAGS=-G $ldflags}" ;;
netbsd*) DLLDFLAGS="${DLLDFLAGS=-x -shared --whole-archive}" ;;
aix*) DLLDFLAGS="${DLLDFLAGS=-G -bexpall -lc}" ;;
solaris*|sysv4*|esix*) DLLDFLAGS="${DLLDFLAGS=-G}" ;;
esac
case "$host_os" in
hpux*) EXTRA_LDFLAGS="${EXTRA_LDFLAGS=-Wl,-E}" ;;
@ -958,7 +981,7 @@ char *argv[];
esac
AC_CACHE_CHECK(if your dlsym() needs a leading underscore,
zsh_cv_func_dlsym_needs_underscore,
[cat >conftest.c <<EOM
[echo failed >conftestval && cat >conftest.c <<EOM
fred () { }
EOM
$CC -c $CFLAGS $CPPFLAGS $DLCFLAGS conftest.c 1>&5 2>&5 &&
@ -1006,8 +1029,12 @@ main()
zsh_cv_func_dlsym_needs_underscore=failed
dynamic=no,
zsh_cv_func_dlsym_needs_underscore=no)])
if test "$zsh_cv_func_dlsym_needs_underscore" = yes; then
if test "x$zsh_cv_func_dlsym_needs_underscore" = xyes; then
AC_DEFINE(DLSYM_NEEDS_UNDERSCORE)
elif test "x$zsh_cv_func_dlsym_needs_underscore" != xno; then
dnl Do not cache failed value
unset zsh_cv_func_dlsym_needs_underscore
dynamic=no
fi
fi
@ -1045,13 +1072,23 @@ else
D=N
fi
if test "x$aixdynamic" = xyes; then
E=E
AC_DEFINE(AIXDYNAMIC)dnl
else
E=N
fi
AC_DEFINE_UNQUOTED(DL_EXT, "$DL_EXT")dnl
AC_SUBST(D)dnl
AC_SUBST(DL_EXT)dnl
AC_SUBST(DLLD)dnl
AC_SUBST(DLCFLAGS)dnl
AC_SUBST(DLLDFLAGS)dnl
AC_SUBST(E)dnl
AC_SUBST(EXTRA_LDFLAGS)dnl
AC_SUBST(EXPOPT)dnl
AC_SUBST(IMPOPT)dnl
AC_SUBST(L)dnl
AC_SUBST(RTLD_GLOBAL_OK)dnl