home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-02-19 | 54.4 KB | 1,987 lines |
- Newsgroups: comp.sources.misc
- From: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
- Subject: v35i063: zsh - The Z Shell, version 2.3.1, Part13/22
- Message-ID: <1993Feb20.212531.28970@sparky.imd.sterling.com>
- X-Md4-Signature: b001b8458fd97ee8644a8d118cca3eeb
- Date: Sat, 20 Feb 1993 21:25:31 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
- Posting-number: Volume 35, Issue 63
- Archive-name: zsh/part13
- Environment: UNIX
- Supersedes: zsh2.2: Volume 29, Issue 97-113
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: FAQ help/pushd src/zle_tricky.c
- # Wrapped by mattson@odin on Sat Feb 6 14:41:54 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 13 (of 22)."'
- if test -f 'FAQ' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'FAQ'\"
- else
- echo shar: Extracting \"'FAQ'\" \(21578 characters\)
- sed "s/^X//" >'FAQ' <<'END_OF_FILE'
- XArchive-Name: zsh.FAQ
- XSubmitted-By: pws@s-a.amtp.liv.ac.uk (Peter Stephenson)
- X
- X$Id: FAQ,v 1.3 1993/02/04 10:17:55 pws Exp pws $
- X
- XThis document contains a list of frequently-asked (or otherwise
- Xsignificant) questions concerning the Z-shell, a powerful command
- Xinterpreter for many UNIX systems.
- X
- XIf you have never heard of `sh', `csh' or `ksh', then you are probably
- Xbetter off to start by reading a general introduction to UNIX rather
- Xthan this document.
- X
- XAnother useful source of information is the collection of FAQ articles
- Xposted bi-weekly to the Usenet news groups comp.unix.questions,
- Xcomp.unix.shells and news.answers with answers to general questions
- Xabout UNIX. The fifth of the seven articles deals with shells,
- Xincluding zsh, with a brief description of differences. (This article
- Xalso talks about shell startup files which would otherwise rate a
- Xmention here.)
- X
- XIf you just want to know how to get your hands on the latest version,
- Xskip to question 4; if you want to know what to do with insoluble
- Xproblems, go to 17.
- X
- XNotation: Quotes `like this' are ordinary textual quotation
- Xmarks. Other uses of quotation marks are input to the shell.
- X
- XContents:
- X1) What is it?
- X2) On what machines will it run?
- X3) What's the latest version?
- X4) Where do I get it?
- X5) How does zsh differ from sh, ksh, csh,...?
- X6) Why do my csh aliases not work?
- X7) How do I get the meta key to work on my xterm?
- X8) Why does my terminal act funny in way x?
- X9) Why does `$vble' where vble="foo bar" not do what I expect?
- X10) How does base arithmetic work?
- X11) How do I get a newline in my prompt?
- X12) Why does `bindkey ^a command-name' do something funny?
- X13) How do I reference command `foo' from within function `foo'?
- X14) I don't have root access: how do I make zsh my login shell?
- X15) What bugs are currently known and unfixed?
- X16) Where do I report bugs, get more info / who's working on zsh?
- X17) What's on the wish-list?
- X
- X
- X1) What is it?
- X
- X Zsh is a UNIX command interpreter (shell) which of the standard shells
- X most resembles the Korn shell (ksh), although it is not completely
- X compatible. It includes enhancements of many types, notably in the
- X command-line editor, options for customising its behaviour, filename
- X globbing, features to make C-shell (csh) users feel more at home and
- X extra features drawn from tcsh (another `custom' shell).
- X
- X It was written by Paul Falstad <pf@ttisms.com> when a student at
- X Princeton; however, Paul doesn't maintain it any more and enquiries
- X should be sent to the mailing list (see question 17). It is freely
- X available to anyone under unrestrictive conditions.
- X
- X For more information, the files doc/intro.txt or doc/intro.troff
- X included with the source distribution are highly recommended. The
- X files intro.ps.Z and intro.txt.Z can also be FTP'd separately from the
- X archive (see 4). A list of features is given in FEATURES, also with
- X the source.
- X
- X
- X2) On what machines will it run?
- X
- X Zsh was written for machines of the Berkeley UNIX family; most such
- X machines (and all the most popular) will run it without major surgery.
- X Modifications have been made so that it should work under SYSVR4-based
- X operating systems such as Solaris 2.x. This best thing is to suck it
- X and see. You may not have to change too much: if you do change
- X anything, arrange for the shell script `buildzsh' to set the
- X necessary #define's, etc., without human intervention.
- X
- X
- X3) What's the latest version?
- X
- X The latest production version is 2.3.1, which has just been released.
- X New patches occur frequently and are added to the archive (next
- X question).
- X
- X
- X4) Where do I get it?
- X
- X The current release is available for anonymous FTP from
- X cs.ucsd.edu (132.239.51.3):pub/zsh/zsh2.3.1.tar.Z
- X The archive maintainer currently is Jim Mattson <mattson@cs.UCSD.EDU>,
- X who also reads the mailing list.
- X
- X Bas de Bakker (bas@phys.uva.nl) will shortly be taking over the archive
- X and new patches are likely to be available from:
- X carlo.phys.uva.nl (145.18.220.25):/pub/bas/zsh
- X
- X Richard Ohnemus will probably have a North American reflector at
- X ftp.sterling.com.
- X
- X
- X5) How does zsh differ from sh, ksh, csh,...?
- X
- X As mentioned, zsh is most similar to ksh, while many of the additions are
- X to please csh users.
- X
- X i) ksh:
- X Most features of ksh are implemented in zsh; problems can arise
- X because the implementation is slightly different. Note also not all
- X ksh's are the same either. I have based this on SunOS 4, which is
- X essentially the 11/16/88 version of ksh.
- X
- X Differences from ksh which might prove significant for ksh
- X programmers, some of which may be interpreted as bugs (there must be
- X more) include:
- X Shell word splitting: see question 14.
- X Arrays are more csh-like than ksh-like:
- X subscripts start at 1, not 0; array[0] refers to array[1];
- X `$array' refers to the whole array, not $array[0];
- X braces are unnecessary: $a[1] == ${a[1]}, etc.
- X Path not searched for commands specified at invocation without -c.
- X Management of histories in multiple shells may be different.
- X Coprocesses are established by `coproc'; `|&' behaves like csh.
- X PS1 does not do parameter substitution.
- X Globbing does not allow ksh-style `pattern-lists'.
- X The options emacs, gmacs, privileged, trackall, viraw are not supported.
- X The `keyword' option does not exist and -k is instead interactivecomments.
- X [ ] is a shell built-in, rather than a call to /bin/test.
- X There is no built-in command newgrp: use a shell function.
- X The order in which aliases and functions are defined is significant.
- X Some built-ins (true, false, r, ...) were aliases in ksh.
- X Aliases and functions cannot be exported.
- X There are no tracked aliases.
- X There is no ENV variable.
- X No built-in commands cause automatic termination of a script.
- X The -- flag to terminate option processing is not recognised
- X as an argument to the shell (it is recognised by set).
- X `jobs' has no `-n' flag.
- X Treatment of backslashes within backquotes is different.
- X Variable assignments with tilde expansions are special-cased.
- X Editing:
- X \ does not escape editing chars (use ^V).
- X Not all ksh bindings are set (e.g. `<ESC>#').
- X The following is particularly near the feature/bug borderline:
- X To turn off signal traps, use `trap - <signo>', not `trap <signo>'.
- X "$@" always indicates at least one argument (older sh's do this too).
- X
- X ii) csh:
- X
- X Although certain features aim to ease the withdrawal symptoms of Csh
- X (ab)users, the syntax is in general rather different and you should
- X certainly not try to run scripts without modification. The c2z script
- X is provided with the source (in scripts/c2z) to help convert .cshrc
- X and .login files; see also the next question concerning aliases.
- X
- X Csh-compatibility additions include:
- X Logout, rehash, source, (un)limit built-in commands.
- X *rc file for interactive shells.
- X Directory stacks.
- X Cshjunkie*, ignoreeof options.
- X The nonomatch option.
- X >&, |& etc. redirection.
- X foreach ... loops.
- X $PROMPT as well as $PS1, $status as well as $?, $#argv as well as $#, ....
- X Escape sequences via % for prompts.
- X Special array variables $PATH etc. are colon-separated, $path are arrays.
- X !-type history (which may be turned off).
- X Arrays have csh-like features (see i)).
- X
- X iii) tcsh:
- X
- X Certain features have been borrowed from tcsh, including $watch,
- X run-help, $savehist, $histlit, periodic commands etc., extended
- X prompts, sched and which/where built-ins. This list is not
- X definitive: some features have gone in the other direction.
- X
- X iv) specific features:
- X
- X Things that zsh is particularly good at (no claim of exclusivity is made,
- X especially as shells copy one another) include:
- X Command line editing:
- X multi-line commands,
- X variable editing,
- X command buffer stack,
- X execution of unbound commands,
- X menu completion,
- X variable, host, editing function and option name completion,
- X inline expansion of variables, history commands,
- X path expansion (=foo).
- X Globbing:
- X recursive globbing (c.f find),
- X file attribute qualifiers,
- X full alternation and negation of patterns.
- X Large number of options for tailoring.
- X Adaptable messages for spelling, watch, time as well as prompt.
- X Named directories.
- X Comprehensive integer arithmetic.
- X Manipulation of arrays.
- X Spelling correction.
- X
- X
- X6) Why do my csh aliases not work?
- X
- X First of all, check you are using the syntax
- X alias newcmd='list of commands'
- X and not
- X alias newcmd 'list of commands'
- X which won't work. (It tells you if `newcmd' and `list of commands' are
- X already defined as aliases.)
- X
- X Otherwise, your aliases probably contain references to the command
- X line of the form `\!*', etc. Zsh does not handle this behaviour as it
- X has shell functions which provide a way of solving this problem more
- X consistent with other forms of argument handling. For example, the
- X csh alias
- X alias cd 'cd \!*; echo $cwd'
- X can be replaced by the zsh function,
- X cd() { builtin cd $*; echo $PWD; }
- X (the `builtin' tells zsh to use its own `cd', avoiding an infinite loop)
- X or, perhaps better,
- X cd() { builtin cd $*; print -D $PWD; }
- X (which converts your home directory to a ~). In fact, this problem is
- X better solved by defining the special function chpwd() (see the manual).
- X
- X Note also that the `;' at the end of the function is optional in zsh,
- X but not in ksh or sh (for sh's where it exists).
- X
- X Here is Bart Schaefer's guide to converting csh aliases for zsh.
- X
- X 1. If the csh alias references "parameters" (\!:1 \!* etc.),
- X then in zsh you need a function (referencing $1 $* etc.).
- X Otherwise, you can use a zsh alias.
- X
- X 2. If you use a zsh function, you need to refer _at_least_ to
- X $* in the body (inside the { }). Parameters don't magically
- X appear inside the { } the way they get appended to an alias.
- X
- X 3. If the csh alias references its own name (alias rm "rm -i"),
- X then in a zsh function you need the "command" keyword
- X (function rm() { command rm -i $* }), but in a zsh alias
- X you don't (alias rm="rm -i").
- X
- X 4. If you have aliases that refer to each other (alias ls "ls -C";
- X alias lf "ls -F" ==> lf == ls -C -F) then you must either:
- X a. convert all of them to zsh functions; or
- X b. after converting, be sure your .zshrc defines all of your
- X aliases before it defines any of your functions.
- X
- X Those first four are all you really need, but here are four more for
- X heavy csh alias junkies:
- X
- X 5. Mapping from csh alias "parameter referencing" into zsh function
- X (assuming shwordsplit is NOT set in zsh):
- X csh zsh
- X ===== ==========
- X \!* $* (or $argv)
- X \!^ $1 (or $argv[1])
- X \!:1 $1
- X \!:2 $2 (or $argv[2], etc.)
- X \!$ $*[$#] (or $argv[$#], or $*[-1])
- X \!:1-4 $*[1,4]
- X \!:1- $*[1,$#-1] (or $*[1,-2])
- X \!^- $*[1,$#-1]
- X \!*:q "$@" ($*:q doesn't work (yet))
- X \!*:x $=* ($*:x doesn't work (yet))
- X
- X 6. Remember that it is NOT a syntax error in a zsh function to
- X refer to a position ($1, $2, etc.) greater than the number of
- X parameters. (E.g., in a csh alias, a reference to \!:5 will
- X cause an error if 4 or fewer arguments are given; in a zsh
- X function, $5 is the empty string if there are 4 or fewer
- X parameters.)
- X
- X 7. To begin a zsh alias with a - (dash, hyphen) character, use
- X "alias --":
- X csh zsh
- X =============== ==================
- X alias - "fg %-" alias -- -="fg %-"
- X
- X 8. Stay away from "alias -g" in zsh until you REALLY know what
- X you're doing.
- X
- X
- X7) How do I get the meta key to work on my xterm?
- X
- X As stated in the manual, zsh needs to be told about the meta key by
- X using `bindkey -me' or `bindkey -mv' in your .zshrc or on the command
- X line. You probably also need to tell the terminal driver to allow the
- X `meta' bit of the character through; `stty pass8' is the usual
- X incantation. Sample .zshrc entry:
- X [[ $TERM = "xterm" ]] && stty pass8 && bindkey -me
- X Make sure this comes *before* any bindkey entries in your .zshrc which
- X redefine keys normally defined in the emacs/vi keymap.
- X
- X
- X8) Why does my terminal act funny in way x?
- X
- X If you are using an OpenWindows cmdtool as your terminal, any
- X escape sequences (such as those produced by cursor keys) will be
- X swallowed up and never reach zsh. Either use shelltool or avoid
- X commands with escape sequences. You can also disable scrolling from
- X the cmdtool pane menu (which effectively turns it into a shelltool).
- X If you still want scrolling, try using an xterm with the scrollbar
- X activated.
- X
- X If that's not the problem, and you are using stty to change some tty
- X settings, make sure you haven't asked zsh to freeze the tty settings:
- X type
- X ttyctl -u
- X before any stty commands you use.
- X
- X If _that's_ not the problem, and you are having difficulties with
- X external commands (not part of zsh), and you think some terminal
- X setting is wrong (e.g. ignpar should be -ignpar: see the stty(1)
- X manual page), try:
- X ttyctl -u
- X STTY='-ignpar' commandname
- X (in this not-very-useful example). Note that zsh doesn't reset the
- X terminal completely afterwards: just the modes it uses itself.
- X
- X
- X9) Why does `$var' where var="foo bar" not do what I expect?
- X
- X In most Bourne-shell derivatives, multi-word variables such as
- X var="foo bar"
- X are split into words when passed to a command or used in a `for foo in $var'
- X loop. By default, zsh does not have that behaviour: the variable remains
- X intact. An option (shwordsplit) exists to provide compatibility.
- X
- X For example, defining the function args to show the number of its
- X arguments:
- X args() { echo $#; }
- X and with our definition of vble,
- X args $vble
- X produces the output `1'. After
- X setopt shwordsplit
- X the same function produces the output `2', like sh and ksh.
- X
- X Unless you need strict sh/ksh compatibility, you should ask yourself
- X whether you really want this behaviour, as it can produce unexpected
- X effects for variables with entirely innocuous embedded spaces. The
- X natural way to produce word-splitting behaviour in zsh is via arrays.
- X For example,
- X set -A array one two three twenty
- X (or
- X array=(one two three twenty)
- X if you prefer), followed by
- X args $array
- X produces the output `4', regardless of the setting of shwordsplit.
- X Arrays are also much more versatile than single strings.
- X
- X Note also the "$@" method of word splitting is always available in zsh
- X functions and scripts (though strictly this does array splitting, not
- X word splitting), also the substitution ${=foo} to toggle word
- X splitting on variable `foo'.
- X
- X
- X10) How does base arithmetic work?
- X
- X The syntax (e.g. using the `let' builtin is)
- X let 'foo = [16]ff'
- X or equivalently
- X (( foo = [16]ff ))
- X Then
- X echo $foo
- X gives the answer `255'. It is possible to declare variables explicitly
- X to be integers, via
- X typeset -i foo
- X which has a different effect: namely the base used in the first
- X assignment (hexadecimal in the example) is subsequently used whenever
- X `foo' is displayed (although the internal representation is unchanged).
- X To ensure foo is always displayed in decimal, declare it as
- X typeset -i 10 foo
- X which requests base 10 for output. You can change the output base of an
- X existing variable in this fashion. Using the `$[ ... ]' method will
- X always display in decimal.
- X
- X
- X11) How do I get a newline in my prompt?
- X
- X You can place a literal newline in quotes, i.e.
- X PROMPT="Hi Joe,
- X what now?%# "
- X If you have the bad taste to set the option cshjunkiequotes, which
- X inhibits such behaviour, you will have to bracket this with
- X `unsetopt cshjunkiequotes' and `setopt cshjunkiequotes', or put it in
- X your .zshrc before the option is set.
- X
- X
- X12) Why does `bindkey ^a command-name' do something funny?
- X
- X You probably have the extendedglob option set in which case ^ and #
- X are metacharacters. ^a matches any file except one called a, so the
- X line is interpreted as bindkey followed by a list of files. Quote the
- X ^ with a backslash or put quotation marks around ^a.
- X
- X
- X13) How do I reference command `foo' from within function `foo'?
- X
- X The command `command foo' does just that. You don't need this with
- X aliases, but you do with functions. Note that the error message
- X zsh: job table full or recursion limit exceeded
- X is a good sign that you tried calling `foo' in function `foo' without
- X using `command'.
- X
- X
- X14) I don't have root access: how do I make zsh my login shell?
- X
- X Unfortunately, on many machines you can't use `chsh' to change your
- X shell unless the name of the shell is contained in /etc/shells, so if
- X you have your own copy of zsh you need some sleight-of-hand to use it
- X when you log on. (Simply typing `zsh' is not really a solution since
- X you still have your original login shell waiting for when you exit.)
- X
- X The basic idea is to use `exec <zsh-path>' to replace the current
- X shell with zsh. Often you can do this in a login file such as
- X .profile (if your shell is sh or ksh) or .login (if it's csh). Make
- X sure you have some way of altering the file (e.g. via FTP) before you
- X try this as `exec' is often rather unforgiving.
- X
- X In .profile, try something like
- X [ -f $HOME/bin/zsh ] && exec $HOME/bin/zsh -l
- X and in .login, try something like
- X if ( -f ~/bin/zsh ) exec ~/bin/zsh -l
- X (in each case the -l tells zsh it is a login shell).
- X
- X It's not a good idea to put this (even without the -l) into .cshrc, at
- X least without some tests on what the csh is supposed to be doing, as
- X that will cause _every_ instance of csh to turn into a zsh and will
- X cause csh scripts (yes, some people write these) to fail. If you want
- X to tell xterm to run zsh, change the SHELL environment variable to the
- X full path of zsh.
- X
- X If you like your login shell to appear in the process list as '-zsh',
- X you can link zsh to -zsh (e.g. by `ln -s ~/bin/zsh ~/bin/-zsh') and
- X change the exec to `exec -zsh'. (Make sure -zsh is in your path.)
- X This has the same effect as the `-l' option.
- X
- X
- X15) What bugs are currently known and unfixed?
- X
- X Here are some of the more well-known ones, very roughly in decreasing
- X order of significance. A fuller bug list is now maintained by Carlos
- X Carvalho <carlos@snfep1.if.usp.br>. Many of these can also be counted
- X against differences from ksh in question 5). Bugs marked [2.4] are
- X fixed in patches which should appear in early versions of the next
- X release.
- X
- X Unsetting multiply-named functions via a name other than the first
- X crashes the shell. [2.4]
- X Functions are a bit half-hearted about local variables. [2.4]
- X `return' in a trap simply returns from the trap. [2.4]
- X `return' in a shell script should act as `exit'.
- X Pipelines ending in a while/until/for loop are uninterruptible.
- X Certain built-ins won't allow the `VAR=value command ...' assignment.
- X The ones that do don't unset VAR after use.
- X Killing a command substitution in a loop doesn't kill the loop. [2.4]
- X Assigments in a typeset are overenthusiastic about tildes.
- X `bindkey -a -[ed]' modifies the alternate keymap.
- X `echo !-2:$ !$' substitutes !-2:$ twice.
- X The :q modifier doesn't split words and -q and -x don't work for variables.
- X `echo -n ^V^J!<return>' causes a shell crash [2.4]
- X Command line editing in vi mode:
- X `.' doesn't repeat `x' (repeats command before `x').
- X `u' can go past original modification point.
- X `.' doesn't repeat count for `s', `cw', `dw', `r' (and others?).
- X If a command has both file and command completion enabled,
- X completion of a word that is a directory finds only commands in
- X the directory, not files and commands.
- X $_ returns the last unexpanded word from the previous line (not command).
- X Autocd won't use globbed filenames and sometimes refuses to work.
- X `if (( 1 )) command' and `if (( 1 )) { ...' do not work
- X (and related syntax problems).
- X The rmstar feature doesn't handle shell variables properly.
- X
- X
- X16) Where do I report bugs, get more info / who's working on zsh?
- X
- X Zsh is now maintained by a motley collection of enthusiasts who
- X subscribe to the mailing list, so any suggestions, complaints,
- X questions and matters for discussion should be addressed to:
- X zsh-list@cs.uow.edu.au
- X (if you want someone to mail you directly, say so). If you wish to
- X subscribe to the mailing list, ask
- X zsh-request@cs.uow.edu.au
- X which is in the hands of Peter Gray, who also reads the list. It is
- X by no means restricted to source-code hackers.
- X
- X
- X17) What's on the wish-list?
- X
- X `compctl' to be enhanced to shut up tcsh-users.
- X Option for glob qualifiers to follow perl syntax.
- X Selective expansion of history, variables, globs on <TAB>.
- X Option to quote !-history lexically via '' but not "" (hard).
- X Binding of external commands to zle functions (arg-passing mechanism??).
- X Ksh compatibility could be improved if required.
- X
- X
- XAcknowledgments:
- X
- XThanks to zsh-list, in particular Bart Schaefer, for suggestions
- Xregarding this document; thanks to Jim Mattson for his hard work as
- Xarchivist.
- END_OF_FILE
- if test 21578 -ne `wc -c <'FAQ'`; then
- echo shar: \"'FAQ'\" unpacked with wrong size!
- fi
- # end of 'FAQ'
- fi
- if test -f 'help/pushd' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'help/pushd'\"
- else
- echo shar: Extracting \"'help/pushd'\" \(1305 characters\)
- sed "s/^X//" >'help/pushd' <<'END_OF_FILE'
- X pushd [ arg ]
- X pushd old new
- X pushd +-n
- X Change the current directory, and push the old current
- X directory onto the directory stack. In the first form,
- X change the current directory to arg. If arg is not
- X specified, change to the second directory on the stack
- X (that is, exchange the top two entries), or change to
- X the value of HOME if the PUSHD_TO_HOME option is set or
- X if there is only one entry on the stack. If arg is -,
- X change to the value of OLDPWD, the previous directory.
- X If a directory named arg is not found in the current
- X directory and arg does not contain a slash, search each
- X component of the shell parameter cdpath. If the option
- X CDABLEVARS is set, and a parameter named arg exists
- X whose value begins with a slash, treat its value as the
- X directory. If the option PUSHD_SILENT is not set, the
- X directory stack will be printed after a pushd is per-
- X formed.
- X
- X The second form of pushd substitutes the string new for
- X the string old in the name of the current directory,
- X and tries to change to this new directory.
- X
- X The third form of pushd is equivalent to popd.
- END_OF_FILE
- if test 1305 -ne `wc -c <'help/pushd'`; then
- echo shar: \"'help/pushd'\" unpacked with wrong size!
- fi
- # end of 'help/pushd'
- fi
- if test -f 'src/zle_tricky.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/zle_tricky.c'\"
- else
- echo shar: Extracting \"'src/zle_tricky.c'\" \(28258 characters\)
- sed "s/^X//" >'src/zle_tricky.c' <<'END_OF_FILE'
- X/*
- X *
- X * zle_tricky.c - expansion and completion
- X *
- X * This file is part of zsh, the Z shell.
- X *
- X * This software is Copyright 1992 by Paul Falstad
- X *
- X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
- X * use this software as long as: there is no monetary profit gained
- X * specifically from the use or reproduction of this software, it is not
- X * sold, rented, traded or otherwise marketed, and this copyright notice is
- X * included prominently in any copy made.
- X *
- X * The author make no claims as to the fitness or correctness of this software
- X * for any use whatsoever, and it is provided as is. Any use of this software
- X * is at the user's own risk.
- X *
- X */
- X
- X#define ZLE
- X#include "zsh.h"
- X#include <pwd.h>
- X#ifdef HAS_NIS_PASSWD
- X#include <rpc/rpc.h>
- X#include <rpcsvc/ypclnt.h>
- X#include <rpcsvc/yp_prot.h>
- X
- X#define PASSWD_FILE "/etc/passwd"
- X#define PASSWD_MAP "passwd.byname"
- X
- Xtypedef struct {
- X int len;
- X char *s;
- X } dopestring;
- X#endif
- X
- Xstatic int we,wb,usemenu,useglob;
- X
- Xstatic int menub,menue,menuw;
- Xstatic Lklist menulist;
- Xstatic Lknode menunode;
- X
- X#define inststr(X) inststrlen((X),-1)
- X
- Xint usetab() /**/
- X{
- Xunsigned char *s = line+cs-1;
- X
- X for (; s >= line && *s != '\n'; s--)
- X if (*s != '\t' && *s != ' ')
- X return 0;
- X return 1;
- X}
- X
- X#define COMP_COMPLETE 0
- X#define COMP_LIST_COMPLETE 1
- X#define COMP_SPELL 2
- X#define COMP_EXPAND 3
- X#define COMP_EXPAND_COMPLETE 4
- X#define COMP_LIST_EXPAND 5
- X#define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND)
- X
- Xvoid completeword() /**/
- X{
- X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
- X if (c == '\t' && usetab())
- X selfinsert();
- X else
- X docomplete(COMP_COMPLETE);
- X}
- X
- Xvoid menucompleteword() /**/
- X{
- X usemenu = 1; useglob = isset(GLOBCOMPLETE);
- X if (c == '\t' && usetab())
- X selfinsert();
- X else
- X docomplete(COMP_COMPLETE);
- X}
- X
- Xvoid listchoices() /**/
- X{
- X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
- X docomplete(COMP_LIST_COMPLETE);
- X}
- X
- Xvoid spellword() /**/
- X{
- X usemenu = useglob = 0;
- X docomplete(COMP_SPELL);
- X}
- X
- Xvoid deletecharorlist() /**/
- X{
- X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
- X if (cs != ll)
- X deletechar();
- X else
- X docomplete(COMP_LIST_COMPLETE);
- X}
- X
- Xvoid expandword() /**/
- X{
- X usemenu = useglob = 0;
- X if (c == '\t' && usetab())
- X selfinsert();
- X else
- X docomplete(COMP_EXPAND);
- X}
- X
- Xvoid expandorcomplete() /**/
- X{
- X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
- X if (c == '\t' && usetab())
- X selfinsert();
- X else
- X docomplete(COMP_EXPAND_COMPLETE);
- X}
- X
- Xvoid menuexpandorcomplete() /**/
- X{
- X usemenu = 1; useglob = isset(GLOBCOMPLETE);
- X if (c == '\t' && usetab())
- X selfinsert();
- X else
- X docomplete(COMP_EXPAND_COMPLETE);
- X}
- X
- Xvoid listexpand() /**/
- X{
- X usemenu = isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE);
- X docomplete(COMP_LIST_EXPAND);
- X}
- X
- Xvoid reversemenucomplete() /**/
- X{
- X if (!menucmp)
- X menucompleteword(); /* better than just feep'ing, pem */
- X if (!menucmp) return;
- X cs = menub;
- X foredel(menue-menub);
- X if (menunode == firstnode(menulist))
- X menunode = lastnode(menulist);
- X else
- X menunode = prevnode(menunode);
- X inststr(menunode->dat);
- X menue = cs;
- X}
- X
- X/*
- X * Accepts the current completion and starts a new arg,
- X * with the next completions. This gives you a way to accept
- X * several selections from the list of matches.
- X */
- Xvoid acceptandmenucomplete() /**/
- X{
- Xint t0,t1;
- X
- X if (!menucmp) {
- X feep();
- X return;
- X }
- X spaceinline(1);
- X line[cs++] = ' ';
- X spaceinline(menub-menuw);
- X t1 = cs;
- X for (t0 = menuw; t0 != menub; t0++)
- X line[cs++] = line[t0];
- X menue = menub = cs;
- X menuw = t1;
- X menucompleteword();
- X}
- X
- Xstatic char *lastmenu = NULL;
- Xstatic int lastmenupos = -1;
- Xstatic int lincmd,linredir,lastambig;
- Xstatic char *cmdstr;
- X
- Xvoid docomplete(lst) /**/
- Xint lst;
- X{
- Xchar *s;
- X
- X if (isset(AUTOMENU) && !menucmp && c == '\t' &&
- X (lastcmd & ZLE_MENUCMP) && lastambig) usemenu = 1;
- X if (menucmp) { do_menucmp(lst); return; }
- X if (doexpandhist()) return;
- X s = get_comp_string();
- X if (s) {
- X if (lst == COMP_EXPAND_COMPLETE) {
- X char *q = s;
- X
- X if (*q == Tilde) q++;
- X else if (*q == Equals) {
- X q = s+1;
- X if (gethnode(q,cmdnamtab) || hashcmd(q,pathchecked))
- X lst = COMP_EXPAND;
- X } else {
- X for (; *q && *q != String; q++);
- X if (*q == String && q[1] != Inpar) {
- X if (getsparam(q+1)) lst = COMP_EXPAND;
- X else lst = COMP_COMPLETE;
- X }
- X q = s;
- X }
- X if (lst == COMP_EXPAND_COMPLETE) {
- X for (; *q; q++)
- X if (itok(*q))
- X break;
- X if (!*q)
- X lst = COMP_COMPLETE;
- X }
- X }
- X if (lst == COMP_SPELL) {
- X char **x = &s;
- X char *q = s;
- X for(; *q; q++) if (INULL(*q)) *q = Nularg;
- X untokenize(s);
- X cs = wb;
- X foredel(we-wb);
- X /* call the real spell checker, ash@aaii.oz.zu */
- X spckword(x, NULL, NULL, !lincmd, 0);
- X inststr(*x);
- X } else if (COMP_ISEXPAND(lst))
- X doexpansion(s,lst,lincmd);
- X else {
- X docompletion(s,lst,lincmd);
- X }
- X free(s);
- X }
- X popheap();
- X lexrestore();
- X}
- X
- Xvoid do_menucmp(lst) /**/
- Xint lst;
- X{
- Xchar *s;
- X
- X if (isset(LASTMENU) && lastmenu) {
- X if (COMP_ISEXPAND(lst) || cs != lastmenupos ||
- X strcmp((char *) line, lastmenu) != 0) {
- X free(lastmenu);
- X lastmenu = NULL;
- X lastmenupos = -1;
- X freemenu();
- X }
- X }
- X if (lst == COMP_LIST_COMPLETE) {
- X listmatches(menulist, NULL);
- X return;
- X }
- X cs = menub;
- X foredel(menue-menub);
- X incnode(menunode);
- X if (!menunode)
- X menunode = firstnode(menulist);
- X s = menunode->dat;
- X if (*s == '~' || *s == '=' || *s == '$') {
- X spaceinline(1);
- X line[cs++] = *s++;
- X }
- X inststr(s = menunode->dat);
- X if (isset(LASTMENU)) {
- X if (lastmenu) free(lastmenu);
- X lastmenu = ztrdup(UTOSCP(line));
- X lastmenupos = cs;
- X }
- X menue = cs;
- X}
- X
- Xchar *get_comp_string() /**/
- X{
- Xint t0;
- Xunsigned char *s = NULL,*linptr;
- X
- X linptr = line;
- Xstart:
- X lincmd = incmdpos;
- X linredir = inredir;
- X cmdstr = NULL;
- X zleparse = 1;
- X lexsave();
- X hungets(" "); /* KLUDGE! */
- X hungets(UTOSCP(linptr));
- X strinbeg();
- X pushheap();
- X do {
- X lincmd = incmdpos;
- X linredir = inredir;
- X ctxtlex();
- X if (tok == ENDINPUT) break;
- X if (lincmd && tok == STRING) cmdstr = strdup(tokstr);
- X } while (tok != ENDINPUT && zleparse);
- X t0 = tok;
- X if (t0 == ENDINPUT) {
- X s = (unsigned char *)ztrdup("");
- X we = wb = cs;
- X t0 = STRING;
- X } else if (t0 == STRING) {
- X s = (unsigned char *)ztrdup(tokstr);
- X } else if (t0 == ENVSTRING) {
- X for (s = (unsigned char *)tokstr; *s && *s != (unsigned char)'='; s++, wb++);
- X if (*s) { s++; wb++; t0 = STRING; s = STOUCP(ztrdup(UTOSCP(s))); }
- X lincmd = 1;
- X }
- X hflush();
- X strinend();
- X errflag = zleparse = 0;
- X if (we > ll) we = ll;
- X if (t0 == LEXERR && parbegin != -1) {
- X linptr += ll+1-parbegin;
- X popheap();
- X lexrestore();
- X goto start;
- X }
- X if (t0 != STRING) { feep(); return NULL; }
- X return (char *)s;
- X}
- X
- Xvoid doexpansion(s,lst,lincmd) /**/
- Xchar *s;int lst;int lincmd;
- X{
- XLklist vl = newlist();
- Xchar *ss;
- X
- X pushheap();
- X addnode(vl,s);
- X prefork(vl);
- X if (errflag)
- X goto end;
- X postfork(vl,1);
- X if (errflag)
- X goto end;
- X if (empty(vl) || !*(char *) peekfirst(vl)) {
- X feep();
- X goto end;
- X }
- X if (lst == COMP_LIST_EXPAND) {
- X listmatches(vl,NULL);
- X goto end;
- X } else if (peekfirst(vl) == s) {
- X if (lst == COMP_EXPAND_COMPLETE) {
- X docompletion(s,COMP_COMPLETE,lincmd);
- X } else
- X feep();
- X goto end;
- X }
- X cs = wb;
- X foredel(we-wb);
- X while (ss = ugetnode(vl)) {
- X untokenize(ss);
- X inststr(ss);
- X#if 0
- X if (full(vl)) {
- X spaceinline(1);
- X line[cs++] = ' ';
- X }
- X#endif
- X spaceinline(1);
- X line[cs++] = ' ';
- X }
- Xend:
- X popheap();
- X setterm();
- X}
- X
- Xvoid gotword(s) /**/
- Xchar *s;
- X{
- X we = ll+1-inbufct;
- X if (cs <= we)
- X {
- X wb = ll-wordbeg;
- X zleparse = 0;
- X /* major hack ahead */
- X if (wb && line[wb] == '!' && line[wb-1] == '\\')
- X wb--;
- X }
- X}
- X
- Xvoid inststrlen(s,l) /**/
- Xchar *s;int l;
- X{
- Xchar *t,*u,*v;
- X
- X t = halloc(strlen(s)*2+2);
- X u = s;
- X v = t;
- X for (; *u; u++)
- X {
- X if (l != -1 && !l--)
- X break;
- X if (ispecial(*u))
- X if (*u == '\n')
- X {
- X *v++ = '\'';
- X *v++ = '\n';
- X *v++ = '\'';
- X continue;
- X }
- X else
- X *v++ = '\\';
- X *v++ = *u;
- X }
- X *v = '\0';
- X spaceinline(strlen(t));
- X strncpy((char *) line+cs,t,strlen(t));
- X cs += strlen(t);
- X}
- X
- Xstatic int ambig,haspath,exact;
- Xstatic Lklist matches;
- Xstatic char *pat,*exactstr;
- Xstatic int typechar;
- X
- Xvoid addmatch(s) /**/
- Xchar *s;
- X{
- X if (full(matches))
- X {
- X int y = pfxlen(peekfirst(matches),s);
- X
- X if (y < ambig)
- X ambig = y;
- X }
- X else
- X ambig = strlen(s);
- X if (!strcmp(pat,s)) { exact = 1; exactstr = pat; }
- X addnodeinorder(matches,strdup(s));
- X}
- X
- X
- Xvoid addcmdmatch(s,t) /**/
- Xchar *s;char *t;
- X{
- X if (strpfx(pat,s)) addmatch(s);
- X}
- X
- Xvoid addcmddirparam(s,t) /**/
- Xchar *s;char *t;
- X{
- XParam pm = (Param) t;
- X
- X if (strpfx(pat,s) && pmtype(pm) == PMFLAG_s) {
- X t = pm->gets.cfn(pm);
- X if (t && *t == '/') addmatch(s);
- X }
- X}
- X
- Xvoid addcmdnodis(s,t) /**/
- Xchar *s;char *t;
- X{
- X if (strpfx(pat,s) && ((Cmdnam) t)->type != DISABLED) addmatch(s);
- X}
- X
- X#ifdef HAS_NIS_PASSWD
- Xstatic int match_username(status, key, keylen, val, vallen, data)
- Xint status;
- Xchar *key, *val;
- Xint keylen, vallen;
- Xdopestring *data;
- X{
- X if (errflag || status != YP_TRUE) return 1;
- X
- X if (vallen > keylen && val[keylen] == ':')
- X {
- X val[keylen] = '\0';
- X /* Can't call getpwnam() here; it breaks yp_all() */
- X if(strncmp(val,data->s,data->len) == 0) addmatch(val);
- X }
- X return 0;
- X}
- X#endif
- X
- Xvoid maketildelist(s) /**/
- Xchar *s;
- X{
- X#ifdef HAS_NIS_PASSWD
- X char domain[YPMAXDOMAIN];
- X struct ypall_callback cb;
- X dopestring data;
- X Lknode n;
- X FILE *pwf;
- X char buf[BUFSIZ], *p;
- X int skipping;
- X
- X data.s = ++s;
- X data.len = strlen(s);
- X if(*s == '+' || *s == '-')
- X {
- X /* We don't want to match any NIS inclusions/exclusions */
- X *s = '\0';
- X return;
- X }
- X /* Get potential matches from NIS and cull those without local accounts */
- X if (getdomainname(domain, YPMAXDOMAIN) == 0)
- X {
- X cb.foreach = match_username;
- X cb.data = (char *) &data;
- X yp_all(domain, PASSWD_MAP, &cb);
- X for(n = firstnode(matches); n; incnode(n))
- X if(getpwnam(getdata(n)) == NULL) uremnode(matches,n);
- X }
- X /* Don't forget the non-NIS matches from the flat passwd file */
- X if ((pwf = fopen(PASSWD_FILE, "r")) != NULL)
- X {
- X skipping = 0;
- X while (fgets(buf, BUFSIZ, pwf) != NULL)
- X {
- X if (strchr(buf, '\n') != NULL)
- X {
- X if (!skipping)
- X {
- X if (strncmp(buf,data.s,data.len) == 0 &&
- X (p = strchr(buf, ':')) != NULL)
- X {
- X *p = '\0';
- X addmatch(buf);
- X }
- X }
- X else skipping = 0;
- X }
- X else skipping = 1;
- X }
- X fclose(pwf);
- X }
- X#else
- X struct passwd *pwd;
- X int len,i;
- X
- X if (!usernamescached)
- X {
- X setpwent();
- X while((pwd=getpwent()) != NULL && !errflag)
- X adduserdir(pwd->pw_name,pwd->pw_dir);
- X endpwent();
- X usernamescached=1;
- X }
- X
- X s++;
- X len = strlen(s);
- X
- X for(i=0;i<userdirsz;i++)
- X {
- X if(usernames[i] && userdirs[i] &&
- X strncmp(usernames[i],s,len)==0) addmatch(usernames[i]);
- X }
- X#endif
- X *s = 0;
- X}
- X
- X/*
- X * opendir that handles '~' and '=' and '$'.
- X * orig. by ash@aaii.oz.au, mod. by pf
- X */
- XDIR *OPENDIR(s)
- Xchar *s;
- X{
- X if (*s != '~' && *s != '=' && *s != '$')
- X return(opendir(s));
- X s = strdup(s);
- X *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
- X singsub(&s);
- X return(opendir(s));
- X}
- Xchar *dirname(s)
- Xchar *s;
- X{
- X if (*s == '~' || *s == '=' || *s == '$') {
- X s = strdup(s);
- X *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
- X singsub(&s);
- X }
- X return(s);
- X}
- X
- Xint Isdir(s) /**/
- Xchar *s;
- X{
- Xstruct stat sbuf;
- X
- X if (!*s) return 0;
- X if (stat(s,&sbuf) == -1) return 0;
- X return S_ISDIR(sbuf.st_mode);
- X}
- X
- X/* this will work whether s is tokenized or not */
- Xint isdir(t,s) /**/
- Xchar *t;char *s;
- X{
- Xchar buf[MAXPATHLEN];
- X
- X if (typechar != '$')
- X sprintf(buf,"%s/%s",(s) ? s : ".",t);
- X else
- X sprintf(buf,"$%s",t);
- X s = buf;
- X if (*s != '~' && *s != '=' && *s != Tilde && *s != Equals &&
- X *s != '$' && *s != String)
- X return(Isdir(s));
- X s = strdup(s);
- X if (*s == '~' || *s == '=' || *s == '$')
- X *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
- X singsub(&s);
- X return(Isdir(s));
- X}
- X
- X#define SLASH_YES 0
- X#define SLASH_NO 1
- X#define SLASH_MAYBE 2
- X
- Xint slashflag;
- Xint addedstar;
- Xchar *pathprefix;
- X
- Xvoid docompletion(s,lst,incmd) /**/
- Xchar *s;int lst;int incmd;
- X{
- Xchar *tokorigs = NULL;
- Xchar *origs;
- XCompctl cc;
- Xchar *u;
- Xchar *pfx = s;
- X
- X slashflag = SLASH_MAYBE;
- X addedstar = 0;
- X lastambig = 0;
- X
- X heapalloc();
- X pushheap();
- X if (useglob)
- X tokorigs = strdup(s);
- X untokenize(s);
- X origs = strdup(s);
- X matches = newlist();
- X if (incmd)
- X cc = &cc_compos;
- X else if (linredir || !(cmdstr && (cc = gethnode(cmdstr,compctltab))))
- X cc = &cc_default;
- X exact = 0;
- X if (cc->mask & CC_COMMPATH) gen_matches_reg(s,1,(cc->mask & CC_FILES));
- X else if (cc->mask & CC_FILES) gen_matches_reg(s,0,1);
- X else {
- X haspath = 0;
- X slashflag = SLASH_NO;
- X }
- X if (cc->mask & (CC_FILES|CC_COMMPATH)) {
- X /* only do "globbed" completion if regular completion fails.
- X pem, 7Oct91 */
- X if ((empty(matches) || errflag) && useglob) {
- X gen_matches_glob(tokorigs,incmd);
- X /*
- X * gen_matches_glob changes the insert line to be correct up
- X * to the match, so the prefix string must be "". ash, 7Oct91
- X */
- X *s = 0;
- X }
- X }
- X pat = s;
- X if ((cc->mask & CC_HOSTS) && !haspath) {
- X char **x;
- X for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
- X
- X/* we now try to do expansion if there is an @ symbol in the string */
- X
- X haspath = 0;
- X for (u = s+strlen(s); u >= s; u--)
- X if (*u == '@' ) break;
- X if (u >= s) {
- X typechar = *u;
- X *u++ = '\0';
- X haspath = 1;
- X } else u = s;
- X pat = u;
- X if (typechar == '@' && haspath ) {
- X char **x;
- X slashflag = SLASH_NO;
- X for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
- X }
- X }
- X pat = s;
- X if ((cc->mask & CC_OPTIONS) && !haspath) {
- X struct option *o;
- X for (o = optns; o->name; o++) addcmdmatch(o->name,NULL);
- X }
- X if ((cc->mask & CC_VARS) && !haspath) listhtable(paramtab,addcmdmatch);
- X if ((cc->mask & CC_BINDINGS) && !haspath) {
- X int t0;
- X for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
- X if (*zlecmds[t0].name) addcmdmatch(zlecmds[t0].name,NULL);
- X }
- X if (cc->mask & CC_USRKEYS) {
- X char **usr = get_user_var(cc->keyvar);
- X if (usr) while (*usr) addcmdmatch(*usr++,NULL);
- X }
- X if (lst != COMP_LIST_COMPLETE) do_fignore(origs);
- X if (empty(matches) || errflag) {
- X feep();
- X } else if (lst == COMP_LIST_COMPLETE) {
- X listmatches(matches,
- X unset(LISTTYPES) ? NULL :
- X (haspath) ? pathprefix : "./");
- X } else if (nextnode(firstnode(matches))) {
- X do_ambiguous(pfx);
- X } else {
- X do_single(pfx);
- X }
- X ll = strlen((char *) line);
- X setterm();
- X popheap();
- X permalloc();
- X}
- X
- Xchar **get_user_var(nam) /**/
- Xchar *nam;
- X{
- X return (nam) ? getaparam(nam) : NULL;
- X}
- X
- Xvoid gen_matches_glob(s,incmd) /**/
- Xchar *s;int incmd;
- X{
- Xchar *pt,*u;
- Xint hasp = 0;
- XDIR *d;
- Xstruct direct *de;
- X
- X /*
- X * Find the longest prefix string without any
- X * chars special to glob - ash.
- X */
- X for (pt = s; *pt; pt++) {
- X if (pt == s && (*pt == Tilde || *pt == Equals)) continue;
- X if (ispecial(*pt) || itok(*pt)) break;
- X }
- X for (; pt > s && *pt != '/'; pt--) ;
- X if (*pt == '/') {
- X *pt = 0;
- X u = pt + 1;
- X wb += strlen(s);
- X hasp = 1;
- X } else u = s;
- X if (!hasp && (*s == Tilde || *s == Equals)) {
- X /* string contains only ~xx, so do tilde expansion */
- X maketildelist(s);
- X wb++;
- X pathprefix = s;
- X slashflag = SLASH_YES;
- X } else if (incmd && !hasp) {
- X slashflag = SLASH_NO;
- X pat = s;
- X listhtable(aliastab ,addcmdmatch);
- X if (isset(HASHLISTALL)) fullhash();
- X listhtable(cmdnamtab,addcmdnodis);
- X if (isset(AUTOCD)) listhtable(paramtab ,addcmddirparam);
- X if (d = opendir(".")) {
- X char *q;
- X
- X readdir(d); readdir(d);
- X while ((de = readdir(d)) && !errflag)
- X if (strpfx(pat,q = de->d_name) &&
- X (*q != '.' || *u == '.' || isset(GLOBDOTS)))
- X addmatch(q);
- X closedir(d);
- X }
- X } else {
- X int commonprefix = 0;
- X char *prefix;
- X Lknode n;
- X int nonomatch = isset(NONOMATCH);
- X
- X opts[NONOMATCH] = 1;
- X if (hasp) {
- X /* Find the longest common prefix string
- X * after globbing the input. All expansions
- X * '~foo/bar/*' will turn into something like
- X * /tmp_mnt/hosts/somehost/home/foo/...
- X * We will remove this common prefix from the matches.
- X * ash, 7 May '91
- X */
- X pathprefix = s;
- X addnode(matches,s);
- X prefork(matches);
- X if (!errflag) postfork(matches,1);
- X if (!errflag) {
- X prefix = peekfirst(matches);
- X if (prefix) commonprefix = strlen(prefix) + 1;
- X *pt = '/';
- X }
- X }
- X if (s[strlen(s) - 1] == '/') {
- X /* if strings ends in a '/' always add a '*' */
- X s = dyncat(s,"x");
- X s[strlen(s)-1] = Star;
- X addedstar = 1;
- X }
- X matches = newlist();
- X addnode(matches,s);
- X prefork(matches);
- X if (!errflag) postfork(matches,1);
- X opts[NONOMATCH] = nonomatch;
- X if (errflag || empty(matches) || !nextnode(firstnode(matches))) {
- X /* if there were no matches (or only one)
- X add a trailing * and try again */
- X s = dyncat(s,"x");
- X s[strlen(s)-1] = Star;
- X addedstar = 1;
- X matches = newlist();
- X addnode(matches,s);
- X prefork(matches);
- X if (errflag) return;
- X postfork(matches,1);
- X if (errflag) return;
- X }
- X /* remove the common prefix from all the matches */
- X if (commonprefix)
- X for (n = firstnode(matches); n; incnode(n))
- X n->dat = (char *) n->dat+commonprefix;
- X s = pt;
- X *s = 0;
- X }
- X}
- X
- Xvoid gen_matches_reg(s,incmd,regfiles) /**/
- Xchar *s;int incmd;int regfiles;
- X{
- Xchar *u;
- XDIR *d;
- Xstruct direct *de;
- X
- X haspath = 0;
- X for (u = s+strlen(s); u >= s; u--)
- X if (*u == '/' || *u == '@' || *u == '$') break;
- X if (u >= s) {
- X typechar = *u;
- X *u++ = '\0';
- X haspath = 1;
- X } else if (*s == '=') {
- X typechar = '=';
- X *s = '\0'; u = s+1;
- X haspath = 1;
- X } else u = s;
- X pat = u;
- X if (typechar == '$' && haspath) {
- X /* slashflag = SLASH_NO; */
- X listhtable(paramtab,addcmdmatch);
- X } else if (typechar == '=' && haspath) {
- X slashflag = SLASH_NO;
- X if (isset(HASHLISTALL)) fullhash();
- X listhtable(cmdnamtab,addcmdnodis);
- X } else if (typechar == '@' && haspath) {
- X char **x;
- X slashflag = SLASH_NO;
- X for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
- X } else if (*s == '~' && !haspath) {
- X maketildelist(s);
- X pathprefix = s;
- X slashflag = SLASH_YES;
- X } else if (incmd && !haspath) {
- X slashflag = SLASH_NO;
- X listhtable(aliastab ,addcmdmatch);
- X if (isset(HASHLISTALL)) fullhash();
- X listhtable(cmdnamtab,addcmdnodis);
- X if (isset(AUTOCD) && isset(CDABLEVARS))
- X listhtable(paramtab ,addcmddirparam);
- X if (d = opendir(".")) {
- X char *q;
- X struct stat buf;
- X
- X readdir(d); readdir(d);
- X if (regfiles) {
- X while ((de = readdir(d)) && !errflag)
- X if (strpfx(pat,q = de->d_name) &&
- X (*q != '.' || *u == '.' || isset(GLOBDOTS))) addmatch(q);
- X } else if (isset(AUTOCD)) {
- X while ((de = readdir(d)) && !errflag)
- X if (strpfx(pat,q = de->d_name) &&
- X (*q != '.' || *u == '.' || isset(GLOBDOTS)) &&
- X stat(q,&buf) >= 0 &&
- X (buf.st_mode & S_IEXEC) == S_IEXEC) addmatch(q);
- X } else {
- X while ((de = readdir(d)) && !errflag)
- X if (strpfx(pat,q = de->d_name) &&
- X (*q != '.' || *u == '.' || isset(GLOBDOTS)) &&
- X stat(q,&buf) >= 0 &&
- X (buf.st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC))
- X addmatch(q);
- X }
- X closedir(d);
- X }
- X } else if (d = OPENDIR(pathprefix =
- X ((haspath || *s == '~') ? ((*s) ? s : "/") : "."))) {
- X char *q,buf2[MAXPATHLEN];
- X struct stat buf;
- X char dn[MAXPATHLEN];
- X
- X strcpy(dn,dirname(pathprefix));
- X readdir(d); readdir(d);
- X while ((de = readdir(d)) && !errflag)
- X if (strpfx(pat,q = de->d_name) &&
- X (*q != '.' || *u == '.' || isset(GLOBDOTS))) {
- X if (incmd) {
- X sprintf(buf2,"%s/%s",dn,q);
- X if (stat(buf2,&buf) < 0 ||
- X (buf.st_mode & S_IEXEC) == S_IEXEC) {
- X addmatch(q);
- X }
- X } else {
- X addmatch(q);
- X }
- X }
- X closedir(d);
- X }
- X}
- X
- Xvoid do_fignore(origstr) /**/
- Xchar *origstr;
- X{
- X if (full(matches) && nextnode(firstnode(matches))) {
- X Lknode z,zn;
- X
- X ambig = 1000;
- X for (z = firstnode(matches); z; z = zn) {
- X char *q = getdata(z);
- X int namlen = strlen(q);
- X int slen = strlen(origstr);
- X int slpt;
- X char **pt = fignore;
- X
- X zn = nextnode(z);
- X for (; *pt; pt++) {
- X /* We try to be smart here and override the
- X fignore variable if the user has explicity
- X used the ignored prefix, pem, 7 May 1991 */
- X slpt = strlen(*pt);
- X if (!addedstar && slen > slpt &&
- X strcmp(origstr+slen-slpt, *pt) == 0)
- X continue;
- X if (slpt < namlen && !strcmp(q+namlen-slpt,*pt)) {
- X uremnode(matches,z);
- X break;
- X }
- X }
- X if (!*pt) {
- X int y = pfxlen(peekfirst(matches),q);
- X if (y < ambig) ambig = y;
- X }
- X }
- X }
- X}
- X
- Xvoid do_ambiguous(s) /**/
- Xchar *s;
- X{
- X lastambig = 1;
- X if (usemenu) { do_ambig_menu(s); return; }
- X if (useglob) {
- X feep();
- X if (isset(AUTOLIST))
- X listmatches(matches,
- X unset(LISTTYPES) ? NULL : (haspath) ? pathprefix : "./");
- X return;
- X }
- X cs = wb;
- X foredel(we-wb);
- X if (*s == '~' || *s == '=' || *s == '$') {
- X spaceinline(1);
- X line[cs++] = *s++;
- X }
- X if (haspath) {
- X inststr(s);
- X spaceinline(1);
- X line[cs++] = typechar;
- X }
- X if (isset(RECEXACT) && exact) {
- X lastambig = 0;
- X if ((*pat == '~' || *pat == '=' || *pat == '$') && !haspath) {
- X spaceinline(1);
- X line[cs++] = *s++;
- X }
- X inststr(exactstr);
- X spaceinline(1);
- X switch (slashflag) {
- X case SLASH_YES: line[cs++] = '/'; break;
- X case SLASH_NO : line[cs++] = ' '; break;
- X case SLASH_MAYBE: line[cs++] =
- X isdir(exactstr,pathprefix) ? '/' : ' '; break;
- X }
- X return;
- X }
- X s = peekfirst(matches);
- X if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
- X spaceinline(1);
- X line[cs++] = *s++;
- X ambig--;
- X }
- X inststrlen(s,ambig);
- X refresh();
- X if (isset(AUTOLIST)) {
- X if (unset(NOLISTBEEP)) feep();
- X listmatches(matches,
- X unset(LISTTYPES) ? NULL : (haspath) ? pathprefix : "./");
- X } else feep();
- X}
- X
- Xvoid do_single(s) /**/
- Xchar *s;
- X{
- X cs = wb;
- X foredel(we-wb);
- X if (*s == '~' || *s == '=' || *s == '$') {
- X spaceinline(1);
- X line[cs++] = *s++;
- X }
- X if (haspath) {
- X inststr(s);
- X spaceinline(1);
- X line[cs++] = typechar;
- X }
- X s = peekfirst(matches);
- X if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
- X spaceinline(1);
- X line[cs++] = *s++;
- X }
- X inststr(s);
- X spaceinline(1);
- X switch (slashflag) {
- X case SLASH_YES: line[cs++] = '/'; break;
- X case SLASH_NO : line[cs++] = ' '; break;
- X case SLASH_MAYBE: line[cs++] = isdir(s,pathprefix) ? '/' : ' '; break;
- X }
- X if (isset(AUTOREMOVESLASH) && line[cs-1] == '/') addedslash = 1;
- X}
- X
- Xvoid do_ambig_menu(s) /**/
- Xchar *s;
- X{
- X menucmp = 1;
- X if (isset(MENUCOMPLETEBEEP)) feep();
- X cs = wb;
- X menuw = cs;
- X foredel(we-wb);
- X if (*s == '~' || *s == '=' || *s == '$') {
- X spaceinline(1);
- X line[cs++] = *s++;
- X }
- X if (haspath) {
- X inststr(s);
- X spaceinline(1);
- X line[cs++] = typechar;
- X }
- X menub = cs;
- X s = peekfirst(matches);
- X if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
- X spaceinline(1);
- X line[cs++] = *s++;
- X }
- X inststr(s);
- X menue = cs;
- X permalloc();
- X menulist = duplist(matches,(VFunc)ztrdup);
- X heapalloc();
- X menunode = firstnode(menulist);
- X permalloc();
- X if (isset(LASTMENU)) {
- X if (lastmenu)
- X free(lastmenu);
- X lastmenu = ztrdup(UTOSCP(line));
- X lastmenupos = cs;
- X }
- X}
- X
- Xint strpfx(s,t) /**/
- Xchar *s;char *t;
- X{
- X while (*s && *s == *t) s++,t++;
- X return !*s;
- X}
- X
- Xint pfxlen(s,t) /**/
- Xchar *s;char *t;
- X{
- Xint i = 0;
- X
- X while (*s && *s == *t) s++,t++,i++;
- X return i;
- X}
- X
- Xvoid listmatches(l,apps) /**/
- XLklist l;char *apps;
- X{
- Xint longest = 1,fct,fw = 0,colsz,t0,t1,ct;
- XLknode n;
- Xchar **arr,**ap;
- X
- X trashzle();
- X ct = countnodes(l);
- X if (listmax && ct > listmax)
- X {
- X fprintf(stdout,"zsh: do you wish to see all %d possibilities? ",ct);
- X fflush(stdout);
- X if (getquery() != 'y')
- X return;
- X }
- X ap = arr = alloc((countnodes(l)+1)*sizeof(char **));
- X for (n = firstnode(l); n; incnode(n))
- X *ap++ = getdata(n);
- X *ap = NULL;
- X for (ap = arr; *ap; ap++)
- X if (strlen(*ap) > longest)
- X longest = strlen(*ap);
- X if (apps)
- X {
- X apps = strdup(apps);
- X if (*apps == '~')
- X *apps = Tilde;
- X else if (*apps == '=')
- X *apps = Equals;
- X else if (*apps == '$')
- X *apps = String;
- X singsub(&apps);
- X longest++;
- X }
- X qsort((vptr)arr,ct,sizeof(char *),
- X (int (*) DCLPROTO((const void *, const void *)))forstrcmp);
- X fct = (columns-1)/(longest+2);
- X if (fct == 0)
- X fct = 1;
- X else
- X fw = (columns-1)/fct;
- X colsz = (ct+fct-1)/fct;
- X for (t1 = 0; t1 != colsz; t1++)
- X {
- X ap = arr+t1;
- X if (apps)
- X {
- X do
- X {
- X int t2 = strlen(*ap)+1;
- X char pbuf[MAXPATHLEN];
- X struct stat buf;
- X
- X printf("%s",*ap);
- X sprintf(pbuf,"%s/%s",apps,*ap);
- X if (lstat(pbuf,&buf)) putchar(' ');
- X else switch (buf.st_mode & S_IFMT) /* screw POSIX */
- X {
- X case S_IFDIR: putchar('/'); break;
- X#ifdef S_IFIFO
- X case S_IFIFO: putchar('|'); break;
- X#endif
- X case S_IFCHR: putchar('%'); break;
- X case S_IFBLK: putchar('#'); break;
- X#ifdef S_IFLNK
- X case S_IFLNK: putchar(
- X (access(pbuf,F_OK) == -1) ? '&' : '@'); break;
- X#endif
- X#ifdef S_IFSOCK
- X case S_IFSOCK: putchar('='); break;
- X#endif
- X default:
- X if (buf.st_mode & 0111)
- X putchar('*');
- X else
- X putchar(' ');
- X break;
- X }
- X for (; t2 < fw; t2++) putchar(' ');
- X for (t0 = colsz; t0 && *ap; t0--,ap++);
- X }
- X while (*ap);
- X }
- X else
- X do
- X {
- X int t2 = strlen(*ap);
- X
- X printf("%s",*ap);
- X for (; t2 < fw; t2++) putchar(' ');
- X for (t0 = colsz; t0 && *ap; t0--,ap++);
- X }
- X while (*ap);
- X putchar('\n');
- X }
- X resetneeded = 1;
- X fflush(stdout);
- X}
- X
- Xvoid selectlist(l) /**/
- XLklist l;
- X{
- Xint longest = 1,fct,fw = 0,colsz,t0,t1,ct;
- XLknode n;
- Xchar **arr,**ap;
- X
- X trashzle();
- X ct = countnodes(l);
- X ap = arr = alloc((countnodes(l)+1)*sizeof(char **));
- X for (n = firstnode(l); n; incnode(n))
- X *ap++ = getdata(n);
- X *ap = NULL;
- X for (ap = arr; *ap; ap++)
- X if (strlen(*ap) > longest)
- X longest = strlen(*ap);
- X t0 = ct;
- X longest++;
- X while (t0)
- X t0 /= 10, longest++;
- X fct = (columns-1)/(longest+3); /* to compensate for added ')' */
- X if (fct == 0)
- X fct = 1;
- X else
- X fw = (columns-1)/fct;
- X colsz = (ct+fct-1)/fct;
- X for (t1 = 0; t1 != colsz; t1++) {
- X ap = arr+t1;
- X do {
- X int t2 = strlen(*ap)+2,t3;
- X
- X fprintf(stderr,"%d) %s",t3 = ap-arr+1,*ap);
- X while (t3) t2++,t3 /= 10;
- X for (; t2 < fw; t2++) fputc(' ',stderr);
- X for (t0 = colsz; t0 && *ap; t0--,ap++);
- X } while (*ap);
- X fputc('\n',stderr);
- X }
- X
- X/* Below is a simple attempt at doing it the Korn Way..
- X ap = arr;
- X t0 = 0;
- X do
- X {
- X t0++;
- X fprintf(stderr,"%d) %s\n",t0,*ap);
- X ap++;
- X }
- X while (*ap);*/
- X resetneeded = 1;
- X fflush(stderr);
- X}
- X
- Xint doexpandhist() /**/
- X{
- Xunsigned char *cc,*ce;
- Xint t0,oldcs,oldll;
- X
- X for (cc = line, ce = line+ll; cc < ce; cc++)
- X if (*cc == '\\' && cc[1])
- X cc++;
- X else if (*cc == bangchar ||
- X (*cc == hatchar && *line == hatchar && cc != line))
- X break;
- X if (*cc == bangchar && cc[1] == '"') return 0;
- X if (cc == ce) return 0;
- X oldcs = cs;
- X oldll = ll;
- X zleparse = 1;
- X lexsave();
- X hungets(UTOSCP(line));
- X strinbeg();
- X pushheap();
- X ll = cs = 0;
- X for(;;)
- X {
- X t0 = hgetc();
- X if (lexstop)
- X break;
- X spaceinline(1);
- X line[cs++] = t0;
- X }
- X hflush();
- X popheap();
- X strinend();
- X errflag = zleparse = 0;
- X t0 = histdone;
- X lexrestore();
- X line[ll = cs] = '\0';
- X if (ll == oldll) cs = oldcs;
- X return t0;
- X}
- X
- Xvoid magicspace() /**/
- X{
- X c = ' ';
- X selfinsert();
- X doexpandhist();
- X}
- X
- Xvoid expandhistory() /**/
- X{
- X if (!doexpandhist())
- X feep();
- X}
- X
- Xstatic int cmdwb,cmdwe;
- X
- Xchar *getcurcmd() /**/
- X{
- Xint lincmd;
- Xchar *s = NULL;
- X
- X zleparse = 1;
- X lexsave();
- X hungets(" "); /* KLUDGE! */
- X hungets(UTOSCP(line));
- X strinbeg();
- X pushheap();
- X do {
- X lincmd = incmdpos;
- X ctxtlex();
- X if (tok == ENDINPUT) break;
- X if (tok == STRING && lincmd) {
- X if (s) free(s);
- X s = ztrdup(tokstr);
- X cmdwb = ll-wordbeg; cmdwe = ll+1-inbufct;
- X }
- X } while (tok != ENDINPUT && zleparse);
- X hflush();
- X popheap();
- X strinend();
- X errflag = zleparse = 0;
- X lexrestore();
- X return s;
- X}
- X
- Xvoid processcmd() /**/
- X{
- Xchar *s,*t;
- X
- X s = getcurcmd();
- X if (!s) { feep(); return; }
- X t = zlecmds[bindk].name;
- X mult = 1;
- X pushline();
- X sizeline(strlen(s)+strlen(t)+1);
- X strcpy((char *) line,t);
- X strcat((char *) line," ");
- X cs = ll = strlen((char *) line);
- X inststr(s);
- X free(s);
- X done = 1;
- X}
- X
- Xvoid expandcmdpath() /**/
- X{
- Xint oldcs = cs;
- Xchar *s,*str;
- X
- X s = getcurcmd();
- X if (!s) { feep(); return; }
- X str = findcmd(s);
- X free(s);
- X if (!str) { feep(); return; }
- X cs = cmdwb;
- X foredel(cmdwe-cmdwb);
- X spaceinline(strlen(str));
- X strncpy((char *) line+cs,str,strlen(str));
- X cs = oldcs;
- X if (cs >= cmdwe) cs += cmdwe-cmdwb+strlen(str);
- X if (cs > ll) cs = ll;
- X free(str);
- X}
- X
- Xvoid freemenu() /**/
- X{
- X if (menucmp && (unset(LASTMENU) || lastmenu == NULL)) {
- X menucmp = 0;
- X freetable(menulist,freestr);
- X }
- X}
- X
- Xint inarray(s,a) /**/
- Xchar *s; char **a;
- X{
- X for (; *a; a++) if (!strcmp(*a,s)) return 1;
- X return 0;
- X}
- X
- END_OF_FILE
- if test 28258 -ne `wc -c <'src/zle_tricky.c'`; then
- echo shar: \"'src/zle_tricky.c'\" unpacked with wrong size!
- fi
- # end of 'src/zle_tricky.c'
- fi
- echo shar: End of archive 13 \(of 22\).
- cp /dev/null ark13isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 22 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
-
- exit 0 # Just in case...
-