home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / zsh / part13 < prev    next >
Encoding:
Text File  |  1993-02-19  |  54.4 KB  |  1,987 lines

  1. Newsgroups: comp.sources.misc
  2. From: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
  3. Subject: v35i063:  zsh - The Z Shell, version 2.3.1, Part13/22
  4. Message-ID: <1993Feb20.212531.28970@sparky.imd.sterling.com>
  5. X-Md4-Signature: b001b8458fd97ee8644a8d118cca3eeb
  6. Date: Sat, 20 Feb 1993 21:25:31 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
  10. Posting-number: Volume 35, Issue 63
  11. Archive-name: zsh/part13
  12. Environment: UNIX
  13. Supersedes: zsh2.2: Volume 29, Issue 97-113
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  20. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  21. # Contents:  FAQ help/pushd src/zle_tricky.c
  22. # Wrapped by mattson@odin on Sat Feb  6 14:41:54 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 13 (of 22)."'
  26. if test -f 'FAQ' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'FAQ'\"
  28. else
  29.   echo shar: Extracting \"'FAQ'\" \(21578 characters\)
  30.   sed "s/^X//" >'FAQ' <<'END_OF_FILE'
  31. XArchive-Name: zsh.FAQ
  32. XSubmitted-By: pws@s-a.amtp.liv.ac.uk (Peter Stephenson)
  33. X
  34. X$Id: FAQ,v 1.3 1993/02/04 10:17:55 pws Exp pws $
  35. X
  36. XThis document contains a list of frequently-asked (or otherwise
  37. Xsignificant) questions concerning the Z-shell, a powerful command
  38. Xinterpreter for many UNIX systems.
  39. X
  40. XIf you have never heard of `sh', `csh' or `ksh', then you are probably
  41. Xbetter off to start by reading a general introduction to UNIX rather
  42. Xthan this document.
  43. X
  44. XAnother useful source of information is the collection of FAQ articles
  45. Xposted bi-weekly to the Usenet news groups comp.unix.questions,
  46. Xcomp.unix.shells and news.answers with answers to general questions
  47. Xabout UNIX.  The fifth of the seven articles deals with shells,
  48. Xincluding zsh, with a brief description of differences.  (This article
  49. Xalso talks about shell startup files which would otherwise rate a
  50. Xmention here.)
  51. X
  52. XIf you just want to know how to get your hands on the latest version,
  53. Xskip to question 4; if you want to know what to do with insoluble
  54. Xproblems, go to 17.
  55. X
  56. XNotation: Quotes `like this' are ordinary textual quotation
  57. Xmarks.  Other uses of quotation marks are input to the shell.
  58. X
  59. XContents:
  60. X1) What is it?
  61. X2) On what machines will it run?
  62. X3) What's the latest version?
  63. X4) Where do I get it?
  64. X5) How does zsh differ from sh, ksh, csh,...?
  65. X6) Why do my csh aliases not work?
  66. X7) How do I get the meta key to work on my xterm?
  67. X8) Why does my terminal act funny in way x?
  68. X9) Why does `$vble' where vble="foo bar" not do what I expect?
  69. X10) How does base arithmetic work?
  70. X11) How do I get a newline in my prompt?
  71. X12) Why does `bindkey ^a command-name' do something funny?
  72. X13) How do I reference command `foo' from within function `foo'?
  73. X14) I don't have root access: how do I make zsh my login shell?
  74. X15) What bugs are currently known and unfixed?
  75. X16) Where do I report bugs, get more info / who's working on zsh?
  76. X17) What's on the wish-list?
  77. X
  78. X
  79. X1) What is it?
  80. X
  81. X  Zsh is a UNIX command interpreter (shell) which of the standard shells
  82. X  most resembles the Korn shell (ksh), although it is not completely
  83. X  compatible.  It includes enhancements of many types, notably in the
  84. X  command-line editor, options for customising its behaviour, filename
  85. X  globbing, features to make C-shell (csh) users feel more at home and
  86. X  extra features drawn from tcsh (another `custom' shell).
  87. X
  88. X  It was written by Paul Falstad <pf@ttisms.com> when a student at
  89. X  Princeton; however, Paul doesn't maintain it any more and enquiries
  90. X  should be sent to the mailing list (see question 17).  It is freely
  91. X  available to anyone under unrestrictive conditions.
  92. X
  93. X  For more information, the files doc/intro.txt or doc/intro.troff
  94. X  included with the source distribution are highly recommended.  The
  95. X  files intro.ps.Z and intro.txt.Z can also be FTP'd separately from the
  96. X  archive (see 4).  A list of features is given in FEATURES, also with
  97. X  the source.
  98. X
  99. X
  100. X2) On what machines will it run?
  101. X
  102. X  Zsh was written for machines of the Berkeley UNIX family; most such
  103. X  machines (and all the most popular) will run it without major surgery.
  104. X  Modifications have been made so that it should work under SYSVR4-based
  105. X  operating systems such as Solaris 2.x.  This best thing is to suck it
  106. X  and see.  You may not have to change too much:  if you do change
  107. X  anything,  arrange for the shell script `buildzsh' to set the
  108. X  necessary #define's, etc., without human intervention.
  109. X
  110. X
  111. X3) What's the latest version?
  112. X  
  113. X  The latest production version is 2.3.1, which has just been released.
  114. X  New patches occur frequently and are added to the archive (next
  115. X  question).
  116. X
  117. X
  118. X4) Where do I get it?
  119. X
  120. X  The current release is available for anonymous FTP from
  121. X    cs.ucsd.edu (132.239.51.3):pub/zsh/zsh2.3.1.tar.Z
  122. X  The archive maintainer currently is Jim Mattson <mattson@cs.UCSD.EDU>,
  123. X  who also reads the mailing list.
  124. X
  125. X  Bas de Bakker (bas@phys.uva.nl) will shortly be taking over the archive
  126. X  and new patches are likely to be available from:
  127. X    carlo.phys.uva.nl (145.18.220.25):/pub/bas/zsh
  128. X  
  129. X  Richard Ohnemus will probably have a North American reflector at
  130. X  ftp.sterling.com.
  131. X
  132. X
  133. X5) How does zsh differ from sh, ksh, csh,...?
  134. X
  135. X  As mentioned, zsh is most similar to ksh, while many of the additions are
  136. X  to please csh users.
  137. X
  138. X  i) ksh:
  139. X  Most features of ksh are implemented in zsh; problems can arise
  140. X  because the implementation is slightly different.  Note also not all
  141. X  ksh's are the same either.  I have based this on SunOS 4, which is
  142. X  essentially the 11/16/88 version of ksh.
  143. X
  144. X  Differences from ksh which might prove significant for ksh
  145. X  programmers, some of which may be interpreted as bugs (there must be
  146. X  more) include:
  147. X    Shell word splitting: see question 14.
  148. X    Arrays are more csh-like than ksh-like:
  149. X      subscripts start at 1, not 0; array[0] refers to array[1];
  150. X      `$array' refers to the whole array, not $array[0];
  151. X      braces are unnecessary: $a[1] == ${a[1]}, etc.
  152. X    Path not searched for commands specified at invocation without -c.
  153. X    Management of histories in multiple shells may be different.
  154. X    Coprocesses are established by `coproc'; `|&' behaves like csh.
  155. X    PS1 does not do parameter substitution.
  156. X    Globbing does not allow ksh-style `pattern-lists'.
  157. X    The options emacs, gmacs, privileged, trackall, viraw are not supported.
  158. X    The `keyword' option does not exist and -k is instead interactivecomments.
  159. X    [ ] is a shell built-in, rather than a call to /bin/test.
  160. X    There is no built-in command newgrp: use a shell function.
  161. X    The order in which aliases and functions are defined is significant.
  162. X    Some built-ins (true, false, r, ...) were aliases in ksh.
  163. X    Aliases and functions cannot be exported.
  164. X    There are no tracked aliases.
  165. X    There is no ENV variable.
  166. X    No built-in commands cause automatic termination of a script.
  167. X    The -- flag to terminate option processing is not recognised
  168. X       as an argument to the shell (it is recognised by set).
  169. X    `jobs' has no `-n' flag.
  170. X    Treatment of backslashes within backquotes is different.
  171. X    Variable assignments with tilde expansions are special-cased.
  172. X    Editing:
  173. X      \ does not escape editing chars (use ^V).
  174. X      Not all ksh bindings are set (e.g. `<ESC>#').
  175. X  The following is particularly near the feature/bug borderline:
  176. X    To turn off signal traps, use `trap - <signo>', not `trap <signo>'.
  177. X    "$@" always indicates at least one argument (older sh's do this too).
  178. X
  179. X  ii) csh:
  180. X
  181. X  Although certain features aim to ease the withdrawal symptoms of Csh
  182. X  (ab)users, the syntax is in general rather different and you should
  183. X  certainly not try to run scripts without modification.  The c2z script
  184. X  is provided with the source (in scripts/c2z) to help convert .cshrc
  185. X  and .login files; see also the next question concerning aliases.
  186. X
  187. X  Csh-compatibility additions include:
  188. X    Logout, rehash, source, (un)limit built-in commands.
  189. X    *rc file for interactive shells.
  190. X    Directory stacks.
  191. X    Cshjunkie*, ignoreeof options.
  192. X    The nonomatch option.
  193. X    >&, |& etc. redirection.
  194. X    foreach ... loops.
  195. X    $PROMPT as well as $PS1, $status as well as $?, $#argv as well as $#, ....
  196. X    Escape sequences via % for prompts.
  197. X    Special array variables $PATH etc. are colon-separated, $path are arrays.
  198. X    !-type history (which may be turned off).
  199. X    Arrays have csh-like features (see i)).
  200. X
  201. X  iii) tcsh:
  202. X
  203. X  Certain features have been borrowed from tcsh, including $watch,
  204. X  run-help, $savehist, $histlit, periodic commands etc., extended
  205. X  prompts, sched and which/where built-ins.  This list is not
  206. X  definitive: some features have gone in the other direction.
  207. X
  208. X  iv) specific features:
  209. X
  210. X  Things that zsh is particularly good at (no claim of exclusivity is made,
  211. X  especially as shells copy one another) include:
  212. X    Command line editing:
  213. X      multi-line commands,
  214. X      variable editing,
  215. X      command buffer stack,
  216. X      execution of unbound commands,
  217. X      menu completion,
  218. X      variable, host, editing function and option name completion,
  219. X      inline expansion of variables, history commands,
  220. X      path expansion (=foo).
  221. X    Globbing:
  222. X      recursive globbing (c.f find),
  223. X      file attribute qualifiers,
  224. X      full alternation and negation of patterns.
  225. X    Large number of options for tailoring.
  226. X    Adaptable messages for spelling, watch, time as well as prompt.
  227. X    Named directories.
  228. X    Comprehensive integer arithmetic.
  229. X    Manipulation of arrays.
  230. X    Spelling correction.
  231. X
  232. X
  233. X6) Why do my csh aliases not work?
  234. X
  235. X  First of all, check you are using the syntax
  236. X    alias newcmd='list of commands'
  237. X  and not
  238. X    alias newcmd 'list of commands'
  239. X  which won't work. (It tells you if `newcmd' and `list of commands' are
  240. X  already defined as aliases.)
  241. X
  242. X  Otherwise, your aliases probably contain references to the command
  243. X  line of the form `\!*', etc.  Zsh does not handle this behaviour as it
  244. X  has shell functions which provide a way of solving this problem more
  245. X  consistent with other forms of argument handling.  For example, the
  246. X  csh alias
  247. X    alias cd 'cd \!*; echo $cwd'
  248. X  can be replaced by the zsh function,
  249. X    cd() { builtin cd $*; echo $PWD; }
  250. X  (the `builtin' tells zsh to use its own `cd', avoiding an infinite loop)
  251. X  or, perhaps better,
  252. X    cd() { builtin cd $*; print -D $PWD; }
  253. X  (which converts your home directory to a ~).  In fact, this problem is
  254. X  better solved by defining the special function chpwd() (see the manual).
  255. X
  256. X  Note also that the `;' at the end of the function is optional in zsh,
  257. X  but not in ksh or sh (for sh's where it exists).
  258. X
  259. X  Here is Bart Schaefer's guide to converting csh aliases for zsh.
  260. X
  261. X    1.  If the csh alias references "parameters" (\!:1 \!* etc.),
  262. X        then in zsh you need a function (referencing $1 $* etc.).
  263. X        Otherwise, you can use a zsh alias.
  264. X
  265. X    2.  If you use a zsh function, you need to refer _at_least_ to
  266. X        $* in the body (inside the { }).  Parameters don't magically
  267. X        appear inside the { } the way they get appended to an alias.
  268. X    
  269. X    3.  If the csh alias references its own name (alias rm "rm -i"),
  270. X        then in a zsh function you need the "command" keyword
  271. X        (function rm() { command rm -i $* }), but in a zsh alias
  272. X        you don't (alias rm="rm -i").
  273. X
  274. X    4.  If you have aliases that refer to each other (alias ls "ls -C";
  275. X        alias lf "ls -F" ==> lf == ls -C -F) then you must either:
  276. X        a.  convert all of them to zsh functions; or
  277. X        b.  after converting, be sure your .zshrc defines all of your
  278. X            aliases before it defines any of your functions.
  279. X
  280. X    Those first four are all you really need, but here are four more for
  281. X    heavy csh alias junkies:
  282. X
  283. X    5.  Mapping from csh alias "parameter referencing" into zsh function
  284. X        (assuming shwordsplit is NOT set in zsh):
  285. X             csh                   zsh
  286. X            =====               ==========
  287. X            \!*                 $*              (or $argv)
  288. X            \!^                 $1              (or $argv[1])
  289. X            \!:1                $1
  290. X            \!:2                $2              (or $argv[2], etc.)
  291. X            \!$                 $*[$#]          (or $argv[$#], or $*[-1])
  292. X            \!:1-4              $*[1,4]
  293. X            \!:1-               $*[1,$#-1]      (or $*[1,-2])
  294. X            \!^-                $*[1,$#-1]
  295. X            \!*:q               "$@"            ($*:q doesn't work (yet))
  296. X            \!*:x               $=*             ($*:x doesn't work (yet))
  297. X
  298. X    6.  Remember that it is NOT a syntax error in a zsh function to
  299. X        refer to a position ($1, $2, etc.) greater than the number of
  300. X        parameters. (E.g., in a csh alias, a reference to \!:5 will
  301. X        cause an error if 4 or fewer arguments are given; in a zsh
  302. X    function, $5 is the empty string if there are 4 or fewer
  303. X    parameters.)
  304. X
  305. X    7.  To begin a zsh alias with a - (dash, hyphen) character, use
  306. X        "alias --":
  307. X                 csh                            zsh
  308. X            ===============             ==================
  309. X            alias - "fg %-"             alias -- -="fg %-"
  310. X
  311. X    8.  Stay away from "alias -g" in zsh until you REALLY know what
  312. X        you're doing.
  313. X
  314. X
  315. X7) How do I get the meta key to work on my xterm?
  316. X
  317. X  As stated in the manual, zsh needs to be told about the meta key by
  318. X  using `bindkey -me' or `bindkey -mv' in your .zshrc or on the command
  319. X  line.  You probably also need to tell the terminal driver to allow the
  320. X  `meta' bit of the character through; `stty pass8' is the usual
  321. X  incantation.  Sample .zshrc entry:
  322. X    [[ $TERM = "xterm" ]] && stty pass8 && bindkey -me
  323. X  Make sure this comes *before* any bindkey entries in your .zshrc which
  324. X  redefine keys normally defined in the emacs/vi keymap.
  325. X
  326. X
  327. X8) Why does my terminal act funny in way x?
  328. X
  329. X  If you are using an OpenWindows cmdtool as your terminal, any
  330. X  escape sequences (such as those produced by cursor keys) will be
  331. X  swallowed up and never reach zsh.  Either use shelltool or avoid
  332. X  commands with escape sequences.  You can also disable scrolling from
  333. X  the cmdtool pane menu (which effectively turns it into a shelltool).
  334. X  If you still want scrolling, try using an xterm with the scrollbar
  335. X  activated.
  336. X
  337. X  If that's not the problem, and you are using stty to change some tty
  338. X  settings, make sure you haven't asked zsh to freeze the tty settings:
  339. X  type
  340. X    ttyctl -u
  341. X  before any stty commands you use.
  342. X
  343. X  If _that's_ not the problem, and you are having difficulties with
  344. X  external commands (not part of zsh), and you think some terminal
  345. X  setting is wrong (e.g. ignpar should be -ignpar: see the stty(1)
  346. X  manual page), try:
  347. X    ttyctl -u
  348. X    STTY='-ignpar' commandname
  349. X  (in this not-very-useful example).  Note that zsh doesn't reset the
  350. X  terminal completely afterwards: just the modes it uses itself.
  351. X
  352. X
  353. X9) Why does `$var' where var="foo bar" not do what I expect?
  354. X
  355. X  In most Bourne-shell derivatives, multi-word variables such as
  356. X    var="foo bar"
  357. X  are split into words when passed to a command or used in a `for foo in $var'
  358. X  loop.  By default, zsh does not have that behaviour:  the variable remains
  359. X  intact.  An option (shwordsplit) exists to provide compatibility.
  360. X  
  361. X  For example, defining the function args to show the number of its
  362. X  arguments:
  363. X    args() { echo $#; }
  364. X  and with our definition of vble,
  365. X    args $vble
  366. X  produces the output `1'.  After
  367. X    setopt shwordsplit
  368. X  the same function produces the output `2', like sh and ksh.
  369. X  
  370. X  Unless you need strict sh/ksh compatibility, you should ask yourself
  371. X  whether you really want this behaviour, as it can produce unexpected
  372. X  effects for variables with entirely innocuous embedded spaces.  The
  373. X  natural way to produce word-splitting behaviour in zsh is via arrays.
  374. X  For example,
  375. X    set -A array one two three twenty
  376. X  (or
  377. X        array=(one two three twenty)
  378. X  if you prefer), followed by
  379. X    args $array
  380. X  produces the output `4', regardless of the setting of shwordsplit.
  381. X  Arrays are also much more versatile than single strings.
  382. X  
  383. X  Note also the "$@" method of word splitting is always available in zsh
  384. X  functions and scripts (though strictly this does array splitting, not
  385. X  word splitting), also the substitution ${=foo} to toggle word
  386. X  splitting on variable `foo'.
  387. X
  388. X
  389. X10) How does base arithmetic work?
  390. X
  391. X  The syntax (e.g. using the `let' builtin is)
  392. X    let 'foo = [16]ff'
  393. X  or equivalently
  394. X    (( foo = [16]ff ))
  395. X  Then
  396. X    echo $foo
  397. X  gives the answer `255'.  It is possible to declare variables explicitly
  398. X  to be integers, via
  399. X    typeset -i foo
  400. X  which has a different effect: namely the base used in the first
  401. X  assignment (hexadecimal in the example) is subsequently used whenever
  402. X  `foo' is displayed (although the internal representation is unchanged).
  403. X  To ensure foo is always displayed in decimal, declare it as
  404. X    typeset -i 10 foo
  405. X  which requests base 10 for output.  You can change the output base of an
  406. X  existing variable in this fashion.  Using the `$[ ... ]' method will
  407. X  always display in decimal.
  408. X
  409. X
  410. X11) How do I get a newline in my prompt?
  411. X
  412. X  You can place a literal newline in quotes, i.e.
  413. X    PROMPT="Hi Joe,
  414. X    what now?%# "
  415. X  If you have the bad taste to set the option cshjunkiequotes, which
  416. X  inhibits such behaviour, you will have to bracket this with 
  417. X  `unsetopt cshjunkiequotes' and `setopt cshjunkiequotes', or put it in
  418. X  your .zshrc before the option is set.
  419. X
  420. X
  421. X12) Why does `bindkey ^a command-name' do something funny?
  422. X
  423. X  You probably have the extendedglob option set in which case ^ and #
  424. X  are metacharacters.  ^a matches any file except one called a, so the
  425. X  line is interpreted as bindkey followed by a list of files.  Quote the
  426. X  ^ with a backslash or put quotation marks around ^a.
  427. X
  428. X
  429. X13) How do I reference command `foo' from within function `foo'?
  430. X
  431. X  The command `command foo' does just that.  You don't need this with
  432. X  aliases, but you do with functions.  Note that the error message
  433. X        zsh: job table full or recursion limit exceeded
  434. X  is a good sign that you tried calling `foo' in function `foo' without
  435. X  using `command'.
  436. X
  437. X
  438. X14) I don't have root access: how do I make zsh my login shell?
  439. X
  440. X  Unfortunately, on many machines you can't use `chsh' to change your
  441. X  shell unless the name of the shell is contained in /etc/shells, so if
  442. X  you have your own copy of zsh you need some sleight-of-hand to use it
  443. X  when you log on.  (Simply typing `zsh' is not really a solution since
  444. X  you still have your original login shell waiting for when you exit.)
  445. X  
  446. X  The basic idea is to use `exec <zsh-path>' to replace the current
  447. X  shell with zsh.  Often you can do this in a login file such as
  448. X  .profile (if your shell is sh or ksh) or .login (if it's csh).  Make
  449. X  sure you have some way of altering the file (e.g. via FTP) before you
  450. X  try this as `exec' is often rather unforgiving.
  451. X
  452. X  In .profile, try something like
  453. X    [ -f $HOME/bin/zsh ] && exec $HOME/bin/zsh -l
  454. X  and in .login, try something like
  455. X    if ( -f ~/bin/zsh ) exec ~/bin/zsh -l
  456. X  (in each case the -l tells zsh it is a login shell).  
  457. X
  458. X  It's not a good idea to put this (even without the -l) into .cshrc, at
  459. X  least without some tests on what the csh is supposed to be doing, as
  460. X  that will cause _every_ instance of csh to turn into a zsh and will
  461. X  cause csh scripts (yes, some people write these) to fail.  If you want
  462. X  to tell xterm to run zsh, change the SHELL environment variable to the
  463. X  full path of zsh.
  464. X
  465. X  If you like your login shell to appear in the process list as '-zsh',
  466. X  you can link zsh to -zsh (e.g. by `ln -s ~/bin/zsh ~/bin/-zsh') and
  467. X  change the exec to `exec -zsh'.  (Make sure -zsh is in your path.)
  468. X  This has the same effect as the `-l' option.
  469. X
  470. X
  471. X15) What bugs are currently known and unfixed?
  472. X
  473. X  Here are some of the more well-known ones, very roughly in decreasing
  474. X  order of significance.  A fuller bug list is now maintained by Carlos
  475. X  Carvalho <carlos@snfep1.if.usp.br>. Many of these can also be counted
  476. X  against differences from ksh in question 5).  Bugs marked [2.4] are
  477. X  fixed in patches which should appear in early versions of the next
  478. X  release.
  479. X
  480. X  Unsetting multiply-named functions via a name other than the first
  481. X    crashes the shell. [2.4]
  482. X  Functions are a bit half-hearted about local variables. [2.4]
  483. X  `return' in a trap simply returns from the trap. [2.4]
  484. X  `return' in a shell script should act as `exit'.
  485. X  Pipelines ending in a while/until/for loop are uninterruptible.
  486. X  Certain built-ins won't allow the `VAR=value command ...' assignment.
  487. X  The ones that do don't unset VAR after use.
  488. X  Killing a command substitution in a loop doesn't kill the loop. [2.4]
  489. X  Assigments in a typeset are overenthusiastic about tildes.
  490. X  `bindkey -a -[ed]' modifies the alternate keymap.
  491. X  `echo  !-2:$ !$' substitutes !-2:$ twice.
  492. X  The :q modifier doesn't split words and -q and -x don't work for variables.
  493. X  `echo -n ^V^J!<return>' causes a shell crash [2.4]
  494. X  Command line editing in vi mode:
  495. X    `.' doesn't repeat `x' (repeats command before `x').
  496. X    `u' can go past original modification point.
  497. X    `.' doesn't repeat count for `s', `cw', `dw', `r' (and others?).
  498. X  If a command has both file and command completion enabled,
  499. X    completion of a word that is a directory finds only commands in
  500. X    the directory, not files and commands.
  501. X  $_ returns the last unexpanded word from the previous line (not command).
  502. X  Autocd won't use globbed filenames and sometimes refuses to work.
  503. X  `if (( 1 )) command' and `if (( 1 )) { ...' do not work
  504. X    (and related syntax problems).
  505. X  The rmstar feature doesn't handle shell variables properly.
  506. X
  507. X
  508. X16) Where do I report bugs, get more info / who's working on zsh?
  509. X
  510. X  Zsh is now maintained by a motley collection of enthusiasts who
  511. X  subscribe to the mailing list, so any suggestions, complaints,
  512. X  questions and matters for discussion should be addressed to:
  513. X    zsh-list@cs.uow.edu.au
  514. X  (if you want someone to mail you directly, say so).  If you wish to
  515. X  subscribe to the mailing list, ask
  516. X    zsh-request@cs.uow.edu.au
  517. X  which is in the hands of Peter Gray, who also reads the list.  It is
  518. X  by no means restricted to source-code hackers.
  519. X
  520. X
  521. X17) What's on the wish-list?
  522. X
  523. X  `compctl' to be enhanced to shut up tcsh-users.
  524. X  Option for glob qualifiers to follow perl syntax.
  525. X  Selective expansion of history, variables, globs on <TAB>.
  526. X  Option to quote !-history lexically via '' but not "" (hard).
  527. X  Binding of external commands to zle functions (arg-passing mechanism??).
  528. X  Ksh compatibility could be improved if required.
  529. X
  530. X
  531. XAcknowledgments:
  532. X
  533. XThanks to zsh-list, in particular Bart Schaefer, for suggestions
  534. Xregarding this document; thanks to Jim Mattson for his hard work as
  535. Xarchivist.
  536. END_OF_FILE
  537.   if test 21578 -ne `wc -c <'FAQ'`; then
  538.     echo shar: \"'FAQ'\" unpacked with wrong size!
  539.   fi
  540.   # end of 'FAQ'
  541. fi
  542. if test -f 'help/pushd' -a "${1}" != "-c" ; then 
  543.   echo shar: Will not clobber existing file \"'help/pushd'\"
  544. else
  545.   echo shar: Extracting \"'help/pushd'\" \(1305 characters\)
  546.   sed "s/^X//" >'help/pushd' <<'END_OF_FILE'
  547. X     pushd [ arg ]
  548. X     pushd old new
  549. X     pushd +-n
  550. X          Change the current directory, and push the old  current
  551. X          directory onto the directory stack.  In the first form,
  552. X          change the current directory to arg.   If  arg  is  not
  553. X          specified,  change to the second directory on the stack
  554. X          (that is, exchange the top two entries), or  change  to
  555. X          the value of HOME if the PUSHD_TO_HOME option is set or
  556. X          if there is only one entry on the stack.  If arg is  -,
  557. X          change  to the value of OLDPWD, the previous directory.
  558. X          If a directory named arg is not found  in  the  current
  559. X          directory and arg does not contain a slash, search each
  560. X          component of the shell parameter cdpath.  If the option
  561. X          CDABLEVARS  is  set,  and  a parameter named arg exists
  562. X          whose value begins with a slash, treat its value as the
  563. X          directory.   If the option PUSHD_SILENT is not set, the
  564. X          directory stack will be printed after a pushd  is  per-
  565. X          formed.
  566. X
  567. X          The second form of pushd substitutes the string new for
  568. X          the  string  old  in the name of the current directory,
  569. X          and tries to change to this new directory.
  570. X
  571. X          The third form of pushd is equivalent to popd.
  572. END_OF_FILE
  573.   if test 1305 -ne `wc -c <'help/pushd'`; then
  574.     echo shar: \"'help/pushd'\" unpacked with wrong size!
  575.   fi
  576.   # end of 'help/pushd'
  577. fi
  578. if test -f 'src/zle_tricky.c' -a "${1}" != "-c" ; then 
  579.   echo shar: Will not clobber existing file \"'src/zle_tricky.c'\"
  580. else
  581.   echo shar: Extracting \"'src/zle_tricky.c'\" \(28258 characters\)
  582.   sed "s/^X//" >'src/zle_tricky.c' <<'END_OF_FILE'
  583. X/*
  584. X *
  585. X * zle_tricky.c - expansion and completion
  586. X *
  587. X * This file is part of zsh, the Z shell.
  588. X *
  589. X * This software is Copyright 1992 by Paul Falstad
  590. X *
  591. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  592. X * use this software as long as: there is no monetary profit gained
  593. X * specifically from the use or reproduction of this software, it is not
  594. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  595. X * included prominently in any copy made. 
  596. X *
  597. X * The author make no claims as to the fitness or correctness of this software
  598. X * for any use whatsoever, and it is provided as is. Any use of this software
  599. X * is at the user's own risk. 
  600. X *
  601. X */
  602. X
  603. X#define ZLE
  604. X#include "zsh.h"
  605. X#include    <pwd.h>
  606. X#ifdef HAS_NIS_PASSWD
  607. X#include    <rpc/rpc.h>
  608. X#include    <rpcsvc/ypclnt.h>
  609. X#include    <rpcsvc/yp_prot.h>
  610. X
  611. X#define PASSWD_FILE    "/etc/passwd"
  612. X#define PASSWD_MAP    "passwd.byname"
  613. X
  614. Xtypedef struct {
  615. X    int len;
  616. X    char *s;
  617. X    } dopestring;
  618. X#endif
  619. X
  620. Xstatic int we,wb,usemenu,useglob;
  621. X
  622. Xstatic int menub,menue,menuw;
  623. Xstatic Lklist menulist;
  624. Xstatic Lknode menunode;
  625. X
  626. X#define inststr(X) inststrlen((X),-1)
  627. X
  628. Xint usetab() /**/
  629. X{
  630. Xunsigned char *s = line+cs-1;
  631. X
  632. X    for (; s >= line && *s != '\n'; s--)
  633. X        if (*s != '\t' && *s != ' ')
  634. X            return 0;
  635. X    return 1;
  636. X}
  637. X
  638. X#define COMP_COMPLETE 0
  639. X#define COMP_LIST_COMPLETE 1
  640. X#define COMP_SPELL 2
  641. X#define COMP_EXPAND 3
  642. X#define COMP_EXPAND_COMPLETE 4
  643. X#define COMP_LIST_EXPAND 5
  644. X#define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND)
  645. X
  646. Xvoid completeword() /**/
  647. X{
  648. X    usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
  649. X    if (c == '\t' && usetab())
  650. X        selfinsert();
  651. X    else
  652. X        docomplete(COMP_COMPLETE);
  653. X}
  654. X
  655. Xvoid menucompleteword() /**/
  656. X{
  657. X    usemenu = 1; useglob = isset(GLOBCOMPLETE);
  658. X    if (c == '\t' && usetab())
  659. X        selfinsert();
  660. X    else
  661. X        docomplete(COMP_COMPLETE);
  662. X}
  663. X
  664. Xvoid listchoices() /**/
  665. X{
  666. X    usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
  667. X    docomplete(COMP_LIST_COMPLETE);
  668. X}
  669. X
  670. Xvoid spellword() /**/
  671. X{
  672. X    usemenu = useglob = 0;
  673. X    docomplete(COMP_SPELL);
  674. X}
  675. X
  676. Xvoid deletecharorlist() /**/
  677. X{
  678. X    usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
  679. X    if (cs != ll)
  680. X        deletechar();
  681. X    else
  682. X        docomplete(COMP_LIST_COMPLETE);
  683. X}
  684. X
  685. Xvoid expandword() /**/
  686. X{
  687. X    usemenu = useglob = 0;
  688. X    if (c == '\t' && usetab())
  689. X        selfinsert();
  690. X    else
  691. X        docomplete(COMP_EXPAND);
  692. X}
  693. X
  694. Xvoid expandorcomplete() /**/
  695. X{
  696. X    usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
  697. X    if (c == '\t' && usetab())
  698. X        selfinsert();
  699. X    else
  700. X        docomplete(COMP_EXPAND_COMPLETE);
  701. X}
  702. X
  703. Xvoid menuexpandorcomplete() /**/
  704. X{
  705. X    usemenu = 1; useglob = isset(GLOBCOMPLETE);
  706. X    if (c == '\t' && usetab())
  707. X        selfinsert();
  708. X    else
  709. X        docomplete(COMP_EXPAND_COMPLETE);
  710. X}
  711. X
  712. Xvoid listexpand() /**/
  713. X{
  714. X    usemenu = isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE);
  715. X    docomplete(COMP_LIST_EXPAND);
  716. X}
  717. X
  718. Xvoid reversemenucomplete() /**/
  719. X{
  720. X    if (!menucmp)
  721. X        menucompleteword();    /* better than just feep'ing, pem */
  722. X    if (!menucmp) return;
  723. X    cs = menub;
  724. X    foredel(menue-menub);
  725. X    if (menunode == firstnode(menulist))
  726. X        menunode = lastnode(menulist);
  727. X    else
  728. X        menunode = prevnode(menunode);
  729. X    inststr(menunode->dat);
  730. X    menue = cs;
  731. X}
  732. X
  733. X/*
  734. X * Accepts the current completion and starts a new arg,
  735. X * with the next completions. This gives you a way to accept
  736. X * several selections from the list of matches.
  737. X */
  738. Xvoid acceptandmenucomplete() /**/
  739. X{
  740. Xint t0,t1;
  741. X
  742. X    if (!menucmp) {
  743. X        feep();
  744. X        return;
  745. X    }
  746. X    spaceinline(1);
  747. X    line[cs++] = ' ';
  748. X    spaceinline(menub-menuw);
  749. X    t1 = cs;
  750. X    for (t0 = menuw; t0 != menub; t0++)
  751. X        line[cs++] = line[t0];
  752. X    menue = menub = cs;
  753. X    menuw = t1;
  754. X    menucompleteword();
  755. X}
  756. X
  757. Xstatic char *lastmenu = NULL;
  758. Xstatic int lastmenupos = -1;
  759. Xstatic int lincmd,linredir,lastambig;
  760. Xstatic char *cmdstr;
  761. X
  762. Xvoid docomplete(lst) /**/
  763. Xint lst;
  764. X{
  765. Xchar *s;
  766. X
  767. X    if (isset(AUTOMENU) && !menucmp && c == '\t' &&
  768. X        (lastcmd & ZLE_MENUCMP) && lastambig) usemenu = 1;
  769. X    if (menucmp) { do_menucmp(lst); return; }
  770. X    if (doexpandhist()) return;
  771. X    s = get_comp_string();
  772. X    if (s) {
  773. X        if (lst == COMP_EXPAND_COMPLETE) {
  774. X            char *q = s;
  775. X
  776. X            if (*q == Tilde) q++;
  777. X            else if (*q == Equals) {
  778. X                q = s+1;
  779. X                if (gethnode(q,cmdnamtab) || hashcmd(q,pathchecked))
  780. X                    lst = COMP_EXPAND;
  781. X            } else {
  782. X                for (; *q && *q != String; q++);
  783. X                if (*q == String && q[1] != Inpar) {
  784. X                    if (getsparam(q+1)) lst = COMP_EXPAND;
  785. X                    else lst = COMP_COMPLETE;
  786. X                }
  787. X                q = s;
  788. X            }
  789. X            if (lst == COMP_EXPAND_COMPLETE) {
  790. X                for (; *q; q++)
  791. X                    if (itok(*q))
  792. X                        break;
  793. X                if (!*q)
  794. X                    lst = COMP_COMPLETE;
  795. X            }
  796. X        }
  797. X        if (lst == COMP_SPELL) {
  798. X            char    **x = &s;
  799. X            char *q = s;
  800. X            for(; *q; q++) if (INULL(*q)) *q = Nularg;
  801. X            untokenize(s);
  802. X            cs = wb;
  803. X            foredel(we-wb);
  804. X            /* call the real spell checker, ash@aaii.oz.zu */
  805. X            spckword(x, NULL, NULL, !lincmd, 0);
  806. X            inststr(*x);
  807. X        } else if (COMP_ISEXPAND(lst))
  808. X            doexpansion(s,lst,lincmd);
  809. X        else {
  810. X            docompletion(s,lst,lincmd);
  811. X        }
  812. X        free(s);
  813. X    }
  814. X    popheap();
  815. X    lexrestore();
  816. X}
  817. X
  818. Xvoid do_menucmp(lst) /**/
  819. Xint lst;
  820. X{
  821. Xchar *s;
  822. X
  823. X    if (isset(LASTMENU) && lastmenu) {
  824. X        if (COMP_ISEXPAND(lst) || cs != lastmenupos ||
  825. X                strcmp((char *) line, lastmenu) != 0) {
  826. X            free(lastmenu);
  827. X            lastmenu = NULL;
  828. X            lastmenupos = -1;
  829. X            freemenu();
  830. X        }
  831. X    }
  832. X    if (lst == COMP_LIST_COMPLETE) {
  833. X        listmatches(menulist, NULL);
  834. X        return;
  835. X    }
  836. X    cs = menub;
  837. X    foredel(menue-menub);
  838. X    incnode(menunode);
  839. X    if (!menunode)
  840. X        menunode = firstnode(menulist);
  841. X    s = menunode->dat;
  842. X    if (*s == '~' || *s == '=' || *s == '$') {
  843. X        spaceinline(1);
  844. X        line[cs++] = *s++;
  845. X    }
  846. X    inststr(s = menunode->dat);
  847. X    if (isset(LASTMENU)) {
  848. X        if (lastmenu) free(lastmenu);
  849. X        lastmenu = ztrdup(UTOSCP(line));
  850. X        lastmenupos = cs;
  851. X    }
  852. X    menue = cs;
  853. X}
  854. X
  855. Xchar *get_comp_string() /**/
  856. X{
  857. Xint t0;
  858. Xunsigned char *s = NULL,*linptr;
  859. X
  860. X    linptr = line;
  861. Xstart:
  862. X    lincmd = incmdpos;
  863. X    linredir = inredir;
  864. X    cmdstr = NULL;
  865. X    zleparse = 1;
  866. X    lexsave();
  867. X    hungets(" "); /* KLUDGE! */
  868. X    hungets(UTOSCP(linptr));
  869. X    strinbeg();
  870. X    pushheap();
  871. X    do {
  872. X        lincmd = incmdpos;
  873. X        linredir = inredir;
  874. X        ctxtlex();
  875. X        if (tok == ENDINPUT) break;
  876. X        if (lincmd && tok == STRING) cmdstr = strdup(tokstr);
  877. X    } while (tok != ENDINPUT && zleparse);
  878. X    t0 = tok;
  879. X    if (t0 == ENDINPUT) {
  880. X        s = (unsigned char *)ztrdup("");
  881. X        we = wb = cs;
  882. X        t0 = STRING;
  883. X    } else if (t0 == STRING) {
  884. X        s = (unsigned char *)ztrdup(tokstr);
  885. X    } else if (t0 == ENVSTRING) {
  886. X        for (s = (unsigned char *)tokstr; *s && *s != (unsigned char)'='; s++, wb++);
  887. X        if (*s) { s++; wb++; t0 = STRING; s = STOUCP(ztrdup(UTOSCP(s))); }
  888. X        lincmd = 1;
  889. X    }
  890. X    hflush();
  891. X    strinend();
  892. X    errflag = zleparse = 0;
  893. X    if (we > ll) we = ll;
  894. X    if (t0 == LEXERR && parbegin != -1) {
  895. X        linptr += ll+1-parbegin;
  896. X        popheap();
  897. X        lexrestore();
  898. X        goto start;
  899. X    }
  900. X    if (t0 != STRING) { feep(); return NULL; }
  901. X    return (char *)s;
  902. X}
  903. X
  904. Xvoid doexpansion(s,lst,lincmd) /**/
  905. Xchar *s;int lst;int lincmd;
  906. X{
  907. XLklist vl = newlist();
  908. Xchar *ss;
  909. X
  910. X    pushheap();
  911. X    addnode(vl,s);
  912. X    prefork(vl);
  913. X    if (errflag)
  914. X        goto end;
  915. X    postfork(vl,1);
  916. X    if (errflag)
  917. X        goto end;
  918. X    if (empty(vl) || !*(char *) peekfirst(vl)) {
  919. X        feep();
  920. X        goto end;
  921. X    }
  922. X    if (lst == COMP_LIST_EXPAND) {
  923. X        listmatches(vl,NULL);
  924. X        goto end;
  925. X    } else if (peekfirst(vl) == s) {
  926. X        if (lst == COMP_EXPAND_COMPLETE) {
  927. X            docompletion(s,COMP_COMPLETE,lincmd);
  928. X        } else
  929. X            feep();
  930. X        goto end;
  931. X    }
  932. X    cs = wb;
  933. X    foredel(we-wb);
  934. X    while (ss = ugetnode(vl)) {
  935. X        untokenize(ss);
  936. X        inststr(ss);
  937. X#if 0
  938. X        if (full(vl)) {
  939. X            spaceinline(1);
  940. X            line[cs++] = ' ';
  941. X        }
  942. X#endif
  943. X        spaceinline(1);
  944. X        line[cs++] = ' ';
  945. X    }
  946. Xend:
  947. X    popheap();
  948. X    setterm();
  949. X}
  950. X
  951. Xvoid gotword(s) /**/
  952. Xchar *s;
  953. X{
  954. X    we = ll+1-inbufct;
  955. X    if (cs <= we)
  956. X        {
  957. X        wb = ll-wordbeg;
  958. X        zleparse = 0;
  959. X        /* major hack ahead */
  960. X        if (wb && line[wb] == '!' && line[wb-1] == '\\')
  961. X            wb--;
  962. X        }
  963. X}
  964. X
  965. Xvoid inststrlen(s,l) /**/
  966. Xchar *s;int l;
  967. X{
  968. Xchar *t,*u,*v;
  969. X
  970. X    t = halloc(strlen(s)*2+2);
  971. X    u = s;
  972. X    v = t;
  973. X    for (; *u; u++)
  974. X        {
  975. X        if (l != -1 && !l--)
  976. X            break;
  977. X        if (ispecial(*u))
  978. X            if (*u == '\n')
  979. X                {
  980. X                *v++ = '\'';
  981. X                *v++ = '\n';
  982. X                *v++ = '\'';
  983. X                continue;
  984. X                }
  985. X            else
  986. X                *v++ = '\\';
  987. X        *v++ = *u;
  988. X        }
  989. X    *v = '\0';
  990. X    spaceinline(strlen(t));
  991. X    strncpy((char *) line+cs,t,strlen(t));
  992. X    cs += strlen(t);
  993. X}
  994. X
  995. Xstatic int ambig,haspath,exact;
  996. Xstatic Lklist matches;
  997. Xstatic char *pat,*exactstr;
  998. Xstatic int typechar;
  999. X
  1000. Xvoid addmatch(s) /**/
  1001. Xchar *s;
  1002. X{
  1003. X    if (full(matches))
  1004. X        {
  1005. X        int y = pfxlen(peekfirst(matches),s);
  1006. X
  1007. X        if (y < ambig)
  1008. X            ambig = y;
  1009. X        }
  1010. X    else
  1011. X        ambig = strlen(s);
  1012. X    if (!strcmp(pat,s)) { exact = 1; exactstr = pat; }
  1013. X    addnodeinorder(matches,strdup(s));
  1014. X}
  1015. X
  1016. X
  1017. Xvoid addcmdmatch(s,t) /**/
  1018. Xchar *s;char *t;
  1019. X{
  1020. X    if (strpfx(pat,s)) addmatch(s);
  1021. X}
  1022. X
  1023. Xvoid addcmddirparam(s,t) /**/
  1024. Xchar *s;char *t;
  1025. X{
  1026. XParam pm = (Param) t;
  1027. X
  1028. X    if (strpfx(pat,s) && pmtype(pm) == PMFLAG_s) {
  1029. X        t = pm->gets.cfn(pm);
  1030. X        if (t && *t == '/') addmatch(s);
  1031. X    }
  1032. X}
  1033. X
  1034. Xvoid addcmdnodis(s,t) /**/
  1035. Xchar *s;char *t;
  1036. X{
  1037. X    if (strpfx(pat,s) && ((Cmdnam) t)->type != DISABLED) addmatch(s);
  1038. X}
  1039. X
  1040. X#ifdef HAS_NIS_PASSWD
  1041. Xstatic int match_username(status, key, keylen, val, vallen, data)
  1042. Xint status;
  1043. Xchar *key, *val;
  1044. Xint keylen, vallen;
  1045. Xdopestring *data;
  1046. X{
  1047. X    if (errflag || status != YP_TRUE) return 1;
  1048. X
  1049. X    if (vallen > keylen && val[keylen] == ':')
  1050. X        {
  1051. X        val[keylen] = '\0';
  1052. X        /* Can't call getpwnam() here; it breaks yp_all() */
  1053. X        if(strncmp(val,data->s,data->len) == 0) addmatch(val);
  1054. X        }
  1055. X    return 0;
  1056. X}
  1057. X#endif
  1058. X
  1059. Xvoid maketildelist(s) /**/
  1060. Xchar    *s;
  1061. X{
  1062. X#ifdef HAS_NIS_PASSWD
  1063. X    char domain[YPMAXDOMAIN];
  1064. X    struct ypall_callback cb;
  1065. X    dopestring data;
  1066. X    Lknode n;
  1067. X    FILE *pwf;
  1068. X    char buf[BUFSIZ], *p;
  1069. X    int skipping;
  1070. X    
  1071. X    data.s = ++s;
  1072. X    data.len = strlen(s);
  1073. X    if(*s == '+' || *s == '-')
  1074. X        {
  1075. X        /* We don't want to match any NIS inclusions/exclusions */
  1076. X        *s = '\0';
  1077. X        return;
  1078. X        }
  1079. X    /* Get potential matches from NIS and cull those without local accounts */
  1080. X    if (getdomainname(domain, YPMAXDOMAIN) == 0)
  1081. X        {
  1082. X        cb.foreach = match_username;
  1083. X        cb.data = (char *) &data;
  1084. X        yp_all(domain, PASSWD_MAP, &cb);
  1085. X        for(n = firstnode(matches); n; incnode(n))
  1086. X            if(getpwnam(getdata(n)) == NULL) uremnode(matches,n);
  1087. X        }
  1088. X    /* Don't forget the non-NIS matches from the flat passwd file */
  1089. X    if ((pwf = fopen(PASSWD_FILE, "r")) != NULL)
  1090. X        {
  1091. X        skipping = 0;
  1092. X        while (fgets(buf, BUFSIZ, pwf) != NULL)
  1093. X            {
  1094. X            if (strchr(buf, '\n') != NULL)
  1095. X                {
  1096. X                if (!skipping)
  1097. X                    {
  1098. X                    if (strncmp(buf,data.s,data.len) == 0 &&
  1099. X                            (p = strchr(buf, ':')) != NULL)
  1100. X                        {
  1101. X                        *p = '\0';
  1102. X                        addmatch(buf);
  1103. X                        }
  1104. X                    }
  1105. X                else skipping = 0;
  1106. X                }
  1107. X            else skipping = 1;
  1108. X            }
  1109. X        fclose(pwf);
  1110. X        }
  1111. X#else
  1112. X    struct passwd    *pwd;
  1113. X    int        len,i;
  1114. X
  1115. X    if (!usernamescached)
  1116. X        {
  1117. X        setpwent();
  1118. X        while((pwd=getpwent()) != NULL && !errflag)
  1119. X            adduserdir(pwd->pw_name,pwd->pw_dir);
  1120. X        endpwent();
  1121. X        usernamescached=1;
  1122. X        }
  1123. X
  1124. X    s++;
  1125. X    len = strlen(s);
  1126. X
  1127. X    for(i=0;i<userdirsz;i++)
  1128. X        {
  1129. X        if(usernames[i] && userdirs[i] &&
  1130. X            strncmp(usernames[i],s,len)==0) addmatch(usernames[i]);
  1131. X        }
  1132. X#endif
  1133. X    *s = 0;
  1134. X}
  1135. X
  1136. X/*
  1137. X * opendir that handles '~' and '=' and '$'.
  1138. X * orig. by ash@aaii.oz.au, mod. by pf
  1139. X */
  1140. XDIR *OPENDIR(s)
  1141. Xchar    *s;
  1142. X{
  1143. X    if (*s != '~' && *s != '=' && *s != '$')
  1144. X        return(opendir(s));
  1145. X    s = strdup(s);
  1146. X    *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
  1147. X    singsub(&s);
  1148. X    return(opendir(s));
  1149. X}
  1150. Xchar *dirname(s)
  1151. Xchar    *s;
  1152. X{
  1153. X    if (*s == '~' || *s == '=' || *s == '$') {
  1154. X      s = strdup(s);
  1155. X      *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
  1156. X      singsub(&s);
  1157. X    }
  1158. X    return(s);
  1159. X}
  1160. X
  1161. Xint Isdir(s) /**/
  1162. Xchar *s;
  1163. X{
  1164. Xstruct stat sbuf;
  1165. X
  1166. X    if (!*s) return 0;
  1167. X   if (stat(s,&sbuf) == -1) return 0;
  1168. X   return S_ISDIR(sbuf.st_mode);
  1169. X}
  1170. X
  1171. X/* this will work whether s is tokenized or not */
  1172. Xint isdir(t,s) /**/
  1173. Xchar *t;char *s;
  1174. X{
  1175. Xchar buf[MAXPATHLEN];
  1176. X
  1177. X    if (typechar != '$')
  1178. X        sprintf(buf,"%s/%s",(s) ? s : ".",t);
  1179. X    else
  1180. X        sprintf(buf,"$%s",t);
  1181. X    s = buf;
  1182. X    if (*s != '~' && *s != '=' && *s != Tilde && *s != Equals &&
  1183. X         *s != '$' && *s != String)
  1184. X        return(Isdir(s));
  1185. X    s = strdup(s);
  1186. X    if (*s == '~' || *s == '=' || *s == '$')
  1187. X        *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
  1188. X    singsub(&s);
  1189. X    return(Isdir(s));
  1190. X}
  1191. X
  1192. X#define SLASH_YES   0
  1193. X#define SLASH_NO    1
  1194. X#define SLASH_MAYBE 2
  1195. X
  1196. Xint slashflag;
  1197. Xint addedstar;
  1198. Xchar *pathprefix;
  1199. X
  1200. Xvoid docompletion(s,lst,incmd) /**/
  1201. Xchar *s;int lst;int incmd;
  1202. X{
  1203. Xchar *tokorigs = NULL;
  1204. Xchar *origs;
  1205. XCompctl cc;
  1206. Xchar *u;
  1207. Xchar *pfx = s;
  1208. X
  1209. X    slashflag = SLASH_MAYBE;
  1210. X    addedstar = 0;
  1211. X    lastambig = 0;
  1212. X
  1213. X    heapalloc();
  1214. X    pushheap();
  1215. X    if (useglob)
  1216. X        tokorigs = strdup(s);
  1217. X    untokenize(s);
  1218. X    origs = strdup(s);
  1219. X    matches = newlist();
  1220. X    if (incmd)
  1221. X        cc = &cc_compos;
  1222. X    else if (linredir || !(cmdstr && (cc = gethnode(cmdstr,compctltab))))
  1223. X        cc = &cc_default;
  1224. X    exact = 0;
  1225. X    if (cc->mask & CC_COMMPATH) gen_matches_reg(s,1,(cc->mask & CC_FILES));
  1226. X    else if (cc->mask & CC_FILES) gen_matches_reg(s,0,1);
  1227. X    else {
  1228. X        haspath = 0;
  1229. X        slashflag = SLASH_NO;
  1230. X    }
  1231. X    if (cc->mask & (CC_FILES|CC_COMMPATH)) {
  1232. X        /* only do "globbed" completion if regular completion fails.
  1233. X           pem, 7Oct91 */
  1234. X        if ((empty(matches) || errflag) && useglob) {
  1235. X            gen_matches_glob(tokorigs,incmd);
  1236. X            /*
  1237. X             * gen_matches_glob changes the insert line to be correct up
  1238. X             * to the match, so the prefix string must be "". ash, 7Oct91
  1239. X             */
  1240. X            *s = 0;
  1241. X        }
  1242. X    }
  1243. X    pat = s;
  1244. X    if ((cc->mask & CC_HOSTS) && !haspath) {
  1245. X        char **x;
  1246. X        for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
  1247. X
  1248. X/* we now try to do expansion if there is an @ symbol in the string */
  1249. X
  1250. X        haspath = 0;
  1251. X        for (u = s+strlen(s); u >= s; u--)
  1252. X            if (*u == '@' ) break;
  1253. X        if (u >= s) {
  1254. X            typechar = *u;
  1255. X            *u++ = '\0';
  1256. X            haspath = 1;
  1257. X        } else u = s;
  1258. X        pat = u;
  1259. X        if (typechar == '@' && haspath ) {
  1260. X            char **x;
  1261. X            slashflag = SLASH_NO;
  1262. X            for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
  1263. X        }
  1264. X    }
  1265. X    pat = s;
  1266. X    if ((cc->mask & CC_OPTIONS) && !haspath) {
  1267. X        struct option *o;
  1268. X        for (o = optns; o->name; o++) addcmdmatch(o->name,NULL);
  1269. X    }
  1270. X    if ((cc->mask & CC_VARS) && !haspath) listhtable(paramtab,addcmdmatch);
  1271. X    if ((cc->mask & CC_BINDINGS) && !haspath) {
  1272. X        int t0;
  1273. X        for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  1274. X            if (*zlecmds[t0].name) addcmdmatch(zlecmds[t0].name,NULL);
  1275. X    }
  1276. X    if (cc->mask & CC_USRKEYS) {
  1277. X        char **usr = get_user_var(cc->keyvar);
  1278. X        if (usr) while (*usr) addcmdmatch(*usr++,NULL);
  1279. X    }
  1280. X    if (lst != COMP_LIST_COMPLETE) do_fignore(origs);
  1281. X    if (empty(matches) || errflag) {
  1282. X        feep();
  1283. X    } else if (lst == COMP_LIST_COMPLETE) {
  1284. X        listmatches(matches,
  1285. X            unset(LISTTYPES) ? NULL :
  1286. X                (haspath) ? pathprefix : "./");
  1287. X    } else if (nextnode(firstnode(matches))) {
  1288. X        do_ambiguous(pfx);
  1289. X    } else {
  1290. X        do_single(pfx);
  1291. X    }
  1292. X    ll = strlen((char *) line);
  1293. X    setterm();
  1294. X    popheap();
  1295. X    permalloc();
  1296. X}
  1297. X
  1298. Xchar **get_user_var(nam) /**/
  1299. Xchar *nam;
  1300. X{
  1301. X    return (nam) ? getaparam(nam) : NULL;
  1302. X}
  1303. X
  1304. Xvoid gen_matches_glob(s,incmd) /**/
  1305. Xchar *s;int incmd;
  1306. X{
  1307. Xchar *pt,*u;
  1308. Xint hasp = 0;
  1309. XDIR *d;
  1310. Xstruct direct *de;
  1311. X
  1312. X    /*
  1313. X     * Find the longest prefix string without any
  1314. X     * chars special to glob - ash.
  1315. X     */
  1316. X    for (pt = s; *pt; pt++) {
  1317. X        if (pt == s && (*pt == Tilde || *pt == Equals)) continue;
  1318. X        if (ispecial(*pt) || itok(*pt)) break;
  1319. X    }
  1320. X    for (; pt > s && *pt != '/'; pt--) ;
  1321. X    if (*pt == '/') {
  1322. X        *pt = 0;
  1323. X        u = pt + 1;
  1324. X        wb += strlen(s);
  1325. X        hasp = 1;
  1326. X    } else u = s;
  1327. X    if (!hasp && (*s == Tilde || *s == Equals)) {
  1328. X        /* string contains only ~xx, so do tilde expansion */
  1329. X        maketildelist(s);
  1330. X        wb++;
  1331. X        pathprefix = s;
  1332. X        slashflag = SLASH_YES;
  1333. X    } else if (incmd && !hasp) {
  1334. X        slashflag = SLASH_NO;
  1335. X        pat = s;
  1336. X        listhtable(aliastab ,addcmdmatch);
  1337. X        if (isset(HASHLISTALL)) fullhash();
  1338. X        listhtable(cmdnamtab,addcmdnodis);
  1339. X        if (isset(AUTOCD)) listhtable(paramtab ,addcmddirparam);
  1340. X        if (d = opendir(".")) {
  1341. X            char *q;
  1342. X
  1343. X            readdir(d); readdir(d);
  1344. X            while ((de = readdir(d)) && !errflag)
  1345. X                if (strpfx(pat,q = de->d_name) &&
  1346. X                            (*q != '.' || *u == '.' || isset(GLOBDOTS)))
  1347. X                    addmatch(q);
  1348. X            closedir(d);
  1349. X        }
  1350. X    } else {
  1351. X         int     commonprefix = 0;
  1352. X         char    *prefix;
  1353. X         Lknode    n;
  1354. X         int        nonomatch = isset(NONOMATCH);
  1355. X
  1356. X         opts[NONOMATCH] = 1;
  1357. X         if (hasp) {
  1358. X            /* Find the longest common prefix string
  1359. X             * after globbing the input. All expansions
  1360. X             * '~foo/bar/*' will turn into something like
  1361. X             * /tmp_mnt/hosts/somehost/home/foo/...
  1362. X             * We will remove this common prefix from the matches.
  1363. X             * ash, 7 May '91
  1364. X             */
  1365. X            pathprefix = s;
  1366. X            addnode(matches,s);
  1367. X            prefork(matches);
  1368. X            if (!errflag) postfork(matches,1);
  1369. X            if (!errflag) {
  1370. X                prefix = peekfirst(matches);
  1371. X                if (prefix) commonprefix = strlen(prefix) + 1;
  1372. X                *pt = '/';
  1373. X            }
  1374. X        }
  1375. X        if (s[strlen(s) - 1] == '/') {
  1376. X            /* if strings ends in a '/' always add a '*' */
  1377. X            s = dyncat(s,"x");
  1378. X            s[strlen(s)-1] = Star;
  1379. X            addedstar = 1;
  1380. X        }
  1381. X        matches = newlist();
  1382. X        addnode(matches,s);
  1383. X        prefork(matches);
  1384. X        if (!errflag) postfork(matches,1);
  1385. X        opts[NONOMATCH] = nonomatch;
  1386. X        if (errflag || empty(matches) || !nextnode(firstnode(matches))) {
  1387. X            /* if there were no matches (or only one)
  1388. X                add a trailing * and try again */
  1389. X            s = dyncat(s,"x");
  1390. X            s[strlen(s)-1] = Star;
  1391. X            addedstar = 1;
  1392. X            matches = newlist();
  1393. X            addnode(matches,s);
  1394. X            prefork(matches);
  1395. X            if (errflag) return;
  1396. X            postfork(matches,1);
  1397. X            if (errflag) return;
  1398. X        }
  1399. X        /* remove the common prefix from all the matches */
  1400. X        if (commonprefix)
  1401. X            for (n = firstnode(matches); n; incnode(n))
  1402. X                n->dat = (char *) n->dat+commonprefix;
  1403. X        s = pt;
  1404. X        *s = 0;
  1405. X    }
  1406. X}
  1407. X
  1408. Xvoid gen_matches_reg(s,incmd,regfiles) /**/
  1409. Xchar *s;int incmd;int regfiles;
  1410. X{
  1411. Xchar *u;
  1412. XDIR *d;
  1413. Xstruct direct *de;
  1414. X
  1415. X    haspath = 0;
  1416. X    for (u = s+strlen(s); u >= s; u--)
  1417. X        if (*u == '/' || *u == '@' || *u == '$') break;
  1418. X    if (u >= s) {
  1419. X        typechar = *u;
  1420. X        *u++ = '\0';
  1421. X        haspath = 1;
  1422. X    } else if (*s == '=') {
  1423. X        typechar = '=';
  1424. X        *s = '\0'; u = s+1;
  1425. X        haspath = 1;
  1426. X    } else u = s;
  1427. X    pat = u;
  1428. X    if (typechar == '$' && haspath) {
  1429. X        /* slashflag = SLASH_NO; */
  1430. X        listhtable(paramtab,addcmdmatch);
  1431. X    } else if (typechar == '=' && haspath) {
  1432. X        slashflag = SLASH_NO;
  1433. X        if (isset(HASHLISTALL)) fullhash();
  1434. X        listhtable(cmdnamtab,addcmdnodis);
  1435. X    } else if (typechar == '@' && haspath) {
  1436. X        char **x;
  1437. X        slashflag = SLASH_NO;
  1438. X        for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
  1439. X    } else if (*s == '~' && !haspath) {
  1440. X        maketildelist(s);
  1441. X        pathprefix = s;
  1442. X        slashflag = SLASH_YES;
  1443. X    } else if (incmd && !haspath) {
  1444. X        slashflag = SLASH_NO;
  1445. X        listhtable(aliastab ,addcmdmatch);
  1446. X        if (isset(HASHLISTALL)) fullhash();
  1447. X        listhtable(cmdnamtab,addcmdnodis);
  1448. X        if (isset(AUTOCD) && isset(CDABLEVARS))
  1449. X            listhtable(paramtab ,addcmddirparam);
  1450. X        if (d = opendir(".")) {
  1451. X            char *q;
  1452. X            struct stat buf;
  1453. X
  1454. X            readdir(d); readdir(d);
  1455. X            if (regfiles) {
  1456. X                while ((de = readdir(d)) && !errflag)
  1457. X                    if (strpfx(pat,q = de->d_name) &&
  1458. X                        (*q != '.' || *u == '.' || isset(GLOBDOTS))) addmatch(q);
  1459. X            } else if (isset(AUTOCD)) {
  1460. X                while ((de = readdir(d)) && !errflag)
  1461. X                    if (strpfx(pat,q = de->d_name) &&
  1462. X                        (*q != '.' || *u == '.' || isset(GLOBDOTS)) &&
  1463. X                        stat(q,&buf) >= 0 &&
  1464. X                        (buf.st_mode & S_IEXEC) == S_IEXEC) addmatch(q);
  1465. X            } else {
  1466. X                while ((de = readdir(d)) && !errflag)
  1467. X                    if (strpfx(pat,q = de->d_name) &&
  1468. X                        (*q != '.' || *u == '.' || isset(GLOBDOTS)) &&
  1469. X                        stat(q,&buf) >= 0 &&
  1470. X                        (buf.st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC))
  1471. X                            addmatch(q);
  1472. X            }
  1473. X            closedir(d);
  1474. X        }
  1475. X    } else if (d = OPENDIR(pathprefix =
  1476. X            ((haspath || *s == '~') ? ((*s) ? s : "/") : "."))) {
  1477. X        char *q,buf2[MAXPATHLEN];
  1478. X        struct stat buf;
  1479. X        char dn[MAXPATHLEN];
  1480. X        
  1481. X        strcpy(dn,dirname(pathprefix));
  1482. X        readdir(d); readdir(d);
  1483. X        while ((de = readdir(d)) && !errflag)
  1484. X          if (strpfx(pat,q = de->d_name) &&
  1485. X                (*q != '.' || *u == '.' || isset(GLOBDOTS))) {
  1486. X             if (incmd) {
  1487. X                sprintf(buf2,"%s/%s",dn,q);
  1488. X                if (stat(buf2,&buf) < 0 ||
  1489. X                     (buf.st_mode & S_IEXEC) == S_IEXEC) {
  1490. X                  addmatch(q);
  1491. X                }
  1492. X             } else {
  1493. X                addmatch(q);
  1494. X             }
  1495. X          }
  1496. X        closedir(d);
  1497. X    }
  1498. X}
  1499. X
  1500. Xvoid do_fignore(origstr) /**/
  1501. Xchar *origstr;
  1502. X{
  1503. X    if (full(matches) && nextnode(firstnode(matches))) {
  1504. X        Lknode z,zn;
  1505. X
  1506. X        ambig = 1000;
  1507. X        for (z = firstnode(matches); z; z = zn) {
  1508. X            char *q = getdata(z);
  1509. X            int namlen = strlen(q);
  1510. X            int    slen = strlen(origstr);
  1511. X            int    slpt;
  1512. X            char **pt = fignore;
  1513. X    
  1514. X            zn = nextnode(z);
  1515. X            for (; *pt; pt++) {
  1516. X                /* We try to be smart here and override the
  1517. X                   fignore variable if the user has explicity
  1518. X                   used the ignored prefix, pem, 7 May 1991 */
  1519. X                slpt = strlen(*pt);
  1520. X                if (!addedstar && slen > slpt &&
  1521. X                        strcmp(origstr+slen-slpt, *pt) == 0)
  1522. X                    continue;
  1523. X                if (slpt < namlen && !strcmp(q+namlen-slpt,*pt)) {
  1524. X                    uremnode(matches,z);
  1525. X                    break;
  1526. X                }
  1527. X            }
  1528. X            if (!*pt) {
  1529. X                int y = pfxlen(peekfirst(matches),q);
  1530. X                if (y < ambig) ambig = y;
  1531. X            }
  1532. X        }
  1533. X    }
  1534. X}
  1535. X
  1536. Xvoid do_ambiguous(s) /**/
  1537. Xchar *s;
  1538. X{
  1539. X    lastambig = 1;
  1540. X    if (usemenu) { do_ambig_menu(s); return; }
  1541. X    if (useglob) {
  1542. X        feep();
  1543. X        if (isset(AUTOLIST))
  1544. X            listmatches(matches,
  1545. X                unset(LISTTYPES) ? NULL : (haspath) ? pathprefix : "./");
  1546. X        return;
  1547. X    }
  1548. X    cs = wb;
  1549. X    foredel(we-wb);
  1550. X    if (*s == '~' || *s == '=' || *s == '$') {
  1551. X        spaceinline(1);
  1552. X        line[cs++] = *s++;
  1553. X    }
  1554. X    if (haspath) {
  1555. X        inststr(s);
  1556. X        spaceinline(1);
  1557. X        line[cs++] = typechar;
  1558. X    }
  1559. X    if (isset(RECEXACT) && exact) {
  1560. X        lastambig = 0;
  1561. X        if ((*pat == '~' || *pat == '=' || *pat == '$') && !haspath) {
  1562. X            spaceinline(1);
  1563. X            line[cs++] = *s++;
  1564. X        }
  1565. X        inststr(exactstr);
  1566. X        spaceinline(1);
  1567. X        switch (slashflag) {
  1568. X            case SLASH_YES: line[cs++] = '/'; break;
  1569. X            case SLASH_NO : line[cs++] = ' '; break;
  1570. X            case SLASH_MAYBE: line[cs++] =
  1571. X                isdir(exactstr,pathprefix) ? '/' : ' '; break;
  1572. X        }
  1573. X        return;
  1574. X    }
  1575. X    s = peekfirst(matches);
  1576. X    if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
  1577. X        spaceinline(1);
  1578. X        line[cs++] = *s++;
  1579. X        ambig--;
  1580. X    }
  1581. X    inststrlen(s,ambig);
  1582. X    refresh();
  1583. X    if (isset(AUTOLIST)) {
  1584. X        if (unset(NOLISTBEEP)) feep();
  1585. X        listmatches(matches,
  1586. X            unset(LISTTYPES) ? NULL : (haspath) ? pathprefix : "./");
  1587. X    } else feep();
  1588. X}
  1589. X
  1590. Xvoid do_single(s) /**/
  1591. Xchar *s;
  1592. X{
  1593. X    cs = wb;
  1594. X    foredel(we-wb);
  1595. X    if (*s == '~' || *s == '=' || *s == '$') {
  1596. X        spaceinline(1);
  1597. X        line[cs++] = *s++;
  1598. X    }
  1599. X    if (haspath) {
  1600. X        inststr(s);
  1601. X        spaceinline(1);
  1602. X        line[cs++] = typechar;
  1603. X    }
  1604. X    s = peekfirst(matches);
  1605. X    if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
  1606. X        spaceinline(1);
  1607. X        line[cs++] = *s++;
  1608. X    }
  1609. X    inststr(s);
  1610. X    spaceinline(1);
  1611. X    switch (slashflag) {
  1612. X        case SLASH_YES: line[cs++] = '/'; break;
  1613. X        case SLASH_NO : line[cs++] = ' '; break;
  1614. X        case SLASH_MAYBE: line[cs++] = isdir(s,pathprefix) ? '/' : ' '; break;
  1615. X    }
  1616. X    if (isset(AUTOREMOVESLASH) && line[cs-1] == '/') addedslash = 1;
  1617. X}
  1618. X
  1619. Xvoid do_ambig_menu(s) /**/
  1620. Xchar *s;
  1621. X{
  1622. X    menucmp = 1;
  1623. X    if (isset(MENUCOMPLETEBEEP)) feep();
  1624. X    cs = wb;
  1625. X    menuw = cs;
  1626. X    foredel(we-wb);
  1627. X    if (*s == '~' || *s == '=' || *s == '$') {
  1628. X        spaceinline(1);
  1629. X        line[cs++] = *s++;
  1630. X    }
  1631. X    if (haspath) {
  1632. X        inststr(s);
  1633. X        spaceinline(1);
  1634. X        line[cs++] = typechar;
  1635. X    }
  1636. X    menub = cs;
  1637. X    s = peekfirst(matches);
  1638. X    if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
  1639. X        spaceinline(1);
  1640. X        line[cs++] = *s++;
  1641. X    }
  1642. X    inststr(s);
  1643. X    menue = cs;
  1644. X    permalloc();
  1645. X    menulist = duplist(matches,(VFunc)ztrdup);
  1646. X    heapalloc();
  1647. X    menunode = firstnode(menulist);
  1648. X    permalloc();
  1649. X    if (isset(LASTMENU)) {
  1650. X        if (lastmenu)
  1651. X            free(lastmenu);
  1652. X        lastmenu = ztrdup(UTOSCP(line));
  1653. X        lastmenupos = cs;
  1654. X    }
  1655. X}
  1656. X
  1657. Xint strpfx(s,t) /**/
  1658. Xchar *s;char *t;
  1659. X{
  1660. X    while (*s && *s == *t) s++,t++;
  1661. X    return !*s;
  1662. X}
  1663. X
  1664. Xint pfxlen(s,t) /**/
  1665. Xchar *s;char *t;
  1666. X{
  1667. Xint i = 0;
  1668. X
  1669. X    while (*s && *s == *t) s++,t++,i++;
  1670. X    return i;
  1671. X}
  1672. X
  1673. Xvoid listmatches(l,apps) /**/
  1674. XLklist l;char *apps;
  1675. X{
  1676. Xint longest = 1,fct,fw = 0,colsz,t0,t1,ct;
  1677. XLknode n;
  1678. Xchar **arr,**ap;
  1679. X
  1680. X    trashzle();
  1681. X    ct = countnodes(l);
  1682. X    if (listmax && ct > listmax)
  1683. X        {
  1684. X        fprintf(stdout,"zsh: do you wish to see all %d possibilities? ",ct);
  1685. X        fflush(stdout);
  1686. X        if (getquery() != 'y')
  1687. X            return;
  1688. X        }
  1689. X    ap = arr = alloc((countnodes(l)+1)*sizeof(char **));
  1690. X    for (n = firstnode(l); n; incnode(n))
  1691. X        *ap++ = getdata(n);
  1692. X    *ap = NULL;
  1693. X    for (ap = arr; *ap; ap++)
  1694. X        if (strlen(*ap) > longest)
  1695. X            longest = strlen(*ap);
  1696. X    if (apps)
  1697. X        {
  1698. X        apps = strdup(apps);
  1699. X        if (*apps == '~')
  1700. X            *apps = Tilde;
  1701. X        else if (*apps == '=')
  1702. X            *apps = Equals;
  1703. X        else if (*apps == '$')
  1704. X            *apps = String;
  1705. X        singsub(&apps);
  1706. X        longest++;
  1707. X        }
  1708. X    qsort((vptr)arr,ct,sizeof(char *),
  1709. X            (int (*) DCLPROTO((const void *, const void *)))forstrcmp);
  1710. X    fct = (columns-1)/(longest+2);
  1711. X    if (fct == 0)
  1712. X        fct = 1;
  1713. X    else
  1714. X        fw = (columns-1)/fct;
  1715. X    colsz = (ct+fct-1)/fct;
  1716. X    for (t1 = 0; t1 != colsz; t1++)
  1717. X        {
  1718. X        ap = arr+t1;
  1719. X        if (apps)
  1720. X            {
  1721. X            do
  1722. X                {
  1723. X                int t2 = strlen(*ap)+1;
  1724. X                char pbuf[MAXPATHLEN];
  1725. X                struct stat buf;
  1726. X
  1727. X                printf("%s",*ap);
  1728. X                sprintf(pbuf,"%s/%s",apps,*ap);
  1729. X                if (lstat(pbuf,&buf)) putchar(' ');
  1730. X                else switch (buf.st_mode & S_IFMT) /* screw POSIX */
  1731. X                    {
  1732. X                    case S_IFDIR: putchar('/'); break;
  1733. X#ifdef S_IFIFO
  1734. X                    case S_IFIFO: putchar('|'); break;
  1735. X#endif
  1736. X                    case S_IFCHR: putchar('%'); break;
  1737. X                    case S_IFBLK: putchar('#'); break;
  1738. X#ifdef S_IFLNK
  1739. X                    case S_IFLNK: putchar(
  1740. X                        (access(pbuf,F_OK) == -1) ? '&' : '@'); break;
  1741. X#endif
  1742. X#ifdef S_IFSOCK
  1743. X                    case S_IFSOCK: putchar('='); break;
  1744. X#endif
  1745. X                    default:
  1746. X                        if (buf.st_mode & 0111)
  1747. X                            putchar('*');
  1748. X                        else
  1749. X                            putchar(' ');
  1750. X                        break;
  1751. X                    }
  1752. X                for (; t2 < fw; t2++) putchar(' ');
  1753. X                for (t0 = colsz; t0 && *ap; t0--,ap++);
  1754. X                }
  1755. X            while (*ap);
  1756. X            }
  1757. X        else
  1758. X            do
  1759. X                {
  1760. X                int t2 = strlen(*ap);
  1761. X
  1762. X                printf("%s",*ap);
  1763. X                for (; t2 < fw; t2++) putchar(' ');
  1764. X                for (t0 = colsz; t0 && *ap; t0--,ap++);
  1765. X                }
  1766. X            while (*ap);
  1767. X        putchar('\n');
  1768. X        }
  1769. X    resetneeded = 1;
  1770. X    fflush(stdout);
  1771. X}
  1772. X
  1773. Xvoid selectlist(l) /**/
  1774. XLklist l;
  1775. X{
  1776. Xint longest = 1,fct,fw = 0,colsz,t0,t1,ct;
  1777. XLknode n;
  1778. Xchar **arr,**ap;
  1779. X
  1780. X    trashzle();
  1781. X    ct = countnodes(l);
  1782. X    ap = arr = alloc((countnodes(l)+1)*sizeof(char **));
  1783. X    for (n = firstnode(l); n; incnode(n))
  1784. X        *ap++ = getdata(n);
  1785. X    *ap = NULL;
  1786. X    for (ap = arr; *ap; ap++)
  1787. X        if (strlen(*ap) > longest)
  1788. X            longest = strlen(*ap);
  1789. X    t0 = ct;
  1790. X    longest++;
  1791. X    while (t0)
  1792. X        t0 /= 10, longest++;
  1793. X    fct = (columns-1)/(longest+3); /* to compensate for added ')' */
  1794. X    if (fct == 0)
  1795. X        fct = 1;
  1796. X    else
  1797. X        fw = (columns-1)/fct;
  1798. X    colsz = (ct+fct-1)/fct;
  1799. X    for (t1 = 0; t1 != colsz; t1++) {
  1800. X        ap = arr+t1;
  1801. X        do {
  1802. X            int t2 = strlen(*ap)+2,t3;
  1803. X
  1804. X            fprintf(stderr,"%d) %s",t3 = ap-arr+1,*ap);
  1805. X            while (t3) t2++,t3 /= 10;
  1806. X            for (; t2 < fw; t2++) fputc(' ',stderr);
  1807. X            for (t0 = colsz; t0 && *ap; t0--,ap++);
  1808. X        } while (*ap);
  1809. X        fputc('\n',stderr);
  1810. X    } 
  1811. X
  1812. X/* Below is a simple attempt at doing it the Korn Way.. 
  1813. X    ap = arr;
  1814. X    t0 = 0;
  1815. X    do
  1816. X        {
  1817. X        t0++;
  1818. X        fprintf(stderr,"%d) %s\n",t0,*ap);
  1819. X        ap++;
  1820. X        }
  1821. X    while (*ap);*/
  1822. X    resetneeded = 1;
  1823. X    fflush(stderr);
  1824. X}
  1825. X
  1826. Xint doexpandhist() /**/
  1827. X{
  1828. Xunsigned char *cc,*ce;
  1829. Xint t0,oldcs,oldll;
  1830. X
  1831. X    for (cc = line, ce = line+ll; cc < ce; cc++)
  1832. X        if (*cc == '\\' && cc[1])
  1833. X            cc++;
  1834. X        else if (*cc == bangchar ||
  1835. X                (*cc == hatchar && *line == hatchar && cc != line))
  1836. X            break;
  1837. X    if (*cc == bangchar && cc[1] == '"') return 0;
  1838. X    if (cc == ce) return 0;
  1839. X    oldcs = cs;
  1840. X    oldll = ll;
  1841. X    zleparse = 1;
  1842. X    lexsave();
  1843. X    hungets(UTOSCP(line));
  1844. X    strinbeg();
  1845. X    pushheap();
  1846. X    ll = cs = 0;
  1847. X    for(;;)
  1848. X        {
  1849. X        t0 = hgetc();
  1850. X        if (lexstop)
  1851. X            break;
  1852. X        spaceinline(1);
  1853. X        line[cs++] = t0;
  1854. X        }
  1855. X    hflush();
  1856. X    popheap();
  1857. X    strinend();
  1858. X    errflag = zleparse = 0;
  1859. X    t0 = histdone;
  1860. X    lexrestore();
  1861. X    line[ll = cs] = '\0';
  1862. X    if (ll == oldll) cs = oldcs;
  1863. X    return t0;
  1864. X}
  1865. X
  1866. Xvoid magicspace() /**/
  1867. X{
  1868. X    c = ' ';
  1869. X    selfinsert();
  1870. X    doexpandhist();
  1871. X}
  1872. X
  1873. Xvoid expandhistory() /**/
  1874. X{
  1875. X    if (!doexpandhist())
  1876. X        feep();
  1877. X}
  1878. X
  1879. Xstatic int cmdwb,cmdwe;
  1880. X
  1881. Xchar *getcurcmd() /**/
  1882. X{
  1883. Xint lincmd;
  1884. Xchar *s = NULL;
  1885. X
  1886. X    zleparse = 1;
  1887. X    lexsave();
  1888. X    hungets(" "); /* KLUDGE! */
  1889. X    hungets(UTOSCP(line));
  1890. X    strinbeg();
  1891. X    pushheap();
  1892. X    do {
  1893. X        lincmd = incmdpos;
  1894. X        ctxtlex();
  1895. X        if (tok == ENDINPUT) break;
  1896. X        if (tok == STRING && lincmd) {
  1897. X            if (s) free(s);
  1898. X            s = ztrdup(tokstr);
  1899. X            cmdwb = ll-wordbeg; cmdwe = ll+1-inbufct;
  1900. X        }
  1901. X    } while (tok != ENDINPUT && zleparse);
  1902. X    hflush();
  1903. X    popheap();
  1904. X    strinend();
  1905. X    errflag = zleparse = 0;
  1906. X    lexrestore();
  1907. X    return s;
  1908. X}
  1909. X
  1910. Xvoid processcmd() /**/
  1911. X{
  1912. Xchar *s,*t;
  1913. X
  1914. X    s = getcurcmd();
  1915. X    if (!s) { feep(); return; }
  1916. X    t = zlecmds[bindk].name;
  1917. X    mult = 1;
  1918. X    pushline();
  1919. X    sizeline(strlen(s)+strlen(t)+1);
  1920. X    strcpy((char *) line,t);
  1921. X    strcat((char *) line," ");
  1922. X    cs = ll = strlen((char *) line);
  1923. X    inststr(s);
  1924. X    free(s);
  1925. X    done = 1;
  1926. X}
  1927. X
  1928. Xvoid expandcmdpath() /**/
  1929. X{
  1930. Xint oldcs = cs;
  1931. Xchar *s,*str;
  1932. X
  1933. X    s = getcurcmd();
  1934. X    if (!s) { feep(); return; }
  1935. X    str = findcmd(s);
  1936. X    free(s);
  1937. X    if (!str) { feep(); return; }
  1938. X    cs = cmdwb;
  1939. X    foredel(cmdwe-cmdwb);
  1940. X    spaceinline(strlen(str));
  1941. X    strncpy((char *) line+cs,str,strlen(str));
  1942. X    cs = oldcs;
  1943. X    if (cs >= cmdwe) cs += cmdwe-cmdwb+strlen(str);
  1944. X    if (cs > ll) cs = ll;
  1945. X    free(str);
  1946. X}
  1947. X
  1948. Xvoid freemenu() /**/
  1949. X{
  1950. X    if (menucmp && (unset(LASTMENU) || lastmenu == NULL)) {
  1951. X        menucmp = 0;
  1952. X        freetable(menulist,freestr);
  1953. X    }
  1954. X}
  1955. X
  1956. Xint inarray(s,a) /**/
  1957. Xchar *s; char **a;
  1958. X{
  1959. X    for (; *a; a++) if (!strcmp(*a,s)) return 1;
  1960. X    return 0;
  1961. X}
  1962. X
  1963. END_OF_FILE
  1964.   if test 28258 -ne `wc -c <'src/zle_tricky.c'`; then
  1965.     echo shar: \"'src/zle_tricky.c'\" unpacked with wrong size!
  1966.   fi
  1967.   # end of 'src/zle_tricky.c'
  1968. fi
  1969. echo shar: End of archive 13 \(of 22\).
  1970. cp /dev/null ark13isdone
  1971. MISSING=""
  1972. 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
  1973.     if test ! -f ark${I}isdone ; then
  1974.     MISSING="${MISSING} ${I}"
  1975.     fi
  1976. done
  1977. if test "${MISSING}" = "" ; then
  1978.     echo You have unpacked all 22 archives.
  1979.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1980. else
  1981.     echo You still must unpack the following archives:
  1982.     echo "        " ${MISSING}
  1983. fi
  1984. exit 0
  1985.  
  1986. exit 0 # Just in case...
  1987.