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 / utils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-25  |  68.2 KB  |  3,455 lines

  1. /*
  2.  * $Id: utils.c,v 2.61 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * utils.c - miscellaneous utilities
  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. #include "zsh.h"
  33.  
  34. /* Print an error */
  35.  
  36. /**/
  37. void
  38. zwarnnam(char *cmd, char *fmt, char *str, int num)
  39. {
  40.     int waserr;
  41.  
  42.     waserr = errflag;
  43.     zerrnam(cmd, fmt, str, num);
  44.     errflag = waserr;
  45. }
  46.  
  47. /**/
  48. void
  49. zerr(char *fmt, char *str, int num)
  50. {
  51.     if (errflag || noerrs)
  52.     return;
  53.     errflag = 1;
  54.     trashzle();
  55.     /*
  56.      * scriptname is set when sourcing scripts, so that we get the
  57.      * correct name instead of the generic name of whatever
  58.      * program/script is running.
  59.      */
  60.     nicezputs(isset(SHINSTDIN) ? "zsh" :
  61.           scriptname ? scriptname : argzero, stderr);
  62.     fputs(": ", stderr);
  63.     zerrnam(NULL, fmt, str, num);
  64. }
  65.  
  66. /**/
  67. void
  68. zerrnam(char *cmd, char *fmt, char *str, int num)
  69. {
  70.     if (cmd) {
  71.     if (errflag || noerrs)
  72.         return;
  73.     errflag = 1;
  74.     trashzle();
  75.     if(unset(SHINSTDIN)) {
  76.         nicezputs(scriptname ? scriptname : argzero, stderr);
  77.         fputs(": ", stderr);
  78.     }
  79.     nicezputs(cmd, stderr);
  80.     fputs(": ", stderr);
  81.     }
  82.     while (*fmt)
  83.     if (*fmt == '%') {
  84.         fmt++;
  85.         switch (*fmt++) {
  86.         case 's':
  87.         nicezputs(str, stderr);
  88.         break;
  89.         case 'l': {
  90.         char sav;
  91.         num = metalen(str, num);
  92.         sav = str[num];
  93.         str[num] = '\0';
  94.         nicezputs(str, stderr);
  95.         str[num] = sav;
  96.         break;
  97.         }
  98.         case 'd':
  99.         fprintf(stderr, "%d", num);
  100.         break;
  101.         case '%':
  102.         putc('%', stderr);
  103.         break;
  104.         case 'c':
  105.         fputs(nicechar(num), stderr);
  106.         break;
  107.         case 'e':
  108.         /* print the corresponding message for this errno */
  109.         if (num == EINTR) {
  110.             fputs("interrupt\n", stderr);
  111.             errflag = 1;
  112.             return;
  113.         }
  114.         /* If the message is not about I/O problems, it looks better *
  115.          * if we uncapitalize the first letter of the message        */
  116.         if (num == EIO)
  117.             fputs(strerror(num), stderr);
  118.         else {
  119.             char *errmsg = strerror(num);
  120.             fputc(tulower(errmsg[0]), stderr);
  121.             fputs(errmsg + 1, stderr);
  122.         }
  123.         break;
  124.         }
  125.     } else {
  126.         putc(*fmt == Meta ? *++fmt ^ 32 : *fmt, stderr);
  127.         fmt++;
  128.     }
  129.     if (unset(SHINSTDIN) && lineno)
  130.     fprintf(stderr, " [%ld]\n", lineno);
  131.     else
  132.     putc('\n', stderr);
  133.     fflush(stderr);
  134. }
  135.  
  136. /* Output a single character, for the termcap routines.     *
  137.  * This is used instead of putchar since it can be a macro. */
  138.  
  139. /**/
  140. int
  141. putraw(int c)
  142. {
  143.     putc(c, stdout);
  144.     return 0;
  145. }
  146.  
  147. /* Output a single character, for the termcap routines. */
  148.  
  149. /**/
  150. int
  151. putshout(int c)
  152. {
  153.     putc(c, shout);
  154.     return 0;
  155. }
  156.  
  157. /* Turn a character into a visible representation thereof.  The visible *
  158.  * string is put together in a static buffer, and this function returns *
  159.  * a pointer to it.  Printable characters stand for themselves, DEL is  *
  160.  * represented as "^?", newline and tab are represented as "\n" and     *
  161.  * "\t", and normal control characters are represented in "^C" form.    *
  162.  * Characters with bit 7 set, if unprintable, are represented as "\M-"  *
  163.  * followed by the visible representation of the character with bit 7   *
  164.  * stripped off.  Tokens are interpreted, rather than being treated as  *
  165.  * literal characters.                                                  */
  166.  
  167. /**/
  168. char *
  169. nicechar(int c)
  170. {
  171.     static char buf[6];
  172.     char *s = buf;
  173.     c &= 0xff;
  174.     if (isprint(c))
  175.     goto done;
  176.     if (c & 0x80) {
  177.     *s++ = '\\';
  178.     *s++ = 'M';
  179.     *s++ = '-';
  180.     c &= 0x7f;
  181.     if(isprint(c))
  182.         goto done;
  183.     }
  184.     if (c == 0x7f) {
  185.     *s++ = '^';
  186.     c = '?';
  187.     } else if (c == '\n') {
  188.     *s++ = '\\';
  189.     c = 'n';
  190.     } else if (c == '\t') {
  191.     *s++ = '\\';
  192.     c = 't';
  193.     } else if (c < 0x20) {
  194.     *s++ = '^';
  195.     c += 0x40;
  196.     }
  197.     done:
  198.     *s++ = c;
  199.     *s = 0;
  200.     return buf;
  201. }
  202.  
  203. #if 0
  204. /* Output a string's visible representation. */
  205.  
  206. /**/
  207. void
  208. nicefputs(char *s, FILE *f)
  209. {
  210.     for (; *s; s++)
  211.     fputs(nicechar(STOUC(*s)), f);
  212. }
  213. #endif
  214.  
  215. /* Return the length of the visible representation of a string. */
  216.  
  217. /**/
  218. size_t
  219. nicestrlen(char *s)
  220. {
  221.     size_t l = 0;
  222.  
  223.     for (; *s; s++)
  224.     l += strlen(nicechar(STOUC(*s)));
  225.     return l;
  226. }
  227.  
  228. /* get a symlink-free pathname for s relative to PWD */
  229.  
  230. /**/
  231. char *
  232. findpwd(char *s)
  233. {
  234.     char *t;
  235.  
  236.     if (*s == '/')
  237.     return xsymlink(s);
  238.     s = tricat((pwd[1]) ? pwd : "", "/", s);
  239.     t = xsymlink(s);
  240.     zsfree(s);
  241.     return t;
  242. }
  243.  
  244. /* Check whether a string contains the *
  245.  * name of the present directory.      */
  246.  
  247. /**/
  248. int
  249. ispwd(char *s)
  250. {
  251.     struct stat sbuf, tbuf;
  252.  
  253.     if (stat(unmeta(s), &sbuf) == 0 && stat(".", &tbuf) == 0)
  254.     if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
  255.         return 1;
  256.     return 0;
  257. }
  258.  
  259. static char xbuf[PATH_MAX*2];
  260.  
  261. /**/
  262. char **
  263. slashsplit(char *s)
  264. {
  265.     char *t, **r, **q;
  266.     int t0;
  267.  
  268.     if (!*s)
  269.     return (char **) zcalloc(sizeof(char **));
  270.  
  271.     for (t = s, t0 = 0; *t; t++)
  272.     if (*t == '/')
  273.         t0++;
  274.     q = r = (char **) zalloc(sizeof(char **) * (t0 + 2));
  275.  
  276.     while ((t = strchr(s, '/'))) {
  277.     *q++ = ztrduppfx(s, t - s);
  278.     while (*t == '/')
  279.         t++;
  280.     if (!*t) {
  281.         *q = NULL;
  282.         return r;
  283.     }
  284.     s = t;
  285.     }
  286.     *q++ = ztrdup(s);
  287.     *q = NULL;
  288.     return r;
  289. }
  290.  
  291. /* expands symlinks and .. or . expressions */
  292. /* if flag = 0, only expand .. and . expressions */
  293.  
  294. static int
  295. xsymlinks(char *s, int flag)
  296. {
  297.     char **pp, **opp;
  298.     char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2];
  299.     int t0;
  300.  
  301.     opp = pp = slashsplit(s);
  302.     for (; *pp; pp++) {
  303.     if (!strcmp(*pp, ".")) {
  304.         zsfree(*pp);
  305.         continue;
  306.     }
  307.     if (!strcmp(*pp, "..")) {
  308.         char *p;
  309.  
  310.         zsfree(*pp);
  311.         if (!strcmp(xbuf, "/"))
  312.         continue;
  313.         p = xbuf + strlen(xbuf);
  314.         while (*--p != '/');
  315.         *p = '\0';
  316.         continue;
  317.     }
  318.     if (unset(CHASELINKS)) {
  319.         strcat(xbuf, "/");
  320.         strcat(xbuf, *pp);
  321.         zsfree(*pp);
  322.         continue;
  323.     }
  324.     sprintf(xbuf2, "%s/%s", xbuf, *pp);
  325.     t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX);
  326.     if (t0 == -1 || !flag) {
  327.         strcat(xbuf, "/");
  328.         strcat(xbuf, *pp);
  329.         zsfree(*pp);
  330.     } else {
  331.         metafy(xbuf3, t0, META_NOALLOC);
  332.         if (*xbuf3 == '/') {
  333.         strcpy(xbuf, "");
  334.         if (xsymlinks(xbuf3 + 1, flag))
  335.             return 1;
  336.         } else if (xsymlinks(xbuf3, flag))
  337.         return 1;
  338.         zsfree(*pp);
  339.     }
  340.     }
  341.     free(opp);
  342.     return 0;
  343. }
  344.  
  345. /* expand symlinks in s, and remove other weird things */
  346.  
  347. /**/
  348. char *
  349. xsymlink(char *s)
  350. {
  351.     if (unset(CHASELINKS))
  352.     return ztrdup(s);
  353.     if (*s != '/')
  354.     return NULL;
  355.     *xbuf = '\0';
  356.     if (xsymlinks(s + 1, 1))
  357.     return ztrdup(s);
  358.     if (!*xbuf)
  359.     return ztrdup("/");
  360.     return ztrdup(xbuf);
  361. }
  362.  
  363. /* print a directory */
  364.  
  365. /**/
  366. void
  367. fprintdir(char *s, FILE *f)
  368. {
  369.     Nameddir d = finddir(s);
  370.  
  371.     if (!d)
  372.     fputs(unmeta(s), f);
  373.     else {
  374.     putc('~', f);
  375.     fputs(unmeta(d->nam), f);
  376.     fputs(unmeta(s + strlen(d->dir)), f);
  377.     }
  378. }
  379.  
  380. /* Returns the current username.  It caches the username *
  381.  * and uid to try to avoid requerying the password files *
  382.  * or NIS/NIS+ database.                                 */
  383.  
  384. /**/
  385. char *
  386. get_username(void)
  387. {
  388.     struct passwd *pswd;
  389.     uid_t current_uid;
  390.  
  391.     current_uid = getuid();
  392.     if (current_uid != cached_uid) {
  393.     cached_uid = current_uid;
  394.     zsfree(cached_username);
  395.     if ((pswd = getpwuid(current_uid)))
  396.         cached_username = ztrdup(pswd->pw_name);
  397.     else
  398.         cached_username = ztrdup("");
  399.     }
  400.     return cached_username;
  401. }
  402.  
  403. /* static variables needed by finddir(). */
  404.  
  405. static char finddir_full[PATH_MAX];
  406. static Nameddir finddir_last;
  407. static int finddir_best;
  408.  
  409. /* ScanFunc used by finddir(). */
  410.  
  411. static void finddir_scan _((HashNode, int));
  412.  
  413. static void
  414. finddir_scan(HashNode hn, int flags)
  415. {
  416.     Nameddir nd = (Nameddir) hn;
  417.  
  418.     if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full)) {
  419.     finddir_last=nd;
  420.     finddir_best=nd->diff;
  421.     }
  422. }
  423.  
  424. /* See if a path has a named directory as its prefix. *
  425.  * If passed a NULL argument, it will invalidate any  *
  426.  * cached information.                                */
  427.  
  428. /**/
  429. Nameddir
  430. finddir(char *s)
  431. {
  432.     static struct nameddir homenode = { NULL, "", 0, NULL, 0 };
  433.  
  434.     /* Invalidate directory cache if argument is NULL.  This is called *
  435.      * whenever a node is added to or removed from the hash table, and *
  436.      * whenever the value of $HOME changes.  (On startup, too.)        */
  437.     if (!s) {
  438.     homenode.dir = home;
  439.     homenode.diff = strlen(home);
  440.     if(homenode.diff==1 || homenode.diff>=PATH_MAX)
  441.         homenode.diff = 0;
  442.     finddir_full[0] = 0;
  443.     return finddir_last = NULL;
  444.     }
  445.  
  446.     if (!strcmp(s, finddir_full))
  447.     return finddir_last;
  448.  
  449.     strcpy(finddir_full, s);
  450.     finddir_best=0;
  451.     finddir_last=NULL;
  452.     finddir_scan((HashNode)&homenode, 0);
  453.     scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0);
  454.     return finddir_last;
  455. }
  456.  
  457. /* add a named directory */
  458.  
  459. /**/
  460. void
  461. adduserdir(char *s, char *t, int flags, int always)
  462. {
  463.     Nameddir nd;
  464.  
  465.     /* We don't maintain a hash table in non-interactive shells. */
  466.     if (!interact)
  467.     return;
  468.  
  469.     /* The ND_USERNAME flag means that this possible hash table *
  470.      * entry is derived from a passwd entry.  Such entries are  *
  471.      * subordinate to explicitly generated entries.             */
  472.     if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s))
  473.     return;
  474.  
  475.     /* Normal parameter assignments generate calls to this function, *
  476.      * with always==0.  Unless the AUTO_NAME_DIRS option is set, we  *
  477.      * don't let such assignments actually create directory names.   *
  478.      * Instead, a reference to the parameter as a directory name can *
  479.      * cause the actual creation of the hash table entry.            */
  480.     if (!always && unset(AUTONAMEDIRS) &&
  481.         !nameddirtab->getnode2(nameddirtab, s))
  482.     return;
  483.  
  484.     if (!t || *t != '/' || strlen(t) >= PATH_MAX) {
  485.     /* We can't use this value as a directory, so simply remove *
  486.      * the corresponding entry in the hash table, if any.       */
  487.     HashNode hn = nameddirtab->removenode(nameddirtab, s);
  488.  
  489.     if(hn)
  490.         nameddirtab->freenode(hn);
  491.     return;
  492.     }
  493.  
  494.     /* add the name */
  495.     nd = (Nameddir) zcalloc(sizeof *nd);
  496.     nd->flags = flags;
  497.     nd->dir = ztrdup(t);
  498.     nameddirtab->addnode(nameddirtab, ztrdup(s), nd);
  499. }
  500.  
  501. /* Get a named directory: this function can cause a directory name *
  502.  * to be added to the hash table, if it isn't there already.       */
  503.  
  504. /**/
  505. char *
  506. getnameddir(char *name)
  507. {
  508.     Param pm;
  509.     char *str;
  510.     struct passwd *pw;
  511.     Nameddir nd;
  512.  
  513.     /* Check if it is already in the named directory table */
  514.     if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)))
  515.     return dupstring(nd->dir);
  516.  
  517.     /* Check if there is a scalar parameter with this name whose value *
  518.      * begins with a `/'.  If there is, add it to the hash table and   *
  519.      * return the new value.                                           */
  520.     if ((pm = (Param) paramtab->getnode(paramtab, name)) &&
  521.         (PM_TYPE(pm->flags) == PM_SCALAR) &&
  522.         (str = getsparam(name)) && *str == '/') {
  523.     adduserdir(name, str, 0, 1);
  524.     return str;
  525.     }
  526.  
  527.     /* Retrieve an entry from the password table/database for this user. */
  528.     if ((pw = getpwnam(name))) {
  529.     char *dir = xsymlink(pw->pw_dir);
  530.     adduserdir(name, dir, ND_USERNAME, 1);
  531.     str = dupstring(dir);
  532.     zsfree(dir);
  533.     return str;
  534.     }
  535.  
  536.     /* There are no more possible sources of directory names, so give up. */
  537.     return NULL;
  538. }
  539.  
  540. /**/
  541. int
  542. dircmp(char *s, char *t)
  543. {
  544.     if (s) {
  545.     for (; *s == *t; s++, t++)
  546.         if (!*s)
  547.         return 0;
  548.     if (!*s && *t == '/')
  549.         return 0;
  550.     }
  551.     return 1;
  552. }
  553.  
  554. /* do pre-prompt stuff */
  555.  
  556. /**/
  557. void
  558. preprompt(void)
  559. {
  560.     List list;
  561.     struct schedcmd *sch, *schl;
  562.     int period = getiparam("PERIOD");
  563.     int mailcheck = getiparam("MAILCHECK");
  564.  
  565.     in_vared = 0;
  566.     /* If NOTIFY is not set, then check for completed *
  567.      * jobs before we print the prompt.               */
  568.     if (unset(NOTIFY))
  569.     scanjobs();
  570.     if (errflag)
  571.     return;
  572.  
  573.     /* If a shell function named "precmd" exists, *
  574.      * then execute it.                           */
  575.     if ((list = getshfunc("precmd")))
  576.     doshfunc(list, NULL, 0, 1);
  577.     if (errflag)
  578.     return;
  579.  
  580.     /* If 1) the parameter PERIOD exists, 2) the shell function     *
  581.      * "periodic" exists, 3) it's been greater than PERIOD since we *
  582.      * executed "periodic", then execute it now.                    */
  583.     if (period && (time(NULL) > lastperiodic + period) &&
  584.     (list = getshfunc("periodic"))) {
  585.     doshfunc(list, NULL, 0, 1);
  586.     lastperiodic = time(NULL);
  587.     }
  588.     if (errflag)
  589.     return;
  590.  
  591.     /* If WATCH is set, then check for the *
  592.      * specified login/logout events.      */
  593.     if (watch) {
  594.     if ((int) difftime(time(NULL), lastwatch) > getiparam("LOGCHECK")) {
  595.         dowatch();
  596.         lastwatch = time(NULL);
  597.     }
  598.     }
  599.     if (errflag)
  600.     return;
  601.  
  602.     /* Check mail */
  603.     if (mailcheck && (int) difftime(time(NULL), lastmailcheck) > mailcheck) {
  604.     char *mailfile;
  605.  
  606.     if (mailpath && *mailpath && **mailpath)
  607.         checkmailpath(mailpath);
  608.     else if ((mailfile = getsparam("MAIL")) && *mailfile) {
  609.         char *x[2];
  610.  
  611.         x[0] = mailfile;
  612.         x[1] = NULL;
  613.         checkmailpath(x);
  614.     }
  615.     lastmailcheck = time(NULL);
  616.     }
  617.  
  618.     /* Check scheduled commands */
  619.     for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds; sch;
  620.      sch = (schl = sch)->next) {
  621.     if (sch->time < time(NULL)) {
  622.         execstring(sch->cmd, 0, 0);
  623.         schl->next = sch->next;
  624.         zsfree(sch->cmd);
  625.         zfree(sch, sizeof(struct schedcmd));
  626.  
  627.         sch = schl;
  628.     }
  629.     if (errflag)
  630.         return;
  631.     }
  632. }
  633.  
  634. /**/
  635. void
  636. checkmailpath(char **s)
  637. {
  638.     struct stat st;
  639.     char *v, *u, c;
  640.  
  641.     while (*s) {
  642.     for (v = *s; *v && *v != '?'; v++);
  643.     c = *v;
  644.     *v = '\0';
  645.     if (c != '?')
  646.         u = NULL;
  647.     else
  648.         u = v + 1;
  649.     if (**s == 0) {
  650.         *v = c;
  651.         zerr("empty MAILPATH component: %s", *s, 0);
  652.     } else if (stat(unmeta(*s), &st) == -1) {
  653.         if (errno != ENOENT)
  654.         zerr("%e: %s", *s, errno);
  655.     } else if (S_ISDIR(st.st_mode)) {
  656.         LinkList l;
  657.         DIR *lock = opendir(unmeta(*s));
  658.         char buf[PATH_MAX * 2], **arr, **ap;
  659.         int ct = 1;
  660.  
  661.         if (lock) {
  662.         char *fn;
  663.         HEAPALLOC {
  664.             pushheap();
  665.             l = newlinklist();
  666.             while ((fn = zreaddir(lock))) {
  667.             if (errflag)
  668.                 break;
  669.             /* Ignore `.' and `..'. */
  670.             if (fn[0] == '.' &&
  671.                 (fn[1] == '\0' ||
  672.                  (fn[1] == '.' && fn[2] == '\0')))
  673.                 continue;
  674.             if (u)
  675.                 sprintf(buf, "%s/%s?%s", *s, fn, u);
  676.             else
  677.                 sprintf(buf, "%s/%s", *s, fn);
  678.             addlinknode(l, dupstring(buf));
  679.             ct++;
  680.             }
  681.             closedir(lock);
  682.             ap = arr = (char **) alloc(ct * sizeof(char *));
  683.  
  684.             while ((*ap++ = (char *)ugetnode(l)));
  685.             checkmailpath(arr);
  686.             popheap();
  687.         } LASTALLOC;
  688.         }
  689.     } else {
  690.         if (st.st_size && st.st_atime <= st.st_mtime &&
  691.         st.st_mtime > lastmailcheck)
  692.         if (!u) {
  693.             fprintf(stderr, "You have new mail.\n");
  694.             fflush(stderr);
  695.         } else {
  696.             char *usav = underscore;
  697.  
  698.             underscore = *s;
  699.             HEAPALLOC {
  700.             u = dupstring(u);
  701.             if (! parsestr(u)) {
  702.                 singsub(&u);
  703.                 zputs(u, stderr);
  704.                 fputc('\n', stderr);
  705.                 fflush(stderr);
  706.             }
  707.             underscore = usav;
  708.             } LASTALLOC;
  709.         }
  710.         if (isset(MAILWARNING) && st.st_atime > st.st_mtime &&
  711.         st.st_atime > lastmailcheck && st.st_size) {
  712.         fprintf(stderr, "The mail in %s has been read.\n", unmeta(*s));
  713.         fflush(stderr);
  714.         }
  715.     }
  716.     *v = c;
  717.     s++;
  718.     }
  719. }
  720.  
  721. /**/
  722. void
  723. freecompcond(void *a)
  724. {
  725.     Compcond cc = (Compcond) a;
  726.     Compcond and, or, c;
  727.     int n;
  728.  
  729.     for (c = cc; c; c = or) {
  730.     or = c->or;
  731.     for (; c; c = and) {
  732.         and = c->and;
  733.         if (c->type == CCT_POS ||
  734.         c->type == CCT_NUMWORDS) {
  735.         free(c->u.r.a);
  736.         free(c->u.r.b);
  737.         } else if (c->type == CCT_CURSUF ||
  738.                c->type == CCT_CURPRE) {
  739.         for (n = 0; n < c->n; n++)
  740.             if (c->u.s.s[n])
  741.             zsfree(c->u.s.s[n]);
  742.         free(c->u.s.s);
  743.         } else if (c->type == CCT_RANGESTR ||
  744.                c->type == CCT_RANGEPAT) {
  745.         for (n = 0; n < c->n; n++)
  746.             if (c->u.l.a[n])
  747.             zsfree(c->u.l.a[n]);
  748.         free(c->u.l.a);
  749.         for (n = 0; n < c->n; n++)
  750.             if (c->u.l.b[n])
  751.             zsfree(c->u.l.b[n]);
  752.         free(c->u.l.b);
  753.         } else {
  754.         for (n = 0; n < c->n; n++)
  755.             if (c->u.s.s[n])
  756.             zsfree(c->u.s.s[n]);
  757.         free(c->u.s.p);
  758.         free(c->u.s.s);
  759.         }
  760.         zfree(c, sizeof(struct compcond));
  761.     }
  762.     }
  763. }
  764.  
  765. /**/
  766. void
  767. freestr(void *a)
  768. {
  769.     zsfree(a);
  770. }
  771.  
  772. /**/
  773. void
  774. gettyinfo(struct ttyinfo *ti)
  775. {
  776.     if (SHTTY != -1) {
  777. #ifdef HAVE_TERMIOS_H
  778. # ifdef HAVE_TCGETATTR
  779.     if (tcgetattr(SHTTY, &ti->tio) == -1)
  780. # else
  781.     if (ioctl(SHTTY, TCGETS, &ti->tio) == -1)
  782. # endif
  783.         zerr("bad tcgets: %e", NULL, errno);
  784. #else
  785. # ifdef HAVE_TERMIO_H
  786.     ioctl(SHTTY, TCGETA, &ti->tio);
  787. # else
  788.     ioctl(SHTTY, TIOCGETP, &ti->sgttyb);
  789.     ioctl(SHTTY, TIOCLGET, &ti->lmodes);
  790.     ioctl(SHTTY, TIOCGETC, &ti->tchars);
  791.     ioctl(SHTTY, TIOCGLTC, &ti->ltchars);
  792. # endif
  793. #endif
  794.     }
  795. }
  796.  
  797. /**/
  798. void
  799. settyinfo(struct ttyinfo *ti)
  800. {
  801.     if (SHTTY != -1) {
  802. #ifdef HAVE_TERMIOS_H
  803. # ifdef HAVE_TCGETATTR
  804. #  ifndef TCSADRAIN
  805. #   define TCSADRAIN 1    /* XXX Princeton's include files are screwed up */
  806. #  endif
  807.     tcsetattr(SHTTY, TCSADRAIN, &ti->tio);
  808.     /* if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1) */
  809. # else
  810.     ioctl(SHTTY, TCSETS, &ti->tio);
  811.     /* if (ioctl(SHTTY, TCSETS, &ti->tio) == -1) */
  812. # endif
  813.     /*    zerr("settyinfo: %e",NULL,errno)*/ ;
  814. #else
  815. # ifdef HAVE_TERMIO_H
  816.     ioctl(SHTTY, TCSETA, &ti->tio);
  817. # else
  818.     ioctl(SHTTY, TIOCSETN, &ti->sgttyb);
  819.     ioctl(SHTTY, TIOCLSET, &ti->lmodes);
  820.     ioctl(SHTTY, TIOCSETC, &ti->tchars);
  821.     ioctl(SHTTY, TIOCSLTC, &ti->ltchars);
  822. # endif
  823. #endif
  824.     }
  825. }
  826.  
  827. #ifdef TIOCGWINSZ
  828. extern winchanged;
  829. #endif
  830.  
  831. /* check the size of the window and adjust if necessary. *
  832.  * The value of from:                     *
  833.  *   0: called from update_job or setupvals         *
  834.  *   1: called from the SIGWINCH handler         *
  835.  *   2: the user have just changed LINES manually     *
  836.  *   3: the user have just changed COLUMNS manually      */
  837.  
  838. /**/
  839. void
  840. adjustwinsize(int from)
  841. {
  842.     int oldcols = columns, oldrows = lines;
  843.  
  844. #ifdef TIOCGWINSZ
  845.     static int userlines, usercols;
  846.  
  847.     if (SHTTY == -1)
  848.     return;
  849.  
  850.     if (from == 2)
  851.     userlines = lines > 0;
  852.     if (from == 3)
  853.     usercols = columns > 0;
  854.  
  855.     if (!ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize)) {
  856.     if (!userlines)
  857.         lines = shttyinfo.winsize.ws_row;
  858.     if (!usercols)
  859.         columns = shttyinfo.winsize.ws_col;
  860.     }
  861. #endif   /* TIOCGWINSZ */
  862.  
  863.     if (lines <= 0)
  864.     lines = tclines > 0 ? tclines : 24;
  865.     if (columns <= 0)
  866.     columns = tccolumns > 0 ? tccolumns : 80;
  867.     if (lines > 2)
  868.     termflags &= ~TERM_SHORT;
  869.     else
  870.     termflags |= TERM_SHORT;
  871.     if (columns > 2)
  872.     termflags &= ~TERM_NARROW;
  873.     else
  874.     termflags |= TERM_NARROW;
  875.  
  876. #ifdef TIOCGWINSZ
  877.     if (from >= 2) {
  878.     shttyinfo.winsize.ws_row = lines;
  879.     shttyinfo.winsize.ws_col = columns;
  880.     ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize);
  881.     }
  882. #endif
  883.  
  884.     if (zleactive && (from >= 2 || oldcols != columns || oldrows != lines)) {
  885.     resetneeded = winchanged = 1;
  886.     refresh();
  887.     }
  888. }
  889.  
  890. /* Move a fd to a place >= 10 and mark the new fd in fdtable.  If the fd *
  891.  * is already >= 10, it is not moved.  If it is invalid, -1 is returned. */
  892.  
  893. /**/
  894. int
  895. movefd(int fd)
  896. {
  897.     if(fd != -1 && fd < 10) {
  898. #ifdef F_DUPFD
  899.     int fe = fcntl(fd, F_DUPFD, 10);
  900. #else
  901.     int fe = movefd(dup(fd));
  902. #endif
  903.     zclose(fd);
  904.     fd = fe;
  905.     }
  906.     if(fd != -1) {
  907.     if (fd > max_zsh_fd) {
  908.         while (fd >= fdtable_size)
  909.         fdtable = zrealloc(fdtable, (fdtable_size *= 2));
  910.         max_zsh_fd = fd;
  911.     }
  912.     fdtable[fd] = 1;
  913.     }
  914.     return fd;
  915. }
  916.  
  917. /* Move fd x to y.  If x == -1, fd y is closed. */
  918.  
  919. /**/
  920. void
  921. redup(int x, int y)
  922. {
  923.     if(x < 0)
  924.     zclose(y);
  925.     else if (x != y) {
  926.     while (y >= fdtable_size)
  927.         fdtable = zrealloc(fdtable, (fdtable_size *= 2));
  928.     dup2(x, y);
  929.     if ((fdtable[y] = fdtable[x]) && y > max_zsh_fd)
  930.         max_zsh_fd = y;
  931.     zclose(x);
  932.     }
  933. }
  934.  
  935. /* Close the given fd, and clear it from fdtable. */
  936.  
  937. /**/
  938. int
  939. zclose(int fd)
  940. {
  941.     if (fd >= 0) {
  942.     fdtable[fd] = 0;
  943.     while (max_zsh_fd > 0 && !fdtable[max_zsh_fd])
  944.         max_zsh_fd--;
  945.     if (fd == coprocin)
  946.         coprocin = -1;
  947.     if (fd == coprocout)
  948.         coprocout = -1;
  949.     }
  950.     return close(fd);
  951. }
  952.  
  953. /* Get a file name relative to $TMPPREFIX which *
  954.  * is unique, for use as a temporary file.      */
  955.  
  956. /**/
  957. char *
  958. gettempname(void)
  959. {
  960.     char *s;
  961.  
  962.     if (!(s = getsparam("TMPPREFIX")))
  963.     s = DEFAULT_TMPPREFIX;
  964.  
  965.     return ((char *) mktemp(dyncat(unmeta(s), "XXXXXX")));
  966. }
  967.  
  968. /* Check if a string contains a token */
  969.  
  970. /**/
  971. int
  972. has_token(const char *s)
  973. {
  974.     while(*s)
  975.     if(itok(*s++))
  976.         return 1;
  977.     return 0;
  978. }
  979.  
  980. /* Delete a character in a string */
  981.  
  982. /**/
  983. void
  984. chuck(char *str)
  985. {
  986.     while ((str[0] = str[1]))
  987.     str++;
  988. }
  989.  
  990. /**/
  991. int
  992. tulower(int c)
  993. {
  994.     c &= 0xff;
  995.     return (isupper(c) ? tolower(c) : c);
  996. }
  997.  
  998. /**/
  999. int
  1000. tuupper(int c)
  1001. {
  1002.     c &= 0xff;
  1003.     return (islower(c) ? toupper(c) : c);
  1004. }
  1005.  
  1006. /* copy len chars from t into s, and null terminate */
  1007.  
  1008. /**/
  1009. void
  1010. ztrncpy(char *s, char *t, int len)
  1011. {
  1012.     while (len--)
  1013.     *s++ = *t++;
  1014.     *s = '\0';
  1015. }
  1016.  
  1017. /* copy t into *s and update s */
  1018.  
  1019. /**/
  1020. void
  1021. strucpy(char **s, char *t)
  1022. {
  1023.     char *u = *s;
  1024.  
  1025.     while ((*u++ = *t++));
  1026.     *s = u - 1;
  1027. }
  1028.  
  1029. /**/
  1030. void
  1031. struncpy(char **s, char *t, int n)
  1032. {
  1033.     char *u = *s;
  1034.  
  1035.     while (n--)
  1036.     *u++ = *t++;
  1037.     *s = u;
  1038.     *u = '\0';
  1039. }
  1040.  
  1041. /* Return the number of elements in an array of pointers. *
  1042.  * It doesn't count the NULL pointer at the end.          */
  1043.  
  1044. /**/
  1045. int
  1046. arrlen(char **s)
  1047. {
  1048.     int count;
  1049.  
  1050.     for (count = 0; *s; s++, count++);
  1051.     return count;
  1052. }
  1053.  
  1054. /* Skip over a balanced pair of parenthesis. */
  1055.  
  1056. /**/
  1057. int
  1058. skipparens(char inpar, char outpar, char **s)
  1059. {
  1060.     int level;
  1061.  
  1062.     if (**s != inpar)
  1063.     return -1;
  1064.  
  1065.     for (level = 1; *++*s && level;)
  1066.     if (**s == inpar)
  1067.        ++level;
  1068.     else if (**s == outpar)
  1069.        --level;
  1070.  
  1071.    return level;
  1072. }
  1073.  
  1074. /* Convert string to long.  This function (without the z) *
  1075.  * is contained in the ANSI standard C library, but a lot *
  1076.  * of them seem to be broken.                             */
  1077.  
  1078. /**/
  1079. long
  1080. zstrtol(const char *s, char **t, int base)
  1081. {
  1082.     long ret = 0;
  1083.     int neg;
  1084.  
  1085.     while (inblank(*s))
  1086.     s++;
  1087.  
  1088.     if ((neg = (*s == '-')))
  1089.     s++;
  1090.     else if (*s == '+')
  1091.     s++;
  1092.  
  1093.     if (!base)
  1094.     if (*s != '0')
  1095.         base = 10;
  1096.     else if (*++s == 'x' || *s == 'X')
  1097.         base = 16, s++;
  1098.     else
  1099.         base = 8;
  1100.  
  1101.     if (base <= 10)
  1102.     for (; *s >= '0' && *s < ('0' + base); s++)
  1103.         ret = ret * base + *s - '0';
  1104.     else
  1105.     for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
  1106.          || (*s >= 'A' && *s < ('A' + base - 10)); s++)
  1107.         ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
  1108.     if (t)
  1109.     *t = (char *)s;
  1110.     return neg ? -ret : ret;
  1111. }
  1112.  
  1113. /* Convert string to quad_t. */
  1114.  
  1115. #if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_UNSIGNED)
  1116.  
  1117. /**/
  1118. rlim_t
  1119. zstrtorlimit(const char *s, char **t, int base)
  1120. {
  1121.     rlim_t ret = 0;
  1122.  
  1123.     if (!base)
  1124.     if (*s != '0')
  1125.         base = 10;
  1126.     else if (*++s == 'x' || *s == 'X')
  1127.         base = 16, s++;
  1128.     else
  1129.         base = 8;
  1130.  
  1131.     if (base <= 10)
  1132.     for (; *s >= '0' && *s < ('0' + base); s++)
  1133.         ret = ret * base + *s - '0';
  1134.     else
  1135.     for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
  1136.          || (*s >= 'A' && *s < ('A' + base - 10)); s++)
  1137.         ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
  1138.     if (t)
  1139.     *t = (char *)s;
  1140.     return ret;
  1141. }
  1142. #endif
  1143.  
  1144. /**/
  1145. int
  1146. checkrmall(char *s)
  1147. {
  1148.     fflush(stdin);
  1149.     fprintf(shout, "zsh: sure you want to delete all the files in ");
  1150.     if (*s != '/') {
  1151.     nicezputs(pwd[1] ? unmeta(pwd) : "", shout);
  1152.     fputc('/', shout);
  1153.     }
  1154.     nicezputs(s, shout);
  1155.     fputs(" [yn]? ", shout);
  1156.     fflush(shout);
  1157.     feep();
  1158.     return (getquery("ny") == 'y');
  1159. }
  1160.  
  1161. /**/
  1162. int
  1163. setblock_stdin(void)
  1164. {
  1165. #ifdef O_NONBLOCK
  1166.     struct stat st;
  1167.     long mode;
  1168.  
  1169.     if (!fstat(0, &st) && !S_ISREG(st.st_mode)) {
  1170.     mode = fcntl(0, F_GETFL);
  1171.     if (mode != -1 && (mode & O_NONBLOCK) &&
  1172.         !fcntl(0, F_SETFL, mode & ~O_NONBLOCK))
  1173.         return 1;
  1174.     }
  1175. #endif
  1176.     return 0;
  1177. }
  1178.  
  1179. /**/
  1180. int
  1181. getquery(char *valid_chars)
  1182. {
  1183.     char c, d;
  1184.     int isem = !strcmp(term, "emacs");
  1185.  
  1186. #ifdef FIONREAD
  1187.     int val = 0;
  1188. #endif
  1189.  
  1190.     attachtty(mypgrp);
  1191.     if (!isem)
  1192.     setcbreak();
  1193.  
  1194. #ifdef FIONREAD
  1195.     ioctl(SHTTY, FIONREAD, (char *)&val);
  1196.     if (val) {
  1197.     if (!isem)
  1198.         settyinfo(&shttyinfo);
  1199.     write(SHTTY, "n\n", 2);
  1200.     return 'n';
  1201.     }
  1202. #endif
  1203.     while (read(SHTTY, &c, 1) == 1) {
  1204.     if (c == 'Y' || c == '\t')
  1205.         c = 'y';
  1206.     else if (c == 'N')
  1207.         c = 'n';
  1208.     if (!valid_chars)
  1209.         break;
  1210.     if (c == '\n') {
  1211.         c = *valid_chars;
  1212.         break;
  1213.     }
  1214.     if (strchr(valid_chars, c)) {
  1215.         write(2, "\n", 1);
  1216.         break;
  1217.     }
  1218.     feep();
  1219.     if (icntrl(c))
  1220.         write(2, "\b \b", 3);
  1221.     write(2, "\b \b", 3);
  1222.     }
  1223.     if (isem) {
  1224.     if (c != '\n')
  1225.         while (read(SHTTY, &d, 1) == 1 && d != '\n');
  1226.     } else {
  1227.     settyinfo(&shttyinfo);
  1228.     if (c != '\n' && !valid_chars)
  1229.         write(2, "\n", 1);
  1230.     }
  1231.     return (int)c;
  1232. }
  1233.  
  1234. static int d;
  1235. static char *guess, *best;
  1236.  
  1237. /**/
  1238. void
  1239. spscan(HashNode hn, int scanflags)
  1240. {
  1241.     int nd;
  1242.  
  1243.     nd = spdist(hn->nam, guess, (int) strlen(guess) / 4 + 1);
  1244.     if (nd <= d) {
  1245.     best = hn->nam;
  1246.     d = nd;
  1247.     }
  1248. }
  1249.  
  1250. /* spellcheck a word */
  1251. /* fix s ; if hist is nonzero, fix the history list too */
  1252.  
  1253. /**/
  1254. void
  1255. spckword(char **s, int hist, int cmd, int ask)
  1256. {
  1257.     char *t, *u;
  1258.     int x;
  1259.     char ic = '\0';
  1260.     int ne;
  1261.     int preflen = 0;
  1262.  
  1263.     if ((histdone & HISTFLAG_NOEXEC) || **s == '-' || **s == '%')
  1264.     return;
  1265.     if (!strcmp(*s, "in"))
  1266.     return;
  1267.     if (!(*s)[0] || !(*s)[1])
  1268.     return;
  1269.     if (shfunctab->getnode(shfunctab, *s) ||
  1270.     builtintab->getnode(builtintab, *s) ||
  1271.     cmdnamtab->getnode(cmdnamtab, *s) ||
  1272.     aliastab->getnode(aliastab, *s)  ||
  1273.     reswdtab->getnode(reswdtab, *s))
  1274.     return;
  1275.     else if (isset(HASHLISTALL)) {
  1276.     cmdnamtab->filltable(cmdnamtab);
  1277.     if (cmdnamtab->getnode(cmdnamtab, *s))
  1278.         return;
  1279.     }
  1280.     t = *s;
  1281.     if (*t == Tilde || *t == Equals || *t == String)
  1282.     t++;
  1283.     for (; *t; t++)
  1284.     if (itok(*t))
  1285.         return;
  1286.     best = NULL;
  1287.     for (t = *s; *t; t++)
  1288.     if (*t == '/')
  1289.         break;
  1290.     if (**s == Tilde && !*t)
  1291.     return;
  1292.     if (**s == String && !*t) {
  1293.     guess = *s + 1;
  1294.     if (*t || !ialpha(*guess))
  1295.         return;
  1296.     ic = String;
  1297.     d = 100;
  1298.     scanhashtable(paramtab, 1, 0, 0, spscan, 0);
  1299.     } else if (**s == Equals) {
  1300.     if (*t)
  1301.         return;
  1302.     if (hashcmd(guess = *s + 1, pathchecked))
  1303.         return;
  1304.     d = 100;
  1305.     ic = Equals;
  1306.     scanhashtable(aliastab, 1, 0, 0, spscan, 0);
  1307.     scanhashtable(cmdnamtab, 1, 0, 0, spscan, 0);
  1308.     } else {
  1309.     guess = *s;
  1310.     if (*guess == Tilde || *guess == String) {
  1311.         ic = *guess;
  1312.         if (!*++t)
  1313.         return;
  1314.         guess = dupstring(guess);
  1315.         ne = noerrs;
  1316.         noerrs = 1;
  1317.         singsub(&guess);
  1318.         noerrs = ne;
  1319.         if (!guess)
  1320.         return;
  1321.         preflen = strlen(guess) - strlen(t);
  1322.     }
  1323.     if (access(unmeta(guess), F_OK) == 0)
  1324.         return;
  1325.     if ((u = spname(guess)) != guess)
  1326.         best = u;
  1327.     if (!*t && cmd) {
  1328.         if (hashcmd(guess, pathchecked))
  1329.         return;
  1330.         d = 100;
  1331.         scanhashtable(reswdtab, 1, 0, 0, spscan, 0);
  1332.         scanhashtable(aliastab, 1, 0, 0, spscan, 0);
  1333.         scanhashtable(shfunctab, 1, 0, 0, spscan, 0);
  1334.         scanhashtable(builtintab, 1, 0, 0, spscan, 0);
  1335.         scanhashtable(cmdnamtab, 1, 0, 0, spscan, 0);
  1336.     }
  1337.     }
  1338.     if (errflag)
  1339.     return;
  1340.     if (best && (int)strlen(best) > 1 && strcmp(best, guess)) {
  1341.     if (ic) {
  1342.         if (preflen) {
  1343.         /* do not correct the result of an expansion */
  1344.         if (strncmp(guess, best, preflen))
  1345.             return;
  1346.         /* replace the temporarily expanded prefix with the original */
  1347.         u = (char *) ncalloc(t - *s + strlen(best + preflen) + 1);
  1348.         strncpy(u, *s, t - *s);
  1349.         strcpy(u + (t - *s), best + preflen);
  1350.         } else {
  1351.         u = (char *) ncalloc(strlen(best) + 2);
  1352.         strcpy(u + 1, best);
  1353.         }
  1354.         best = u;
  1355.         guess = *s;
  1356.         *guess = *best = ztokens[ic - Pound];
  1357.     }
  1358.     if (ask) {
  1359.         char *pptbuf;
  1360.         int pptlen;
  1361.         rstring = best;
  1362.         Rstring = guess;
  1363.         pptbuf = putprompt(sprompt, &pptlen, NULL, 1);
  1364.         fwrite(pptbuf, pptlen, 1, stderr);
  1365.         free(pptbuf);
  1366.         fflush(stderr);
  1367.         feep();
  1368.         x = getquery("nyae ");
  1369.     } else
  1370.         x = 'y';
  1371.     if (x == 'y' || x == ' ') {
  1372.         *s = dupstring(best);
  1373.         if (hist)
  1374.         hwrep(best);
  1375.     } else if (x == 'a') {
  1376.         histdone |= HISTFLAG_NOEXEC;
  1377.     } else if (x == 'e') {
  1378.         histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL;
  1379.     }
  1380.     if (ic)
  1381.         **s = ic;
  1382.     }
  1383. }
  1384.  
  1385. /**/
  1386. int
  1387. ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm)
  1388. {
  1389. #ifndef HAVE_STRFTIME
  1390.     static char *astr[] =
  1391.     {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  1392.     static char *estr[] =
  1393.     {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  1394.      "Aug", "Sep", "Oct", "Nov", "Dec"};
  1395. #else
  1396.     char *origbuf = buf;
  1397. #endif
  1398.     static char *lstr[] =
  1399.     {"12", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9",
  1400.      "10", "11"};
  1401.     char tmp[3];
  1402.  
  1403.  
  1404.     tmp[0] = '%';
  1405.     tmp[2] = '\0';
  1406.     while (*fmt)
  1407.     if (*fmt == '%') {
  1408.         fmt++;
  1409.         switch (*fmt++) {
  1410.         case 'd':
  1411.         *buf++ = '0' + tm->tm_mday / 10;
  1412.         *buf++ = '0' + tm->tm_mday % 10;
  1413.         break;
  1414.         case 'e':
  1415.         if (tm->tm_mday > 9)
  1416.             *buf++ = '0' + tm->tm_mday / 10;
  1417.         *buf++ = '0' + tm->tm_mday % 10;
  1418.         break;
  1419.         case 'k':
  1420.         if (tm->tm_hour > 9)
  1421.             *buf++ = '0' + tm->tm_hour / 10;
  1422.         *buf++ = '0' + tm->tm_hour % 10;
  1423.         break;
  1424.         case 'l':
  1425.         strucpy(&buf, lstr[tm->tm_hour % 12]);
  1426.         break;
  1427.         case 'm':
  1428.         *buf++ = '0' + (tm->tm_mon + 1) / 10;
  1429.         *buf++ = '0' + (tm->tm_mon + 1) % 10;
  1430.         break;
  1431.         case 'M':
  1432.         *buf++ = '0' + tm->tm_min / 10;
  1433.         *buf++ = '0' + tm->tm_min % 10;
  1434.         break;
  1435.         case 'S':
  1436.         *buf++ = '0' + tm->tm_sec / 10;
  1437.         *buf++ = '0' + tm->tm_sec % 10;
  1438.         break;
  1439.         case 'y':
  1440.         *buf++ = '0' + tm->tm_year / 10;
  1441.         *buf++ = '0' + tm->tm_year % 10;
  1442.         break;
  1443. #ifndef HAVE_STRFTIME
  1444.         case 'a':
  1445.         strucpy(&buf, astr[tm->tm_wday]);
  1446.         break;
  1447.         case 'b':
  1448.         strucpy(&buf, estr[tm->tm_mon]);
  1449.         break;
  1450.         case 'p':
  1451.         *buf++ = (tm->tm_hour > 11) ? 'p' : 'a';
  1452.         *buf++ = 'm';
  1453.         break;
  1454.         default:
  1455.         *buf++ = '%';
  1456.         if (fmt[-1] != '%')
  1457.             *buf++ = fmt[-1];
  1458. #else
  1459.         default:
  1460.         *buf = '\0';
  1461.         tmp[1] = fmt[-1];
  1462.         strftime(buf, bufsize - strlen(origbuf), tmp, tm);
  1463.         buf += strlen(buf);
  1464. #endif
  1465.         break;
  1466.         }
  1467.     } else
  1468.         *buf++ = *fmt++;
  1469.     *buf = '\0';
  1470.     return 0;
  1471. }
  1472.  
  1473. /**/
  1474. char *
  1475. zjoin(char **arr, int delim)
  1476. {
  1477.     int len = 0;
  1478.     char **s, *ret, *ptr;
  1479.  
  1480.     for (s = arr; *s; s++)
  1481.     len += strlen(*s) + 1;
  1482.     if (!len)
  1483.     return "";
  1484.     ptr = ret = (char *) ncalloc(len);
  1485.     for (s = arr; *s; s++) {
  1486.     strucpy(&ptr, *s);
  1487.     if (delim)
  1488.         *ptr++ = delim;
  1489.     }
  1490.     ptr[-1] = '\0';
  1491.     return ret;
  1492. }
  1493.  
  1494. /* Split a string containing a colon separated list *
  1495.  * of items into an array of strings.               */
  1496.  
  1497. /**/
  1498. char **
  1499. colonsplit(char *s, int uniq)
  1500. {
  1501.     int ct;
  1502.     char *t, **ret, **ptr, **p;
  1503.  
  1504.     for (t = s, ct = 0; *t; t++) /* count number of colons */
  1505.     if (*t == ':')
  1506.         ct++;
  1507.     ptr = ret = (char **) zalloc(sizeof(char **) * (ct + 2));
  1508.  
  1509.     t = s;
  1510.     do {
  1511.     s = t;
  1512.         /* move t to point at next colon */
  1513.     for (; *t && *t != ':'; t++);
  1514.     if (uniq)
  1515.         for (p = ret; p < ptr; p++)
  1516.         if (strlen(*p) == t - s && ! strncmp(*p, s, t - s))
  1517.             goto cont;
  1518.     *ptr = (char *) zalloc((t - s) + 1);
  1519.     ztrncpy(*ptr++, s, t - s);
  1520.       cont: ;
  1521.     }
  1522.     while (*t++);
  1523.     *ptr = NULL;
  1524.     return ret;
  1525. }
  1526.  
  1527. /**/
  1528. int
  1529. skipwsep(char **s)
  1530. {
  1531.     char *t = *s;
  1532.     int i = 0;
  1533.  
  1534.     while (*t && iwsep(*t == Meta ? t[1] ^ 32 : *t)) {
  1535.     if (*t == Meta)
  1536.         t++;
  1537.     t++;
  1538.     i++;
  1539.     }
  1540.     *s = t;
  1541.     return i;
  1542. }
  1543.  
  1544. /**/
  1545. char **
  1546. spacesplit(char *s, int allownull)
  1547. {
  1548.     char *t, **ret, **ptr;
  1549.  
  1550.     ptr = ret = (char **) ncalloc(sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1));
  1551.  
  1552.     t = s;
  1553.     skipwsep(&s);
  1554.     if (*s && isep(*s == Meta ? s[1] ^ 32 : *s))
  1555.     *ptr++ = dupstring(allownull ? "" : nulstring);
  1556.     else if (!allownull && t != s)
  1557.     *ptr++ = dupstring("");
  1558.     while (*s) {
  1559.     if (isep(*s == Meta ? s[1] ^ 32 : *s)) {
  1560.         if (*s == Meta)
  1561.         s++;
  1562.         s++;
  1563.         skipwsep(&s);
  1564.     }
  1565.     t = s;
  1566.     findsep(&s, NULL);
  1567.     if (s > t || allownull) {
  1568.         *ptr = (char *) ncalloc((s - t) + 1);
  1569.         ztrncpy(*ptr++, t, s - t);
  1570.     } else
  1571.         *ptr++ = dupstring(nulstring);
  1572.     t = s;
  1573.     skipwsep(&s);
  1574.     }
  1575.     if (!allownull && t != s)
  1576.     *ptr++ = dupstring("");
  1577.     *ptr = NULL;
  1578.     return ret;
  1579. }
  1580.  
  1581. /**/
  1582. int
  1583. findsep(char **s, char *sep)
  1584. {
  1585.     int i;
  1586.     char *t, *tt;
  1587.  
  1588.     if (!sep) {
  1589.     for (t = *s; *t; t++) {
  1590.         if (*t == Meta) {
  1591.         if (isep(t[1] ^ 32))
  1592.             break;
  1593.         t++;
  1594.         } else if (isep(*t))
  1595.         break;
  1596.     }
  1597.     i = t - *s;
  1598.     *s = t;
  1599.     return i;
  1600.     }
  1601.     if (!sep[0]) {
  1602.     return **s ? ++*s, 1 : -1;
  1603.     }
  1604.     for (i = 0; **s; i++) {
  1605.     for (t = sep, tt = *s; *t && *tt && *t == *tt; t++, tt++);
  1606.     if (!*t)
  1607.         return i;
  1608.     if (*(*s)++ == Meta) {
  1609.         (*s)++;
  1610. #ifdef DEBUG
  1611.         if (! **s)
  1612.         fprintf(stderr, "BUG: unexpected end of string in findsep()\n");
  1613. #endif
  1614.     }
  1615.     }
  1616.     return -1;
  1617. }
  1618.  
  1619. /**/
  1620. char *
  1621. findword(char **s, char *sep)
  1622. {
  1623.     char *r, *t;
  1624.     int sl;
  1625.  
  1626.     if (!**s)
  1627.     return NULL;
  1628.  
  1629.     if (sep) {
  1630.     sl = strlen(sep);
  1631.     r = *s;
  1632.     while (! findsep(s, sep)) {
  1633.         r = *s += sl;
  1634.     }
  1635.     return r;
  1636.     }
  1637.     for (t = *s; *t; t++) {
  1638.     if (*t == Meta) {
  1639.         if (! isep(t[1] ^ 32))
  1640.         break;
  1641.         t++;
  1642.     } else if (! isep(*t))
  1643.         break;
  1644.     }
  1645.     *s = t;
  1646.     findsep(s, sep);
  1647.     return t;
  1648. }
  1649.  
  1650. /**/
  1651. int
  1652. wordcount(char *s, char *sep, int mul)
  1653. {
  1654.     int r, sl, c;
  1655.  
  1656.     if (sep) {
  1657.     r = 1;
  1658.     sl = strlen(sep);
  1659.     for (; (c = findsep(&s, sep)) >= 0; s += sl)
  1660.         if ((c && *(s + sl)) || mul)
  1661.         r++;
  1662.     } else {
  1663.     char *t = s;
  1664.  
  1665.     r = 0;
  1666.     if (mul <= 0)
  1667.         skipwsep(&s);
  1668.     if ((*s && isep(*s == Meta ? s[1] ^ 32 : *s)) ||
  1669.         (mul < 0 && t != s))
  1670.         r++;
  1671.     for (; *s; r++) {
  1672.         if (isep(*s == Meta ? s[1] ^ 32 : *s)) {
  1673.         if (*s == Meta)
  1674.             s++;
  1675.         s++;
  1676.         if (mul <= 0)
  1677.             skipwsep(&s);
  1678.         }
  1679.         findsep(&s, NULL);
  1680.         t = s;
  1681.         if (mul <= 0)
  1682.         skipwsep(&s);
  1683.     }
  1684.     if (mul < 0 && t != s)
  1685.         r++;
  1686.     }
  1687.     return r;
  1688. }
  1689.  
  1690. /**/
  1691. char *
  1692. sepjoin(char **s, char *sep)
  1693. {
  1694.     char *r, *p, **t;
  1695.     int l, sl, elide = 0;
  1696.     char sepbuf[3];
  1697.  
  1698.     if (!*s)
  1699.     return "";
  1700.     if (!sep) {
  1701.     elide = 1;
  1702.     sep = sepbuf;
  1703.     sepbuf[0] = *ifs;
  1704.     sepbuf[1] = *ifs == Meta ? ifs[1] ^ 32 : '\0';
  1705.     sepbuf[2] = '\0';
  1706.     }
  1707.     sl = strlen(sep);
  1708.     for (t = s, l = 1 - sl; *t; l += strlen(*t) + sl, t++);
  1709.     r = p = (char *) ncalloc(l);
  1710.     t = s;
  1711.     while (*t) {
  1712.     strucpy(&p, *t);
  1713.     if (*++t)
  1714.         strucpy(&p, sep);
  1715.     }
  1716.     *p = '\0';
  1717.     return r;
  1718. }
  1719.  
  1720. /**/
  1721. char **
  1722. sepsplit(char *s, char *sep, int allownull)
  1723. {
  1724.     int n, sl;
  1725.     char *t, *tt, **r, **p;
  1726.  
  1727.     if (!sep)
  1728.     return spacesplit(s, allownull);
  1729.  
  1730.     sl = strlen(sep);
  1731.     n = wordcount(s, sep, 1);
  1732.     r = p = (char **) ncalloc((n + 1) * sizeof(char *));
  1733.  
  1734.     for (t = s; n--;) {
  1735.     tt = t;
  1736.     findsep(&t, sep);
  1737.     *p = (char *) ncalloc(t - tt + 1);
  1738.     strncpy(*p, tt, t - tt);
  1739.     (*p)[t - tt] = '\0';
  1740.     p++;
  1741.     t += sl;
  1742.     }
  1743.     *p = NULL;
  1744.  
  1745.     return r;
  1746. }
  1747.  
  1748. /* Get the definition of a shell function */
  1749.  
  1750. /**/
  1751. List
  1752. getshfunc(char *nam)
  1753. {
  1754.     Shfunc shf;
  1755.     List l;
  1756.  
  1757.     if ((shf = (Shfunc) shfunctab->getnode(shfunctab, nam))) {
  1758.     /* if autoloaded and currently undefined */
  1759.     if (shf->flags & PM_UNDEFINED) {
  1760.         if (!(l = getfpfunc(nam))) {
  1761.         zerr("function not found: %s", nam, 0);
  1762.         return NULL;
  1763.         }
  1764.         shf->flags &= ~PM_UNDEFINED;
  1765.         PERMALLOC {
  1766.         shf->funcdef = (List) dupstruct(l);
  1767.         } LASTALLOC;
  1768.     }
  1769.     return shf->funcdef;
  1770.     } else {
  1771.     return NULL;
  1772.     }
  1773. }
  1774.  
  1775. /* allocate a tree element */
  1776.  
  1777. static int sizetab[N_COUNT] =
  1778. {
  1779.     sizeof(struct list),
  1780.     sizeof(struct sublist),
  1781.     sizeof(struct pline),
  1782.     sizeof(struct cmd),
  1783.     sizeof(struct redir),
  1784.     sizeof(struct cond),
  1785.     sizeof(struct forcmd),
  1786.     sizeof(struct casecmd),
  1787.     sizeof(struct ifcmd),
  1788.     sizeof(struct whilecmd),
  1789.     sizeof(struct varasg)};
  1790.  
  1791. static int flagtab[N_COUNT] =
  1792. {
  1793.     NT_SET(N_LIST, 1, NT_NODE, NT_NODE, 0, 0),
  1794.     NT_SET(N_SUBLIST, 2, NT_NODE, NT_NODE, 0, 0),
  1795.     NT_SET(N_PLINE, 1, NT_NODE, NT_NODE, 0, 0),
  1796.     NT_SET(N_CMD, 2, NT_STR | NT_LIST, NT_NODE, NT_NODE | NT_LIST, NT_NODE | NT_LIST),
  1797.     NT_SET(N_REDIR, 3, NT_STR, 0, 0, 0),
  1798.     NT_SET(N_COND, 1, NT_NODE, NT_NODE, 0, 0),
  1799.     NT_SET(N_FOR, 1, NT_STR, NT_NODE, 0, 0),
  1800.     NT_SET(N_CASE, 0, NT_STR | NT_ARR, NT_NODE | NT_ARR, 0, 0),
  1801.     NT_SET(N_IF, 0, NT_NODE | NT_ARR, NT_NODE | NT_ARR, 0, 0),
  1802.     NT_SET(N_WHILE, 1, NT_NODE, NT_NODE, 0, 0),
  1803.     NT_SET(N_VARASG, 1, NT_STR, NT_STR, NT_STR | NT_LIST, 0)};
  1804.  
  1805. /**/
  1806. void *
  1807. allocnode(int type)
  1808. {
  1809.     struct node *n;
  1810.  
  1811.     n = (struct node *) alloc(sizetab[type]);
  1812.     memset((void *) n, 0, sizetab[type]);
  1813.     n->ntype = flagtab[type];
  1814.     if (useheap)
  1815.     n->ntype |= NT_HEAP;
  1816.  
  1817.     return (void *) n;
  1818. }
  1819.  
  1820. /**/
  1821. void *
  1822. dupstruct(void *a)
  1823. {
  1824.     struct node *n, *r;
  1825.  
  1826.     n = (struct node *) a;
  1827.     if (!a || ((List) a) == &dummy_list)
  1828.     return (void *) a;
  1829.  
  1830.     if ((n->ntype & NT_HEAP) && !useheap) {
  1831.     HEAPALLOC {
  1832.         n = (struct node *) dupstruct2((void *) n);
  1833.     } LASTALLOC;
  1834.     n = simplifystruct(n);
  1835.     }
  1836.     r = (struct node *)dupstruct2((void *) n);
  1837.  
  1838.     if (!(n->ntype & NT_HEAP) && useheap)
  1839.     r = expandstruct(r, N_LIST);
  1840.  
  1841.     return (void *) r;
  1842. }
  1843.  
  1844. /**/
  1845. struct node *
  1846. simplifystruct(struct node *n)
  1847. {
  1848.     if (!n || ((List) n) == &dummy_list)
  1849.     return n;
  1850.  
  1851.     switch (NT_TYPE(n->ntype)) {
  1852.     case N_LIST:
  1853.     {
  1854.         List l = (List) n;
  1855.  
  1856.         l->left = (Sublist) simplifystruct((struct node *)l->left);
  1857.         if ((l->type & Z_SYNC) && !l->right)
  1858.         return (struct node *)l->left;
  1859.     }
  1860.     break;
  1861.     case N_SUBLIST:
  1862.     {
  1863.         Sublist sl = (Sublist) n;
  1864.  
  1865.         sl->left = (Pline) simplifystruct((struct node *)sl->left);
  1866.         if (sl->type == END && !sl->flags && !sl->right)
  1867.         return (struct node *)sl->left;
  1868.     }
  1869.     break;
  1870.     case N_PLINE:
  1871.     {
  1872.         Pline pl = (Pline) n;
  1873.  
  1874.         pl->left = (Cmd) simplifystruct((struct node *)pl->left);
  1875.         if (pl->type == END && !pl->right)
  1876.         return (struct node *)pl->left;
  1877.     }
  1878.     break;
  1879.     case N_CMD:
  1880.     {
  1881.         Cmd c = (Cmd) n;
  1882.         int i = 0;
  1883.  
  1884.         if (empty(c->args))
  1885.         c->args = NULL, i++;
  1886.         if (empty(c->redir))
  1887.         c->redir = NULL, i++;
  1888.         if (empty(c->vars))
  1889.         c->vars = NULL, i++;
  1890.  
  1891.         c->u.list = (List) simplifystruct((struct node *)c->u.list);
  1892.         if (i == 3 && !c->flags &&
  1893.         (c->type == CWHILE || c->type == CIF ||
  1894.          c->type == COND))
  1895.         return (struct node *)c->u.list;
  1896.     }
  1897.     break;
  1898.     case N_FOR:
  1899.     {
  1900.         Forcmd f = (Forcmd) n;
  1901.  
  1902.         f->list = (List) simplifystruct((struct node *)f->list);
  1903.     }
  1904.     break;
  1905.     case N_CASE:
  1906.     {
  1907.         struct casecmd *c = (struct casecmd *)n;
  1908.         List *l;
  1909.  
  1910.         for (l = c->lists; *l; l++)
  1911.         *l = (List) simplifystruct((struct node *)*l);
  1912.     }
  1913.     break;
  1914.     case N_IF:
  1915.     {
  1916.         struct ifcmd *i = (struct ifcmd *)n;
  1917.         List *l;
  1918.  
  1919.         for (l = i->ifls; *l; l++)
  1920.         *l = (List) simplifystruct((struct node *)*l);
  1921.         for (l = i->thenls; *l; l++)
  1922.         *l = (List) simplifystruct((struct node *)*l);
  1923.     }
  1924.     break;
  1925.     case N_WHILE:
  1926.     {
  1927.         struct whilecmd *w = (struct whilecmd *)n;
  1928.  
  1929.         w->cont = (List) simplifystruct((struct node *)w->cont);
  1930.         w->loop = (List) simplifystruct((struct node *)w->loop);
  1931.     }
  1932.     }
  1933.  
  1934.     return n;
  1935. }
  1936.  
  1937. /**/
  1938. struct node *
  1939. expandstruct(struct node *n, int exp)
  1940. {
  1941.     struct node *m;
  1942.  
  1943.     if (!n || ((List) n) == &dummy_list)
  1944.     return n;
  1945.  
  1946.     if (exp != N_COUNT && exp != NT_TYPE(n->ntype)) {
  1947.     switch (exp) {
  1948.     case N_LIST:
  1949.         {
  1950.         List l;
  1951.  
  1952.         m = (struct node *) allocnode(N_LIST);
  1953.         l = (List) m;
  1954.         l->type = Z_SYNC;
  1955.         l->left = (Sublist) expandstruct(n, N_SUBLIST);
  1956.  
  1957.         return (struct node *)l;
  1958.         }
  1959.     case N_SUBLIST:
  1960.         {
  1961.         Sublist sl;
  1962.  
  1963.         m = (struct node *) allocnode(N_SUBLIST);
  1964.         sl = (Sublist) m;
  1965.         sl->type = END;
  1966.         sl->left = (Pline) expandstruct(n, N_PLINE);
  1967.  
  1968.         return (struct node *)sl;
  1969.         }
  1970.     case N_PLINE:
  1971.         {
  1972.         Pline pl;
  1973.  
  1974.         m = (struct node *) allocnode(N_PLINE);
  1975.         pl = (Pline) m;
  1976.         pl->type = END;
  1977.         pl->left = (Cmd) expandstruct(n, N_CMD);
  1978.  
  1979.         return (struct node *)pl;
  1980.         }
  1981.     case N_CMD:
  1982.         {
  1983.         Cmd c;
  1984.  
  1985.         m = (struct node *) allocnode(N_CMD);
  1986.         c = (Cmd) m;
  1987.         switch (NT_TYPE(n->ntype)) {
  1988.         case N_WHILE:
  1989.             c->type = CWHILE;
  1990.             break;
  1991.         case N_IF:
  1992.             c->type = CIF;
  1993.             break;
  1994.         case N_COND:
  1995.             c->type = COND;
  1996.         }
  1997.         c->u.list = (List) expandstruct(n, NT_TYPE(n->ntype));
  1998.         c->args = newlinklist();
  1999.         c->vars = newlinklist();
  2000.         c->redir = newlinklist();
  2001.  
  2002.         return (struct node *)c;
  2003.         }
  2004.     }
  2005.     } else
  2006.     switch (NT_TYPE(n->ntype)) {
  2007.     case N_LIST:
  2008.         {
  2009.         List l = (List) n;
  2010.  
  2011.         l->left = (Sublist) expandstruct((struct node *)l->left,
  2012.                          N_SUBLIST);
  2013.         l->right = (List) expandstruct((struct node *)l->right,
  2014.                            N_LIST);
  2015.         }
  2016.         break;
  2017.     case N_SUBLIST:
  2018.         {
  2019.         Sublist sl = (Sublist) n;
  2020.  
  2021.         sl->left = (Pline) expandstruct((struct node *)sl->left,
  2022.                         N_PLINE);
  2023.         sl->right = (Sublist) expandstruct((struct node *)sl->right,
  2024.                            N_SUBLIST);
  2025.         }
  2026.         break;
  2027.     case N_PLINE:
  2028.         {
  2029.         Pline pl = (Pline) n;
  2030.  
  2031.         pl->left = (Cmd) expandstruct((struct node *)pl->left,
  2032.                           N_CMD);
  2033.         pl->right = (Pline) expandstruct((struct node *)pl->right,
  2034.                          N_PLINE);
  2035.         }
  2036.         break;
  2037.     case N_CMD:
  2038.         {
  2039.         Cmd c = (Cmd) n;
  2040.  
  2041.         if (!c->args)
  2042.             c->args = newlinklist();
  2043.         if (!c->vars)
  2044.             c->vars = newlinklist();
  2045.         if (!c->redir)
  2046.             c->redir = newlinklist();
  2047.  
  2048.         switch (c->type) {
  2049.         case CFOR:
  2050.         case CSELECT:
  2051.             c->u.list = (List) expandstruct((struct node *)c->u.list,
  2052.                             N_FOR);
  2053.             break;
  2054.         case CWHILE:
  2055.             c->u.list = (List) expandstruct((struct node *)c->u.list,
  2056.                             N_WHILE);
  2057.             break;
  2058.         case CIF:
  2059.             c->u.list = (List) expandstruct((struct node *)c->u.list,
  2060.                             N_IF);
  2061.             break;
  2062.         case CCASE:
  2063.             c->u.list = (List) expandstruct((struct node *)c->u.list,
  2064.                             N_CASE);
  2065.             break;
  2066.         case COND:
  2067.             c->u.list = (List) expandstruct((struct node *)c->u.list,
  2068.                             N_COND);
  2069.             break;
  2070.         case ZCTIME:
  2071.             c->u.list = (List) expandstruct((struct node *)c->u.list,
  2072.                             N_SUBLIST);
  2073.             break;
  2074.         default:
  2075.             c->u.list = (List) expandstruct((struct node *)c->u.list,
  2076.                             N_LIST);
  2077.         }
  2078.         }
  2079.         break;
  2080.     case N_FOR:
  2081.         {
  2082.         Forcmd f = (Forcmd) n;
  2083.  
  2084.         f->list = (List) expandstruct((struct node *)f->list,
  2085.                           N_LIST);
  2086.         }
  2087.         break;
  2088.     case N_CASE:
  2089.         {
  2090.         struct casecmd *c = (struct casecmd *)n;
  2091.         List *l;
  2092.  
  2093.         for (l = c->lists; *l; l++)
  2094.             *l = (List) expandstruct((struct node *)*l, N_LIST);
  2095.         }
  2096.         break;
  2097.     case N_IF:
  2098.         {
  2099.         struct ifcmd *i = (struct ifcmd *)n;
  2100.         List *l;
  2101.  
  2102.         for (l = i->ifls; *l; l++)
  2103.             *l = (List) expandstruct((struct node *)*l, N_LIST);
  2104.         for (l = i->thenls; *l; l++)
  2105.             *l = (List) expandstruct((struct node *)*l, N_LIST);
  2106.         }
  2107.         break;
  2108.     case N_WHILE:
  2109.         {
  2110.         struct whilecmd *w = (struct whilecmd *)n;
  2111.  
  2112.         w->cont = (List) expandstruct((struct node *)w->cont,
  2113.                           N_LIST);
  2114.         w->loop = (List) expandstruct((struct node *)w->loop,
  2115.                           N_LIST);
  2116.         }
  2117.     }
  2118.  
  2119.     return n;
  2120. }
  2121.  
  2122. /* duplicate a syntax tree node of given type, argument number */
  2123.  
  2124. /**/
  2125. void *
  2126. dupnode(int type, void *a, int argnum)
  2127. {
  2128.     if (!a)
  2129.     return NULL;
  2130.     switch (NT_N(type, argnum)) {
  2131.     case NT_NODE:
  2132.     return (void *) dupstruct2(a);
  2133.     case NT_STR:
  2134.     return (useheap) ? ((void *) dupstring(a)) :
  2135.         ((void *) ztrdup(a));
  2136.     case NT_LIST | NT_NODE:
  2137.     if (type & NT_HEAP)
  2138.         if (useheap)
  2139.         return (void *) duplist(a, (VFunc) dupstruct2);
  2140.         else
  2141.         return (void *) list2arr(a, (VFunc) dupstruct2);
  2142.     else if (useheap)
  2143.         return (void *) arr2list(a, (VFunc) dupstruct2);
  2144.     else
  2145.         return (void *) duparray(a, (VFunc) dupstruct2);
  2146.     case NT_LIST | NT_STR:
  2147.     if (type & NT_HEAP)
  2148.         if (useheap)
  2149.         return (void *) duplist(a, (VFunc) dupstring);
  2150.         else
  2151.         return (void *) list2arr(a, (VFunc) ztrdup);
  2152.     else if (useheap)
  2153.         return (void *) arr2list(a, (VFunc) dupstring);
  2154.     else
  2155.         return (void *) duparray(a, (VFunc) ztrdup);
  2156.     case NT_NODE | NT_ARR:
  2157.     return (void *) duparray(a, (VFunc) dupstruct2);
  2158.     case NT_STR | NT_ARR:
  2159.     return (void *) duparray(a, (VFunc) (useheap ? dupstring : ztrdup));
  2160.     default:
  2161.     abort();
  2162.     }
  2163. }
  2164.  
  2165. /* Free a syntax tree node of given type, argument number */
  2166.  
  2167. /**/
  2168. void
  2169. freetreenode(int type, void *a, int argnum)
  2170. {
  2171.     if (!a)
  2172.     return;
  2173.     switch (NT_N(type, argnum)) {
  2174.     case NT_NODE:
  2175.     freestruct(a);
  2176.     break;
  2177.     case NT_STR:
  2178.     zsfree(a);
  2179.     break;
  2180.     case NT_LIST | NT_NODE:
  2181.     case NT_NODE | NT_ARR:
  2182.     {
  2183.         char **p = (char **)a;
  2184.  
  2185.         while (*p)
  2186.         freestruct(*p++);
  2187.         free(a);
  2188.     }
  2189.     break;
  2190.     case NT_LIST | NT_STR:
  2191.     case NT_STR | NT_ARR:
  2192.     freearray(a);
  2193.     break;
  2194.     default:
  2195.     abort();
  2196.     }
  2197. }
  2198.  
  2199. /* duplicate a syntax tree */
  2200.  
  2201. /**/
  2202. void **
  2203. dupstruct2(void *a)
  2204. {
  2205.     struct node *n = (struct node *)a, *m;
  2206.     int type;
  2207.  
  2208.     if (!n || ((List) n) == &dummy_list)
  2209.     return a;
  2210.     type = n->ntype;
  2211.     m = (struct node *) alloc(sizetab[NT_TYPE(type)]);
  2212.     m->ntype = (type & ~NT_HEAP);
  2213.     if (useheap)
  2214.     m->ntype |= NT_HEAP;
  2215.     switch (NT_TYPE(type)) {
  2216.     case N_LIST:
  2217.     {
  2218.         List nl = (List) n;
  2219.         List ml = (List) m;
  2220.  
  2221.         ml->type = nl->type;
  2222.         ml->left = (Sublist) dupnode(type, nl->left, 0);
  2223.         ml->right = (List) dupnode(type, nl->right, 1);
  2224.     }
  2225.     break;
  2226.     case N_SUBLIST:
  2227.     {
  2228.         Sublist nsl = (Sublist) n;
  2229.         Sublist msl = (Sublist) m;
  2230.  
  2231.         msl->type = nsl->type;
  2232.         msl->flags = nsl->flags;
  2233.         msl->left = (Pline) dupnode(type, nsl->left, 0);
  2234.         msl->right = (Sublist) dupnode(type, nsl->right, 1);
  2235.     }
  2236.     break;
  2237.     case N_PLINE:
  2238.     {
  2239.         Pline npl = (Pline) n;
  2240.         Pline mpl = (Pline) m;
  2241.  
  2242.         mpl->type = npl->type;
  2243.         mpl->left = (Cmd) dupnode(type, npl->left, 0);
  2244.         mpl->right = (Pline) dupnode(type, npl->right, 1);
  2245.     }
  2246.     break;
  2247.     case N_CMD:
  2248.     {
  2249.         Cmd nc = (Cmd) n;
  2250.         Cmd mc = (Cmd) m;
  2251.  
  2252.         mc->type = nc->type;
  2253.         mc->flags = nc->flags;
  2254.         mc->lineno = nc->lineno;
  2255.         mc->args = (LinkList) dupnode(type, nc->args, 0);
  2256.         mc->u.generic = (void *) dupnode(type, nc->u.generic, 1);
  2257.         mc->redir = (LinkList) dupnode(type, nc->redir, 2);
  2258.         mc->vars = (LinkList) dupnode(type, nc->vars, 3);
  2259.     }
  2260.     break;
  2261.     case N_REDIR:
  2262.     {
  2263.         Redir nr = (Redir) n;
  2264.         Redir mr = (Redir) m;
  2265.  
  2266.         mr->type = nr->type;
  2267.         mr->fd1 = nr->fd1;
  2268.         mr->fd2 = nr->fd2;
  2269.         mr->name = (char *)dupnode(type, nr->name, 0);
  2270.     }
  2271.     break;
  2272.     case N_COND:
  2273.     {
  2274.         Cond nco = (Cond) n;
  2275.         Cond mco = (Cond) m;
  2276.  
  2277.         mco->type = nco->type;
  2278.         mco->left = (void *) dupnode(type, nco->left, 0);
  2279.         mco->right = (void *) dupnode(type, nco->right, 1);
  2280.     }
  2281.     break;
  2282.     case N_FOR:
  2283.     {
  2284.         Forcmd nf = (Forcmd) n;
  2285.         Forcmd mf = (Forcmd) m;
  2286.  
  2287.         mf->inflag = nf->inflag;
  2288.         mf->name = (char *)dupnode(type, nf->name, 0);
  2289.         mf->list = (List) dupnode(type, nf->list, 1);
  2290.     }
  2291.     break;
  2292.     case N_CASE:
  2293.     {
  2294.         struct casecmd *ncc = (struct casecmd *)n;
  2295.         struct casecmd *mcc = (struct casecmd *)m;
  2296.  
  2297.         mcc->pats = (char **)dupnode(type, ncc->pats, 0);
  2298.         mcc->lists = (List *) dupnode(type, ncc->lists, 1);
  2299.     }
  2300.     break;
  2301.     case N_IF:
  2302.     {
  2303.         struct ifcmd *nic = (struct ifcmd *)n;
  2304.         struct ifcmd *mic = (struct ifcmd *)m;
  2305.  
  2306.         mic->ifls = (List *) dupnode(type, nic->ifls, 0);
  2307.         mic->thenls = (List *) dupnode(type, nic->thenls, 1);
  2308.  
  2309.     }
  2310.     break;
  2311.     case N_WHILE:
  2312.     {
  2313.         struct whilecmd *nwc = (struct whilecmd *)n;
  2314.         struct whilecmd *mwc = (struct whilecmd *)m;
  2315.  
  2316.         mwc->cond = nwc->cond;
  2317.         mwc->cont = (List) dupnode(type, nwc->cont, 0);
  2318.         mwc->loop = (List) dupnode(type, nwc->loop, 1);
  2319.     }
  2320.     break;
  2321.     case N_VARASG:
  2322.     {
  2323.         Varasg nva = (Varasg) n;
  2324.         Varasg mva = (Varasg) m;
  2325.  
  2326.         mva->type = nva->type;
  2327.         mva->name = (char *)dupnode(type, nva->name, 0);
  2328.         mva->str = (char *)dupnode(type, nva->str, 1);
  2329.         mva->arr = (LinkList) dupnode(type, nva->arr, 2);
  2330.     }
  2331.     break;
  2332.     }
  2333.     return (void **) m;
  2334. }
  2335.  
  2336. /* free a syntax tree */
  2337.  
  2338. /**/
  2339. void
  2340. freestruct(void *a)
  2341. {
  2342.     struct node *n = (struct node *)a;
  2343.     int type;
  2344.  
  2345.     if (!n || ((List) n) == &dummy_list)
  2346.     return;
  2347.  
  2348.     type = n->ntype;
  2349.     switch (NT_TYPE(type)) {
  2350.     case N_LIST:
  2351.     {
  2352.         List nl = (List) n;
  2353.  
  2354.         freetreenode(type, nl->left, 0);
  2355.         freetreenode(type, nl->right, 1);
  2356.     }
  2357.     break;
  2358.     case N_SUBLIST:
  2359.     {
  2360.         Sublist nsl = (Sublist) n;
  2361.  
  2362.         freetreenode(type, nsl->left, 0);
  2363.         freetreenode(type, nsl->right, 1);
  2364.     }
  2365.     break;
  2366.     case N_PLINE:
  2367.     {
  2368.         Pline npl = (Pline) n;
  2369.  
  2370.         freetreenode(type, npl->left, 0);
  2371.         freetreenode(type, npl->right, 1);
  2372.     }
  2373.     break;
  2374.     case N_CMD:
  2375.     {
  2376.         Cmd nc = (Cmd) n;
  2377.  
  2378.         freetreenode(type, nc->args, 0);
  2379.         freetreenode(type, nc->u.generic, 1);
  2380.         freetreenode(type, nc->redir, 2);
  2381.         freetreenode(type, nc->vars, 3);
  2382.     }
  2383.     break;
  2384.     case N_REDIR:
  2385.     {
  2386.         Redir nr = (Redir) n;
  2387.  
  2388.         freetreenode(type, nr->name, 0);
  2389.     }
  2390.     break;
  2391.     case N_COND:
  2392.     {
  2393.         Cond nco = (Cond) n;
  2394.  
  2395.         freetreenode(type, nco->left, 0);
  2396.         freetreenode(type, nco->right, 1);
  2397.     }
  2398.     break;
  2399.     case N_FOR:
  2400.     {
  2401.         Forcmd nf = (Forcmd) n;
  2402.  
  2403.         freetreenode(type, nf->name, 0);
  2404.         freetreenode(type, nf->list, 1);
  2405.     }
  2406.     break;
  2407.     case N_CASE:
  2408.     {
  2409.         struct casecmd *ncc = (struct casecmd *)n;
  2410.  
  2411.         freetreenode(type, ncc->pats, 0);
  2412.         freetreenode(type, ncc->lists, 1);
  2413.     }
  2414.     break;
  2415.     case N_IF:
  2416.     {
  2417.         struct ifcmd *nic = (struct ifcmd *)n;
  2418.  
  2419.         freetreenode(type, nic->ifls, 0);
  2420.         freetreenode(type, nic->thenls, 1);
  2421.  
  2422.     }
  2423.     break;
  2424.     case N_WHILE:
  2425.     {
  2426.         struct whilecmd *nwc = (struct whilecmd *)n;
  2427.  
  2428.         freetreenode(type, nwc->cont, 0);
  2429.         freetreenode(type, nwc->loop, 1);
  2430.     }
  2431.     break;
  2432.     case N_VARASG:
  2433.     {
  2434.         Varasg nva = (Varasg) n;
  2435.  
  2436.         freetreenode(type, nva->name, 0);
  2437.         freetreenode(type, nva->str, 1);
  2438.         freetreenode(type, nva->arr, 2);
  2439.     }
  2440.     break;
  2441.     }
  2442.     zfree(n, sizetab[NT_TYPE(type)]);
  2443. }
  2444.  
  2445. /**/
  2446. LinkList
  2447. duplist(LinkList l, VFunc func)
  2448. {
  2449.     LinkList ret;
  2450.     LinkNode node;
  2451.  
  2452.     ret = newlinklist();
  2453.     for (node = firstnode(l); node; incnode(node))
  2454.     addlinknode(ret, func(getdata(node)));
  2455.     return ret;
  2456. }
  2457.  
  2458. /**/
  2459. char **
  2460. duparray(char **arr, VFunc func)
  2461. {
  2462.     char **ret, **rr;
  2463.  
  2464.     ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *));
  2465.     for (rr = ret; *arr;)
  2466.     *rr++ = (char *)func(*arr++);
  2467.     *rr = NULL;
  2468.  
  2469.     return ret;
  2470. }
  2471.  
  2472. /**/
  2473. char **
  2474. list2arr(LinkList l, VFunc func)
  2475. {
  2476.     char **arr, **r;
  2477.     LinkNode n;
  2478.  
  2479.     arr = r = (char **) alloc((countlinknodes(l) + 1) * sizeof(char *));
  2480.  
  2481.     for (n = firstnode(l); n; incnode(n))
  2482.     *r++ = (char *)func(getdata(n));
  2483.     *r = NULL;
  2484.  
  2485.     return arr;
  2486. }
  2487.  
  2488. /**/
  2489. LinkList
  2490. arr2list(char **arr, VFunc func)
  2491. {
  2492.     LinkList l = newlinklist();
  2493.  
  2494.     while (*arr)
  2495.     addlinknode(l, func(*arr++));
  2496.  
  2497.     return l;
  2498. }
  2499.  
  2500. /**/
  2501. char **
  2502. mkarray(char *s)
  2503. {
  2504.     char **t = (char **) zalloc((s) ? (2 * sizeof s) : (sizeof s));
  2505.  
  2506.     if ((*t = s))
  2507.     t[1] = NULL;
  2508.     return t;
  2509. }
  2510.  
  2511. /**/
  2512. void
  2513. feep(void)
  2514. {
  2515.     if (isset(BEEP))
  2516.     write(2, "\07", 1);
  2517. }
  2518.  
  2519. /**/
  2520. void
  2521. freearray(char **s)
  2522. {
  2523.     char **t = s;
  2524.  
  2525.     while (*s)
  2526.     zsfree(*s++);
  2527.     free(t);
  2528. }
  2529.  
  2530. /**/
  2531. int
  2532. equalsplit(char *s, char **t)
  2533. {
  2534.     for (; *s && *s != '='; s++);
  2535.     if (*s == '=') {
  2536.     *s++ = '\0';
  2537.     *t = s;
  2538.     return 1;
  2539.     }
  2540.     return 0;
  2541. }
  2542.  
  2543. /* see if the right side of a list is trivial */
  2544.  
  2545. /**/
  2546. void
  2547. simplifyright(List l)
  2548. {
  2549.     Cmd c;
  2550.  
  2551.     if (l == &dummy_list || !l->right)
  2552.     return;
  2553.     if (l->right->right || l->right->left->right ||
  2554.     l->right->left->flags || l->right->left->left->right ||
  2555.     l->left->flags)
  2556.     return;
  2557.     c = l->left->left->left;
  2558.     if (c->type != SIMPLE || nonempty(c->args) || nonempty(c->redir)
  2559.     || nonempty(c->vars))
  2560.     return;
  2561.     l->right = NULL;
  2562.     return;
  2563. }
  2564.  
  2565. /* initialize the ztypes table */
  2566.  
  2567. /**/
  2568. void
  2569. inittyptab(void)
  2570. {
  2571.     int t0;
  2572.     char *s;
  2573.  
  2574.     for (t0 = 0; t0 != 256; t0++)
  2575.     typtab[t0] = 0;
  2576.     for (t0 = 0; t0 != 32; t0++)
  2577.     typtab[t0] = typtab[t0 + 128] = ICNTRL;
  2578.     typtab[127] = ICNTRL;
  2579.     for (t0 = '0'; t0 <= '9'; t0++)
  2580.     typtab[t0] = IDIGIT | IALNUM | IWORD | IIDENT | IUSER;
  2581.     for (t0 = 'a'; t0 <= 'z'; t0++)
  2582.     typtab[t0] = typtab[t0 - 'a' + 'A'] = IALPHA | IALNUM | IIDENT | IUSER | IWORD;
  2583.     for (t0 = 0240; t0 != 0400; t0++)
  2584.     typtab[t0] = IALPHA | IALNUM | IIDENT | IUSER | IWORD;
  2585.     typtab['_'] = IIDENT | IUSER;
  2586.     typtab['-'] = IUSER;
  2587.     typtab[' '] |= IBLANK | INBLANK;
  2588.     typtab['\t'] |= IBLANK | INBLANK;
  2589.     typtab['\n'] |= INBLANK;
  2590.     typtab['\0'] |= IMETA;
  2591.     typtab[STOUC(Meta)  ] |= IMETA;
  2592.     typtab[STOUC(Marker)] |= IMETA;
  2593.     for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Nularg); t0++)
  2594.     typtab[t0] |= ITOK | IMETA;
  2595.     for (s = ifs ? ifs : DEFAULT_IFS; *s; s++) {
  2596.     if (inblank(*s))
  2597.         if (s[1] == *s)
  2598.         s++;
  2599.         else
  2600.         typtab[STOUC(*s)] |= IWSEP;
  2601.     typtab[STOUC(*s == Meta ? *++s ^ 32 : *s)] |= ISEP;
  2602.     }
  2603.     for (s = wordchars ? wordchars : DEFAULT_WORDCHARS; *s; s++)
  2604.     typtab[STOUC(*s == Meta ? *++s ^ 32 : *s)] |= IWORD;
  2605.     for (s = SPECCHARS; *s; s++)
  2606.     typtab[STOUC(*s)] |= ISPECIAL;
  2607.     if (isset(BANGHIST) && bangchar && interact && isset(SHINSTDIN))
  2608.     typtab[bangchar] |= ISPECIAL;
  2609. }
  2610.  
  2611. /**/
  2612. char **
  2613. arrdup(char **s)
  2614. {
  2615.     char **x, **y;
  2616.  
  2617.     y = x = (char **) ncalloc(sizeof(char *) * (arrlen(s) + 1));
  2618.  
  2619.     while ((*x++ = dupstring(*s++)));
  2620.     return y;
  2621. }
  2622.  
  2623. /**/
  2624. char *
  2625. spname(char *oldname)
  2626. {
  2627.     char *p, spnameguess[PATH_MAX + 1], spnamebest[PATH_MAX + 1];
  2628.     static char newname[PATH_MAX + 1];
  2629.     char *new = newname, *old;
  2630.     int bestdist = 200, thisdist;
  2631.  
  2632.     old = oldname;
  2633.     for (;;) {
  2634.     while (*old == '/')
  2635.         *new++ = *old++;
  2636.     *new = '\0';
  2637.     if (*old == '\0')
  2638.         return newname;
  2639.     p = spnameguess;
  2640.     for (; *old != '/' && *old != '\0'; old++)
  2641.         if (p < spnameguess + PATH_MAX)
  2642.         *p++ = *old;
  2643.     *p = '\0';
  2644.     if ((thisdist = mindist(newname, spnameguess, spnamebest)) >= 3) {
  2645.         if (bestdist < 3) {
  2646.         strcpy(new, spnameguess);
  2647.         strcat(new, old);
  2648.         return newname;
  2649.         } else
  2650.             return NULL;
  2651.     } else
  2652.         bestdist = thisdist;
  2653.     for (p = spnamebest; (*new = *p++);)
  2654.         new++;
  2655.     }
  2656. }
  2657.  
  2658. /**/
  2659. int
  2660. mindist(char *dir, char *mindistguess, char *mindistbest)
  2661. {
  2662.     int mindistd, nd;
  2663.     DIR *dd;
  2664.     char *fn;
  2665.     char buf[PATH_MAX];
  2666.  
  2667.     if (dir[0] == '\0')
  2668.     dir = ".";
  2669.     mindistd = 100;
  2670.     sprintf(buf, "%s/%s", dir, mindistguess);
  2671.     if (access(unmeta(buf), F_OK) == 0) {
  2672.     strcpy(mindistbest, mindistguess);
  2673.     return 0;
  2674.     }
  2675.     if (!(dd = opendir(unmeta(dir))))
  2676.     return mindistd;
  2677.     while ((fn = zreaddir(dd))) {
  2678.     nd = spdist(fn, mindistguess,
  2679.             (int)strlen(mindistguess) / 4 + 1);
  2680.     if (nd <= mindistd) {
  2681.         strcpy(mindistbest, fn);
  2682.         mindistd = nd;
  2683.         if (mindistd == 0)
  2684.         break;
  2685.     }
  2686.     }
  2687.     closedir(dd);
  2688.     return mindistd;
  2689. }
  2690.  
  2691. /**/
  2692. int
  2693. spdist(char *s, char *t, int thresh)
  2694. {
  2695.     char *p, *q;
  2696.     char *keymap =
  2697.     "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  2698. \t1234567890-=\t\
  2699. \tqwertyuiop[]\t\
  2700. \tasdfghjkl;'\n\t\
  2701. \tzxcvbnm,./\t\t\t\
  2702. \n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  2703. \t!@#$%^&*()_+\t\
  2704. \tQWERTYUIOP{}\t\
  2705. \tASDFGHJKL:\"\n\t\
  2706. \tZXCVBNM<>?\n\n\t\
  2707. \n\n\n\n\n\n\n\n\n\n\n\n\n\n";
  2708.  
  2709.     if (!strcmp(s, t))
  2710.     return 0;
  2711. /* any number of upper/lower mistakes allowed (dist = 1) */
  2712.     for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++, q++);
  2713.     if (!*p && !*q)
  2714.     return 1;
  2715.     if (!thresh)
  2716.     return 200;
  2717.     for (p = s, q = t; *p && *q; p++, q++)
  2718.     if (*p == *q)
  2719.         continue;        /* don't consider "aa" transposed, ash */
  2720.     else if (p[1] == q[0] && q[1] == p[0])    /* transpositions */
  2721.         return spdist(p + 2, q + 2, thresh - 1) + 1;
  2722.     else if (p[1] == q[0])    /* missing letter */
  2723.         return spdist(p + 1, q + 0, thresh - 1) + 2;
  2724.     else if (p[0] == q[1])    /* missing letter */
  2725.         return spdist(p + 0, q + 1, thresh - 1) + 2;
  2726.     else if (*p != *q)
  2727.         break;
  2728.     if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1))
  2729.     return 2;
  2730.     for (p = s, q = t; *p && *q; p++, q++)
  2731.     if (p[0] != q[0] && p[1] == q[1]) {
  2732.         int t0;
  2733.         char *z;
  2734.  
  2735.     /* mistyped letter */
  2736.  
  2737.         if (!(z = strchr(keymap, p[0])) || *z == '\n' || *z == '\t')
  2738.         return spdist(p + 1, q + 1, thresh - 1) + 1;
  2739.         t0 = z - keymap;
  2740.         if (*q == keymap[t0 - 15] || *q == keymap[t0 - 14] ||
  2741.         *q == keymap[t0 - 13] ||
  2742.         *q == keymap[t0 - 1] || *q == keymap[t0 + 1] ||
  2743.         *q == keymap[t0 + 13] || *q == keymap[t0 + 14] ||
  2744.         *q == keymap[t0 + 15])
  2745.         return spdist(p + 1, q + 1, thresh - 1) + 2;
  2746.         return 200;
  2747.     } else if (*p != *q)
  2748.         break;
  2749.     return 200;
  2750. }
  2751.  
  2752. /* set cbreak mode, or the equivalent */
  2753.  
  2754. /**/
  2755. void
  2756. setcbreak(void)
  2757. {
  2758.     struct ttyinfo ti;
  2759.  
  2760.     ti = shttyinfo;
  2761. #ifdef HAS_TIO
  2762.     ti.tio.c_lflag &= ~ICANON;
  2763.     ti.tio.c_cc[VMIN] = 1;
  2764.     ti.tio.c_cc[VTIME] = 0;
  2765. #else
  2766.     ti.sgttyb.sg_flags |= CBREAK;
  2767. #endif
  2768.     settyinfo(&ti);
  2769. }
  2770.  
  2771. /* give the tty to some process */
  2772.  
  2773. /**/
  2774. void
  2775. attachtty(pid_t pgrp)
  2776. {
  2777.     static int ep = 0;
  2778.  
  2779.     if (jobbing) {
  2780. #ifdef HAVE_TCSETPGRP
  2781.     if (SHTTY != -1 && tcsetpgrp(SHTTY, pgrp) == -1 && !ep)
  2782. #else
  2783. # if ardent
  2784.     if (SHTTY != -1 && setpgrp() == -1 && !ep)
  2785. # else
  2786.     int arg = pgrp;
  2787.  
  2788.     if (SHTTY != -1 && ioctl(SHTTY, TIOCSPGRP, &arg) == -1 && !ep)
  2789. # endif
  2790. #endif
  2791.     {
  2792.         if (pgrp != mypgrp && kill(pgrp, 0) == -1)
  2793.         attachtty(mypgrp);
  2794.         else {
  2795.         if (errno != ENOTTY)
  2796.         {
  2797.             zerr("can't set tty pgrp: %e", NULL, errno);
  2798.             fflush(stderr);
  2799.         }
  2800.         opts[MONITOR] = 0;
  2801.         ep = 1;
  2802.         errflag = 0;
  2803.         }
  2804.     }
  2805.     }
  2806. }
  2807.  
  2808. /* get the process group associated with the tty */
  2809.  
  2810. /**/
  2811. pid_t
  2812. gettygrp(void)
  2813. {
  2814.     pid_t arg;
  2815.  
  2816.     if (SHTTY == -1)
  2817.     return -1;
  2818.  
  2819. #ifdef HAVE_TCSETPGRP
  2820.     arg = tcgetpgrp(SHTTY);
  2821. #else
  2822.     ioctl(SHTTY, TIOCGPGRP, &arg);
  2823. #endif
  2824.  
  2825.     return arg;
  2826. }
  2827.  
  2828. /* Return the output baudrate */
  2829.  
  2830. #ifdef HAVE_SELECT
  2831. /**/
  2832. long
  2833. getbaudrate(struct ttyinfo *shttyinfo)
  2834. {
  2835.     long speedcode;
  2836.  
  2837. #ifdef HAS_TIO
  2838. # if defined(HAVE_TCGETATTR) && defined(HAVE_TERMIOS_H)
  2839.     speedcode = cfgetospeed(&shttyinfo->tio);
  2840. # else
  2841.     speedcode = shttyinfo->tio.c_cflag & CBAUD;
  2842. # endif
  2843. #else
  2844.     speedcode = shttyinfo->sgttyb.sg_ospeed;
  2845. #endif
  2846.  
  2847.     switch (speedcode) {
  2848.     case B0:
  2849.     return (0L);
  2850.     case B50:
  2851.     return (50L);
  2852.     case B75:
  2853.     return (75L);
  2854.     case B110:
  2855.     return (110L);
  2856.     case B134:
  2857.     return (134L);
  2858.     case B150:
  2859.     return (150L);
  2860.     case B200:
  2861.     return (200L);
  2862.     case B300:
  2863.     return (300L);
  2864.     case B600:
  2865.     return (600L);
  2866. #ifdef _B900
  2867.     case _B900:
  2868.     return (900L);
  2869. #endif
  2870.     case B1200:
  2871.     return (1200L);
  2872.     case B1800:
  2873.     return (1800L);
  2874.     case B2400:
  2875.     return (2400L);
  2876. #ifdef _B3600
  2877.     case _B3600:
  2878.     return (3600L);
  2879. #endif
  2880.     case B4800:
  2881.     return (4800L);
  2882. #ifdef _B7200
  2883.     case _B7200:
  2884.     return (7200L);
  2885. #endif
  2886.     case B9600:
  2887.     return (9600L);
  2888. #ifdef B19200
  2889.     case B19200:
  2890.     return (19200L);
  2891. #else
  2892. # ifdef EXTA
  2893.     case EXTA:
  2894.     return (19200L);
  2895. # endif
  2896. #endif
  2897. #ifdef B38400
  2898.     case B38400:
  2899.     return (38400L);
  2900. #else
  2901. # ifdef EXTB
  2902.     case EXTB:
  2903.     return (38400L);
  2904. # endif
  2905. #endif
  2906. #ifdef B57600
  2907.     case B57600:
  2908.     return (57600L);
  2909. #endif
  2910. #ifdef B115200
  2911.     case B115200:
  2912.     return (115200L);
  2913. #endif
  2914. #ifdef B230400
  2915.     case B230400:
  2916.     return (230400L);
  2917. #endif
  2918. #ifdef B460800
  2919.     case B460800:
  2920.     return (460800L);
  2921. #endif
  2922.     default:
  2923.     if (speedcode >= 100)
  2924.         return speedcode;
  2925.     break;
  2926.     }
  2927.     return (0L);
  2928. }
  2929. #endif
  2930.  
  2931. /* Escape tokens and null characters.  Buf is the string which should be    *
  2932.  * escaped.  len is the length of the string.  If len is -1, buf should     *
  2933.  * be null terminated.  If len is non-zero and the third paramerer is not   *
  2934.  * META_DUP buf should point to an at least len+1 long memory area.  The    *
  2935.  * return value points to the quoted string.  If the given string does not  *
  2936.  * contain any special character which should be quoted and the third       *
  2937.  * parameter is not META_DUP, buf is returned unchanged (a terminating null *
  2938.  * character is appended to buf if necessary).  Otherwise the third `heap'  *
  2939.  * argument determines the method used to allocate space for the result.    *
  2940.  * It can have the following values:                                        *
  2941.  *   META_REALLOC: use zrealloc on buf                                      *
  2942.  *   META_USEHEAP: get memory from the heap                                 *
  2943.  *   META_NOALLOC: buf points to a memory area which is long enough to hold *
  2944.  *                 the quoted form, just quote it and return buf.           *
  2945.  *   META_STATIC:  store the quoted string in a static area.  The original  *
  2946.  *                 sting should be at most PATH_MAX long.                   *
  2947.  *   META_ALLOC:   allocate memory for the new string with zalloc().        *
  2948.  *   META_DUP:     leave buf unchanged and allocate space for the return    *
  2949.  *                 value even if buf does not contains special characters   *
  2950.  *   META_HEAPDUP: same as META_DUP, but uses the heap                      */
  2951.  
  2952. /**/
  2953. char *
  2954. metafy(char *buf, int len, int heap)
  2955. {
  2956.     int meta = 0;
  2957.     char *t, *p, *e;
  2958.     static char mbuf[PATH_MAX*2+1];
  2959.  
  2960.     if (len == -1) {
  2961.     for (e = buf, len = 0; *e; len++)
  2962.         if (imeta(*e++))
  2963.         meta++;
  2964.     } else
  2965.     for (e = buf; e < buf + len;)
  2966.         if (imeta(*e++))
  2967.         meta++;
  2968.  
  2969.     if (meta || heap == META_DUP || heap == META_HEAPDUP) {
  2970.     switch (heap) {
  2971.     case META_REALLOC:
  2972.         buf = zrealloc(buf, len + meta + 1);
  2973.         break;
  2974.     case META_USEHEAP:
  2975.         buf = hrealloc(buf, len, len + meta + 1);
  2976.         break;
  2977.     case META_ALLOC:
  2978.     case META_DUP:
  2979.         buf = memcpy(zalloc(len + meta + 1), buf, len);
  2980.         break;
  2981.     case META_HEAPDUP:
  2982.         buf = memcpy(halloc(len + meta + 1), buf, len);
  2983.         break;
  2984.     case META_STATIC:
  2985. #ifdef DEBUG
  2986.         if (len > PATH_MAX) {
  2987.         fprintf(stderr, "BUG: len = %d > PATH_MAX in metafy\n", len);
  2988.         fflush(stderr);
  2989.         }
  2990. #endif
  2991.         buf = memcpy(mbuf, buf, len);
  2992.         break;
  2993. #ifdef DEBUG
  2994.     case META_NOALLOC:
  2995.         break;
  2996.     default:
  2997.         fprintf(stderr, "BUG: metafy called with invaild heap value\n");
  2998.         fflush(stderr);
  2999.         break;
  3000. #endif
  3001.     }
  3002.     p = buf + len;
  3003.     e = t = buf + len + meta;
  3004.     while (meta) {
  3005.         if (imeta(*--t = *--p)) {
  3006.         *t-- ^= 32;
  3007.         *t = Meta;
  3008.         meta--;
  3009.         }
  3010.     }
  3011.     }
  3012.     *e = '\0';
  3013.     return buf;
  3014. }
  3015.  
  3016. /**/
  3017. char *
  3018. unmetafy(char *s, int *len)
  3019. {
  3020.     char *p, *t;
  3021.  
  3022.     for (p = s; *p && *p != Meta; p++);
  3023.     for (t = p; (*t = *p++);)
  3024.     if (*t++ == Meta)
  3025.         t[-1] = *p++ ^ 32;
  3026.     if (len)
  3027.     *len = t - s;
  3028.     return s;
  3029. }
  3030.  
  3031. /* Return the character length of a metafied substring, given the      *
  3032.  * unmetafied substring length.                                        */
  3033.  
  3034. /**/
  3035. int
  3036. metalen(char *s, int len)
  3037. {
  3038.     int mlen = len;
  3039.  
  3040.     while (len--) {
  3041.     if (*s++ == Meta) {
  3042.         mlen++;
  3043.         s++;
  3044.     }
  3045.     }
  3046.     return mlen;
  3047. }
  3048.  
  3049. /* This function converts a zsh internal string to a form which can be *
  3050.  * passed to a system call as a filename.  The result is stored in a   *
  3051.  * single static area.  NULL returned if the result is longer than     *
  3052.  * PATH_MAX.                                                           */
  3053.  
  3054. /**/
  3055. char *
  3056. unmeta(char *file_name)
  3057. {
  3058.     static char fn[PATH_MAX];
  3059.     char *p, *t;
  3060.  
  3061.     for (t = file_name, p = fn; *t && p < fn + PATH_MAX - 1; p++)
  3062.     if ((*p = *t++) == Meta)
  3063.         *p = *t++ ^ 32;
  3064.     if (*t)
  3065.     return NULL;
  3066.     if (p - fn == t - file_name)
  3067.     return file_name;
  3068.     *p = '\0';
  3069.     return fn;
  3070. }
  3071.  
  3072. /* Unmetafy and compare two strings, with unsigned characters. *
  3073.  * "a\0" sorts after "a".                                      */
  3074.  
  3075. /**/
  3076. int
  3077. ztrcmp(unsigned char const *s1, unsigned char const *s2)
  3078. {
  3079.     int c1, c2;
  3080.  
  3081.     while(*s1 && *s1 == *s2) {
  3082.     s1++;
  3083.     s2++;
  3084.     }
  3085.  
  3086.     if(!(c1 = *s1))
  3087.     c1 = -1;
  3088.     else if(c1 == STOUC(Meta))
  3089.     c1 = *++s1 ^ 32;
  3090.     if(!(c2 = *s2))
  3091.     c2 = -1;
  3092.     else if(c2 == STOUC(Meta))
  3093.     c2 = *++s2 ^ 32;
  3094.  
  3095.     if(c1 == c2)
  3096.     return 0;
  3097.     else if(c1 < c2)
  3098.     return -1;
  3099.     else
  3100.     return 1;
  3101. }
  3102.  
  3103. /* Return zero if the metafied string s and the non-metafied,  *
  3104.  * len-long string r are the same.  Return -1 if r is a prefix *
  3105.  * of s.  Return 1 if r is the lowercase version of s.  Return *
  3106.  * 2 is r is the lowercase prefix of s and return 3 otherwise. */
  3107.  
  3108. /**/
  3109. int
  3110. metadiffer(char const *s, char const *r, int len)
  3111. {
  3112.     int l = len;
  3113.  
  3114.     while (l-- && *s && *r++ == (*s == Meta ? *++s ^ 32 : *s))
  3115.     s++;
  3116.     if (*s && l < 0)
  3117.     return -1;
  3118.     if (l < 0)
  3119.     return 0;
  3120.     if (!*s)
  3121.     return 3;
  3122.     s -= len - l - 1;
  3123.     r -= len - l;
  3124.     while (len-- && *s && *r++ == tulower(*s == Meta ? *++s ^ 32 : *s))
  3125.     s++;
  3126.     if (*s && len < 0)
  3127.     return 2;
  3128.     if (len < 0)
  3129.     return 1;
  3130.     return 3;
  3131. }
  3132.  
  3133. /* Return the unmetafied length of a metafied string. */
  3134.  
  3135. /**/
  3136. int
  3137. ztrlen(char const *s)
  3138. {
  3139.     int l;
  3140.  
  3141.     for (l = 0; *s; l++)
  3142.     if (*s++ == Meta) {
  3143. #ifdef DEBUG
  3144.         if (! *s)
  3145.         fprintf(stderr, "BUG: unexpected end of string in ztrlen()\n");
  3146.         else
  3147. #endif
  3148.         s++;
  3149.     }
  3150.     return l;
  3151. }
  3152.  
  3153. /* Subtract two pointers in a metafied string. */
  3154.  
  3155. /**/
  3156. int
  3157. ztrsub(char const *t, char const *s)
  3158. {
  3159.     int l = t - s;
  3160.  
  3161.     while (s != t)
  3162.     if (*s++ == Meta) {
  3163. #ifdef DEBUG
  3164.         if (! *s || s == t)
  3165.         fprintf(stderr, "BUG: substring ends in the middle of a metachar in ztrsub()\n");
  3166.         else
  3167. #endif
  3168.         s++;
  3169.         l--;
  3170.     }
  3171.     return l;
  3172. }
  3173.  
  3174. /**/
  3175. char *
  3176. zreaddir(DIR *dir)
  3177. {
  3178.     struct dirent *de = readdir(dir);
  3179.  
  3180.     return de ? metafy(de->d_name, -1, META_STATIC) : NULL;
  3181. }
  3182.  
  3183. /* Unmetafy and output a string. */
  3184.  
  3185. /**/
  3186. int
  3187. zputs(char const *s, FILE *stream)
  3188. {
  3189.     int c;
  3190.  
  3191.     while (*s) {
  3192.     if (*s == Meta)
  3193.         c = *++s ^ 32;
  3194.     else
  3195.         c = *s;
  3196.     s++;
  3197.     if (fputc(c, stream) < 0)
  3198.         return EOF;
  3199.     }
  3200.     return 0;
  3201. }
  3202.  
  3203. /* Unmetafy and output a string, displaying special characters readably. */
  3204.  
  3205. /**/
  3206. int
  3207. nicezputs(char const *s, FILE *stream)
  3208. {
  3209.     int c;
  3210.  
  3211.     while ((c = *s++)) {
  3212.     if (itok(c))
  3213.         if (c <= Comma)
  3214.         c = ztokens[c - Pound];
  3215.         else 
  3216.         continue;
  3217.     if (c == Meta)
  3218.         c = *s++ ^ 32;
  3219.     if(fputs(nicechar(c), stream) < 0)
  3220.         return EOF;
  3221.     }
  3222.     return 0;
  3223. }
  3224.  
  3225. /* Return the length of the visible representation of a metafied string. */
  3226.  
  3227. /**/
  3228. size_t
  3229. niceztrlen(char const *s)
  3230. {
  3231.     size_t l = 0;
  3232.     int c;
  3233.  
  3234.     while ((c = *s++)) {
  3235.     if (itok(c))
  3236.         if (c <= Comma)
  3237.         c = ztokens[c - Pound];
  3238.         else 
  3239.         continue;
  3240.     if (c == Meta)
  3241.         c = *s++ ^ 32;
  3242.     l += strlen(nicechar(STOUC(c)));
  3243.     }
  3244.     return l;
  3245. }
  3246.  
  3247. /* check for special characters in the string */
  3248.  
  3249. /**/
  3250. int
  3251. hasspecial(char const *s)
  3252. {
  3253.     for (; *s; s++)
  3254.     if (ispecial(*s == Meta ? *++s ^ 32 : *s))
  3255.         return 1;
  3256.     return 0;
  3257. }
  3258.  
  3259. /* Unmetafy and output a string, quoted if it contains special characters. */
  3260.  
  3261. /**/
  3262. int
  3263. quotedzputs(char const *s, FILE *stream)
  3264. {
  3265.     int inquote = 0, c;
  3266.  
  3267.     /* check for empty string */
  3268.     if(!*s)
  3269.     return fputs("''", stream);
  3270.  
  3271.     if (!hasspecial(s))
  3272.     return zputs(s, stream);
  3273.  
  3274.     if (isset(RCQUOTES)) {
  3275.     /* use rc-style quotes-within-quotes for the whole string */
  3276.     if(fputc('\'', stream) < 0)
  3277.         return EOF;
  3278.     while(*s) {
  3279.         if (*s == Meta)
  3280.         c = *++s ^ 32;
  3281.         else
  3282.         c = *s;
  3283.         s++;
  3284.         if (c == '\'') {
  3285.         if(fputc('\'', stream) < 0)
  3286.             return EOF;
  3287.         } else if(c == '\n' && isset(CSHJUNKIEQUOTES)) {
  3288.         if(fputc('\\', stream) < 0)
  3289.             return EOF;
  3290.         }
  3291.         if(fputc(c, stream) < 0)
  3292.         return EOF;
  3293.     }
  3294.     if(fputc('\'', stream) < 0)
  3295.         return EOF;
  3296.     } else {
  3297.     /* use Bourne-style quoting, avoiding empty quoted strings */
  3298.     while(*s) {
  3299.         if (*s == Meta)
  3300.         c = *++s ^ 32;
  3301.         else
  3302.         c = *s;
  3303.         s++;
  3304.         if (c == '\'') {
  3305.         if(inquote) {
  3306.             if(fputc('\'', stream) < 0)
  3307.             return EOF;
  3308.             inquote=0;
  3309.         }
  3310.         if(fputs("\\'", stream) < 0)
  3311.             return EOF;
  3312.         } else {
  3313.         if (!inquote) {
  3314.             if(fputc('\'', stream) < 0)
  3315.             return EOF;
  3316.             inquote=1;
  3317.         }
  3318.         if(c == '\n' && isset(CSHJUNKIEQUOTES)) {
  3319.             if(fputc('\\', stream) < 0)
  3320.             return EOF;
  3321.         }
  3322.         if(fputc(c, stream) < 0)
  3323.             return EOF;
  3324.         }
  3325.     }
  3326.     if (inquote) {
  3327.         if(fputc('\'', stream) < 0)
  3328.         return EOF;
  3329.     }
  3330.     }
  3331.     return 0;
  3332. }
  3333.  
  3334. /* Identify an option name */
  3335.  
  3336. /**/
  3337. int
  3338. optlookup(char *s)
  3339. {
  3340.     char *t;
  3341.     int optno, starts_no;
  3342.  
  3343.     t = s = dupstring(s);
  3344.  
  3345.     /* exorcise underscores, and change to lowercase */
  3346.     while (*t)
  3347.     if (*t == '_')
  3348.         chuck(t);
  3349.     else {
  3350.         *t = tulower(*t);
  3351.         t++;
  3352.     }
  3353.     starts_no = (s[0] == 'n' && s[1] == 'o');
  3354.  
  3355.     /* search for name in table */
  3356.     for (optno = OPT_SIZE; --optno; ) {
  3357.     if (!strcmp(optns[optno].name, s))
  3358.         return optno;
  3359.     if (starts_no && !strcmp(optns[optno].name, s+2))
  3360.         return -optno;
  3361.     }
  3362.  
  3363.     return 0;
  3364. }
  3365.  
  3366. /* Identify an option letter */
  3367.  
  3368. /**/
  3369. int
  3370. optlookupc(char c)
  3371. {
  3372.     int optno;
  3373.  
  3374.     if(!c || (c & OPT_REV))
  3375.     return 0;
  3376.  
  3377.     /* search for letter in the table */
  3378.     for (optno = OPT_SIZE; --optno; ) {
  3379.     char id = optid(optns[optno]);
  3380.     if (id == c)
  3381.         return optno;
  3382.     if (id == (char)(c | OPT_REV))
  3383.         return -optno;
  3384.     }
  3385.  
  3386.     return 0;
  3387. }
  3388.  
  3389. /* Set or unset an option.  The option number may be negative, indicating *
  3390.  * that the sense is reversed from the usual meaning of the option.       */
  3391.  
  3392. /**/
  3393. int
  3394. dosetopt(int optno, int value, int force)
  3395. {
  3396.     if(!optno)
  3397.     return -1;
  3398.     if(optno < 0) {
  3399.     optno = -optno;
  3400.     value = !value;
  3401.     }
  3402.     if(!force && (optno == INTERACTIVE || optno == SHINSTDIN ||
  3403.         optno == SINGLECOMMAND)) {
  3404.     /* it is not permitted to change the value of these options */
  3405.     return -1;
  3406.     } else if(!force && optno == USEZLE && value) {
  3407.     /* we require a terminal in order to use ZLE */
  3408.     if(!interact || SHTTY == -1 || !shout)
  3409.         return -1;
  3410.     } else if(optno == PRIVILEGED && !value) {
  3411.     /* unsetting PRIVILEGED causes the shell to make itself unprivileged */
  3412. #ifdef HAVE_SETUID
  3413.     setuid(getuid());
  3414.     setgid(getgid());
  3415. #endif /* HAVE_SETUID */
  3416.     }
  3417.     opts[optno] = value;
  3418.     if (optno == BANGHIST || optno == SHINSTDIN)
  3419.     inittyptab();
  3420.     return 0;
  3421. }
  3422.  
  3423. /**/
  3424. char *
  3425. dupstrpfx(const char *s, int len)
  3426. {
  3427.     char *r = ncalloc(len + 1);
  3428.  
  3429.     memcpy(r, s, len);
  3430.     r[len] = '\0';
  3431.     return r;
  3432. }
  3433.  
  3434. /**/
  3435. char *
  3436. ztrduppfx(const char *s, int len)
  3437. {
  3438.     char *r = zalloc(len + 1);
  3439.  
  3440.     memcpy(r, s, len);
  3441.     r[len] = '\0';
  3442.     return r;
  3443. }
  3444.  
  3445. #ifdef DEBUG
  3446.  
  3447. /**/
  3448. void
  3449. dputs(char *message)
  3450. {
  3451.     fprintf(stderr, "%s\n", message);
  3452.     fflush(stderr);
  3453. }
  3454. #endif
  3455.