home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / zle_tricky.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-25  |  100.7 KB  |  3,972 lines

  1. /*
  2.  * $Id: zle_tricky.c,v 2.82 1996/10/24 10:02:00 hzoli Exp $
  3.  *
  4.  * zle_tricky.c - expansion and completion
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #define ZLE
  33. #include "zsh.h"
  34.  
  35. /* The main part of ZLE maintains the line being edited as binary data, *
  36.  * but here, where we interface with the lexer and other bits of zsh,   *
  37.  * we need the line metafied.  The technique used is quite simple: on   *
  38.  * entry to the expansion/completion system, we metafy the line in      *
  39.  * place, adjusting ll and cs to match.  All completion and expansion   *
  40.  * is done on the metafied line.  Immediately before returning, the     *
  41.  * line is unmetafied again, changing ll and cs back.  (ll and cs might *
  42.  * have changed during completion, so they can't be merely saved and    *
  43.  * restored.)  The various indexes into the line that are used in this  *
  44.  * file only are not translated: they remain indexes into the metafied  *
  45.  * line.                                                                */
  46.  
  47. #ifdef HAVE_NIS_PLUS
  48. # include <rpcsvc/nis.h>
  49. #else
  50. # ifdef HAVE_NIS
  51. #  include    <rpc/types.h>
  52. #  include    <rpc/rpc.h>
  53. #  include    <rpcsvc/ypclnt.h>
  54. #  include    <rpcsvc/yp_prot.h>
  55.  
  56. /* This is used when getting usernames from the NIS. */
  57. typedef struct {
  58.     int len;
  59.     char *s;
  60. }
  61. dopestring;
  62. # endif
  63. #endif
  64.  
  65. #define inststr(X) inststrlen((X),1,-1)
  66.  
  67. /* Prefix and suffix for globbing, used as an optimisation. */
  68.  
  69. extern char *glob_pre, *glob_suf;
  70.  
  71. /* wb and we hold the beginning/end position of the word we are completing. */
  72.  
  73. static int wb, we;
  74.  
  75. /* offs is the cursor position within the tokenized *
  76.  * current word after removing nulargs.             */
  77.  
  78. static int offs;
  79.  
  80. /* These control the type of completion that will be done.  They are    *
  81.  * affected by the choice of ZLE command and by relevant shell options. */
  82.  
  83. static int usemenu, useglob;
  84.  
  85. /* A pointer to the current position in the menu-completion array (the one *
  86.  * that was put in the command line last).                                 */
  87.  
  88. static char **menucur;
  89.  
  90. /* The point (in the command line) where the menu-completion strings are  *
  91.  * inserted, the length of the string that was inserted last, the end     *
  92.  * position of this string in the command line and two flags: menuwe is   *
  93.  * non-zero if the cursor was at the end of the word (which means that we *
  94.  * can add suffixes, e.g. a slash for directories), and menuce is used to *
  95.  * save/restore the value of complexpect during consecutive menu          *
  96.  * completions (complexpect is used when completing after `$' or `${' and *
  97.  * says whether some characters should be treated specially, when the     *
  98.  * option autoparamkeys is set).  menuinsc is nonzero if a trailing slash *
  99.  * marking a directory is added.                                          */
  100.  
  101. static int menupos, menulen, menuend, menuwe, menuce, menuinsc;
  102.  
  103. /* The list of matches.  fmatches contains the matches we first ignore *
  104.  * because of fignore.                                                 */
  105.  
  106. static LinkList matches, fmatches;
  107.  
  108. /* The list of matches turned into an array.  This is used to sort this *
  109.  * list and when menu-completion is used (directly or via automenu).    */
  110.  
  111. static char **amatches;
  112.  
  113. /* The number of matches. */
  114.  
  115. static int nmatches;
  116.  
  117. /* !=0 if we have a valid completion list. */
  118.  
  119. static int validlist;
  120.  
  121. /* This flag is non-zero if we are completing a pattern (with globcomplete) */
  122.  
  123. static int ispattern;
  124.  
  125. /* Two patterns used when doing glob-completion.  The first one is built *
  126.  * from the whole word we are completing and the second one from that    *
  127.  * part of the word that was identified as a possible filename.          */
  128.  
  129. static Comp patcomp, filecomp;
  130.  
  131. /* We store the following prefixes/suffixes:                             *
  132.  * lpre/lsuf -- what's on the line                                       *
  133.  * rpre/rsuf -- same as lpre/lsuf, but expanded                          *
  134.  *                                                                       *
  135.  * ... and if we are completing files, too:                              *
  136.  * ppre/psuf -- the path prefix/suffix                                   *
  137.  * fpre/fsuf -- prefix/suffix of the pathname component the cursor is in *
  138.  * prpre     -- ppre in expanded form usable for opendir                 *
  139.  *                                                                       *
  140.  * The integer variables hold the lengths of lpre, lsuf, rpre, rsuf,     *
  141.  * fpre, and fsuf.  noreal is non-zero if we have rpre/rsuf.             */
  142.  
  143. static char *lpre, *lsuf;
  144. static char *rpre, *rsuf;
  145. static char *ppre, *psuf, *prpre;
  146. static char *fpre, *fsuf;
  147. static int lpl, lsl, rpl, rsl, fpl, fsl;
  148. static int noreal;
  149.  
  150. /* This is used when completing after `$' and holds the whole prefix,   *
  151.  * used in do_single() to check whether the word expands to a directory *
  152.  * name (in that case and if autoparamslash is set, we add a `/').      *
  153.  * qparampre is the same but quoted. The length of it is in qparprelen  */
  154.  
  155. static char *parampre = NULL, *qparampre = NULL;
  156. static int qparprelen;
  157.  
  158. /* This is either zero or equal to the special character the word we are *
  159.  * trying to complete starts with (e.g. Tilde or Equals).                */
  160.  
  161. static char ic;
  162.  
  163. /* These hold the minimum common prefix/suffix lengths (normal and for *
  164.  * fignore ignored).                                                   */
  165.  
  166. static int ab, ae, fab, fae;
  167.  
  168. /* This variable says what we are currently adding to the list of matches. */
  169.    
  170. static int addwhat;
  171.  
  172. /* firstm hold the first match we found, shortest contains the shortest *
  173.  * one (normal and for fignore ignored).                                */
  174.  
  175. static char *firstm, *shortest, *ffirstm, *fshortest;
  176.  
  177. /* This holds the word we are completing in quoted from. */
  178.  
  179. static char *qword;
  180.  
  181. /* This is the length of the shortest match we found (normal and for *
  182.  * fignore ignored).                                                 */
  183.  
  184. static int shortl, fshortl;
  185.  
  186. /* This is non-zero if we are doing a menu-completion and this is not the *
  187.  * first call (e.g. when automenu is set and menu-completion was entered  *
  188.  * due to this). */
  189.  
  190. static int amenu;
  191.  
  192. /* This is used by expandorcompleteprefix to save the position of the *
  193.  * inserted space (so that we can remove it later).                   */
  194.  
  195. static int remove_at = -1;
  196.  
  197. /* Find out if we have to insert a tab (instead of trying to complete). */
  198.  
  199. /**/
  200. int
  201. usetab(void)
  202. {
  203.     unsigned char *s = line + cs - 1;
  204.  
  205.     for (; s >= line && *s != '\n'; s--)
  206.     if (*s != '\t' && *s != ' ')
  207.         return 0;
  208.     return 1;
  209. }
  210.  
  211. #define COMP_COMPLETE 0
  212. #define COMP_LIST_COMPLETE 1
  213. #define COMP_SPELL 2
  214. #define COMP_EXPAND 3
  215. #define COMP_EXPAND_COMPLETE 4
  216. #define COMP_LIST_EXPAND 5
  217. #define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND)
  218.  
  219. /**/
  220. void
  221. completeword(void)
  222. {
  223.     usemenu = isset(MENUCOMPLETE);
  224.     useglob = isset(GLOBCOMPLETE);
  225.     if (c == '\t' && usetab())
  226.     selfinsert();
  227.     else
  228.     docomplete(COMP_COMPLETE);
  229. }
  230.  
  231. /**/
  232. void
  233. menucomplete(void)
  234. {
  235.     usemenu = 1;
  236.     useglob = isset(GLOBCOMPLETE);
  237.     if (c == '\t' && usetab())
  238.     selfinsert();
  239.     else
  240.     docomplete(COMP_COMPLETE);
  241. }
  242.  
  243. /**/
  244. void
  245. listchoices(void)
  246. {
  247.     usemenu = isset(MENUCOMPLETE);
  248.     useglob = isset(GLOBCOMPLETE);
  249.     docomplete(COMP_LIST_COMPLETE);
  250. }
  251.  
  252. /**/
  253. void
  254. spellword(void)
  255. {
  256.     usemenu = useglob = 0;
  257.     docomplete(COMP_SPELL);
  258. }
  259.  
  260. /**/
  261. void
  262. deletecharorlist(void)
  263. {
  264.     char **mc = menucur;
  265.  
  266.     usemenu = isset(MENUCOMPLETE);
  267.     useglob = isset(GLOBCOMPLETE);
  268.     if (cs != ll)
  269.     deletechar();
  270.     else
  271.     docomplete(COMP_LIST_COMPLETE);
  272.  
  273.     menucur = mc;
  274. }
  275.  
  276. /**/
  277. void
  278. expandword(void)
  279. {
  280.     usemenu = useglob = 0;
  281.     if (c == '\t' && usetab())
  282.     selfinsert();
  283.     else
  284.     docomplete(COMP_EXPAND);
  285. }
  286.  
  287. /**/
  288. void
  289. expandorcomplete(void)
  290. {
  291.     usemenu = isset(MENUCOMPLETE);
  292.     useglob = isset(GLOBCOMPLETE);
  293.     if (c == '\t' && usetab())
  294.     selfinsert();
  295.     else
  296.     docomplete(COMP_EXPAND_COMPLETE);
  297. }
  298.  
  299. /**/
  300. void
  301. menuexpandorcomplete(void)
  302. {
  303.     usemenu = 1;
  304.     useglob = isset(GLOBCOMPLETE);
  305.     if (c == '\t' && usetab())
  306.     selfinsert();
  307.     else
  308.     docomplete(COMP_EXPAND_COMPLETE);
  309. }
  310.  
  311. /**/
  312. void
  313. listexpand(void)
  314. {
  315.     usemenu = isset(MENUCOMPLETE);
  316.     useglob = isset(GLOBCOMPLETE);
  317.     docomplete(COMP_LIST_EXPAND);
  318. }
  319.  
  320. /**/
  321. void
  322. reversemenucomplete(void)
  323. {
  324.     if (!menucmp) {
  325.     menucomplete();
  326.     return;
  327.     }
  328.     HEAPALLOC {
  329.     if (menucur == amatches)
  330.         menucur = amatches + nmatches - 1;
  331.     else
  332.         menucur--;
  333.     complexpect = menuce;
  334.     metafy_line();
  335.     do_single(*menucur);
  336.     unmetafy_line();
  337.     } LASTALLOC;
  338. }
  339.  
  340. /* Accepts the current completion and starts a new arg, *
  341.  * with the next completions. This gives you a way to   *
  342.  * accept several selections from the list of matches.  */
  343.  
  344. /**/
  345. void
  346. acceptandmenucomplete(void)
  347. {
  348.     if (!menucmp) {
  349.     feep();
  350.     return;
  351.     }
  352.     cs = menuend;
  353.     inststrlen(" ", 1, 1);
  354.     if (qparampre)
  355.     inststrlen(qparampre, 1, qparprelen);
  356.     if (lpre && !ispattern)
  357.     inststrlen(lpre, 1, -1);
  358.     if (lsuf && !ispattern)
  359.     inststrlen(lsuf, 0, -1);
  360.     menupos = cs;
  361.     menuend = cs + (lsuf ? strlen(lsuf) : 0);
  362.     menulen = 0;
  363.     menuwe = 1;
  364.     menucomplete();
  365. }
  366.  
  367. /* These are flags saying if we are completing in the command *
  368.  * position or in a redirection.                              */
  369.  
  370. static int lincmd, linredir;
  371.  
  372. /* Non-zero if the last completion done was ambiguous (used to find   *
  373.  * out if AUTOMENU should start).  More precisely, it's nonzero after *
  374.  * successfully doing any completion, unless the completion was       *
  375.  * unambiguous and did not cause the display of a completion list.    *
  376.  * From the other point of view, it's nonzero iff AUTOMENU (if set)   *
  377.  * should kick in on another completion (provided the text isn't      *
  378.  * changed in the meantime... AAAAAAAAAAUUUUGGGHH!).                  */
  379.  
  380. static int lastambig;
  381.  
  382. /* This describes some important things collected during the last *
  383.  * completion.  Its value is zero or the inclusive OR of some of  *
  384.  * the HAS_* things below.                                        */
  385.  
  386. static int haswhat;
  387.  
  388. /* We have a suffix to add (given with compctl -S). */
  389.  
  390. #define HAS_SUFFIX  1
  391.  
  392. /* We have filenames in the completion list. */
  393.  
  394. #define HAS_FILES   2
  395.  
  396. /* We have other things than files in the completion list.  If this is *
  397.  * not set but HAS_FILES is, we probably put the file type characters  *
  398.  * in the completion list (if listtypes is set) and we attempt to add  *
  399.  * a slash to completed directories.                                   */
  400.  
  401. #define HAS_MISC    4
  402.  
  403. /* This is set if we have filenames in the completion list that were *
  404.  * generated by a globcompletion pattern.                            */
  405.  
  406. #define HAS_PATHPAT 8
  407.  
  408.  
  409. /* This holds the naem of the current command (used to find the right *
  410.  * compctl).                                                          */
  411.  
  412. static char *cmdstr;
  413.  
  414.  
  415. /* Check if the given string is the name of a parameter and if this *
  416.  * parameter is one worth expanding.                                */
  417.  
  418. /**/
  419. int
  420. checkparams(char *p)
  421. {
  422.     int t0, n, l = strlen(p), e = 0;
  423.     struct hashnode *hn;
  424.  
  425.     for (t0 = paramtab->hsize - 1, n = 0; n < 2 && t0 >= 0; t0--)
  426.     for (hn = paramtab->nodes[t0]; n < 2 && hn; hn = hn->next)
  427.         if (pfxlen(p, hn->nam) == l) {
  428.         n++;
  429.         if (strlen(hn->nam) == l)
  430.             e = 1;
  431.         }
  432.     return (n == 1) ? (getsparam(p) != NULL) :
  433.     (!menucmp && e && isset(RECEXACT));
  434. }
  435.  
  436. /* Check if the given string has wildcards.  The difficulty is that we *
  437.  * have to treat things like job specifications (%...) and parameter   *
  438.  * expressions correctly.                                              */
  439.  
  440. /**/
  441. int
  442. cmphaswilds(char *str)
  443. {
  444.     if ((*str == Inbrack || *str == Outbrack) && !str[1])
  445.     return 0;
  446.  
  447.     /* If a leading % is immediately followed by ?, then don't *
  448.      * treat that ? as a wildcard.  This is so you don't have  *
  449.      * to escape job references such as %?foo.                 */
  450.     if (str[0] == '%' && str[1] ==Quest)
  451.     str += 2;
  452.  
  453.     for (; *str;) {
  454.     if (*str == String || *str == Qstring) {
  455.         /* A parameter expression. */
  456.  
  457.         if (*++str == Inbrace)
  458.         skipparens(Inbrace, Outbrace, &str);
  459.         else if (*str == String || *str == Qstring)
  460.         str++;
  461.         else {
  462.         /* Skip all the things a parameter expression might start *
  463.          * with (before we come to the parameter name).           */
  464.         for (; *str; str++)
  465.             if (*str != '^' && *str != Hat &&
  466.             *str != '=' && *str != Equals &&
  467.             *str != '~' && *str != Tilde)
  468.             break;
  469.         if (*str == '#' || *str == Pound)
  470.             str++;
  471.         /* Star and Quest are parameter names here, not wildcards */
  472.         if (*str == Star || *str == Quest)
  473.             str++;
  474.         }
  475.     } else {
  476.         /* Not a parameter expression so we check for wildcards */
  477.         if (((*str == Pound || *str == Hat) && isset(EXTENDEDGLOB)) ||
  478.         *str == Star || *str == Bar || *str == Quest ||
  479.         !skipparens(Inbrack, Outbrack, &str) ||
  480.         !skipparens(Inang,   Outang,   &str) ||
  481.         (unset(IGNOREBRACES) &&
  482.          !skipparens(Inbrace, Outbrace, &str)) ||
  483.         (*str == Inpar && str[1] == ':' &&
  484.          !skipparens(Inpar, Outpar, &str)))
  485.         return 1;
  486.         if (*str)
  487.         str++;
  488.     }
  489.     }
  490.     return 0;
  491. }
  492.  
  493. /* The main entry point for completion. */
  494.  
  495. /**/
  496. void
  497. docomplete(int lst)
  498. {
  499.     char *s, *ol;
  500.     int olst = lst, chl = 0, ne = noerrs, ocs;
  501.  
  502.     /* If we are doing a menu-completion... */
  503.  
  504.     if (menucmp && lst != COMP_LIST_EXPAND) {
  505.     do_menucmp(lst);
  506.     return;
  507.     }
  508.     
  509.     /* Check if we have to start a menu-completion (via automenu). */
  510.  
  511.     if ((amenu = (isset(AUTOMENU) &&
  512.                (lastcmd & ZLE_MENUCMP) &&
  513.                lastambig)))
  514.     usemenu = 1;
  515.  
  516.     /* Expand history references before starting completion.  If anything *
  517.      * changed, do no more.                                               */
  518.  
  519.     if (doexpandhist())
  520.     return;
  521.  
  522.     metafy_line();
  523.  
  524.     ocs = cs;
  525.     if (!isfirstln && chline != NULL) {
  526.     /* If we are completing in a multi-line buffer (which was not  *
  527.      * taken from the history), we have to prepend the stuff saved *
  528.      * in chline to the contents of line.                          */
  529.  
  530.     ol = dupstring((char *)line);
  531.     /* Make sure that chline is zero-terminated. */
  532.     *hptr = '\0';
  533.     cs = 0;
  534.     inststr(chline);
  535.     chl = cs;
  536.     cs += ocs;
  537.     } else
  538.     ol = NULL;
  539.     inwhat = IN_NOTHING;
  540.     qword = NULL;
  541.     /* Get the word to complete. */
  542.     noerrs = 1;
  543.     s = get_comp_string();
  544.     DPUTS(wb < 0 || cs < wb || cs > we,
  545.       "BUG: 0 <= wb <= cs <= we is not true!");
  546.     noerrs = ne;
  547.     /* For vi mode, reset the start-of-insertion pointer to the beginning *
  548.      * of the word being completed, if it is currently later.  Vi itself  *
  549.      * would never change the pointer in the middle of an insertion, but  *
  550.      * then vi doesn't have completion.  More to the point, this is only  *
  551.      * an emulation.                                                      */
  552.     if (viinsbegin > ztrsub((char *) line + wb, (char *) line))
  553.     viinsbegin = ztrsub((char *) line + wb, (char *) line);
  554.     /* If we added chline to the line buffer, reset the original contents. */
  555.     if (ol) {
  556.     cs -= chl;
  557.     wb -= chl;
  558.     we -= chl;
  559.     if (wb < 0) {
  560.         strcpy((char *) line, ol);
  561.         ll = strlen((char *) line);
  562.         cs = ocs;
  563.         unmetafy_line();
  564.         feep();
  565.         return;
  566.     }
  567.     ocs = cs;
  568.     cs = 0;
  569.     foredel(chl);
  570.     cs = ocs;
  571.     }
  572.     freeheap();
  573.     /* Save the lexer state, in case the completion code uses the lexer *
  574.      * somewhere (e.g. when processing a compctl -s flag).              */
  575.     lexsave();
  576.     if (inwhat == IN_ENV)
  577.     lincmd = 0;
  578.     if (s) {
  579.     if (lst == COMP_EXPAND_COMPLETE) {
  580.         /* Check if we have to do expansion or completion. */
  581.         char *q = s;
  582.  
  583.         if (*q == Equals) {
  584.         /* The word starts with `=', see if we can expand it. */
  585.         q = s + 1;
  586.         if (cmdnamtab->getnode(cmdnamtab, q) || hashcmd(q, pathchecked))
  587.             if (isset(RECEXACT))
  588.             lst = COMP_EXPAND;
  589.             else {
  590.             int t0, n = 0;
  591.             char *fc;
  592.             struct hashnode *hn;
  593.  
  594.             for (t0 = cmdnamtab->hsize - 1; t0 >= 0; t0--)
  595.                 for (hn = cmdnamtab->nodes[t0]; hn;
  596.                  hn = hn->next) {
  597.                 if (strpfx(q, hn->nam) && (fc = findcmd(hn->nam))) {
  598.                     zsfree(fc);
  599.                     n++;
  600.                 }
  601.                 if (n == 2)
  602.                     break;
  603.                 }
  604.  
  605.             if (n == 1)
  606.                 lst = COMP_EXPAND;
  607.             }
  608.         }
  609.         if (lst == COMP_EXPAND_COMPLETE)
  610.         do {
  611.             /* check if there is a parameter expresiion. */
  612.             for (; *q && *q != String; q++);
  613.             if (*q == String && q[1] != Inpar && q[1] != Inbrack) {
  614.             if (*++q == Inbrace) {
  615.                 if (! skipparens(Inbrace, Outbrace, &q) &&
  616.                 q == s + cs - wb)
  617.                 lst = COMP_EXPAND;
  618.             } else {
  619.                 char *t, sav, sav2;
  620.  
  621.                 /* Skip the things parameter expressions might *
  622.                  * start with (the things before the parameter *
  623.                  * name).                                      */
  624.                 for (; *q; q++)
  625.                 if (*q != '^' && *q != Hat &&
  626.                     *q != '=' && *q != Equals &&
  627.                     *q != '~' && *q != Tilde)
  628.                     break;
  629.                 if ((*q == '#' || *q == Pound || *q == '+') &&
  630.                 q[1] != String)
  631.                 q++;
  632.  
  633.                 sav2 = *(t = q);
  634.                 if (*q == Quest || *q == Star || *q == String ||
  635.                 *q == Qstring)
  636.                 *q = ztokens[*q - Pound], ++q;
  637.                 else if (*q == '?' || *q == '*' || *q == '$' ||
  638.                      *q == '-' || *q == '!' || *q == '@')
  639.                 q++;
  640.                 else if (idigit(*q))
  641.                 do q++; while (idigit(*q));
  642.                 else
  643.                 while (iident(*q))
  644.                     q++;
  645.                 sav = *q;
  646.                 *q = '\0';
  647.                 if (cs - wb == q - s &&
  648.                 (idigit(sav2) || checkparams(t)))
  649.                 lst = COMP_EXPAND;
  650.                 *q = sav;
  651.                 *t = sav2;
  652.             }
  653.             if (lst != COMP_EXPAND)
  654.                 lst = COMP_COMPLETE;
  655.             } else
  656.             break;
  657.         } while (q < s + cs - wb);
  658.         if (lst == COMP_EXPAND_COMPLETE) {
  659.         /* If it is still not clear if we should use expansion or   *
  660.          * completion and there is a `$' or a backtick in the word, *
  661.          * than do expansion.                                       */
  662.         for (q = s; *q; q++)
  663.             if (*q == Tick || *q == Qtick ||
  664.             *q == String || *q == Qstring)
  665.             break;
  666.         lst = *q ? COMP_EXPAND : COMP_COMPLETE;
  667.         }
  668.         /* And do expansion if there are wildcards and globcomplete is *
  669.          * not used.                                                   */
  670.         if (unset(GLOBCOMPLETE) && cmphaswilds(s))
  671.         lst = COMP_EXPAND;
  672.     }
  673.     if (lincmd && (inwhat == IN_NOTHING))
  674.         inwhat = IN_CMD;
  675.  
  676.     if (lst == COMP_SPELL) {
  677.         char *x, *q;
  678.  
  679.         for (q = s; *q; q++)
  680.         if (INULL(*q))
  681.             *q = Nularg;
  682.         cs = wb;
  683.         foredel(we - wb);
  684.         HEAPALLOC {
  685.         untokenize(x = dupstring(s));
  686.         if (*s == Tilde || *s == Equals || *s == String)
  687.             *x = *s;
  688.         spckword(&x, 0, lincmd, 0);
  689.         } LASTALLOC;
  690.         untokenize(x);
  691.         inststr(x);
  692.     } else if (COMP_ISEXPAND(lst)) {
  693.         /* Do expansion. */
  694.         char *ol = (olst == COMP_EXPAND_COMPLETE) ?
  695.         dupstring((char *)line) : (char *)line;
  696.         int ocs = cs, ne = noerrs;
  697.  
  698.         noerrs = 1;
  699.         doexpansion(s, lst, olst, lincmd);
  700.         lastambig = 0;
  701.         noerrs = ne;
  702.  
  703.         /* If expandorcomplete was invoked and the expansion didn't *
  704.          * change the command line, do completion.                  */
  705.         if (olst == COMP_EXPAND_COMPLETE &&
  706.         !strcmp(ol, (char *)line)) {
  707.         char *p;
  708.  
  709.         cs = ocs;
  710.         errflag = 0;
  711.  
  712.         p = s;
  713.         if (*p == Tilde || *p == Equals)
  714.             p++;
  715.         for (; *p; p++)
  716.             if (itok(*p))
  717.             if (*p != String && *p != Qstring)
  718.                 *p = ztokens[*p - Pound];
  719.             else if (p[1] == Inbrace)
  720.                 p++, skipparens(Inbrace, Outbrace, &p);
  721.         docompletion(s, lst, lincmd, 1);
  722.         }
  723.     } else
  724.         /* Just do completion. */
  725.         docompletion(s, lst, lincmd, 0);
  726.     zsfree(s);
  727.     }
  728.     /* Reset the lexer state, pop the heap. */
  729.     lexrestore();
  730.     popheap();
  731.     zsfree(qword);
  732.     menuce = complexpect;
  733.     unmetafy_line();
  734. }
  735.  
  736. /* Do completion, given that we are in the middle of a menu completion.  We *
  737.  * don't need to generate a list of matches, because that's already been    *
  738.  * done by previous commands.  We will either list the completions, or      *
  739.  * insert the next completion.                                              */
  740.  
  741. /**/
  742. void
  743. do_menucmp(int lst)
  744. {
  745.     /* Just list the matches if the list was requested. */
  746.     if (lst == COMP_LIST_COMPLETE) {
  747.     showinglist = -2;
  748.     return;
  749.     }
  750.     /* Otherwise go to the next match in the array... */
  751.     HEAPALLOC {
  752.     if (!*++menucur)
  753.         menucur = amatches;
  754.     complexpect = menuce;
  755.     /* ... and insert it into the command line. */
  756.     metafy_line();
  757.     do_single(*menucur);
  758.     unmetafy_line();
  759.     } LASTALLOC;
  760. }
  761.  
  762. /* 1 if x added to complete in a blank between words */
  763. int addedx;
  764.  
  765. /* 1 if we are completing in a string */
  766. int instring;
  767.  
  768. /* This function inserts an `x' in the command line at the cursor position. *
  769.  *                                                                          *
  770.  * Oh, you want to know why?  Well, if completion is tried somewhere on an  *
  771.  * empty part of the command line, the lexer code would normally not be     *
  772.  * able to give us the `word' we want to complete, since there is no word.  *
  773.  * But we need to call the lexer to find out where we are (and for which    *
  774.  * command we are completing and such things).  So we temporarily add a `x' *
  775.  * (any character without special meaning would do the job) at the cursor   *
  776.  * position, than the lexer gives us the word `x' and its beginning and end *
  777.  * positions and we can remove the `x'.                                     */
  778.  
  779. /**/
  780. void
  781. addx(char **ptmp)
  782. {
  783.     if (!line[cs] || line[cs] == '\n' ||
  784.     (iblank(line[cs]) && (!cs || line[cs-1] != '\\')) ||
  785.     line[cs] == ')' || line[cs] == '`' ||
  786.     (instring && (line[cs] == '"' || line[cs] == '\''))) {
  787.     *ptmp = (char *)line;
  788.     line = (unsigned char *)halloc(strlen((char *)line) + 3);
  789.     memcpy(line, *ptmp, cs);
  790.     line[cs] = 'x';
  791.     strcpy((char *)line + cs + 1, (*ptmp) + cs);
  792.     addedx = 1;
  793.     } else {
  794.     addedx = 0;
  795.     *ptmp = NULL;
  796.     }
  797. }
  798.  
  799. /* Like dupstring, but add an extra space at the end of the string. */
  800.  
  801. /**/
  802. char *
  803. dupstrspace(const char *str)
  804. {
  805.     int len = strlen((char *)str);
  806.     char *t = (char *)ncalloc(len + 2);
  807.     strcpy(t, str);
  808.     strcpy(t+len, " ");
  809.     return t;
  810. }
  811.  
  812. /* These functions metafy and unmetafy the ZLE buffer, as described at the *
  813.  * top of this file.  Note that ll and cs are translated.  They *must* be  *
  814.  * called in matching pairs, around all the expansion/completion code.     *
  815.  * Currently, there are four pairs: in history expansion, in the main      *
  816.  * completion function, and one in each of the middle-of-menu-completion   *
  817.  * functions (there's one for each direction).                             */
  818.  
  819. /**/
  820. void
  821. metafy_line(void)
  822. {
  823.     int len = ll;
  824.     char *s;
  825.  
  826.     for (s = (char *) line; s < (char *) line + ll;)
  827.     if (imeta(*s++))
  828.         len++;
  829.     sizeline(len);
  830.     (void) metafy((char *) line, ll, META_NOALLOC);
  831.     ll = len;
  832.     cs = metalen((char *) line, cs);
  833. }
  834.  
  835. /**/
  836. void
  837. unmetafy_line(void)
  838. {
  839.     cs = ztrsub((char *) line + cs, (char *) line);
  840.     (void) unmetafy((char *) line, &ll);
  841. }
  842.  
  843. /* Lasciate ogni speranza.                                                  *
  844.  * This function is a nightmare.  It works, but I'm sure that nobody really *
  845.  * understands why.  The problem is: to make it cleaner we would need       *
  846.  * changes in the lexer code (and then in the parser, and then...).         */
  847.  
  848. /**/
  849. char *
  850. get_comp_string(void)
  851. {
  852.     int t0, tt0, i, j, k, cp, rd, sl, ocs;
  853.     char *s = NULL, *linptr, *tmp, *p, *tt = NULL;
  854.  
  855.     /* This global flag is used to signal the lexer code if it should *
  856.      * expand aliases or not.                                         */
  857.     noaliases = isset(COMPLETEALIASES);
  858.  
  859.     /* Find out if we are somewhere in a `string', i.e. inside '...', *
  860.      * "...", `...`, or ((...)).                                      */
  861.  
  862.     for (i = j = k = 0, p = (char *)line; p < (char *)line + cs; p++)
  863.     if (*p == '`' && !(k & 1))
  864.         i++;
  865.     else if (*p == '\"' && !(k & 1) && !(i & 1))
  866.         j++;
  867.     else if (*p == '\'' && !(j & 1))
  868.         k++;
  869.     else if (*p == '\\' && p[1] && !(k & 1))
  870.         p++;
  871.     instring = (j & 1) ? 2 : (k & 1);
  872.     addx(&tmp);
  873.     if (instring) {
  874.     /* Yes, we are in a string. */
  875.     if (!tmp) {
  876.         tmp = (char *)line;
  877.         line = (unsigned char *) dupstring((char *) line);
  878.     }
  879.     /* Now remove the quotes.                                   *
  880.      * What??  Why that??  Well, we want to be able to complete *
  881.      * inside strings.  The lexer code gives us no help here,   *
  882.      * so we have to cheat.  We remove the quotes, the lexer    *
  883.      * will than treat the words in the strings normally and we *
  884.      * can complete them.                                       *
  885.      * This is completely the wrong thing to do, but it's       *
  886.      * occasionally useful, and we can't handle quotes properly *
  887.      * yet anyway.                                              */
  888.     for (p = (char *)line; *p; p++)
  889.         if (*p == '"' || *p == '\'')
  890.         *p = ' ';
  891.     }
  892.     linptr = (char *)line;
  893.     pushheap();
  894.     HEAPALLOC {
  895.       start:
  896.     inwhat = IN_NOTHING;
  897.     /* Now set up the lexer and start it. */
  898.     parbegin = parend = -1;
  899.     lincmd = incmdpos;
  900.     linredir = inredir;
  901.     zsfree(cmdstr);
  902.     cmdstr = NULL;
  903.     zleparse = 1;
  904.     clwpos = -1;
  905.     lexsave();
  906.     inpush(dupstrspace((char *) linptr), 0, NULL);
  907.     strinbeg();
  908.     stophist = 2;
  909.     i = tt0 = cp = rd = 0;
  910.  
  911.     /* This loop is possibly the wrong way to do this.  It goes through *
  912.      * the previously massaged command line using the lexer.  It stores *
  913.      * each token in each command (commands being regarded, roughly, as *
  914.      * being separated by tokens | & &! |& || &&).  The loop stops when *
  915.      * the end of the command containing the cursor is reached.  It's a *
  916.      * simple way to do things, but suffers from an inability to        *
  917.      * distinguish actual command arguments from, for example,          *
  918.      * filenames in redirections.  (But note that code elsewhere checks *
  919.      * if we are completing *in* a redirection.)  The only way to fix   *
  920.      * this would be to pass the command line through the parser too,   *
  921.      * and get the arguments that way.  Maybe in 3.1...                 */
  922.     do {
  923.         lincmd = incmdpos;
  924.         linredir = inredir;
  925.         /* Get the next token. */
  926.         ctxtlex();
  927.         if (tok == DINPAR)
  928.         tokstr = NULL;
  929.  
  930.         /* We reached the end. */
  931.         if (tok == ENDINPUT)
  932.         break;
  933.         if (tok == BAR    || tok == AMPER     ||
  934.         tok == BARAMP || tok == AMPERBANG ||
  935.         ((tok == DBAR || tok == DAMPER) && !incond)) {
  936.         /* This is one of the things that separate commands.  If we  *
  937.          * already have the things we need (e.g. the token strings), *
  938.          * leave the loop.                                           */
  939.         if (tt)
  940.             break;
  941.         /* Otherwise reset the variables we are collecting data in. */
  942.         i = tt0 = cp = rd = 0;
  943.         }
  944.         if (lincmd && tok == STRING) {
  945.         /* The lexer says, this token is in command position, so *
  946.          * store the token string (to find the right compctl).   */
  947.         zsfree(cmdstr);
  948.         cmdstr = ztrdup(tokstr);
  949.         i = 0;
  950.         }
  951.         if (!zleparse && !tt0) {
  952.         /* This is done when the lexer reached the word the cursor is on. */
  953.         tt = tokstr ? dupstring(tokstr) : NULL;
  954.         /* If we added a `x', remove it. */
  955.         if (addedx && tt)
  956.             chuck(tt + cs - wb - 1);
  957.         tt0 = tok;
  958.         /* Store the number of this word. */
  959.         clwpos = i;
  960.         cp = lincmd;
  961.         rd = linredir;
  962.         if (inwhat == IN_NOTHING && incond)
  963.             inwhat = IN_COND;
  964.         }
  965.         if (!tokstr)
  966.         continue;
  967.         /* We need to store the token strings of all words (for some of *
  968.          * the more complicated compctl -x things).  They are stored in *
  969.          * the clwords array.  Make this array big enough.              */
  970.         if (i + 1 == clwsize) {
  971.         int n;
  972.         clwords = (char **)realloc(clwords,
  973.                        (clwsize *= 2) * sizeof(char *));
  974.         for(n = clwsize; --n > i; )
  975.             clwords[n] = NULL;
  976.         }
  977.         zsfree(clwords[i]);
  978.         /* And store the current token string. */
  979.         clwords[i] = ztrdup(tokstr);
  980.         sl = strlen(tokstr);
  981.         /* Sometimes the lexer gives us token strings ending with *
  982.          * spaces we delete the spaces.                           */
  983.         while (sl && clwords[i][sl - 1] == ' ' &&
  984.            (sl < 2 || (clwords[i][sl - 2] != Bnull &&
  985.                    clwords[i][sl - 2] != Meta)))
  986.         clwords[i][--sl] = '\0';
  987.         /* If this is the word the cursor is in and we added a `x', *
  988.          * remove it.                                               */
  989.         if (clwpos == i++ && addedx)
  990.         chuck(&clwords[i - 1][((cs - wb - 1) >= sl) ?
  991.                      (sl - 1) : (cs - wb - 1)]);
  992.     } while (tok != LEXERR && tok != ENDINPUT &&
  993.          (tok != SEPER || (zleparse && !tt0)));
  994.     /* Calculate the number of words stored in the clwords array. */
  995.     clwnum = (tt || !i) ? i : i - 1;
  996.     zsfree(clwords[clwnum]);
  997.     clwords[clwnum] = NULL;
  998.     t0 = tt0;
  999.     lincmd = cp;
  1000.     linredir = rd;
  1001.     strinend();
  1002.     inpop();
  1003.     errflag = zleparse = 0;
  1004.     if (addedx)
  1005.         wb++;
  1006.     if (parbegin != -1) {
  1007.         /* We are in command or process substitution */
  1008.         if (parend >= 0 && !tmp)
  1009.         line = (unsigned char *) dupstring(tmp = (char *)line);
  1010.         linptr = (char *) line + ll + addedx - parbegin + 1;
  1011.         if (parend >= 0) {
  1012.         ll -= parend;
  1013.         line[ll + addedx] = '\0';
  1014.         }
  1015.         lexrestore();
  1016.         goto start;
  1017.     }
  1018.  
  1019.     if (inwhat == IN_MATH)
  1020.         s = NULL;
  1021.     else if (!t0 || t0 == ENDINPUT) {
  1022.         /* There was no word (empty line). */
  1023.         s = ztrdup("");
  1024.         we = wb = cs;
  1025.         clwpos = clwnum;
  1026.         t0 = STRING;
  1027.     } else if (t0 == STRING) {
  1028.         /* We found a simple string. */
  1029.         s = ztrdup(clwords[clwpos]);
  1030.     } else if (t0 == ENVSTRING) {
  1031.         /* The cursor was inside a parameter assignment. */
  1032.         for (s = tt; iident(*s); s++);
  1033.         if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb)
  1034.         s = NULL, inwhat = IN_MATH;
  1035.         else if (*s == '=') {
  1036.         s++;
  1037.         wb += s - tt;
  1038.         t0 = STRING;
  1039.         s = ztrdup(s);
  1040.         inwhat = IN_ENV;
  1041.         }
  1042.         lincmd = 1;
  1043.     }
  1044.     if (we > ll)
  1045.         we = ll;
  1046.     tt = (char *)line;
  1047.     if (tmp) {
  1048.         line = (unsigned char *)tmp;
  1049.         ll = strlen((char *)line);
  1050.     }
  1051.     if (t0 != STRING && inwhat != IN_MATH) {
  1052.         if (tmp) {
  1053.         tmp = NULL;
  1054.         linptr = (char *)line;
  1055.         lexrestore();
  1056.         goto start;
  1057.         }
  1058.         feep();
  1059.         noaliases = 0;
  1060.         lexrestore();
  1061.         LASTALLOC_RETURN NULL;
  1062.     }
  1063.  
  1064.     noaliases = 0;
  1065.  
  1066.     /* Check if we are in an array subscript.  We simply assume that  *
  1067.      * we are in a subscript if we are in brackets.  Correct solution *
  1068.      * is very difficult.  This is quite close, but gets things like  *
  1069.      * foo[_ wrong (note no $).  If we are in a subscript, treat it   *
  1070.      * as being in math.                                              */
  1071.     if (inwhat != IN_MATH) {
  1072.         int i = 0;
  1073.         for (tt = s; ++tt < s + cs - wb;)
  1074.         if (*tt == Inbrack)
  1075.             i++;
  1076.         else if (i && *tt == Outbrack)
  1077.             i--;
  1078.         if (i)
  1079.         inwhat = IN_MATH;
  1080.     }
  1081.     if (inwhat == IN_MATH) {
  1082.         /* In mathematical expression, we complete parameter names (even *
  1083.          * if they don't have a `$' in front of them).  So we have to    *
  1084.          * find that name.                                               */
  1085.         for (we = cs; iident(line[we]); we++);
  1086.         for (wb = cs; --wb >= 0 && iident(line[wb]););
  1087.         wb++;
  1088.         zsfree(s);
  1089.         s = zalloc(we - wb + 1);
  1090.         strncpy(s, (char *) line + wb, we - wb);
  1091.         s[we - wb] = '\0';
  1092.     }
  1093.     /* This variable will hold the current word in quoted form. */
  1094.     qword = ztrdup(s);
  1095.     /* While building the quoted form, we also clean up the command line. */
  1096.     offs = cs - wb;
  1097.     for (p = s, tt = qword, i = wb; *p; p++, tt++, i++)
  1098.         if (INULL(*p)) {
  1099.         if (i < cs)
  1100.             offs--;
  1101.         if (p[1] || *p != Bnull) {
  1102.             if (*p == Bnull) {
  1103.             *tt = '\\';
  1104.             if (cs == i + 1)
  1105.                 cs++, offs++;
  1106.             } else {
  1107.             ocs = cs;
  1108.             cs = i;
  1109.             foredel(1);
  1110.             chuck(tt--);
  1111.             if ((cs = ocs) > i--)
  1112.                 cs--;
  1113.             we--;
  1114.             }
  1115.         } else {
  1116.             ocs = cs;
  1117.             *tt = '\0';
  1118.             cs = we;
  1119.             backdel(1);
  1120.             if (ocs == we)
  1121.             cs = we - 1;
  1122.             else
  1123.             cs = ocs;
  1124.             we--;
  1125.         }
  1126.         chuck(p--);
  1127.         }
  1128.     } LASTALLOC;
  1129.     lexrestore();
  1130.  
  1131.     return (char *)s;
  1132. }
  1133.  
  1134. /* Expand the current word. */
  1135.  
  1136. /**/
  1137. void
  1138. doexpansion(char *s, int lst, int olst, int explincmd)
  1139. {
  1140.     LinkList vl;
  1141.     char *ss;
  1142.  
  1143.     DPUTS(useheap, "BUG: useheap in doexpansion()");
  1144.     HEAPALLOC {
  1145.     pushheap();
  1146.     vl = newlinklist();
  1147.     ss = dupstring(s);
  1148.     addlinknode(vl, ss);
  1149.     prefork(vl, 0);
  1150.     if (errflag)
  1151.         goto end;
  1152.     if ((lst == COMP_LIST_EXPAND) || (lst == COMP_EXPAND)) {
  1153.         int ng = opts[NULLGLOB];
  1154.  
  1155.         opts[NULLGLOB] = 1;
  1156.         globlist(vl);
  1157.         opts[NULLGLOB] = ng;
  1158.     }
  1159.     if (errflag)
  1160.         goto end;
  1161.     if (empty(vl) || !*(char *)peekfirst(vl)) {
  1162.         if (!noerrs)
  1163.         feep();
  1164.         goto end;
  1165.     }
  1166.     if (peekfirst(vl) == (void *) ss ||
  1167.         (olst == COMP_EXPAND_COMPLETE &&
  1168.          !nextnode(firstnode(vl)) && *s == Tilde &&
  1169.          (ss = dupstring(s), filesubstr(&ss, 0)) &&
  1170.          !strcmp(ss, (char *)peekfirst(vl)))) {
  1171.         /* If expansion didn't change the word, try completion if *
  1172.          * expandorcomplete was called, otherwise, just beep.     */
  1173.         if (lst == COMP_EXPAND_COMPLETE)
  1174.         docompletion(s, COMP_COMPLETE, explincmd, 0);
  1175.         else
  1176.         feep();
  1177.         goto end;
  1178.     }
  1179.     if (lst == COMP_LIST_EXPAND) {
  1180.         /* Only the list of expansions was requested. */
  1181.         listlist(vl);
  1182.         goto end;
  1183.     }
  1184.     /* Remove the current word and put the expansions there. */
  1185.     cs = wb;
  1186.     foredel(we - wb);
  1187.     while ((ss = (char *)ugetnode(vl))) {
  1188.         untokenize(ss);
  1189.         ss = quotename(ss, NULL, NULL, NULL);
  1190.         inststr(ss);
  1191. #if 0
  1192.         if (nonempty(vl)) {
  1193.         spaceinline(1);
  1194.         line[cs++] = ' ';
  1195.         }
  1196. #endif
  1197.         if (olst != COMP_EXPAND_COMPLETE || nonempty(vl) ||
  1198.         (cs && line[cs-1] != '/')) {
  1199.         spaceinline(1);
  1200.         line[cs++] = ' ';
  1201.         }
  1202.     }
  1203.       end:
  1204.     popheap();
  1205.     } LASTALLOC;
  1206. }
  1207.  
  1208. /* This is called from the lexer to give us word positions. */
  1209.  
  1210. /**/
  1211. void
  1212. gotword(void)
  1213. {
  1214.     we = ll + 1 - inbufct;
  1215.     if (cs <= we) {
  1216.     wb = ll - wordbeg;
  1217.     zleparse = 0;
  1218.     }
  1219. }
  1220.  
  1221. /* Insert the given string into the command line.  If move is non-zero, *
  1222.  * the cursor position is changed and len is the length of the string   *
  1223.  * to insert (if it is -1, the length is calculated here).              */
  1224.  
  1225. /**/
  1226. void
  1227. inststrlen(char *str, int move, int len)
  1228. {
  1229.     if (!len)
  1230.     return;
  1231.     if (len == -1)
  1232.     len = strlen(str);
  1233.     spaceinline(len);
  1234.     strncpy((char *)(line + cs), str, len);
  1235.     if (remove_at >= cs)
  1236.         remove_at += len;
  1237.     if (move)
  1238.     cs += len;
  1239. }
  1240.  
  1241. /* Quote the string s and return the result.  If e is non-zero, it the    *
  1242.  * pointer it points to may point to aposition in s and in e the position *
  1243.  * of the corresponding character in the quoted string is returned.  Like *
  1244.  * e, te may point to a position in the string and pl is used to return   *
  1245.  * the position of the character pointed to by te in the quoted string.   *
  1246.  * The string is metafied and may contain tokens.                         */
  1247.  
  1248. /**/
  1249. char *
  1250. quotename(const char *s, char **e, char *te, int *pl)
  1251. {
  1252.     const char *u, *tt;
  1253.     char *v, buf[PATH_MAX * 2];
  1254.     int sf = 0;
  1255.  
  1256.     tt = v = buf;
  1257.     u = s;
  1258.     for (; *u; u++) {
  1259.     if (e && *e == u)
  1260.         *e = v, sf |= 1;
  1261.     if (te == u)
  1262.         *pl = v - tt, sf |= 2;
  1263.     if (ispecial(*u) &&
  1264.         (!instring || (isset(BANGHIST) &&
  1265.                *u == (char)bangchar) ||
  1266.          (instring == 2 &&
  1267.           (*u == '$' || *u == '`' || *u == '\"')) ||
  1268.          (instring == 1 && *u == '\'')))
  1269.         if (*u == '\n' || (instring == 1 && *u == '\'')) {
  1270.         if (unset(RCQUOTES)) {
  1271.             *v++ = '\'';
  1272.             if (*u == '\'')
  1273.             *v++ = '\\';
  1274.             *v++ = *u;
  1275.             *v++ = '\'';
  1276.         } else if (*u == '\n')
  1277.             *v++ = '"', *v++ = '\n', *v++ = '"';
  1278.         else
  1279.             *v++ = '\'', *v++ = '\'';
  1280.         continue;
  1281.         } else
  1282.         *v++ = '\\';
  1283.     if(*u == Meta)
  1284.         *v++ = *u++;
  1285.     *v++ = *u;
  1286.     }
  1287.     *v = '\0';
  1288.     if (strcmp(buf, s))
  1289.     tt = dupstring(buf);
  1290.     else
  1291.     tt = s;
  1292.     v += tt - buf;
  1293.     if (e && (sf & 1))
  1294.     *e += tt - buf;
  1295.  
  1296.     if (e && *e == u)
  1297.     *e = v;
  1298.     if (te == u)
  1299.     *pl = v - tt;
  1300.  
  1301.     return (char *) tt;
  1302. }
  1303.  
  1304. /* This adds a match to the list of matches.  The string to add is given   *
  1305.  * in s, the type of match is given in the global variable addwhat and     *
  1306.  * the parameter t (if not NULL) is a pointer to a hash node node which    *
  1307.  * may be used to give other information to this function.                 *
  1308.  *                                                                         *
  1309.  * addwhat contains either one of the special values (negative, see below) *
  1310.  * or the inclusive OR of some of the CC_* flags used for compctls.        */
  1311.  
  1312. /**/
  1313. void
  1314. addmatch(char *s, char *t)
  1315. {
  1316.     int test = 0, sl = strlen(s), pl = rpl, cc = 0, *bp, *ep, *sp;
  1317.     char *e = NULL, *tt, *te, *fc, **fm;
  1318.     Comp cp = patcomp;
  1319.     HashNode hn;
  1320.     Param pm;
  1321.     LinkList l = matches;
  1322.  
  1323. /*
  1324.  * addwhat: -5 is for files,
  1325.  *          -6 is for glob expansions,
  1326.  *          -8 is for executable files (e.g. command paths),
  1327.  *          -9 is for parameters
  1328.  *          -7 is for command names (from cmdnamtab)
  1329.  *          -4 is for a cdable parameter
  1330.  *          -3 is for executable command names.
  1331.  *          -2 is for anything unquoted
  1332.  *          -1 is for other file specifications
  1333.  *          (things with `~' of `=' at the beginning, ...).
  1334.  */
  1335.  
  1336.     /* Just to make the code cleaner */
  1337.     hn = (HashNode) t;
  1338.     pm = (Param) t;
  1339.  
  1340.     if (!addwhat) {
  1341.     test = 1;
  1342.     } else if (addwhat == -1 || addwhat == -5 || addwhat == -6 ||
  1343.            addwhat == CC_FILES || addwhat == -7 || addwhat == -8) {
  1344.     if (sl < fpl + fsl)
  1345.         return;
  1346.  
  1347.     if ((addwhat == CC_FILES ||
  1348.          addwhat == -5) && !*psuf && !*fsuf) {
  1349.         /* If this is a filename, do the fignore check. */
  1350.         char **pt = fignore;
  1351.         int filell;
  1352.  
  1353.         for (test = 1; test && *pt; pt++)
  1354.         if ((filell = strlen(*pt)) < sl
  1355.             && !strcmp(*pt, s + sl - filell))
  1356.             test = 0;
  1357.  
  1358.         if (!test)
  1359.         l = fmatches;
  1360.     }
  1361.     pl = fpl;
  1362.     if (addwhat == -5 || addwhat == -8) {
  1363.         test = 1;
  1364.         cp = filecomp;
  1365.         cc = cp || ispattern;
  1366.         e = s + sl - fsl;
  1367.     } else {
  1368.         if ((cp = filecomp)) {
  1369.         if ((test = domatch(s, filecomp, 0)))
  1370.             cc = 1;
  1371.         } else {
  1372.         e = s + sl - fsl;
  1373.         if ((test = !strncmp(s, fpre, fpl)))
  1374.             test = !strcmp(e, fsuf);
  1375.         if (ispattern)
  1376.             cc = 1;
  1377.         }
  1378.     }
  1379.     if (test) {
  1380.         fc = NULL;
  1381.         if (addwhat == -7 && !(fc = findcmd(s)))
  1382.         return;
  1383.         if (fc)
  1384.         zsfree(fc);
  1385.         haswhat |= HAS_FILES;
  1386.  
  1387.         if (addwhat == CC_FILES || addwhat == -6 ||
  1388.         addwhat == -5 || addwhat == -8) {
  1389.         te = s + pl;
  1390.         s = quotename(s, &e, te, &pl);
  1391.         sl = strlen(s);
  1392.         } else if (!cc) {
  1393.         s = dupstring(t = s);
  1394.         e += s - t;
  1395.         }
  1396.         if (cc) {
  1397.         tt = (char *)halloc(strlen(ppre) + strlen(psuf) + sl + 1);
  1398.         strcpy(tt, ppre);
  1399.         strcat(tt, s);
  1400.         strcat(tt, psuf);
  1401.         untokenize(s = tt);
  1402.         }
  1403.     }
  1404.     } else if (addwhat == CC_QUOTEFLAG || addwhat == -2  ||
  1405.           (addwhat == -3 && !(hn->flags & DISABLED)) ||
  1406.           (addwhat == -4 && (PM_TYPE(pm->flags) == PM_SCALAR) &&
  1407.            (tt = pm->gets.cfn(pm)) && *tt == '/')    ||
  1408.           (addwhat == -9 && !(hn->flags & PM_UNSET)) ||
  1409.           (addwhat > 0 &&
  1410.            ((!(hn->flags & PM_UNSET) &&
  1411.          (((addwhat & CC_ARRAYS)    &&  (hn->flags & PM_ARRAY))    ||
  1412.           ((addwhat & CC_INTVARS)   &&  (hn->flags & PM_INTEGER))  ||
  1413.           ((addwhat & CC_ENVVARS)   &&  (hn->flags & PM_EXPORTED)) ||
  1414.           ((addwhat & CC_SCALARS)   &&  (hn->flags & PM_SCALAR))   ||
  1415.           ((addwhat & CC_READONLYS) &&  (hn->flags & PM_READONLY)) ||
  1416.           ((addwhat & CC_SPECIALS)  &&  (hn->flags & PM_SPECIAL))  ||
  1417.           ((addwhat & CC_PARAMS)    && !(hn->flags & PM_EXPORTED)))) ||
  1418.         ((( addwhat & CC_SHFUNCS)                  ||
  1419.           ( addwhat & CC_BUILTINS)                  ||
  1420.           ( addwhat & CC_EXTCMDS)                  ||
  1421.           ( addwhat & CC_RESWDS)                  ||
  1422.           ((addwhat & CC_ALREG)   && !(hn->flags & ALIAS_GLOBAL)) ||
  1423.           ((addwhat & CC_ALGLOB)  &&  (hn->flags & ALIAS_GLOBAL))) &&
  1424.          (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) ||
  1425.           ((addwhat & CC_EXCMDS)  && !(hn->flags & DISABLED))))))) {
  1426.     if (sl >= rpl + rsl) {
  1427.         if (cp)
  1428.         test = domatch(s, patcomp, 0);
  1429.         else {
  1430.         e = s + sl - rsl;
  1431.         if ((test = !strncmp(s, rpre, rpl)))
  1432.             test = !strcmp(e, rsuf);
  1433.         }
  1434.     }
  1435.     if (!test && sl < lpl + lsl)
  1436.         return;
  1437.     if (!test && lpre && lsuf && sl >= lpl + lsl) {
  1438.         e = s + sl - lsl;
  1439.         if ((test = !strncmp(s, lpre, lpl)))
  1440.         test = !strcmp(e, lsuf);
  1441.         pl = lpl;
  1442.     }
  1443.     if (addwhat == CC_QUOTEFLAG) {
  1444.         te = s + pl;
  1445.         s = quotename(s, &e, te, &pl);
  1446.         sl = strlen(s);
  1447.     }
  1448.     if (test)
  1449.         haswhat |= HAS_MISC;
  1450.     }
  1451.     if (!test)
  1452.     return;
  1453.  
  1454.     if (ispattern) {
  1455.     t = s;
  1456.     } else {
  1457.     t = s += pl;
  1458.     if (*e)
  1459.         t = s = dupstrpfx(t, e - t);
  1460.     }
  1461.  
  1462.     if (l == fmatches) {
  1463.     bp = &fab;
  1464.     ep = &fae;
  1465.     sp = &fshortl;
  1466.     fm = &ffirstm;
  1467.     } else {
  1468.     bp = &ab;
  1469.     ep = &ae;
  1470.     sp = &shortl;
  1471.     fm = &firstm;
  1472.     }
  1473.  
  1474.     if (!ispattern && *fm) {
  1475.     if ((test = pfxlen(*fm, s)) < *bp)
  1476.         *bp = test;
  1477.     if ((test = sfxlen(*fm, s)) < *ep)
  1478.         *ep = test;
  1479.     }
  1480.  
  1481.     /* If we are doing a glob completion we store the whole string in *
  1482.      * the list. Otherwise only the part that fits between the prefix *
  1483.      * and the suffix is stored.                                      */
  1484.     addlinknode(l, t);
  1485.     if (!*fm) {
  1486.     *bp = *ep = 10000;
  1487.     *fm = t;
  1488.     *sp = 100000;
  1489.     }
  1490.     if (!ispattern && (sl = strlen(t)) < *sp) {
  1491.     *sp = sl;
  1492.     if (l == fmatches)
  1493.         fshortest = t;
  1494.     else
  1495.         shortest = t;
  1496.     }
  1497. }
  1498.  
  1499. #ifdef HAVE_NIS_PLUS
  1500. static int
  1501. match_username(nis_name table, nis_object *object, void *userdata)
  1502. {
  1503.     if (errflag)
  1504.     return 1;
  1505.     else {
  1506.     static char buf[40];
  1507.     register entry_col *ec =
  1508.         object->zo_data.objdata_u.en_data.en_cols.en_cols_val;
  1509.     register int l = minimum(ec->ec_value.ec_value_len, 39);
  1510.  
  1511.     memcpy(buf, ec->ec_value.ec_value_val, l);
  1512.     buf[l] = '\0';
  1513.  
  1514.     addmatch(dupstring(buf), NULL);
  1515.     }
  1516.     return 0;
  1517. }
  1518. #else
  1519. # ifdef HAVE_NIS
  1520. static int
  1521. match_username(int status, char *key, int keylen, char *val, int vallen, dopestring *data)
  1522. {
  1523.     if (errflag || status != YP_TRUE)
  1524.     return 1;
  1525.  
  1526.     if (vallen > keylen && val[keylen] == ':') {
  1527.     val[keylen] = '\0';
  1528.     addmatch(dupstring(val), NULL);
  1529.     }
  1530.     return 0;
  1531. }
  1532. # endif /* HAVE_NIS */
  1533. #endif  /* HAVE_NIS_PLUS */
  1534.  
  1535. /**/
  1536. void
  1537. maketildelist(void)
  1538. {
  1539. #if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS)
  1540.     FILE *pwf;
  1541.     char buf[BUFSIZ], *p;
  1542.     int skipping;
  1543.  
  1544. # ifndef HAVE_NIS_PLUS
  1545.     char domain[YPMAXDOMAIN];
  1546.     struct ypall_callback cb;
  1547.     dopestring data;
  1548.  
  1549.     data.s = fpre;
  1550.     data.len = fpl;
  1551.     /* Get potential matches from NIS and cull those without local accounts */
  1552.     if (getdomainname(domain, YPMAXDOMAIN) == 0) {
  1553.     cb.foreach = (int (*)()) match_username;
  1554.     cb.data = (char *)&data;
  1555.     yp_all(domain, PASSWD_MAP, &cb);
  1556. /*    for (n = firstnode(matches); n; incnode(n))
  1557.         if (getpwnam(getdata(n)) == NULL)
  1558.         uremnode(matches, n);*/
  1559.     }
  1560. # else  /* HAVE_NIS_PLUS */
  1561.        /* Maybe we should turn this string into a #define'd constant...? */
  1562.  
  1563.     nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH,
  1564.          match_username, 0);
  1565. # endif
  1566.     /* Don't forget the non-NIS matches from the flat passwd file */
  1567.     if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) {
  1568.     skipping = 0;
  1569.     while (fgets(buf, BUFSIZ, pwf) != NULL) {
  1570.         if (strchr(buf, '\n') != NULL) {
  1571.         if (!skipping) {
  1572.             if ((p = strchr(buf, ':')) != NULL) {
  1573.             *p = '\0';
  1574.             addmatch(dupstring(buf), NULL);
  1575.             }
  1576.         } else
  1577.             skipping = 0;
  1578.         } else
  1579.         skipping = 1;
  1580.     }
  1581.     fclose(pwf);
  1582.     }
  1583. #else  /* no NIS or NIS_PLUS */
  1584.     /* add all the usernames to the named directory table */
  1585.     nameddirtab->filltable(nameddirtab);
  1586. #endif
  1587.  
  1588.     scanhashtable(nameddirtab, 0, (addwhat==-1) ? 0 : ND_USERNAME, 0,
  1589.         addhnmatch, 0);
  1590. }
  1591.  
  1592. /* Copy the given string and remove backslashes from the copy and return it. */
  1593.  
  1594. /**/
  1595. char *
  1596. rembslash(char *s)
  1597. {
  1598.     char *t = s = dupstring(s);
  1599.  
  1600.     while (*s)
  1601.     if (*s == '\\') {
  1602.         chuck(s);
  1603.         if (*s)
  1604.         s++;
  1605.     } else
  1606.         s++;
  1607.  
  1608.     return t;
  1609. }
  1610.  
  1611. /* This does the check for compctl -x `n' and `N' patterns. */
  1612.  
  1613. /**/
  1614. int
  1615. getcpat(char *wrd, int cpatindex, char *cpat, int class)
  1616. {
  1617.     char *str, *s, *t, *p;
  1618.     int d = 0;
  1619.  
  1620.     if (!wrd || !*wrd)
  1621.     return -1;
  1622.  
  1623.     cpat = rembslash(cpat);
  1624.  
  1625.     str = ztrdup(wrd);
  1626.     untokenize(str);
  1627.     if (!cpatindex)
  1628.     cpatindex++, d = 0;
  1629.     else if ((d = (cpatindex < 0)))
  1630.     cpatindex = -cpatindex;
  1631.  
  1632.     for (s = d ? str + strlen(str) - 1 : str;
  1633.      d ? (s >= str) : *s;
  1634.      d ? s-- : s++) {
  1635.     for (t = s, p = cpat; *t && *p; p++) {
  1636.         if (class) {
  1637.         if (*p == *s && !--cpatindex) {
  1638.             zsfree(str);
  1639.             return (int)(s - str + 1);
  1640.         }
  1641.         } else if (*t++ != *p)
  1642.         break;
  1643.     }
  1644.     if (!class && !*p && !--cpatindex) {
  1645.         zsfree(str);
  1646.         t += wrd - str;
  1647.         for (d = 0; --t >= wrd;)
  1648.         if (! INULL(*t))
  1649.             d++;
  1650.         return d;
  1651.     }
  1652.     }
  1653.     zsfree(str);
  1654.     return -1;
  1655. }
  1656.  
  1657. /* This holds a pointer to the compctl we are using. */
  1658.  
  1659. Compctl ccmain;
  1660.  
  1661.  
  1662. /* Find the compctl to use and return it.  The first argument gives a *
  1663.  * compctl to start searching with (if it is zero, the hash table is  *
  1664.  * searched).  compadd is used to return a number of characters that  *
  1665.  * should be ignored at the beginning of the word and incmd is        *
  1666.  * non-zero if we are in command position.                            */
  1667.  
  1668. /**/
  1669. Compctl
  1670. get_ccompctl(Compctl occ, int *compadd, int incmd)
  1671. {
  1672.     Compctl compc, ret;
  1673.     Compctlp ccp;
  1674.     int t, i, a, b, tt, ra, rb, j, isf = 1;
  1675.     Compcond or, cc;
  1676.     char *s, *ss, *sc, *cmd = dupstring(cmdstr);
  1677.     Comp comp;
  1678.  
  1679.    first_rec:
  1680.     *compadd = 0;
  1681.     ra = 0;
  1682.     rb = clwnum - 1;
  1683.     sc = NULL;
  1684.  
  1685.     if (!(ret = compc = occ)) {
  1686.       if (isf) {
  1687.         isf = 0;
  1688.         ret = &cc_first;
  1689.       }
  1690.       else if (inwhat == IN_ENV)
  1691.         /* Default completion for parameter values. */
  1692.         ret = &cc_default;
  1693.       else if (inwhat == IN_MATH) {
  1694.         /* Parameter names inside mathematical expression. */
  1695.         cc_dummy.mask = CC_PARAMS;
  1696.         ret = &cc_dummy;
  1697.         cc_dummy.refc = 10000;
  1698.     } else if (inwhat == IN_COND) {
  1699.         /* We try to be clever here: in conditions we complete option   *
  1700.          * names after a `-o', file names after `-nt', `-ot', and `-ef' *
  1701.          * and file names and parameter names elsewhere.                */
  1702.         s = clwpos ? clwords[clwpos - 1] : "";
  1703.         cc_dummy.mask = !strcmp("-o", s) ? CC_OPTIONS :
  1704.         ((*s == '-' && s[1] && !s[2]) ||
  1705.          !strcmp("-nt", s) ||
  1706.          !strcmp("-ot", s) ||
  1707.          !strcmp("-ef", s)) ? CC_FILES :
  1708.         (CC_FILES | CC_PARAMS);
  1709.         ret = &cc_dummy;
  1710.         cc_dummy.refc = 10000;
  1711.     } else if (incmd)
  1712.         ret = &cc_compos;
  1713.     /* And in redirections or if there is no command name (and we are *
  1714.      * not in command position) or if no special compctl was given    *
  1715.      * for the command: use default completion.  Note that we first   *
  1716.      * search the complete command name and than the trailing         *
  1717.      * pathname component.                                            */
  1718.     else if (linredir ||
  1719.           !(cmd &&
  1720.             (((ccp = (Compctlp) compctltab->getnode(compctltab, cmd)) &&
  1721.              (compc = ret = ccp->cc)) ||
  1722.              ((s = dupstring(cmd)) && remlpaths(&s) &&
  1723.              (ccp = (Compctlp) compctltab->getnode(compctltab, s)) &&
  1724.              (compc = ret = ccp->cc)))))
  1725.         ret = &cc_default;
  1726.  
  1727.     ccmain = compc = ret;
  1728.     ccmain->refc++;
  1729.     }
  1730.     /* The compctl we found has extended completion patterns, check them. */
  1731.     if (compc && compc->ext) {
  1732.     compc = compc->ext;
  1733.     /* This loops over the patterns separated by `--'. */
  1734.     for (t = 0; compc && !t; compc = compc->next) {
  1735.         /* This loops over OR'ed patterns. */
  1736.         for (cc = compc->cond; cc && !t; cc = or) {
  1737.         or = cc->or;
  1738.         /* This loops over AND'ed patterns. */
  1739.         for (t = 1; cc && t; cc = cc->and) {
  1740.             /* And this loops of [...] pairs. */
  1741.             for (t = i = 0; i < cc->n && !t; i++) {
  1742.             s = NULL;
  1743.             ra = 0;
  1744.             rb = clwnum - 1;
  1745.             switch (cc->type) {
  1746.             case CCT_POS:
  1747.                 tt = clwpos;
  1748.                 goto cct_num;
  1749.             case CCT_NUMWORDS:
  1750.                 tt = clwnum;
  1751.               cct_num:
  1752.                 if ((a = cc->u.r.a[i]) < 0)
  1753.                 a += clwnum;
  1754.                 if ((b = cc->u.r.b[i]) < 0)
  1755.                 b += clwnum;
  1756.                 if (cc->type == CCT_POS)
  1757.                 ra = a, rb = b;
  1758.                 t = (tt >= a && tt <= b);
  1759.                 break;
  1760.             case CCT_CURSUF:
  1761.             case CCT_CURPRE:
  1762.                 s = ztrdup(clwpos < clwnum ? clwords[clwpos] : "");
  1763.                 untokenize(s);
  1764.                 sc = rembslash(cc->u.s.s[i]);
  1765.                 a = strlen(sc);
  1766.                 if (!strncmp(s, sc, a)) {
  1767.                 *compadd = (cc->type == CCT_CURSUF ? a : 0);
  1768.                 t = 1;
  1769.                 }
  1770.                 break;
  1771.             case CCT_CURSUB:
  1772.             case CCT_CURSUBC:
  1773.                 if (clwpos < 0 || clwpos > clwnum)
  1774.                 t = 0;
  1775.                 else {
  1776.                 a = getcpat(clwords[clwpos],
  1777.                         cc->u.s.p[i],
  1778.                         cc->u.s.s[i],
  1779.                         cc->type == CCT_CURSUBC);
  1780.                 if (a != -1)
  1781.                     *compadd = a, t = 1;
  1782.                 }
  1783.                 break;
  1784.  
  1785.             case CCT_CURPAT:
  1786.             case CCT_CURSTR:
  1787.                 tt = clwpos;
  1788.                 goto cct_str;
  1789.             case CCT_WORDPAT:
  1790.             case CCT_WORDSTR:
  1791.                 tt = 0;
  1792.               cct_str:
  1793.                 if ((a = tt + cc->u.s.p[i]) < 0)
  1794.                 a += clwnum;
  1795.                 s = ztrdup((a < 0 || a >= clwnum) ? "" :
  1796.                        clwords[a]);
  1797.                 untokenize(s);
  1798.  
  1799.                 if (cc->type == CCT_CURPAT ||
  1800.                 cc->type == CCT_WORDPAT) {
  1801.                 tokenize(ss = dupstring(cc->u.s.s[i]));
  1802.                 t = ((comp = parsereg(ss)) &&
  1803.                      domatch(s, comp, 0));
  1804.                 } else
  1805.                 t = (!strcmp(s, rembslash(cc->u.s.s[i])));
  1806.                 break;
  1807.             case CCT_RANGESTR:
  1808.             case CCT_RANGEPAT:
  1809.                 if (cc->type == CCT_RANGEPAT)
  1810.                 tokenize(sc = dupstring(cc->u.l.a[i]));
  1811.                 for (j = clwpos; j; j--) {
  1812.                 untokenize(s = ztrdup(clwords[j]));
  1813.                 if (cc->type == CCT_RANGESTR)
  1814.                     sc = rembslash(cc->u.l.a[i]);
  1815.                 if (cc->type == CCT_RANGESTR ?
  1816.                     !strncmp(s, sc, strlen(sc)) :
  1817.                     ((comp = parsereg(sc)) &&
  1818.                      domatch(s, comp, 0))) {
  1819.                     zsfree(s);
  1820.                     ra = j + 1;
  1821.                     t = 1;
  1822.                     break;
  1823.                 }
  1824.                 zsfree(s);
  1825.                 }
  1826.                 if (t) {
  1827.                 if (cc->type == CCT_RANGEPAT)
  1828.                     tokenize(sc = dupstring(cc->u.l.b[i]));
  1829.                 for (j++; j < clwnum; j++) {
  1830.                     untokenize(s = ztrdup(clwords[j]));
  1831.                     if (cc->type == CCT_RANGESTR)
  1832.                     sc = rembslash(cc->u.l.b[i]);
  1833.                     if (cc->type == CCT_RANGESTR ?
  1834.                     !strncmp(s, sc, strlen(sc)) :
  1835.                     ((comp = parsereg(sc)) &&
  1836.                      domatch(s, comp, 0))) {
  1837.                     zsfree(s);
  1838.                     rb = j - 1;
  1839.                     t = clwpos <= rb;
  1840.                     break;
  1841.                     }
  1842.                     zsfree(s);
  1843.                 }
  1844.                 }
  1845.                 s = NULL;
  1846.             }
  1847.             zsfree(s);
  1848.             }
  1849.         }
  1850.         }
  1851.         if (t)
  1852.         break;
  1853.     }
  1854.     if (compc)
  1855.         /* We found a matching pattern, we may return it. */
  1856.         ret = compc;
  1857.     }
  1858.     if (ret->subcmd) {
  1859.     /* The thing we want to return has a subcmd flag (-l). */
  1860.     char **ow = clwords, *os = cmdstr, *ops = NULL;
  1861.     int oldn = clwnum, oldp = clwpos;
  1862.  
  1863.     /* So we restrict the words-array. */
  1864.     if (ra >= clwnum)
  1865.         ra = clwnum - 1;
  1866.     if (ra < 1)
  1867.         ra = 1;
  1868.     if (rb >= clwnum)
  1869.         rb = clwnum - 1;
  1870.     if (rb < 1)
  1871.         rb = 1;
  1872.     clwnum = rb - ra + 1;
  1873.     clwpos = clwpos - ra;
  1874.  
  1875.     if (ret->subcmd[0]) {
  1876.         /* And probably put the command name given to the flag *
  1877.          * in the array.                                       */
  1878.         clwpos++;
  1879.         clwnum++;
  1880.         incmd = 0;
  1881.         ops = clwords[ra - 1];
  1882.         clwords[ra - 1] = cmdstr = ret->subcmd;
  1883.         clwords += ra - 1;
  1884.     } else {
  1885.         cmdstr = clwords[ra];
  1886.         incmd = !clwpos;
  1887.         clwords += ra;
  1888.     }
  1889.     *compadd = 0;
  1890.     if (ccmain != &cc_dummy)
  1891.         freecompctl(ccmain);
  1892.     /* Then we call this function recursively. */
  1893.  
  1894.     ret = get_ccompctl(NULL, compadd, incmd);
  1895.     /* And restore the things we changed. */
  1896.     clwords = ow;
  1897.     cmdstr = os;
  1898.     clwnum = oldn;
  1899.     clwpos = oldp;
  1900.     if (ops)
  1901.         clwords[ra - 1] = ops;
  1902.     }
  1903.     if (ret == &cc_first)
  1904.       goto first_rec;
  1905.     return ret;
  1906. }
  1907.  
  1908. /* Dump a hash table (without sorting).  For each element the addmatch  *
  1909.  * function is called and at the beginning the addwhat variable is set. *
  1910.  * This could be done using scanhashtable(), but this is easy and much  *
  1911.  * more efficient.                                                      */
  1912.  
  1913. /**/
  1914. void
  1915. dumphashtable(HashTable ht, int what)
  1916. {
  1917.     HashNode hn;
  1918.     int i;
  1919.  
  1920.     addwhat = what;
  1921.  
  1922.     for (i = 0; i < ht->hsize; i++)
  1923.     for (hn = ht->nodes[i]; hn; hn = hn->next)
  1924.         addmatch(hn->nam, (char *) hn);
  1925.  
  1926. }
  1927.  
  1928. /* ScanFunc used by maketildelist() et al. */
  1929.  
  1930. /**/
  1931. void
  1932. addhnmatch(HashNode hn, int flags)
  1933. {
  1934.     addmatch(hn->nam, NULL);
  1935. }
  1936.  
  1937. /* Perform expansion on the given string and return the result. *
  1938.  * During this errors are not reported.                         */
  1939.  
  1940. /**/
  1941. char *
  1942. getreal(char *str)
  1943. {
  1944.     LinkList l = newlinklist();
  1945.     int ne = noerrs;
  1946.  
  1947.     noerrs = 1;
  1948.     addlinknode(l, dupstring(str));
  1949.     prefork(l, 0);
  1950.     noerrs = ne;
  1951.     if (!errflag && nonempty(l))
  1952.     return ztrdup(peekfirst(l));
  1953.     errflag = 0;
  1954.  
  1955.     return ztrdup(str);
  1956. }
  1957.  
  1958. /* This reads a directory and adds the files to the list of  *
  1959.  * matches.  The parameters say which files should be added. */
  1960.  
  1961. /**/
  1962. void
  1963. gen_matches_files(int dirs, int execs, int all)
  1964. {
  1965.     DIR *d;
  1966.     struct stat buf;
  1967.     char *n, p[PATH_MAX], *q = NULL, *e;
  1968.     LinkList l = NULL;
  1969.     int ns = 0, ng = opts[NULLGLOB], test, aw = addwhat;
  1970.  
  1971.     addwhat = execs ? -8 : -5;
  1972.     opts[NULLGLOB] = 1;
  1973.  
  1974.     if (*psuf) {
  1975.     /* If there is a path suffix, check if it doesn't have a `*' or *
  1976.      * `)' at the end (this is used to determine if we should use   *
  1977.      * globbing).                                                   */
  1978.     q = psuf + strlen(psuf) - 1;
  1979.     ns = !(*q == Star || *q == Outpar);
  1980.     l = newlinklist();
  1981.     /* And generate only directory names. */
  1982.     dirs = 1;
  1983.     all = execs = 0;
  1984.     }
  1985.     /* Open directory. */
  1986.     if ((d = opendir((prpre && *prpre) ? prpre : "."))) {
  1987.     /* If we search only special files, prepare a path buffer for stat. */
  1988.     if (!all && prpre) {
  1989.         strcpy(p, prpre);
  1990.         q = p + strlen(prpre);
  1991.     }
  1992.     /* Fine, now read the directory. */
  1993.     while ((n = zreaddir(d)) && !errflag) {
  1994.         /* Ignore `.' and `..'. */
  1995.         if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
  1996.         continue;
  1997.         /* Ignore files beginning with `.' unless the thing we found on *
  1998.          * the command line also starts with a dot or GLOBDOTS is set.  */
  1999.         if (*n != '.' || *fpre == '.' || isset(GLOBDOTS)) {
  2000.         if (filecomp)
  2001.             /* If we have a pattern for the filename check, use it. */
  2002.             test = domatch(n, filecomp, 0);
  2003.         else {
  2004.             /* Otherwise use the prefix and suffix strings directly. */
  2005.             e = n + strlen(n) - fsl;
  2006.             if ((test = !strncmp(n, fpre, fpl)))
  2007.             test = !strcmp(e, fsuf);
  2008.         }
  2009.         /* Filename didn't match? */
  2010.         if (!test)
  2011.             continue;
  2012.         if (!all) {
  2013.             /* We still have to check the file type, so prepare *
  2014.              * the path buffer by appending the filename.       */
  2015.             strcpy(q, n);
  2016.             /* And do the stat. */
  2017.             if (stat(p, &buf) < 0)
  2018.             continue;
  2019.         }
  2020.         if (all ||
  2021.             (dirs && (buf.st_mode & S_IFMT) == S_IFDIR) ||
  2022.             (execs && ((buf.st_mode & (S_IFMT | S_IEXEC))
  2023.               == (S_IFREG | S_IEXEC)))) {
  2024.             /* If we want all files or the file has the right type... */
  2025.             if (*psuf) {
  2026.             /* We have to test for a path suffix. */
  2027.             int o = strlen(p), tt;
  2028.  
  2029.             /* Append it to the path buffer. */
  2030.             strcpy(p + o, psuf);
  2031.  
  2032.             /* Do we have to use globbing? */
  2033.             if (ispattern || (ns && isset(GLOBCOMPLETE))) {
  2034.                 /* Yes, so append a `*' if needed. */
  2035.                 if (ns) {
  2036.                 int tl = strlen(p);
  2037.  
  2038.                 p[tl] = Star;
  2039.                 p[tl + 1] = '\0';
  2040.                 }
  2041.                 /* Do the globbing... */
  2042.                 remnulargs(p);
  2043.                 addlinknode(l, p);
  2044.                 globlist(l);
  2045.                 /* And see if that produced a filename. */
  2046.                 tt = nonempty(l);
  2047.                 while (ugetnode(l));
  2048.             } else
  2049.                 /* Otherwise just check, if we have access *
  2050.                  * to the file.                            */
  2051.                 tt = !access(p, F_OK);
  2052.  
  2053.             p[o] = '\0';
  2054.             if (tt)
  2055.                 /* Ok, we can add the filename to the *
  2056.                  * list of matches.                   */
  2057.                 addmatch(dupstring(n), NULL);
  2058.             } else
  2059.             /* We want all files, so just add the name *
  2060.              * to the matches.                         */
  2061.             addmatch(dupstring(n), NULL);
  2062.         }
  2063.         }
  2064.     }
  2065.     closedir(d);
  2066.     }
  2067.     opts[NULLGLOB] = ng;
  2068.     addwhat = aw;
  2069. }
  2070.  
  2071. /* This holds the explanation string we have to print. */
  2072.  
  2073. char *expl;
  2074.  
  2075. /* This holds the suffix to add (given with compctl -S). */
  2076.  
  2077. char *ccsuffix;
  2078.  
  2079. /* This s non-zero if the compctl -q flag was given (the suffix should *
  2080.  * be removed when a space or something like that is typed next).      */
  2081.  
  2082. int remsuffix;
  2083.  
  2084. /**/
  2085. void
  2086. quotepresuf(char **ps)
  2087. {
  2088.     if (*ps) {
  2089.     char *p = quotename(*ps, NULL, NULL, NULL);
  2090.  
  2091.     if (p != *ps) {
  2092.         zsfree(*ps);
  2093.         *ps = ztrdup(p);
  2094.     }
  2095.     }
  2096. }
  2097.  
  2098. /* This is non-zero if the cursor was moved up after showing a list *
  2099.  * of completions (with alwayslastprompt).                          */
  2100.  
  2101. int clearflag;
  2102.  
  2103. /**/
  2104. void
  2105. docompletion(char *s, int lst, int incmd, int untokenized)
  2106. {
  2107.     static int delit, compadd;
  2108.  
  2109.     HEAPALLOC {
  2110.     pushheap();
  2111.  
  2112.     /* Make sure we have the completion list and compctl. */
  2113.     if(makecomplist(s, incmd, &delit, &compadd, untokenized)) {
  2114.         /* Error condition: feeeeeeeeeeeeep(). */
  2115.         feep();
  2116.         goto compend;
  2117.     }
  2118.  
  2119.     if (lst == COMP_LIST_COMPLETE)
  2120.         /* All this and the guy only wants to see the list, sigh. */
  2121.         showinglist = -2;
  2122.     else {
  2123.         /* We have matches. */
  2124.         if (delit) {
  2125.         /* If we have to delete the word from the command line, *
  2126.          * do it now.                                           */
  2127.         wb -= compadd;
  2128.         strcpy((char *)line + wb, (char *)line + we);
  2129.         we = cs = wb;
  2130.         }
  2131.         if (nmatches > 1)
  2132.         /* There are more than one match. */
  2133.         do_ambiguous();
  2134.         else if (nmatches == 1) {
  2135.         /* Only one match. */
  2136.         do_single(amatches[0]);
  2137.         invalidatelist();
  2138.         }
  2139.     }
  2140.  
  2141.     /* Print the explanation string if needed. */
  2142.     if (!showinglist && expl && nmatches != 1) {
  2143.         int up;
  2144.  
  2145.         if (!nmatches)
  2146.         feep();
  2147.         trashzle();
  2148.  
  2149.         clearflag = (isset(USEZLE) && !termflags &&
  2150.              (isset(ALWAYSLASTPROMPT) && !gotmult)) ||
  2151.             (unset(ALWAYSLASTPROMPT) && gotmult);
  2152.  
  2153.         up = printfmt(expl, nmatches, 1);
  2154.  
  2155.         if (clearflag)
  2156.         tcmultout(TCUP, TCMULTUP, up + nlnct);
  2157.         else
  2158.         putc('\n', shout);
  2159.         fflush(shout);
  2160.     }
  2161.       compend:
  2162.     ll = strlen((char *)line);
  2163.     if (cs > ll)
  2164.         cs = ll;
  2165.     popheap();
  2166.     } LASTALLOC;
  2167. }
  2168.  
  2169. /* Create the completion list.  This is called whenever some bit of  *
  2170.  * completion code needs the list.  If the list is already available *
  2171.  * (validlist!=0), this function doesn't do anything.  Along with    *
  2172.  * the list is maintained the prefixes/suffixes etc.  When any of    *
  2173.  * this becomes invalid -- e.g. if some text is changed on the       *
  2174.  * command line -- invalidatelist() should be called, to set         *
  2175.  * validlist to zero and free up the memory used.  This function     *
  2176.  * returns non-zero on error.  delit and compadd return information  *
  2177.  * about bits of the command line that need to be deleted.           */
  2178.  
  2179. /**/
  2180. int
  2181. makecomplist(char *s, int incmd, int *delit, int *compadd, int untokenized)
  2182. {
  2183.     Compctl cc = NULL;
  2184.     int oloffs = offs, owe = we, owb = wb, ocs = cs, oll = ll, isf = 1;
  2185.     int t, sf1, sf2, ooffs;
  2186.     char *p, *sd = NULL, *tt, *s1, *s2, *os = NULL;
  2187.     unsigned char *ol = NULL;
  2188.  
  2189.     /* If we already have a list from a previous execution of this *
  2190.      * function, skip the list building code.                      */
  2191.     if (validlist)
  2192.     return !nmatches;
  2193.  
  2194.     os = dupstring(s);
  2195.     ol = (unsigned char *)dupstring((char *)line);
  2196.  
  2197.   xorrec:
  2198.  
  2199.     DPUTS(ll != strlen((char *) line), "BUG: xorrec: ll != strlen(line)");
  2200.  
  2201.     /* Go to the end of the word if complete_in_word is not set. */
  2202.     if (unset(COMPLETEINWORD) && cs != we)
  2203.     cs = we, offs = strlen(s);
  2204.  
  2205.     ispattern = haswhat = lastambig = 0;
  2206.     patcomp = filecomp = NULL;
  2207.     menucur = NULL;
  2208.     shortest = NULL;
  2209.     fshortest = NULL;
  2210.     rpre = rsuf = lpre = lsuf = ppre = psuf = prpre =
  2211.     fpre = fsuf = firstm = ffirstm = parampre = qparampre = NULL;
  2212.  
  2213.     /* Blank out the lists. */
  2214.     matches = newlinklist();
  2215.     fmatches = newlinklist();
  2216.  
  2217.     /* If we don't have a compctl definition yet or we have a compctl *
  2218.      * with extended completion, get it (or the next one, resp.).     */
  2219.     if (!cc || cc->ext)
  2220.     cc = get_ccompctl(cc, compadd, incmd);
  2221.  
  2222.     /* *compadd is the number of characters we have to ignore at the *
  2223.      * beginning of the word.                                        */
  2224.     wb += *compadd;
  2225.     s += *compadd;
  2226.     if ((offs -= *compadd) < 0)
  2227.     /* It's bigger than our word prefix, so we can't help here... */
  2228.     return 1;
  2229.  
  2230.     /* Insert the prefix (compctl -P), if any. */
  2231.     if (cc->prefix) {
  2232.     int pl = 0, sl = strlen(cc->prefix);
  2233.  
  2234.     if (*s) {
  2235.         /* First find out how much of the prefix is already on the line. */
  2236.         sd = dupstring(s);
  2237.         untokenize(sd);
  2238.         pl = pfxlen(cc->prefix, sd);
  2239.         s += pl;
  2240.     }
  2241.     if (pl < sl) {
  2242.         int savecs = cs;
  2243.  
  2244.         /* Then insert the prefix. */
  2245.         cs = wb + pl;
  2246.         inststrlen(cc->prefix + pl, 0, sl - pl);
  2247.         cs = savecs + sl - pl;
  2248.     }
  2249.     /* And adjust the word beginning/end variables. */
  2250.     wb += sl;
  2251.     we += sl - pl;
  2252.     offs -= pl;
  2253.     }
  2254.     /* Does this compctl have a suffix (compctl -S)? */
  2255.     if ((ccsuffix = cc->suffix) && *ccsuffix) {
  2256.     char *sdup = dupstring(ccsuffix);
  2257.     int sl = strlen(sdup), suffixll;
  2258.  
  2259.     /* Ignore trailing spaces. */
  2260.     for (p = sdup + sl - 1; p >= sdup && *p == ' '; p--, sl--);
  2261.     p[1] = '\0';
  2262.  
  2263.     if (!sd) {
  2264.         sd = dupstring(s);
  2265.         untokenize(sd);
  2266.     }
  2267.     /* If the suffix is already there, ignore it (and don't add *
  2268.      * it again).                                               */
  2269.     if (*sd && (suffixll = strlen(sd)) >= sl &&
  2270.         offs <= suffixll - sl && !strcmp(sdup, sd + suffixll - sl)) {
  2271.         ccsuffix = NULL;
  2272.         haswhat |= HAS_SUFFIX;
  2273.         s[suffixll - sl] = '\0';
  2274.     }
  2275.     }
  2276.     /* Do we have one of the special characters `~' and `=' at the beginning? */
  2277.     if ((ic = *s) != Tilde && ic != Equals)
  2278.     ic = 0;
  2279.  
  2280.     /* Check if we have to complete a parameter name... */
  2281.  
  2282.     complexpect = menuce = 0;
  2283.  
  2284.     /* Try to find a `$'. */
  2285.     for (p = s + offs; p > s && *p != String; p--);
  2286.     if (*p == String) {
  2287.     /* Handle $$'s */
  2288.     while (p > s && p[-1] == String)
  2289.         p--;
  2290.     while (p[1] == String && p[2] == String)
  2291.         p += 2;
  2292.     }
  2293.     if (*p == String &&    p[1] != Inpar && p[1] != Inbrack) {
  2294.     /* This is really a parameter expression (not $(...) or $[...]). */
  2295.     char *b = p + 1, *e = b;
  2296.     int n = 0, br = 1;
  2297.  
  2298.     if (*b == Inbrace) {
  2299.         /* If this is a ${...}, ignore the possible (...) flags. */
  2300.         b++, br++;
  2301.         n = skipparens(Inpar, Outpar, &b);
  2302.     }
  2303.  
  2304.     /* Ignore the stuff before the parameter name. */
  2305.     for (; *b; b++)
  2306.         if (*b != '^' && *b != Hat &&
  2307.         *b != '=' && *b != Equals &&
  2308.         *b != '~' && *b != Tilde)
  2309.         break;
  2310.     if (*b == '#' || *b == Pound || *b == '+')
  2311.         b++;
  2312.  
  2313.     e = b;
  2314.     /* Find the end of the name. */
  2315.     if (*e == Quest || *e == Star || *e == String || *e == Qstring ||
  2316.         *e == '?'   || *e == '*'  || *e == '$'    ||
  2317.         *e == '-'   || *e == '!'  || *e == '@')
  2318.         e++;
  2319.     else if (idigit(*e))
  2320.         while (idigit(*e))
  2321.         e++;
  2322.     else if (iident(*e))
  2323.         while (iident(*e) ||
  2324.            (useglob && (*e == Star || *e == Quest)))
  2325.         e++;
  2326.  
  2327.     /* Now make sure that the cursor is inside the name. */
  2328.     if (offs <= e - s && offs >= b - s && n <= 0) {
  2329.         /* It is, set complexpect. */
  2330.         if (offs == e - s)
  2331.         complexpect = br;
  2332.         /* Get the prefix (anything up to the character before the name). */
  2333.         *e = '\0';
  2334.         parampre = ztrduppfx(s, b - s);
  2335.         qparampre = ztrdup(quotename(parampre, NULL, NULL, NULL));
  2336.         untokenize(qparampre);
  2337.         qparprelen = strlen(qparampre);
  2338.         /* And adjust wb, we, and offs again. */
  2339.         offs -= b - s;
  2340.         wb = cs - offs;
  2341.         we = wb + e - b;
  2342.         s = b;
  2343.         /* And now make sure that we complete parameter names. */
  2344.         cc = ccmain = &cc_dummy;
  2345.         cc_dummy.refc = 10000;
  2346.         cc_dummy.mask = CC_PARAMS | CC_ENVVARS;
  2347.     } else
  2348.         complexpect = 0;
  2349.     }
  2350.     ooffs = offs;
  2351.     /* If we have to ignore the word, do that. */
  2352.     if (cc->mask & CC_DELETE) {
  2353.     *delit = 1;
  2354.     *s = '\0';
  2355.     offs = 0;
  2356.     } else
  2357.     *delit = 0;
  2358.  
  2359.     /* Compute line prefix/suffix. */
  2360.  
  2361.     lpl = offs;
  2362.     lpre = zalloc(lpl + 1);
  2363.     memcpy(lpre, s, lpl);
  2364.     lpre[lpl] = '\0';
  2365.     p = quotename(lpre, NULL, NULL, NULL);
  2366.     if (strcmp(p, lpre) && !strpfx(p, qword)) {
  2367.     int l1, l2;
  2368.  
  2369.     backdel(l1 = cs - wb);
  2370.     untokenize(p);
  2371.     inststrlen(p, 1, l2 = strlen(p));
  2372.     we += l2 - l1;
  2373.     }
  2374.     lsuf = ztrdup(s + offs);
  2375.     lsl = strlen(lsuf);
  2376.     if (lsl && (p = quotename(lsuf, NULL, NULL, NULL)) &&
  2377.     (strcmp(p, lsuf) && !strsfx(p, qword))) {
  2378.     int l1, l2;
  2379.  
  2380.     foredel(l1 = strlen(s + offs));
  2381.     untokenize(p);
  2382.     inststrlen(p, 0, l2 = strlen(p));
  2383.     we += l2 - l1;
  2384.     }
  2385.  
  2386.     /* First check for ~.../... */
  2387.     if (ic == Tilde) {
  2388.     for (p = lpre + lpl; p > lpre; p--)
  2389.         if (*p == '/')
  2390.         break;
  2391.  
  2392.     if (*p == '/')
  2393.         ic = 0;
  2394.     }
  2395.     /* Compute real prefix/suffix. */
  2396.  
  2397.     noreal = !*delit;
  2398.     for (p = lpre; *p && *p != String && *p != Tick; p++);
  2399.     tt = ic && !parampre ? lpre + 1 : lpre;
  2400.     rpre = (*p || *lpre == Tilde || *lpre == Equals) ?
  2401.     (noreal = 0, getreal(tt)) :
  2402.     ztrdup(tt);
  2403.  
  2404.     for (p = lsuf; *p && *p != String && *p != Tick; p++);
  2405.     rsuf = *p ? (noreal = 0, getreal(lsuf)) : ztrdup(lsuf);
  2406.  
  2407.     /* Check if word is a pattern. */
  2408.  
  2409.     for (s1 = NULL, sf1 = 0, p = rpre + (rpl = strlen(rpre)) - 1;
  2410.      p >= rpre && (ispattern != 3 || !sf1);
  2411.      p--)
  2412.     if (itok(*p) && (p > rpre || (*p != Equals && *p != Tilde)))
  2413.         ispattern |= sf1 ? 1 : 2;
  2414.     else if (*p == '/') {
  2415.         sf1++;
  2416.         if (!s1)
  2417.         s1 = p;
  2418.     }
  2419.     for (s2 = NULL, sf2 = t = 0, p = rsuf; *p && (!t || !sf2); p++)
  2420.     if (itok(*p))
  2421.         t |= sf2 ? 4 : 2;
  2422.     else if (*p == '/') {
  2423.         sf2++;
  2424.         if (!s2)
  2425.         s2 = p;
  2426.     }
  2427.     ispattern = ispattern | t;
  2428.  
  2429.     /* But if we were asked not to do glob completion, we never treat the *
  2430.      * thing as a pattern.                                                */
  2431.     if (!useglob)
  2432.     ispattern = 0;
  2433.  
  2434.     if (ispattern) {
  2435.     /* The word should be treated as a pattern, so compute the matcher. */
  2436.     p = (char *)ncalloc(rpl + rsl + 2);
  2437.     strcpy(p, rpre);
  2438.     if (rpl && p[rpl - 1] != Star) {
  2439.         p[rpl] = Star;
  2440.         strcpy(p + rpl + 1, rsuf);
  2441.     } else
  2442.         strcpy(p + rpl, rsuf);
  2443.     patcomp = parsereg(p);
  2444.     }
  2445.     if (!patcomp) {
  2446.     untokenize(rpre);
  2447.     untokenize(rsuf);
  2448.  
  2449.     rpl = strlen(rpre);
  2450.     rsl = strlen(rsuf);
  2451.     }
  2452.     untokenize(lpre);
  2453.     untokenize(lsuf);
  2454.  
  2455.     /* Handle completion of files specially (of course). */
  2456.  
  2457.     if ((cc->mask & (CC_FILES | CC_COMMPATH)) || cc->glob) {
  2458.     /* s1 and s2 point to the last/first slash in the prefix/suffix. */
  2459.     if (!s1)
  2460.         s1 = rpre;
  2461.     if (!s2)
  2462.         s2 = rsuf + rsl;
  2463.  
  2464.     /* Compute the path prefix/suffix. */
  2465.     if (*s1 != '/')
  2466.         ppre = ztrdup("");
  2467.     else
  2468.         ppre = ztrduppfx(rpre, s1 - rpre + 1);
  2469.     psuf = ztrdup(s2);
  2470.  
  2471.     /* And get the file prefix. */
  2472.     fpre = ztrdup(((s1 == s || s1 == rpre || ic) &&
  2473.                (*s != '/' || cs == wb)) ? s1 : s1 + 1);
  2474.     /* And the suffix. */
  2475.     fsuf = ztrduppfx(rsuf, s2 - rsuf);
  2476.  
  2477.     if (useglob && (ispattern & 2)) {
  2478.         int t2;
  2479.  
  2480.         /* We have to use globbing, so compute the pattern from *
  2481.          * the file prefix and suffix with a `*' between them.  */
  2482.         p = (char *)ncalloc((t2 = strlen(fpre)) + strlen(fsuf) + 2);
  2483.         strcpy(p, fpre);
  2484.         if ((!t2 || p[t2 - 1] != Star) && *fsuf != Star)
  2485.         p[t2++] = Star;
  2486.         strcpy(p + t2, fsuf);
  2487.         filecomp = parsereg(p);
  2488.     }
  2489.     if (!filecomp) {
  2490.         untokenize(fpre);
  2491.         untokenize(fsuf);
  2492.  
  2493.         fpl = strlen(fpre);
  2494.         fsl = strlen(fsuf);
  2495.     }
  2496.     addwhat = -1;
  2497.  
  2498.     /* Completion after `~', maketildelist adds the usernames *
  2499.      * and named directories.                                 */
  2500.     if (ic == Tilde)
  2501.         maketildelist();
  2502.     else if (ic == Equals) {
  2503.         /* Completion after `=', get the command names from *
  2504.          * the cmdnamtab and aliases from aliastab.         */
  2505.         if (isset(HASHLISTALL))
  2506.         cmdnamtab->filltable(cmdnamtab);
  2507.         dumphashtable(cmdnamtab, -7);
  2508.         dumphashtable(aliastab, -2);
  2509.     } else {
  2510.         /* Normal file completion... */
  2511.         if (ispattern & 1) {
  2512.         /* But with pattern matching. */
  2513.         LinkList l = newlinklist();
  2514.         LinkNode n;
  2515.         int ng = opts[NULLGLOB];
  2516.  
  2517.         opts[NULLGLOB] = 1;
  2518.  
  2519.         addwhat = 0;
  2520.         p = (char *)ncalloc(lpl + lsl + 3);
  2521.         strcpy(p, lpre);
  2522.         if (*lsuf != '*' && *lpre && lpre[lpl - 1] != '*')
  2523.             strcat(p, "*");
  2524.         strcat(p, lsuf);
  2525.         if (*lsuf && lsuf[lsl - 1] != '*' && lsuf[lsl - 1] != ')')
  2526.             strcat(p, "*");
  2527.  
  2528.         /* Do the globbing. */
  2529.         tokenize(p);
  2530.         remnulargs(p);
  2531.         addlinknode(l, p);
  2532.         globlist(l);
  2533.  
  2534.         if (nonempty(l)) {
  2535.             /* And add the resulting words. */
  2536.             haswhat |= HAS_PATHPAT;
  2537.             for (n = firstnode(l); n; incnode(n))
  2538.             addmatch(getdata(n), NULL);
  2539.         }
  2540.         opts[NULLGLOB] = ng;
  2541.         } else {
  2542.         /* No pattern matching. */
  2543.         addwhat = CC_FILES;
  2544.         prpre = ztrdup(ppre);
  2545.  
  2546.         if (sf2)
  2547.             /* We are in the path, so add only directories. */
  2548.             gen_matches_files(1, 0, 0);
  2549.         else {
  2550.             if (cc->mask & CC_FILES)
  2551.             /* Add all files. */
  2552.             gen_matches_files(0, 0, 1);
  2553.             else if (cc->mask & CC_COMMPATH) {
  2554.             /* Completion of command paths. */
  2555.             if (sf1)
  2556.                 /* There is a path prefix, so add *
  2557.                  * directories and executables.   */
  2558.                 gen_matches_files(1, 1, 0);
  2559.             else {
  2560.                 /* No path prefix, so add the things *
  2561.                  * reachable via the PATH variable.  */
  2562.                 char **pc = path, *pp = prpre;
  2563.  
  2564.                 for (; *pc; pc++)
  2565.                 if (!**pc || (pc[0][0] == '.' && !pc[0][1]))
  2566.                     break;
  2567.                 if (*pc) {
  2568.                 prpre = "./";
  2569.                 gen_matches_files(1, 1, 0);
  2570.                 prpre = pp;
  2571.                 }
  2572.             }
  2573.             }
  2574.             /* The compctl has a glob pattern (compctl -g). */
  2575.             if (cc->glob) {
  2576.             int ns, pl = strlen(prpre), o;
  2577.             char *g = dupstring(cc->glob), pa[PATH_MAX];
  2578.             char *p2, *p3;
  2579.             int ne = noerrs, md = opts[MARKDIRS];
  2580.  
  2581.             /* These are used in the globbing code to make *
  2582.              * things a bit faster.                        */
  2583.             glob_pre = fpre;
  2584.             glob_suf = fsuf;
  2585.  
  2586.             noerrs = 1;
  2587.             addwhat = -6;
  2588.             strcpy(pa, prpre);
  2589.             o = strlen(pa);
  2590.             opts[MARKDIRS] = 0;
  2591.  
  2592.             /* The compctl -g string may contain more than *
  2593.              * one pattern, so we need a loop.             */
  2594.             while (*g) {
  2595.                 LinkList l = newlinklist();
  2596.                 int ng;
  2597.  
  2598.                 /* Find the blank terminating the pattern. */
  2599.                 while (*g && inblank(*g))
  2600.                 g++;
  2601.                 /* Oops, we already reached the end of the
  2602.                    string. */
  2603.                 if (!*g)
  2604.                 break;
  2605.                 for (p = g + 1; *p && !inblank(*p); p++)
  2606.                 if (*p == '\\' && p[1])
  2607.                     p++;
  2608.                 /* Get the pattern string. */
  2609.                 tokenize(g = dupstrpfx(g, p - g));
  2610.                 if (*g == '=')
  2611.                 *g = Equals;
  2612.                 if (*g == '~')
  2613.                 *g = Tilde;
  2614.                 remnulargs(g);
  2615.                 if (*g == Equals || *g == Tilde) {
  2616.                 /* The pattern has a `~' or `=' at the  *
  2617.                  * beginning, so we expand this and use *
  2618.                  * the result.                          */
  2619.                 filesub(&g, 0);
  2620.                 addlinknode(l, dupstring(g));
  2621.                 } else if (*g == '/')
  2622.                 /* The pattern is a full path (starting *
  2623.                  * with '/'), so add it unchanged.      */
  2624.                 addlinknode(l, dupstring(g));
  2625.                 else {
  2626.                 /* It's a simple pattern, so append it to *
  2627.                  * the path we have on the command line.  */
  2628.                 strcpy(pa + o, g);
  2629.                 addlinknode(l, dupstring(pa));
  2630.                 }
  2631.                 /* Do the globbing. */
  2632.                 ng = opts[NULLGLOB];
  2633.                 opts[NULLGLOB] = 1;
  2634.                 globlist(l);
  2635.                 opts[NULLGLOB] = ng;
  2636.                 /* Get the results. */
  2637.                 if (nonempty(l) && peekfirst(l)) {
  2638.                 for (p2 = (char *)peekfirst(l); *p2; p2++)
  2639.                     if (itok(*p2))
  2640.                     break;
  2641.                 if (!*p2) {
  2642.                     if (*g == Equals || *g == Tilde ||
  2643.                     *g == '/') {
  2644.                     /* IF the pattern started with `~',  *
  2645.                      * `=', or `/', add the result only, *
  2646.                      * if it realy matches what we have  *
  2647.                      * on the line.                      */
  2648.                     while ((p2 = (char *)ugetnode(l)))
  2649.                         if (strpfx(prpre, p2))
  2650.                         addmatch(p2 + pl, NULL);
  2651.                     } else {
  2652.                     /* Otherwise ignore the path we *
  2653.                      * prepended to the pattern.    */
  2654.                     while ((p2 = p3 =
  2655.                         (char *)ugetnode(l))) {
  2656.                         for (ns = sf1; *p3 && ns; p3++)
  2657.                         if (*p3 == '/')
  2658.                             ns--;
  2659.  
  2660.                         addmatch(p3, NULL);
  2661.                     }
  2662.                     }
  2663.                 }
  2664.                 }
  2665.                 pa[o] = '\0';
  2666.                 g = p;
  2667.             }
  2668.             glob_pre = glob_suf = NULL;
  2669.             noerrs = ne;
  2670.             opts[MARKDIRS] = md;
  2671.             }
  2672.         }
  2673.         }
  2674.     }
  2675.     }
  2676.     /* Use tricat() instead of dyncat() to get zalloc()'d memory. */
  2677.     if (ic) {
  2678.     /* Now change the `~' and `=' tokens to the real characters so *
  2679.      * that things starting with these characters will be added.   */
  2680.     char *orpre = rpre;
  2681.  
  2682.     rpre = tricat("", (ic == Tilde) ? "~" : "=", rpre);
  2683.     rpl++;
  2684.     zsfree(orpre);
  2685.     }
  2686.     if (!ic && (cc->mask & CC_COMMPATH) && !*ppre && !*psuf) {
  2687.     /* If we have to complete commands, add alias names, *
  2688.      * shell functions and builtins too.                 */
  2689.     dumphashtable(aliastab, -3);
  2690.     dumphashtable(reswdtab, -3);
  2691.     dumphashtable(shfunctab, -3);
  2692.     dumphashtable(builtintab, -3);
  2693.     if (isset(HASHLISTALL))
  2694.         cmdnamtab->filltable(cmdnamtab);
  2695.     dumphashtable(cmdnamtab, -3);
  2696.     /* And parameter names if autocd and cdablevars are set. */
  2697.     if (isset(AUTOCD) && isset(CDABLEVARS))
  2698.         dumphashtable(paramtab, -4);
  2699.     }
  2700.     addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG;
  2701.  
  2702.     if (cc->mask & CC_NAMED)
  2703.     /* Add named directories. */
  2704.     scanhashtable(nameddirtab, 0, 0, 0, addhnmatch, 0);
  2705.     if (cc->mask & CC_OPTIONS) {
  2706.     /* Add option names. */
  2707.     struct option *o;
  2708.  
  2709.     for (o = optns + OPT_SIZE; (--o)->name; )
  2710.         addmatch(dupstring(o->name), NULL);
  2711.     }
  2712.     if (cc->mask & CC_VARS)
  2713.     /* And parameter names. */
  2714.     dumphashtable(paramtab, -9);
  2715.     if (cc->mask & CC_BINDINGS) {
  2716.     /* And zle function names... */
  2717.     int t0;
  2718.  
  2719.     for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  2720.         if (*zlecmds[t0].name)
  2721.         addmatch(dupstring(zlecmds[t0].name), NULL);
  2722.     }
  2723.     if (cc->keyvar) {
  2724.     /* This adds things given to the compctl -k flag *
  2725.      * (from a parameter or a list of words).        */
  2726.     char **usr = get_user_var(cc->keyvar);
  2727.  
  2728.     if (usr)
  2729.         while (*usr)
  2730.         addmatch(*usr++, NULL);
  2731.     }
  2732.     if (cc->mask & CC_USERS)
  2733.     /* Add user names. */
  2734.     maketildelist();
  2735.     if (cc->func) {
  2736.     /* This handles the compctl -K flag. */
  2737.     List list;
  2738.     char **r;
  2739.     int lv = lastval;
  2740.  
  2741.     /* Get the function. */
  2742.     if ((list = getshfunc(cc->func))) {
  2743.         /* We have it, so build a argument list. */
  2744.         LinkList args = newlinklist();
  2745.  
  2746.         addlinknode(args, cc->func);
  2747.  
  2748.         if (*delit) {
  2749.         p = dupstrpfx(os, ooffs);
  2750.         untokenize(p);
  2751.         addlinknode(args, p);
  2752.         p = dupstring(os + ooffs);
  2753.         untokenize(p);
  2754.         addlinknode(args, p);
  2755.         } else {
  2756.         addlinknode(args, lpre);
  2757.         addlinknode(args, lsuf);
  2758.         }
  2759.  
  2760.         /* This flag allows us to use read -l and -c. */
  2761.         inzlefunc = 1;
  2762.         /* Call the function. */
  2763.         doshfunc(list, args, 0, 1);
  2764.         inzlefunc = 0;
  2765.         /* And get the result from the reply parameter. */
  2766.         if ((r = get_user_var("reply")))
  2767.         while (*r)
  2768.             addmatch(*r++, NULL);
  2769.     }
  2770.     lastval = lv;
  2771.     }
  2772.     if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) {
  2773.     /* Get job names. */
  2774.     int i;
  2775.     char *j, *jj;
  2776.  
  2777.     for (i = 0; i < MAXJOB; i++)
  2778.         if (jobtab[i].stat & STAT_INUSE) {
  2779.         int stopped = jobtab[i].stat & STAT_STOPPED;
  2780.  
  2781.         j = jj = dupstring(jobtab[i].procs->text);
  2782.         /* Find the first word. */
  2783.         for (; *jj; jj++)
  2784.             if (*jj == ' ') {
  2785.             *jj = '\0';
  2786.             break;
  2787.             }
  2788.         if ((cc->mask & CC_JOBS) ||
  2789.             (stopped && (cc->mask & CC_STOPPED)) ||
  2790.             (!stopped && (cc->mask & CC_RUNNING)))
  2791.             addmatch(j, NULL);
  2792.         }
  2793.     }
  2794.     if (cc->str) {
  2795.     /* Get the stuff from a compctl -s. */
  2796.     LinkList foo = newlinklist();
  2797.     LinkNode n;
  2798.     int first = 1, ng = opts[NULLGLOB], oowe = we, oowb = wb;
  2799.     char *tmpbuf;
  2800.  
  2801.     opts[NULLGLOB] = 1;
  2802.  
  2803.     /* Put the strin in the lexer buffer and call the lexer to *
  2804.      * get the words we have to expand.                        */
  2805.     zleparse = 1;
  2806.     lexsave();
  2807.     tmpbuf = (char *)halloc(strlen(cc->str) + 5);
  2808.     sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */
  2809.     inpush(tmpbuf, 0, NULL);
  2810.     strinbeg();
  2811.     noaliases = 1;
  2812.     do {
  2813.         ctxtlex();
  2814.         if (tok == ENDINPUT || tok == LEXERR)
  2815.         break;
  2816.         if (!first && tokstr && *tokstr)
  2817.         addlinknode(foo, ztrdup(tokstr));
  2818.         first = 0;
  2819.     } while (tok != ENDINPUT && tok != LEXERR);
  2820.     noaliases = 0;
  2821.     strinend();
  2822.     inpop();
  2823.     errflag = zleparse = 0;
  2824.     lexrestore();
  2825.     /* Fine, now do full expansion. */
  2826.     prefork(foo, 0);
  2827.     if (!errflag) {
  2828.         globlist(foo);
  2829.         if (!errflag)
  2830.         /* And add the resulting words as matches. */
  2831.         for (n = firstnode(foo); n; incnode(n))
  2832.             addmatch((char *)n->dat, NULL);
  2833.     }
  2834.     opts[NULLGLOB] = ng;
  2835.     we = oowe;
  2836.     wb = oowb;
  2837.     }
  2838.     if (cc->hpat) {
  2839.     /* We have a pattern to take things from the history. */
  2840.     Comp compc = NULL;
  2841.     char *e, *h, hpatsav;
  2842.     Histent he;
  2843.     int i = curhist - 1, n = cc->hnum;
  2844.  
  2845.     /* Parse the pattern, if it isn't the null string. */
  2846.     if (*(cc->hpat)) {
  2847.         char *thpat = dupstring(cc->hpat);
  2848.  
  2849.         tokenize(thpat);
  2850.         compc = parsereg(thpat);
  2851.     }
  2852.     /* n holds the number of history line we have to search. */
  2853.     if (!n)
  2854.         n = -1;
  2855.  
  2856.     /* Now search the history. */
  2857.     while (n-- && (he = quietgethist(i--))) {
  2858.         int iwords;
  2859.         for (iwords = 0; iwords < he->nwords; iwords++) {
  2860.         h = he->text + he->words[iwords*2];
  2861.         e = he->text + he->words[iwords*2+1];
  2862.         hpatsav = *e;
  2863.         *e = '\0';
  2864.         /* We now have a word from the history, ignore it *
  2865.          * if it begins with a quote or `$'.              */
  2866.         if (*h != '\'' && *h != '"' && *h != '`' && *h != '$' &&
  2867.             (!compc || domatch(h, compc, 0)))
  2868.             /* Otherwise add it if it was matched. */
  2869.             addmatch(dupstring(h), NULL);
  2870.         if (hpatsav)
  2871.             *e = hpatsav;
  2872.         }
  2873.     }
  2874.     }
  2875.     if ((t = cc->mask & (CC_ARRAYS | CC_INTVARS | CC_ENVVARS | CC_SCALARS |
  2876.              CC_READONLYS | CC_SPECIALS | CC_PARAMS)))
  2877.     /* Add various flavours of parameters. */
  2878.     dumphashtable(paramtab, t);
  2879.     if ((t = cc->mask & CC_SHFUNCS))
  2880.     /* Add shell functions. */
  2881.     dumphashtable(shfunctab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2882.     if ((t = cc->mask & CC_BUILTINS))
  2883.     /* Add builtins. */
  2884.     dumphashtable(builtintab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2885.     if ((t = cc->mask & CC_EXTCMDS))
  2886.     /* Add external commands */
  2887.     dumphashtable(cmdnamtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2888.     if ((t = cc->mask & CC_RESWDS))
  2889.     /* Add reserved words */
  2890.     dumphashtable(reswdtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2891.     if ((t = cc->mask & (CC_ALREG | CC_ALGLOB)))
  2892.     /* Add the two types of aliases. */
  2893.     dumphashtable(aliastab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2894.  
  2895.     /* If we have no matches, ignore fignore. */
  2896.     if (empty(matches)) {
  2897.     matches = fmatches;
  2898.     firstm = ffirstm;
  2899.     shortest = fshortest;
  2900.     ab = fab;
  2901.     ae = fae;
  2902.     shortl = fshortl;
  2903.     }
  2904.  
  2905.     /* Make an array from the list of matches. */
  2906.     makearray(matches);
  2907.     PERMALLOC {
  2908.     amatches = arrdup(amatches);
  2909.     if (firstm)
  2910.         firstm = ztrdup(firstm);
  2911.     /* And quote the prefixes/suffixes. */
  2912.     if (hasspecial(s)) {
  2913.         zfree(lpre, lpl);
  2914.         zfree(lsuf, lsl);
  2915.         lpre = zalloc(lpl + 1);
  2916.         memcpy(lpre, s, lpl);
  2917.         lpre[lpl] = '\0';
  2918.         lsuf = ztrdup(s + offs);
  2919.         quotepresuf(&lpre);
  2920.         quotepresuf(&lsuf);
  2921.         untokenize(lpre);
  2922.         untokenize(lsuf);
  2923.     }
  2924.     quotepresuf(&fpre);
  2925.     quotepresuf(&fsuf);
  2926.     quotepresuf(&ppre);
  2927.     quotepresuf(&psuf);
  2928.     } LASTALLOC;
  2929.  
  2930.     /* Get the explanation string we will have to print. */
  2931.     expl = cc->explain;
  2932.  
  2933.     remsuffix = (cc->mask & CC_REMOVE);
  2934.     ccsuffix = cc->suffix;
  2935.  
  2936.     validlist = 1;
  2937.     if ((nmatches || expl) && !errflag)
  2938.     return 0;
  2939.  
  2940.     if ((isf || cc->xor) && !parampre) {
  2941.     /* We found no matches, but there is a xor'ed completion: *
  2942.      * fine, so go back and continue with that compctl.       */
  2943.     errflag = 0;
  2944.     cc = cc->xor;
  2945.     isf = 0;
  2946.     wb = owb;
  2947.     we = owe;
  2948.     cs = ocs;
  2949.     ll = oll;
  2950.     strcpy((char *)line, (char *)ol);
  2951.     offs = oloffs;
  2952.     s = dupstring(os);
  2953.     free(amatches);
  2954.     zsfree(rpre);
  2955.     zsfree(rsuf);
  2956.     zsfree(lpre);
  2957.     zsfree(lsuf);
  2958.     zsfree(ppre);
  2959.     zsfree(psuf);
  2960.     zsfree(fpre);
  2961.     zsfree(fsuf);
  2962.     zsfree(prpre);
  2963.     zsfree(parampre);
  2964.     zsfree(qparampre);
  2965.     zsfree(firstm);
  2966.     goto xorrec;
  2967.     }
  2968.  
  2969.     /* No matches and xor'ed completion: restore the command line if  *
  2970.      * it was alredy quoted, which is the case when s is untokenized. */
  2971.     if (untokenized)
  2972.     strcpy((char *)line, (char *)ol);
  2973.     return 1;
  2974. }
  2975.  
  2976. /* Invalidate the completion list. */
  2977.  
  2978. /**/
  2979. void
  2980. invalidatelist(void)
  2981. {
  2982.     if(showinglist == -2)
  2983.     listmatches();
  2984.     if(validlist) {
  2985.     freearray(amatches);
  2986.     zsfree(rpre);
  2987.     zsfree(rsuf);
  2988.     zsfree(lpre);
  2989.     zsfree(lsuf);
  2990.     zsfree(ppre);
  2991.     zsfree(psuf);
  2992.     zsfree(fpre);
  2993.     zsfree(fsuf);
  2994.     zsfree(prpre);
  2995.     zsfree(parampre);
  2996.     zsfree(qparampre);
  2997.     zsfree(firstm);
  2998.     if (ccmain != &cc_dummy)
  2999.         freecompctl(ccmain);
  3000.     }
  3001.     menucmp = showinglist = validlist = 0;
  3002.     menucur = NULL;
  3003. }
  3004.  
  3005. /* Get the words from a variable or a compctl -k list. */
  3006.  
  3007. /**/
  3008. char **
  3009. get_user_var(char *nam)
  3010. {
  3011.     if (!nam)
  3012.     return NULL;
  3013.     else if (*nam == '(') {
  3014.     /* It's a (...) list, not a parameter name. */
  3015.     char *ptr, *s, **uarr, **aptr;
  3016.     int count = 0, notempty = 0, brk = 0;
  3017.     LinkList arrlist = newlinklist();
  3018.  
  3019.     ptr = dupstring(nam);
  3020.     s = ptr + 1;
  3021.     while (*++ptr) {
  3022.         if (*ptr == '\\' && ptr[1])
  3023.         chuck(ptr), notempty = 1;
  3024.         else if (*ptr == ',' || inblank(*ptr) || *ptr == ')') {
  3025.         if (*ptr == ')')
  3026.             brk++;
  3027.         if (notempty) {
  3028.             *ptr = '\0';
  3029.             count++;
  3030.             if (*s == '\n')
  3031.             s++;
  3032.             addlinknode(arrlist, s);
  3033.         }
  3034.         s = ptr + 1;
  3035.         notempty = 0;
  3036.         } else {
  3037.         notempty = 1;
  3038.         if(*ptr == Meta)
  3039.             ptr++;
  3040.         }
  3041.         if (brk)
  3042.         break;
  3043.     }
  3044.     if (!brk || !count)
  3045.         return NULL;
  3046.     *ptr = '\0';
  3047.     aptr = uarr = (char **)ncalloc(sizeof(char *) * (count + 1));
  3048.  
  3049.     while ((*aptr++ = (char *)ugetnode(arrlist)));
  3050.     uarr[count] = NULL;
  3051.     return uarr;
  3052.     } else
  3053.     /* Otherwise it should be a parameter name. */
  3054.     return getaparam(nam);
  3055. }
  3056.  
  3057. /* This is strcmp with ignoring backslashes. */
  3058.  
  3059. /**/
  3060. int
  3061. strbpcmp(const void *a, const void *b)
  3062. {
  3063.     char *aa = *((char **)a), *bb = *((char **)b);
  3064.  
  3065.     while (*aa && *bb) {
  3066.     if (*aa == '\\')
  3067.         aa++;
  3068.     if (*bb == '\\')
  3069.         bb++;
  3070.     if (*aa != *bb)
  3071.         return (int)(*aa - *bb);
  3072.     if (*aa)
  3073.         aa++;
  3074.     if (*bb)
  3075.         bb++;
  3076.     }
  3077.     return (int)(*aa - *bb);
  3078. }
  3079.  
  3080. /* Make an array from a linked list */
  3081.  
  3082. /**/
  3083. void
  3084. makearray(LinkList l)
  3085. {
  3086.     char **ap, **bp, **cp;
  3087.     LinkNode nod;
  3088.  
  3089.     /* Build an array for the matches. */
  3090.     ap = amatches = (char **)ncalloc(((nmatches = countlinknodes(l)) + 1) *
  3091.                      sizeof(char *));
  3092.  
  3093.     /* And copy them into it. */
  3094.     for (nod = firstnode(l); nod; incnode(nod))
  3095.     *ap++ = (char *)getdata(nod);
  3096.     *ap = NULL;
  3097.  
  3098.     /* Now sort the array. */
  3099.     qsort((void *) amatches, nmatches, sizeof(char *),
  3100.            (int (*) _((const void *, const void *)))strbpcmp);
  3101.  
  3102.     /* And delete the ones that occur more than once. */
  3103.     for (ap = cp = amatches; *ap; ap++) {
  3104.     *cp++ = *ap;
  3105.     for (bp = ap; bp[1] && !strcmp(*ap, bp[1]); bp++);
  3106.     ap = bp;
  3107.     }
  3108.     *cp = NULL;
  3109.     nmatches = arrlen(amatches);
  3110. }
  3111.  
  3112. /* Handle the case were we found more than one match. */
  3113.  
  3114. /**/
  3115. void
  3116. do_ambiguous(void)
  3117. {
  3118.     int p = (usemenu || ispattern), atend = (cs == we);
  3119.     int inv = 0;
  3120.  
  3121.     menucmp = 0;
  3122.  
  3123.     /* If we have to insert the first match, call do_single().  This is *
  3124.      * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
  3125.      * completion into an unambiguous one.                              */
  3126.     if (shortest && shortl == 0 && isset(RECEXACT) &&
  3127.     (usemenu == 0 || unset(AUTOMENU))) {
  3128.     do_single(shortest);
  3129.     invalidatelist();
  3130.     return;
  3131.     }
  3132.     /* Setting lastambig here means that the completion is ambiguous and *
  3133.      * AUTO_MENU might want to start a menu completion next time round,  *
  3134.      * but this might be overridden below if we can complete an          *
  3135.      * unambiguous prefix.                                               */
  3136.     lastambig = 1;
  3137.     if(p) {
  3138.     /* p is set if we are in a position to start using menu completion *
  3139.      * due to one of the menu completion options, or due to the        *
  3140.      * menu-complete-word command, or due to using GLOB_COMPLETE which *
  3141.      * does menu-style completion regardless of the setting of the     *
  3142.      * normal menu completion options.                                 */
  3143.     do_ambig_menu();
  3144.     } else {
  3145.     /* Sort-of general case: we have an ambiguous completion, and aren't *
  3146.      * starting menu completion or doing anything really weird.  We need *
  3147.      * to insert any unambiguous prefix and suffix, if possible.         */
  3148.     complexpect = 0;
  3149.     if(ab)
  3150.         inststrlen(firstm, 1, ab);
  3151.     if(ae && !atend)
  3152.         inststrlen(firstm + strlen(firstm) - ae, 0, ae);
  3153.     if(ab || (ae && !atend))
  3154.         inv = 1;
  3155.     /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
  3156.      * if the completion is completely ambiguous') is set, and some    *
  3157.      * prefix was inserted, return now, bypassing the list-displaying  *
  3158.      * code.  On the way, invalidate the list and note that we don't   *
  3159.      * want to enter an AUTO_MENU imediately.                          */
  3160.     if(isset(LISTAMBIGUOUS) && inv) {
  3161.         invalidatelist();
  3162.         lastambig = 0;
  3163.         return;
  3164.     }
  3165.     }
  3166.     /* At this point, we might want a completion listing.  Show the listing *
  3167.      * if it is needed.                                                     */
  3168.     if (isset(LISTBEEP))
  3169.     feep();
  3170.     if (isset(AUTOLIST) && !amenu && !showinglist)
  3171.     showinglist = -2;
  3172.     if(inv)
  3173.     invalidatelist();
  3174. }
  3175.  
  3176. /* This is a stat that ignores backslashes in the filename.  The `ls' *
  3177.  * parameter says if we have to do lstat() or stat().  I think this   *
  3178.  * should instead be done by use of a general function to expand a    *
  3179.  * filename (stripping backslashes), combined with the actual         *
  3180.  * (l)stat().                                                         */
  3181.  
  3182. /**/
  3183. int
  3184. ztat(char *nam, struct stat *buf, int ls)
  3185. {
  3186.     char b[PATH_MAX], *p;
  3187.  
  3188.     for (p = b; p < b + sizeof(b) - 1 && *nam; nam++)
  3189.     if (*nam == '\\' && nam[1])
  3190.         *p++ = *++nam;
  3191.     else
  3192.         *p++ = *nam;
  3193.     *p = '\0';
  3194.  
  3195.     return ls ? lstat(b, buf) : stat(b, buf);
  3196. }
  3197.  
  3198. /* Insert a single match in the command line. */
  3199.  
  3200. /**/
  3201. void
  3202. do_single(char *str)
  3203. {
  3204.     int ccs, l, insc = 0, inscs = 0;
  3205.     char singlec = ' ';
  3206.  
  3207.     if (!ccsuffix || !(haswhat & HAS_SUFFIX) || !remsuffix)
  3208.     addedsuffix = 0;
  3209.  
  3210.     if (!menucur) {
  3211.     /* We are currently not in a menu-completion, *
  3212.      * so set the position variables.             */
  3213.     menuinsc = 0;
  3214.     if (ispattern) {
  3215.         cs = we;
  3216.         menupos = wb;
  3217.     } else
  3218.         menupos = cs;
  3219.     menuwe = (cs == we);
  3220.     if (ccsuffix && !(haswhat & HAS_SUFFIX)) {
  3221.         /* Add a compctl -S suffix if we have one. */
  3222.         if (*ccsuffix) {
  3223.         ccs = cs;
  3224.         cs = we;
  3225.         inststrlen(ccsuffix, menuwe, -1);
  3226.         menuend = cs;
  3227.         cs = ccs;
  3228.         if (remsuffix)
  3229.             /* addedsuffix is used by the key input handling  *
  3230.              * code to find out if it has to delete a suffix. */
  3231.             addedsuffix = strlen(ccsuffix);
  3232.         } else
  3233.         menuend = we;
  3234.  
  3235.         haswhat |= HAS_SUFFIX;
  3236.     } else
  3237.         menuend = we;
  3238.     }
  3239.     ccs = cs;
  3240.     /* If we are already in a menu-completion or if we have done a *
  3241.      * glob completion, we have to delete some of the stuff on the *
  3242.      * command line.                                               */
  3243.     if (menucur) {
  3244.     if (menuinsc) {
  3245.         cs = menuend;
  3246.         foredel(1);
  3247.     }
  3248.     l = menulen;
  3249.     } else if (ispattern)
  3250.     l = we - wb;
  3251.     else
  3252.     l = 0;
  3253.     cs = menupos;
  3254.     menuinsc = 0;
  3255.  
  3256.     if (l) {
  3257.     foredel(l);
  3258.     if (menuwe)
  3259.         ccs -= l;
  3260.     menuend -= l;
  3261.     }
  3262.     /* And than we insert the new string. */
  3263.     inststrlen(str, 1, menulen = strlen(str));
  3264.  
  3265.     /* And move the cursor and adjust the menuend variable. */
  3266.     if (menuwe)
  3267.     cs = ccs + menulen;
  3268.     menuend += menulen;
  3269.  
  3270.     if (!(haswhat & HAS_SUFFIX)) {
  3271.     /* There is no suffix, so we may add one. */
  3272.     if (!(haswhat & HAS_MISC) || (parampre && isset(AUTOPARAMSLASH))) {
  3273.         /* If we have only filenames or we completed a parameter name  *
  3274.          * and auto_param_slash is set, lets see if it is a directory. */
  3275.         char *p;
  3276.         struct stat buf;
  3277.  
  3278.         /* Build the path name. */
  3279.         if (ispattern || ic || parampre) {
  3280.         int ne = noerrs;
  3281.  
  3282.         noerrs = 1;
  3283.  
  3284.         if (parampre) {
  3285.             int pl = strlen(parampre);
  3286.             p = (char *) ncalloc(pl + strlen(lpre) + strlen(str) +
  3287.                      strlen(lsuf) + 1);
  3288.             sprintf(p, "%s%s%s%s", parampre, lpre, str, lsuf);
  3289.             if (pl && p[pl-1] == Inbrace)
  3290.             strcpy(p+pl-1, p+pl);
  3291.         }
  3292.         else if (ic) {
  3293.             p = (char *) ncalloc(strlen(ppre) + strlen(fpre) + strlen(str) +
  3294.                      strlen(fsuf) + strlen(psuf) + 2);
  3295.             sprintf(p, "%c%s%s%s%s%s", ic,
  3296.                 ppre, fpre, str, fsuf, psuf);
  3297.         }
  3298.         else
  3299.             p = dupstring(str);
  3300.         parsestr(p);
  3301.         if (ic)
  3302.             *p = ic;
  3303.         singsub(&p);
  3304.  
  3305.         noerrs = ne;
  3306.         } else {
  3307.         p = (char *) ncalloc((prpre ? strlen(prpre) : 0) + strlen(fpre) +
  3308.                      strlen(str) + strlen(fsuf) + strlen(psuf) + 3);
  3309.         sprintf(p, "%s%s%s%s%s",
  3310.             (prpre && *prpre) ? prpre : "./", fpre, str,
  3311.             fsuf, psuf);
  3312.         }
  3313.         /* And do the stat. */
  3314.         if (!ztat(p, &buf, 0) && (buf.st_mode & S_IFMT) == S_IFDIR) {
  3315.         /* It is a directory, so prepare to add *
  3316.          * the slash and set addedsuffix.       */
  3317.         singlec = '/';
  3318.         if (menuwe || isset(ALWAYSTOEND))
  3319.             addedsuffix = isset(AUTOREMOVESLASH) ? 1 : 0;
  3320.         }
  3321.     }
  3322.     if (menuend > ll)
  3323.         menuend = ll;
  3324.     if (menuend && ((((char)line[menuend - 1]) != singlec) ||
  3325.         (menuend > 1 && singlec == ' ' &&
  3326.           (line[menuend - 2] == '\\' || line[menuend - 2] == STOUC(Meta)))))
  3327.         if (parampre && singlec == '/' && ((char)line[menuend]) == '/')
  3328.         addedsuffix = 0;
  3329.         /* Now insert the slash or space if there is none already. */
  3330.         else {
  3331.         ccs = cs;
  3332.         cs = menuend;
  3333.         inststrlen((char *)&singlec, 1, 1);
  3334.         insc = 1;
  3335.         if (singlec != ' ')
  3336.             menuinsc = 1;
  3337.         inscs = cs;
  3338.         if (!menuwe)
  3339.             cs = ccs;
  3340.         }
  3341.     }
  3342.     /* Move to the end of the word if requested. */
  3343.     if (isset(ALWAYSTOEND) || menuwe)
  3344.     cs = menuend + (!(haswhat & HAS_SUFFIX) && insc);
  3345.     if (menucmp && singlec == ' ' && !(haswhat & HAS_SUFFIX)) {
  3346.     /* Get rid of the added space if we are doing menucompletion. */
  3347.     if (insc) {
  3348.         ccs = cs;
  3349.         cs = inscs;
  3350.         backdel(1);
  3351.         if (ccs != inscs)
  3352.           cs = ccs;
  3353.     } else
  3354.         cs--;
  3355.     }
  3356. }
  3357.  
  3358. /* This handles the beginning of menu-completion. */
  3359.  
  3360. /**/
  3361. void
  3362. do_ambig_menu(void)
  3363. {
  3364.     menucmp = 1;
  3365.     menucur = NULL;
  3366.     do_single(amatches[0]);
  3367.     menucur = amatches;
  3368. }
  3369.  
  3370. /* Return non-zero if s is a prefix of t. */
  3371.  
  3372. /**/
  3373. int
  3374. strpfx(char *s, char *t)
  3375. {
  3376.     while (*s && *s == *t)
  3377.     s++, t++;
  3378.     return !*s;
  3379. }
  3380.  
  3381. /* Return non-zero if s is a suffix of t. */
  3382.  
  3383. /**/
  3384. int
  3385. strsfx(char *s, char *t)
  3386. {
  3387.     int ls = strlen(s), lt = strlen(t);
  3388.  
  3389.     if (ls <= lt)
  3390.     return !strcmp(t + lt - ls, s);
  3391.     return 0;
  3392. }
  3393.  
  3394. /* Return the length of the common prefix of s and t. */
  3395.  
  3396. /**/
  3397. int
  3398. pfxlen(char *s, char *t)
  3399. {
  3400.     int i = 0;
  3401.  
  3402.     while (*s && *s == *t)
  3403.     s++, t++, i++;
  3404.     return i;
  3405. }
  3406.  
  3407. /* Return the length of the common suffix of s and t. */
  3408.  
  3409. /**/
  3410. int
  3411. sfxlen(char *s, char *t)
  3412. {
  3413.     if (*s && *t) {
  3414.     int i = 0;
  3415.     char *s2 = s + strlen(s) - 1, *t2 = t + strlen(t) - 1;
  3416.  
  3417.     while (s2 >= s && t2 >= t && *s2 == *t2)
  3418.         s2--, t2--, i++;
  3419.  
  3420.     return i;
  3421.     } else
  3422.     return 0;
  3423. }
  3424.  
  3425. /* This is used to print the explanation string. *
  3426.  * It returns the number of lines printed.       */
  3427.  
  3428. /**/
  3429. int
  3430. printfmt(char *fmt, int n, int dopr)
  3431. {
  3432.     char *p = fmt, nc[DIGBUFSIZE];
  3433.     int l = 0, cc = 0;
  3434.  
  3435.     for (; *p; p++) {
  3436.     /* Handle the `%' stuff (%% == %, %n == <number of matches>). */
  3437.     if (*p == '%') {
  3438.         if (*++p) {
  3439.         switch (*p) {
  3440.         case '%':
  3441.             if (dopr)
  3442.             putc('%', shout);
  3443.             cc++;
  3444.             break;
  3445.         case 'n':
  3446.             sprintf(nc, "%d", n);
  3447.             if (dopr)
  3448.             fprintf(shout, nc);
  3449.             cc += strlen(nc);
  3450.             break;
  3451.         }
  3452.         } else
  3453.         break;
  3454.     } else {
  3455.         cc++;
  3456.         if (*p == '\n') {
  3457.         l += 1 + (cc / columns);
  3458.         cc = 0;
  3459.         }
  3460.         if (dopr)
  3461.         putc(*p, shout);
  3462.     }
  3463.     }
  3464.  
  3465.     return l + (cc / columns);
  3466. }
  3467.  
  3468. /* List the matches.  Note that the list entries are metafied. */
  3469.  
  3470. /**/
  3471. void
  3472. listmatches(void)
  3473. {
  3474.     int longest = 1, fct, fw, colsz, t0, t1, ct, up, cl, xup = 0;
  3475.     int off, boff, nboff;
  3476.     int of = (isset(LISTTYPES) && !(haswhat & HAS_MISC));
  3477.     char **arr, **ap, sav;
  3478.     int nfpl, nfsl, nlpl, nlsl;
  3479.     int listmax = getiparam("LISTMAX");
  3480.  
  3481. #ifdef DEBUG
  3482.     /* Sanity check */
  3483.     if(!validlist) {
  3484.     trashzle();
  3485.     fputs("BUG: listmatches called with bogus list\n", shout);
  3486.     showinglist = 0;
  3487.     return;
  3488.     }
  3489. #endif
  3490.  
  3491.     /* Calculate lengths of prefixes/suffixes to be added */
  3492.     nfpl = fpre ? niceztrlen(fpre) : 0;
  3493.     nfsl = fsuf ? niceztrlen(fsuf) : 0;
  3494.     nlpl = lpre ? niceztrlen(lpre) : 0;
  3495.     nlsl = lsuf ? niceztrlen(lsuf) : 0;
  3496.  
  3497.     /* Calculate the lengths of the prefixes/suffixes we have to ignore
  3498.        during printing. */
  3499.     off = ispattern && ppre && *ppre &&
  3500.     !(haswhat & (HAS_MISC | HAS_PATHPAT)) ? strlen(ppre) : 0;
  3501.     boff = ispattern && psuf && *psuf &&
  3502.     !(haswhat & (HAS_MISC | HAS_PATHPAT)) ? strlen(psuf) : 0;
  3503.     nboff = ispattern && psuf && *psuf &&
  3504.     !(haswhat & (HAS_MISC | HAS_PATHPAT)) ? niceztrlen(psuf) : 0;
  3505.  
  3506.     /* When called from expandorcompleteprefix, we probably have to
  3507.        remove a space now. */
  3508.     if (remove_at >= 0) {
  3509.     int ocs = cs;
  3510.  
  3511.     cs = remove_at;
  3512.     deletechar();
  3513.     remove_at = -1;
  3514.     cs = ocs;
  3515.     }
  3516.  
  3517.     /* Set the cursor below the prompt. */
  3518.     trashzle();
  3519.     ct = nmatches;
  3520.     showinglist = 0;
  3521.  
  3522.     clearflag = (isset(USEZLE) && !termflags &&
  3523.          (isset(ALWAYSLASTPROMPT) && !gotmult)) ||
  3524.     (unset(ALWAYSLASTPROMPT) && gotmult);
  3525.  
  3526.     arr = amatches;
  3527.  
  3528.     /* Calculate the column width, the number of columns and the number
  3529.        of lines. */
  3530.     for (ap = arr; *ap; ap++)
  3531.     if ((cl = niceztrlen(*ap + off) - nboff +
  3532.          (ispattern ? 0 :
  3533.           (!(haswhat & HAS_MISC) ? nfpl + nfsl : nlpl + nlsl))) > longest)
  3534.         longest = cl;
  3535.     if (of)
  3536.     longest++;
  3537.  
  3538.     fw = longest + 2;
  3539.     fct = (columns + 1) / fw;
  3540.     if (fct == 0) {
  3541.     fct = 1;
  3542.     colsz = ct;
  3543.     up = colsz + nlnct - clearflag;
  3544.     for (ap = arr; *ap; ap++)
  3545.         up += (niceztrlen(*ap + off) - nboff + of +
  3546.         (ispattern ? 0 :
  3547.         (!(haswhat & HAS_MISC) ? nfpl + nfsl : nlpl + nlsl))) / columns;
  3548.     } else {
  3549.     colsz = (ct + fct - 1) / fct;
  3550.     up = colsz + nlnct - clearflag + (ct == 0);
  3551.     }
  3552.  
  3553.     /* Print the explanation string, if any. */
  3554.     if (expl) {
  3555.     xup = printfmt(expl, ct, 1) + 1;
  3556.     putc('\n', shout);
  3557.     up += xup;
  3558.     }
  3559.  
  3560.     /* Maybe we have to ask if the user wants to see the list. */
  3561.     if ((listmax && ct > listmax) || (!listmax && up >= lines)) {
  3562.     int qup;
  3563.     setterm();
  3564.     qup = printfmt("zsh: do you wish to see all %n possibilities? ", ct, 1);
  3565.     fflush(shout);
  3566.     if (getzlequery() != 'y') {
  3567.         if (clearflag) {
  3568.         putc('\r', shout);
  3569.         tcmultout(TCUP, TCMULTUP, qup);
  3570.         if (tccan(TCCLEAREOD))
  3571.             tcout(TCCLEAREOD);
  3572.         tcmultout(TCUP, TCMULTUP, nlnct + xup);
  3573.         } else
  3574.         putc('\n', shout);
  3575.         return;
  3576.     }
  3577.     if (clearflag) {
  3578.         putc('\r', shout);
  3579.         tcmultout(TCUP, TCMULTUP, qup);
  3580.         if (tccan(TCCLEAREOD))
  3581.         tcout(TCCLEAREOD);
  3582.     } else
  3583.         putc('\n', shout);
  3584.     settyinfo(&shttyinfo);
  3585.     }
  3586.  
  3587.     /* Now print the matches. */
  3588.     for (t1 = 0; t1 != colsz; t1++) {
  3589.     ap = arr + t1;
  3590.     if (of) {
  3591.         /* We have to print the file types. */
  3592.         while (*ap) {
  3593.         int t2;
  3594.         char *pb;
  3595.         struct stat buf;
  3596.  
  3597.         /* Build the path name for the stat. */
  3598.         if (ispattern) {
  3599.             int cut = strlen(*ap) - boff;
  3600.  
  3601.             sav = ap[0][cut];
  3602.             ap[0][cut] = '\0';
  3603.             nicezputs(*ap + off, shout);
  3604.             t2 = niceztrlen(*ap + off);
  3605.             ap[0][cut] = sav;
  3606.             pb = *ap;
  3607.         } else {
  3608.             nicezputs(fpre, shout);
  3609.             nicezputs(*ap, shout);
  3610.             nicezputs(fsuf, shout);
  3611.             t2 = nfpl + niceztrlen(*ap) + nfsl;
  3612.             pb = (char *) halloc((prpre ? strlen(prpre) : 0) + 3 +
  3613.                      strlen(fpre) + strlen(*ap) + strlen(fsuf));
  3614.             sprintf(pb, "%s%s%s%s",
  3615.                 (prpre && *prpre) ? prpre : "./", fpre, *ap, fsuf);
  3616.         }
  3617.         if (ztat(pb, &buf, 1))
  3618.             putc(' ', shout);
  3619.         else
  3620.             /* Print the file type character. */
  3621.             putc(file_type(buf.st_mode), shout);
  3622.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  3623.         if (*ap)
  3624.             /* And add spaces to make the columns aligned. */
  3625.             for (++t2; t2 < fw; t2++)
  3626.             putc(' ', shout);
  3627.         }
  3628.     } else
  3629.         while (*ap) {
  3630.         int t2;
  3631.  
  3632.         if (ispattern) {
  3633.             int cut = strlen(*ap) - boff;
  3634.  
  3635.             sav = ap[0][cut];
  3636.             ap[0][cut] = '\0';
  3637.             nicezputs(*ap + off, shout);
  3638.             t2 = niceztrlen(*ap + off);
  3639.             ap[0][cut] = sav;
  3640.         } else if (!(haswhat & HAS_MISC)) {
  3641.             nicezputs(fpre, shout);
  3642.             nicezputs(*ap, shout);
  3643.             nicezputs(fsuf, shout);
  3644.             t2 = nfpl + niceztrlen(*ap) + nfsl;
  3645.         } else {
  3646.             nicezputs(lpre, shout);
  3647.             nicezputs(*ap, shout);
  3648.             nicezputs(lsuf, shout);
  3649.             t2 = nlpl + niceztrlen(*ap) + nlsl;
  3650.         }
  3651.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  3652.         if (*ap)
  3653.             for (; t2 < fw; t2++)
  3654.             putc(' ', shout);
  3655.         }
  3656.     if (t1 != colsz - 1 || !clearflag)
  3657.         putc('\n', shout);
  3658.     }
  3659.     if (clearflag)
  3660.     /* Move the cursor up to the prompt, if always_last_prompt *
  3661.      * is set and all that...                                  */
  3662.     if (up < lines) {
  3663.         tcmultout(TCUP, TCMULTUP, up);
  3664.         showinglist = -1;
  3665.     } else
  3666.         clearflag = 0, putc('\n', shout);
  3667. }
  3668.  
  3669. /* This is used to print expansions. */
  3670.  
  3671. /**/
  3672. void
  3673. listlist(LinkList l)
  3674. {
  3675.     int hw = haswhat, ip = ispattern;
  3676.     char *lp = lpre, *ls = lsuf;
  3677.     int nm = nmatches, vl = validlist;
  3678.     char **am = amatches;
  3679.     char *ex = expl;
  3680.  
  3681.     haswhat = HAS_MISC;
  3682.     ispattern = 0;
  3683.     validlist = 1;
  3684.     lpre = lsuf = "";
  3685.     expl = NULL;
  3686.  
  3687.     makearray(l);
  3688.     listmatches();
  3689.     showinglist = 0;
  3690.  
  3691.     expl = ex;
  3692.     amatches = am;
  3693.     nmatches = nm;
  3694.     validlist = vl;
  3695.     lpre = lp;
  3696.     lsuf = ls;
  3697.     ispattern = ip;
  3698.     haswhat = hw;
  3699. }
  3700.  
  3701. /* And this is used to print select lists.  Hm, this function should *
  3702.  * probably be move to loop.c.                                       */
  3703.  
  3704. /**/
  3705. void
  3706. selectlist(LinkList l)
  3707. {
  3708.     size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
  3709.     LinkNode n;
  3710.     char **arr, **ap;
  3711.  
  3712.     trashzle();
  3713.     ct = countlinknodes(l);
  3714.     ap = arr = (char **)alloc((countlinknodes(l) + 1) * sizeof(char **));
  3715.  
  3716.     for (n = (LinkNode) firstnode(l); n; incnode(n))
  3717.     *ap++ = (char *)getdata(n);
  3718.     *ap = NULL;
  3719.     for (ap = arr; *ap; ap++)
  3720.     if (strlen(*ap) > longest)
  3721.         longest = strlen(*ap);
  3722.     t0 = ct;
  3723.     longest++;
  3724.     while (t0)
  3725.     t0 /= 10, longest++;
  3726.     /* to compensate for added ')' */
  3727.     fct = (columns - 1) / (longest + 3);
  3728.     if (fct == 0)
  3729.     fct = 1;
  3730.     else
  3731.     fw = (columns - 1) / fct;
  3732.     colsz = (ct + fct - 1) / fct;
  3733.     for (t1 = 0; t1 != colsz; t1++) {
  3734.     ap = arr + t1;
  3735.     do {
  3736.         int t2 = strlen(*ap) + 2, t3;
  3737.  
  3738.         fprintf(stderr, "%d) %s", t3 = ap - arr + 1, *ap);
  3739.         while (t3)
  3740.         t2++, t3 /= 10;
  3741.         for (; t2 < fw; t2++)
  3742.         fputc(' ', stderr);
  3743.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  3744.     }
  3745.     while (*ap);
  3746.     fputc('\n', stderr);
  3747.     }
  3748.  
  3749.  /* Below is a simple attempt at doing it the Korn Way..
  3750.        ap = arr;
  3751.        t0 = 0;
  3752.        do {
  3753.            t0++;
  3754.            fprintf(stderr,"%d) %s\n",t0,*ap);
  3755.            ap++;
  3756.        }
  3757.        while (*ap);*/
  3758.     fflush(stderr);
  3759. }
  3760.  
  3761. /* Expand the history references. */
  3762.  
  3763. /**/
  3764. int
  3765. doexpandhist(void)
  3766. {
  3767.     unsigned char *ol;
  3768.     int oll, ocs, ne = noerrs, err;
  3769.  
  3770.     DPUTS(useheap, "BUG: useheap in doexpandhist()");
  3771.     HEAPALLOC {
  3772.     pushheap();
  3773.     metafy_line();
  3774.     oll = ll;
  3775.     ocs = cs;
  3776.     ol = (unsigned char *)dupstring((char *)line);
  3777.     expanding = 1;
  3778.     excs = cs;
  3779.     ll = cs = 0;
  3780.     lexsave();
  3781.     /* We push ol as it will remain unchanged */
  3782.     inpush((char *) ol, 0, NULL);
  3783.     strinbeg();
  3784.     noaliases = 1;
  3785.     noerrs = 1;
  3786.     exlast = inbufct;
  3787.     do {
  3788.         ctxtlex();
  3789.     } while (tok != ENDINPUT && tok != LEXERR);
  3790.     stophist = 2;
  3791.     while (!lexstop)
  3792.         hgetc();
  3793.     /* We have to save errflags because it's reset in lexrestore. Since  *
  3794.      * noerrs was set to 1 errflag is true if there was a habort() which *
  3795.      * means that the expanded string is unusable.                       */
  3796.     err = errflag;
  3797.     noerrs = ne;
  3798.     noaliases = 0;
  3799.     strinend();
  3800.     inpop();
  3801.     zleparse = 0;
  3802.     lexrestore();
  3803.     expanding = 0;
  3804.  
  3805.     if (!err) {
  3806.         cs = excs;
  3807.         if (strcmp((char *)line, (char *)ol)) {
  3808.         unmetafy_line();
  3809.         /* For vi mode -- reset the beginning-of-insertion pointer   *
  3810.          * to the beginning of the line.  This seems a little silly, *
  3811.          * if we are, for example, expanding "exec !!".              */
  3812.         if (viinsbegin > findbol())
  3813.             viinsbegin = findbol();
  3814.         popheap();
  3815.         LASTALLOC_RETURN 1;
  3816.         }
  3817.     }
  3818.  
  3819.     strcpy((char *)line, (char *)ol);
  3820.     ll = oll;
  3821.     cs = ocs;
  3822.     unmetafy_line();
  3823.  
  3824.     popheap();
  3825.     } LASTALLOC;
  3826.     return 0;
  3827. }
  3828.  
  3829. /**/
  3830. void
  3831. magicspace(void)
  3832. {
  3833.     c = ' ';
  3834.     selfinsert();
  3835.     doexpandhist();
  3836. }
  3837.  
  3838. /**/
  3839. void
  3840. expandhistory(void)
  3841. {
  3842.     if (!doexpandhist())
  3843.     feep();
  3844. }
  3845.  
  3846. static int cmdwb, cmdwe;
  3847.  
  3848. /**/
  3849. char *
  3850. getcurcmd(void)
  3851. {
  3852.     int curlincmd;
  3853.     char *s = NULL;
  3854.  
  3855.     DPUTS(useheap, "BUG: useheap in getcurcmd()");
  3856.     HEAPALLOC {
  3857.     zleparse = 2;
  3858.     lexsave();
  3859.     metafy_line();
  3860.     inpush(dupstrspace((char *) line), 0, NULL);
  3861.     unmetafy_line();
  3862.     strinbeg();
  3863.     pushheap();
  3864.     do {
  3865.         curlincmd = incmdpos;
  3866.         ctxtlex();
  3867.         if (tok == ENDINPUT || tok == LEXERR)
  3868.         break;
  3869.         if (tok == STRING && curlincmd) {
  3870.         zsfree(s);
  3871.         s = ztrdup(tokstr);
  3872.         cmdwb = ll - wordbeg;
  3873.         cmdwe = ll + 1 - inbufct;
  3874.         }
  3875.     }
  3876.     while (tok != ENDINPUT && tok != LEXERR && zleparse);
  3877.     popheap();
  3878.     strinend();
  3879.     inpop();
  3880.     errflag = zleparse = 0;
  3881.     lexrestore();
  3882.     } LASTALLOC;
  3883.     return s;
  3884. }
  3885.  
  3886. /**/
  3887. void
  3888. processcmd(void)
  3889. {
  3890.     char *s, *t;
  3891.  
  3892.     s = getcurcmd();
  3893.     if (!s) {
  3894.     feep();
  3895.     return;
  3896.     }
  3897.     t = zlecmds[bindk].name;
  3898.     zmult = 1;
  3899.     pushline();
  3900.     inststr(t);
  3901.     inststr(" ");
  3902.     untokenize(s);
  3903.     HEAPALLOC {
  3904.     inststr(quotename(s, NULL, NULL, NULL));
  3905.     } LASTALLOC;
  3906.     zsfree(s);
  3907.     done = 1;
  3908. }
  3909.  
  3910. /**/
  3911. void
  3912. expandcmdpath(void)
  3913. {
  3914.     int oldcs = cs, na = noaliases;
  3915.     char *s, *str;
  3916.  
  3917.     noaliases = 1;
  3918.     s = getcurcmd();
  3919.     noaliases = na;
  3920.     if (!s || cmdwb < 0 || cmdwe < cmdwb) {
  3921.     feep();
  3922.     return;
  3923.     }
  3924.     str = findcmd(s);
  3925.     zsfree(s);
  3926.     if (!str) {
  3927.     feep();
  3928.     return;
  3929.     }
  3930.     cs = cmdwb;
  3931.     foredel(cmdwe - cmdwb);
  3932.     spaceinline(strlen(str));
  3933.     strncpy((char *)line + cs, str, strlen(str));
  3934.     cs = oldcs;
  3935.     if (cs >= cmdwe - 1)
  3936.     cs += cmdwe - cmdwb + strlen(str);
  3937.     if (cs > ll)
  3938.     cs = ll;
  3939.     zsfree(str);
  3940. }
  3941.  
  3942. /* Extra function added by AR Iano-Fletcher. */
  3943. /* This is a expand/complete in the vein of wash. */
  3944.  
  3945. /**/
  3946. void
  3947. expandorcompleteprefix(void)
  3948. {
  3949.     /* global c is the current character typed. */
  3950.     int csafe = c;
  3951.  
  3952.     /* insert a space and backspace. */
  3953.     c = ' ';
  3954.     selfinsert();        /* insert the extra character */
  3955.     forwardchar();        /* move towards beginning */
  3956.     
  3957.     remove_at = cs;
  3958.  
  3959.     /* do the expansion/completion. */
  3960.     c = csafe;
  3961.     zmult = 1;
  3962.     expandorcomplete();        /* complete. */
  3963.     zmult = -1;
  3964.  
  3965.     /* remove the inserted space. */
  3966.     if (remove_at >= 0) {
  3967.     backwardchar();        /* move towards ends */
  3968.     deletechar();        /* delete the added space. */
  3969.     }
  3970.     remove_at = -1;
  3971. }
  3972.