home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / utils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  54.8 KB  |  2,939 lines

  1. /*
  2.  *
  3.  * utils.c - miscellaneous utilities
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made.
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk.
  18.  *
  19.  */
  20.  
  21. #include "zsh.h"
  22. #include <pwd.h>
  23. #include <errno.h>
  24. #include <fcntl.h>
  25.  
  26. /* source a file */
  27.  
  28. int source(s)            /**/
  29. char *s;
  30. {
  31.     int fd, cj = thisjob;
  32.     int oldlineno = lineno, oldshst;
  33.     FILE *obshin = bshin;
  34.     int osubsh = subsh;
  35.  
  36.     fd = SHIN;
  37.     lineno = 0;
  38.     oldshst = opts[SHINSTDIN];
  39.     opts[SHINSTDIN] = OPT_UNSET;
  40.     if ((SHIN = movefd(open(s, O_RDONLY))) == -1) {
  41.     SHIN = fd;
  42.     thisjob = cj;
  43.     opts[SHINSTDIN] = oldshst;
  44.     return 1;
  45.     }
  46.     bshin = fdopen(SHIN, "r");
  47.     subsh = 0;
  48.     sourcelevel++;
  49.     loop(0);
  50.     sourcelevel--;
  51.     fclose(bshin);
  52.     bshin = obshin;
  53.     subsh = osubsh;
  54.     opts[SHINSTDIN] = oldshst;
  55.     SHIN = fd;
  56.     thisjob = cj;
  57.     errflag = 0;
  58.     retflag = 0;
  59.     lineno = oldlineno;
  60.     return 0;
  61. }
  62.  
  63. /* try to source a file in the home directory */
  64.  
  65. void sourcehome(s)        /**/
  66. char *s;
  67. {
  68.     char buf[MAXPATHLEN];
  69.     char *h;
  70.  
  71.     if (!(h = getsparam("ZDOTDIR")))
  72.     h = home;
  73.     sprintf(buf, "%s/%s", h, s);
  74.     (void)source(buf);
  75. }
  76.  
  77. /* print an error */
  78.  
  79. void zwarnnam(cmd, fmt, str, num) /**/
  80. char *cmd;
  81. char *fmt;
  82. char *str;
  83. int num;
  84. {
  85.     int waserr = errflag;
  86.     zerrnam(cmd, fmt, str, num);
  87.     errflag = waserr;
  88. }
  89.  
  90. void zerrnam(cmd, fmt, str, num)/**/
  91. char *cmd;
  92. char *fmt;
  93. char *str;
  94. int num;
  95. {
  96.     if (cmd) {
  97.     if (errflag || noerrs)
  98.         return;
  99.     errflag = 1;
  100.     trashzle();
  101.     if (isset(SHINSTDIN))
  102.         fprintf(stderr, "%s: ", cmd);
  103.     else
  104.         fprintf(stderr, "%s: %s: ", argzero, cmd);
  105.     }
  106.     while (*fmt)
  107.     if (*fmt == '%') {
  108.         fmt++;
  109.         switch (*fmt++) {
  110.         case 's':
  111.         while (*str)
  112.             niceputc(*str++, stderr);
  113.         break;
  114.         case 'l':
  115.         while (num--)
  116.             niceputc(*str++, stderr);
  117.         break;
  118.         case 'd':
  119.         fprintf(stderr, "%d", num);
  120.         break;
  121.         case '%':
  122.         putc('%', stderr);
  123.         break;
  124.         case 'c':
  125.         niceputc(num, stderr);
  126.         break;
  127.         case 'e':
  128.         if (num == EINTR) {
  129.             fputs("interrupt\n", stderr);
  130.             errflag = 1;
  131.             return;
  132.         }
  133.         if (num == EIO)
  134.             fputs(sys_errlist[num], stderr);
  135.         else {
  136.             fputc(tulower(sys_errlist[num][0]), stderr);
  137.             fputs(sys_errlist[num] + 1, stderr);
  138.         }
  139.         break;
  140.         }
  141.     } else
  142.         putc(*fmt++, stderr);
  143.     if (unset(SHINSTDIN) && lineno)
  144.     fprintf(stderr, " [%ld]\n", lineno);
  145.     else
  146.     putc('\n', stderr);
  147.     fflush(stderr);
  148. }
  149.  
  150. void zerr(fmt, str, num)    /**/
  151. char *fmt;
  152. char *str;
  153. int num;
  154. {
  155.     if (errflag || noerrs)
  156.     return;
  157.     errflag = 1;
  158.     trashzle();
  159.     fprintf(stderr, "%s: ", (isset(SHINSTDIN)) ? "zsh" : argzero);
  160.     zerrnam(NULL, fmt, str, num);
  161. }
  162.  
  163. void niceputc(c, f)        /**/
  164. int c;
  165. FILE *f;
  166. {
  167.     if (itok(c)) {
  168.     if (c >= Pound && c <= Comma)
  169.         putc(ztokens[c - Pound], f);
  170.     return;
  171.     }
  172.     c &= 0xff;
  173.     if (isprint(c))
  174.     putc(c, f);
  175.     else if (c == '\n') {
  176.     putc('\\', f);
  177.     putc('n', f);
  178.     } else {
  179.     putc('^', f);
  180.     putc(c | '@', f);
  181.     }
  182. }
  183.  
  184. void sig_handle(sig)        /**/
  185. int sig;
  186. {
  187. #ifdef POSIX
  188.  
  189.     struct sigaction act;
  190.  
  191.     act.sa_handler = (SIGVEC_HANDTYPE) handler;
  192.     sigemptyset(&act.sa_mask);
  193.     sigaddset(&act.sa_mask, sig);
  194. #ifdef SA_INTERRUPT
  195.     if (interact)
  196.     act.sa_flags = SA_INTERRUPT;
  197.     else
  198. #endif
  199.     act.sa_flags = 0;
  200.     sigaction(sig, &act, (struct sigaction *)NULL);
  201.  
  202. #else
  203. #ifdef SV_INTERRUPT
  204.  
  205.     struct sigvec vec;
  206.  
  207.     vec.sv_handler = (SIGVEC_HANDTYPE)handler;
  208.     vec.sv_mask = sigmask(sig);
  209.     vec.sv_flags = SV_INTERRUPT;
  210.     sigvec(sig, &vec, (struct sigvec *)NULL);
  211.  
  212. #else
  213.  
  214.     signal(sig, handler);
  215.  
  216. #endif
  217. #endif
  218. }
  219.  
  220. void sig_ignore(sig)        /**/
  221. int sig;
  222. {
  223.     signal(sig, SIG_IGN);
  224. }
  225.  
  226. void sig_default(sig)        /**/
  227. int sig;
  228. {
  229.     signal(sig, SIG_DFL);
  230. }
  231.  
  232. /* enable ^C interrupts */
  233.  
  234. void intr()
  235. {                /**/
  236.     if (interact)
  237.     sig_handle(SIGINT);
  238. }
  239.  
  240. /* disable ^C interrupts */
  241.  
  242. void nointr()
  243. {                /**/
  244.     if (interact)
  245.     sig_ignore(SIGINT);
  246. }
  247.  
  248. /* temporary hold ^C interrupts */
  249.  
  250. void holdintr()
  251. {                /**/
  252.     if (interact)
  253.     {
  254. #ifdef SIGNAL_MASKS
  255.     sig_block(sig_mask(SIGINT));
  256. #else
  257.     sig_ignore(SIGINT);
  258. #endif
  259.     }
  260. }
  261.  
  262. /* release ^C interrupts */
  263.  
  264. void noholdintr()
  265. {                /**/
  266.     if (interact)
  267.     {
  268. #ifdef SIGNAL_MASKS
  269.     sig_unblock(sig_mask(SIGINT));
  270. #else
  271.     sig_handle(SIGINT);
  272. #endif
  273.     }
  274. }
  275.  
  276. /* block or unblock a signal */
  277.  
  278. sigset_t sig_mask(sig)        /**/
  279. int sig;
  280. {
  281.     sigset_t set;
  282.  
  283.     sigemptyset(&set);
  284.     if (sig)
  285.     sigaddset(&set, sig);
  286.     return set;
  287. }
  288.  
  289. sigset_t sig_notmask(sig)    /**/
  290. int sig;
  291. {
  292.     sigset_t set;
  293.  
  294.     sigfillset(&set);
  295.     if (sig)
  296.     sigdelset(&set, sig);
  297.     return set;
  298. }
  299.  
  300. #if !defined(POSIX) && !defined(SIGNAL_MASKS)
  301. static sigset_t heldset;
  302. #endif
  303.  
  304. sigset_t sig_block(set)        /**/
  305. sigset_t set;
  306. {
  307.     sigset_t oset;
  308.  
  309. #ifdef POSIX
  310.     sigprocmask(SIG_BLOCK, &set, &oset);
  311. #else
  312. #ifdef SIGNAL_MASKS
  313.     oset = sigblock(set);
  314. #else
  315.     int i;
  316.  
  317.     oset = heldset;
  318.     for (i = 1; i <= NSIG; ++i) {
  319.     if (sigismember(&set, i) && !sigismember(&heldset, i)) {
  320.         sigaddset(&heldset, i);
  321.         sighold(i);
  322.     }
  323.     }
  324. #endif
  325. #endif
  326.  
  327.     return oset;
  328. }
  329.  
  330. sigset_t sig_unblock(set)    /**/
  331. sigset_t set;
  332. {
  333.     sigset_t oset;
  334.  
  335. #ifdef POSIX
  336.     sigprocmask(SIG_UNBLOCK, &set, &oset);
  337. #else
  338. #ifdef SIGNAL_MASKS
  339.     sigfillset(&oset);
  340.     oset = sigsetmask(oset);
  341.     sigsetmask(oset & ~set);
  342. #else
  343.     int i;
  344.  
  345.     oset = heldset;
  346.     for (i = 1; i <= NSIG; ++i) {
  347.     if (sigismember(&set, i) && sigismember(&heldset, i)) {
  348.         sigdelset(&heldset, i);
  349.         sigrelse(i);
  350.     }
  351.     }
  352. #endif
  353. #endif
  354.  
  355.     return oset;
  356. }
  357.  
  358. sigset_t sig_setmask(set)    /**/
  359. sigset_t set;
  360. {
  361.     sigset_t oset;
  362.  
  363. #ifdef POSIX
  364.     sigprocmask(SIG_SETMASK, &set, &oset);
  365. #else
  366. #ifdef SIGNAL_MASKS
  367.     oset = sigsetmask(set);
  368. #else
  369.     int i;
  370.  
  371.     oset = heldset;
  372.     for (i = 1; i <= NSIG; ++i) {
  373.     if (sigismember(&set, i) && !sigismember(&heldset, i)) {
  374.         sigaddset(&heldset, i);
  375.         sighold(i);
  376.     }
  377.     else if (!sigismember(&set, i) && sigismember(&heldset, i)) {
  378.         sigdelset(&heldset, i);
  379.         sigrelse(i);
  380.     }
  381.     }
  382. #endif
  383. #endif
  384.  
  385.     return oset;
  386. }
  387.  
  388. int sig_suspend(sig)        /**/
  389. int sig;
  390. {
  391.     int ret;
  392.  
  393. #ifdef POSIX
  394.     sigset_t set;
  395.  
  396.     if (sig) {
  397.     set = sig_notmask(sig);
  398.     sigdelset(&set, SIGHUP);
  399.     }
  400.     else
  401.     sigemptyset(&set);
  402.     ret = sigsuspend(&set);
  403. #else
  404.     ret = sigpause(sig);
  405. #endif
  406.  
  407.     return ret;
  408. }
  409.  
  410. /* get a symlink-free pathname for s relative to PWD */
  411.  
  412. char *findpwd(s)        /**/
  413. char *s;
  414. {
  415.     char *t;
  416.  
  417.     if (*s == '/')
  418.     return xsymlink(s);
  419.     s = tricat((pwd[1]) ? pwd : "", "/", s);
  420.     t = xsymlink(s);
  421.     zsfree(s);
  422.     return t;
  423. }
  424.  
  425. static char xbuf[MAXPATHLEN];
  426.  
  427. int ispwd(s)            /**/
  428. char *s;
  429. {
  430.     struct stat sbuf, tbuf;
  431.  
  432.     if (stat(s, &sbuf) == 0 && stat(".", &tbuf) == 0)
  433.     if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
  434.         return 1;
  435.     return 0;
  436. }
  437.  
  438. /* expand symlinks in s, and remove other weird things */
  439.  
  440. char *xsymlink(s)        /**/
  441. char *s;
  442. {
  443.     if (unset(CHASELINKS))
  444.     return ztrdup(s);
  445.     if (*s != '/')
  446.     return NULL;
  447.     strcpy(xbuf, "");
  448.     if (xsymlinks(s + 1, 1))
  449.     return ztrdup(s);
  450.     if (!*xbuf)
  451.     return ztrdup("/");
  452.     return ztrdup(xbuf);
  453. }
  454.  
  455. char **slashsplit(s)        /**/
  456. char *s;
  457. {
  458.     char *t, **r, **q;
  459.     int t0;
  460.  
  461.     if (!*s)
  462.     return (char **)zcalloc(sizeof(char **));
  463.  
  464.     for (t = s, t0 = 0; *t; t++)
  465.     if (*t == '/')
  466.         t0++;
  467.     q = r = (char **)zalloc(sizeof(char **) * (t0 + 2));
  468.  
  469.     while ((t = strchr(s, '/'))) {
  470.     *t = '\0';
  471.     *q++ = ztrdup(s);
  472.     *t = '/';
  473.     while (*t == '/')
  474.         t++;
  475.     if (!*t) {
  476.         *q = NULL;
  477.         return r;
  478.     }
  479.     s = t;
  480.     }
  481.     *q++ = ztrdup(s);
  482.     *q = NULL;
  483.     return r;
  484. }
  485.  
  486. /* expands symlinks and .. or . expressions */
  487. /* if flag = 0, only expand .. and . expressions */
  488.  
  489. int xsymlinks(s, flag)        /**/
  490. char *s;
  491. int flag;
  492. {
  493.     char **pp, **opp;
  494.     char xbuf2[MAXPATHLEN], xbuf3[MAXPATHLEN];
  495.     int t0;
  496.  
  497.     opp = pp = slashsplit(s);
  498.     for (; *pp; pp++) {
  499.     if (!strcmp(*pp, ".")) {
  500.         zsfree(*pp);
  501.         continue;
  502.     }
  503.     if (!strcmp(*pp, "..")) {
  504.         char *p;
  505.  
  506.         zsfree(*pp);
  507.         if (!strcmp(xbuf, "/"))
  508.         continue;
  509.         p = xbuf + strlen(xbuf);
  510.         while (*--p != '/');
  511.         *p = '\0';
  512.         continue;
  513.     }
  514.     if (unset(CHASELINKS)) {
  515.         strcat(xbuf, "/");
  516.         strcat(xbuf, *pp);
  517.         zsfree(*pp);
  518.         continue;
  519.     }
  520.     sprintf(xbuf2, "%s/%s", xbuf, *pp);
  521.     t0 = readlink(xbuf2, xbuf3, MAXPATHLEN);
  522.     if (t0 == -1 || !flag) {
  523.         strcat(xbuf, "/");
  524.         strcat(xbuf, *pp);
  525.         zsfree(*pp);
  526.     } else {
  527.         xbuf3[t0] = '\0';    /* STUPID */
  528.         if (*xbuf3 == '/') {
  529.         strcpy(xbuf, "");
  530.         if (xsymlinks(xbuf3 + 1, flag))
  531.             return 1;
  532.         } else if (xsymlinks(xbuf3, flag))
  533.         return 1;
  534.         zsfree(*pp);
  535.     }
  536.     }
  537.     free(opp);
  538.     return 0;
  539. }
  540.  
  541. /* print a directory */
  542.  
  543. void fprintdir(s, f)        /**/
  544. char *s;
  545. FILE *f;
  546. {
  547.     int t0;
  548.  
  549.     t0 = finddir(s);
  550.     if (t0 == -1) {
  551.     fputs(s, f);
  552.     } else {
  553.     putc('~', f);
  554.     fputs(namdirs[t0].name, f);
  555.     fputs(s + namdirs[t0].len, f);
  556.     }
  557. }
  558.  
  559. void printdir(s)        /**/
  560. char *s;
  561. {
  562.     fprintdir(s, stdout);
  563. }
  564.  
  565. void printdircr(s)        /**/
  566. char *s;
  567. {
  568.     fprintdir(s, stdout);
  569.     putchar('\n');
  570. }
  571.  
  572. int findname(s)            /**/
  573. char *s;
  574. {
  575.     int t0;
  576.  
  577.     for (t0 = 0; t0 < userdirct; t0++)
  578.     if (!strcmp(namdirs[t0].name, s))
  579.         return t0;
  580.     return -1;
  581. }
  582.  
  583. /* see if a path has a named directory as its prefix */
  584.  
  585. int finddir(s)            /**/
  586. char *s;
  587. {
  588.     int t0, slen, min, max;
  589.     static int last = -1;
  590.     static char previous[MAXPATHLEN] = "\0";
  591.  
  592.     if (!s) {            /* Invalidate directory cache */
  593.     *previous = '\0';
  594.     return last = -1;
  595.     }
  596.     if (!strcmp(s, previous))
  597.     return last;
  598.  
  599. /* The named directories are sorted in increasing length of the path. For the
  600.    same path length, it is sorted in DECREASING order of name length, unless
  601.    HIDE_NAMES is defined, in which case the last included name comes last. */
  602.  
  603. /* This binary search doesn't seem to make much difference but... */
  604.  
  605.     slen = strlen(s);
  606.     min = 0;
  607.     max = userdirct;
  608.     while ((t0 = (min + max) >> 1) != min)
  609.     if (slen < namdirs[t0].len)
  610.         max = t0;
  611.     else
  612.         min = t0;
  613.  
  614. /* Binary search alone doesn't work because we want the longest match, not
  615.    necessarily an exact one */
  616.  
  617.     for (t0 = min; t0 >= 0; t0--)
  618.     if (namdirs[t0].len <= slen && !dircmp(namdirs[t0].dir, s)) {
  619.         strcpy(previous, s);
  620.         return last = t0;
  621.     }
  622.     return -1;
  623. }
  624.  
  625. /* add a named directory */
  626.  
  627. void adduserdir(s, t, ishomedir, always) /**/
  628. char *s;
  629. char *t;
  630. int ishomedir;
  631. int always;
  632. {
  633.     int t0 = -1, t1, t2;
  634.  
  635.     if (!interact)
  636.     return;
  637.  
  638.     if (ishomedir) {
  639.     if (!strcmp(t, "/") || (t0 = findname(s) != -1))
  640.         return;
  641.     } else if (!t || *t != '/' || !strcmp(t, "/")) {
  642.     if ((t0 = findname(s)) != -1) {    /* remove the name */
  643.         zsfree(namdirs[t0].name);
  644.         zsfree(namdirs[t0].dir);
  645.         for (; t0 < userdirct - 1; t0++)
  646.         memcpy((vptr) & namdirs[t0], (vptr) & namdirs[t0 + 1],
  647.                sizeof *namdirs);
  648.         userdirct--;
  649.         finddir(0);
  650.     }
  651.     return;
  652.     }
  653.     if ((!always && !isset(AUTONAMEDIRS)) ||
  654.     (always == 2 && findname(s) == -1))
  655.     return;
  656.  
  657.     t2 = strlen(t);
  658.     if (!ishomedir && t2 < MAXPATHLEN && (t0 = findname(s)) != -1) {
  659.  
  660.     /* update value */
  661.  
  662.     zsfree(namdirs[t0].dir);
  663.     namdirs[t0].dir = ztrdup(t);
  664.     t1 = namdirs[t0].len;
  665.     namdirs[t0].len = t2;
  666.     if (t2 < t1)
  667.         qsort((vptr) namdirs, t0 + 1, sizeof *namdirs,
  668.           (int (*)DCLPROTO((const void *, const void *)))lencmp);
  669.     else
  670.         qsort((vptr) & namdirs[t0], userdirct - t0, sizeof *namdirs,
  671.           (int (*)DCLPROTO((const void *, const void *)))lencmp);
  672.  
  673.     finddir(0);        /* Invalidate directory cache */
  674.     return;
  675.     }
  676.  /* add the name */
  677.  
  678.     if (userdirsz == userdirct) {
  679.     userdirsz *= 2;
  680.     namdirs = (Nameddirs) realloc((vptr) namdirs,
  681.                       sizeof *namdirs * userdirsz);
  682.     if (!namdirs)
  683.         return;
  684.     }
  685.     for (t0 = 0; t0 < userdirct; t0++)
  686.     if (namdirs[t0].len > t2)
  687.         break;
  688.     for (t1 = userdirct; t1 > t0; t1--)
  689.     memcpy((vptr) & namdirs[t1], (vptr) & namdirs[t1 - 1],
  690.            sizeof *namdirs);
  691.     namdirs[t0].len = t2;
  692.     namdirs[t0].namelen = strlen(s);
  693.     namdirs[t0].name = ztrdup(s);
  694.     namdirs[t0].dir = ztrdup(t);
  695.     namdirs[t0].homedir = ishomedir;
  696.     userdirct++;
  697.     if (t0 && namdirs[t0 - 1].len == t2)
  698.     qsort((vptr) namdirs, t0 + 1, sizeof *namdirs,
  699.           (int (*)DCLPROTO((const void *, const void *)))lencmp);
  700.     finddir(0);
  701. }
  702.  
  703. int dircmp(s, t)        /**/
  704. char *s;
  705. char *t;
  706. {
  707.     if (s) {
  708.     for (; *s == *t; s++, t++)
  709.         if (!*s)
  710.         return 0;
  711.     if (!*s && *t == '/')
  712.         return 0;
  713.     }
  714.     return 1;
  715. }
  716.  
  717. int lencmp(first, sec)        /**/
  718. vptr first;
  719. vptr sec;
  720. {
  721.     int i;
  722.  
  723. #ifndef HIDE_NAMES
  724.     if ((i = ((Nameddirs) first)->len - ((Nameddirs) sec)->len))
  725.     return i;
  726.     else
  727.     return            /* for paths with the same lenght put the shortest name AFTER */
  728.         ((Nameddirs) sec)->namelen - ((Nameddirs) first)->namelen;
  729. #else
  730.     return ((Nameddirs) first)->len - ((Nameddirs) sec)->len;
  731. #endif
  732. }
  733.  
  734. int ddifftime(t1, t2)        /**/
  735. time_t t1;
  736. time_t t2;
  737. {
  738.     return ((long)t2 - (long)t1);
  739. }
  740.  
  741. /* see if jobs need printing */
  742.  
  743. void scanjobs()
  744. {                /**/
  745.     int t0;
  746.  
  747.     for (t0 = 1; t0 != MAXJOB; t0++)
  748.     if (jobtab[t0].stat & STAT_CHANGED)
  749.         printjob(jobtab + t0, 0);
  750. }
  751.  
  752. /* do pre-prompt stuff */
  753.  
  754. void preprompt()
  755. {                /**/
  756.     int diff;
  757.     List list;
  758.     struct schedcmd *sch, *schl;
  759.  
  760.     if (unset(NOTIFY))
  761.     scanjobs();
  762.     if (errflag)
  763.     return;
  764.     if ((list = getshfunc("precmd")))
  765.     doshfuncnoval(list, NULL, 0);
  766.     if (errflag)
  767.     return;
  768.     if (period && (time(NULL) > lastperiod + period) &&
  769.     (list = getshfunc("periodic"))) {
  770.     doshfuncnoval(list, NULL, 0);
  771.     lastperiod = time(NULL);
  772.     }
  773.     if (errflag)
  774.     return;
  775.     if (watch) {
  776.     diff = (int)ddifftime(lastwatch, time(NULL));
  777.     if (diff > logcheck) {
  778.         dowatch();
  779.         lastwatch = time(NULL);
  780.     }
  781.     }
  782.     if (errflag)
  783.     return;
  784.     diff = (int)ddifftime(lastmailcheck, time(NULL));
  785.     if (diff > mailcheck) {
  786.     if (mailpath && *mailpath && **mailpath)
  787.         checkmailpath(mailpath);
  788.     else if (mailfile && *mailfile) {
  789.         char *x[2];
  790.  
  791.         x[0] = mailfile;
  792.         x[1] = NULL;
  793.         checkmailpath(x);
  794.     }
  795.     lastmailcheck = time(NULL);
  796.     }
  797.     for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds; sch;
  798.      sch = (schl = sch)->next) {
  799.     if (sch->time < time(NULL)) {
  800.         execstring(sch->cmd);
  801.         schl->next = sch->next;
  802.         zsfree(sch->cmd);
  803.         zfree(sch, sizeof(struct schedcmd));
  804.         sch = schl;
  805.     }
  806.     if (errflag)
  807.         return;
  808.     }
  809. }
  810.  
  811. int arrlen(s)            /**/
  812. char **s;
  813. {
  814.     int t0;
  815.  
  816.     for (t0 = 0; *s; s++, t0++);
  817.     return t0;
  818. }
  819.  
  820. void checkmailpath(s)        /**/
  821. char **s;
  822. {
  823.     struct stat st;
  824.     char *v, *u, c;
  825.  
  826.     while (*s) {
  827.     for (v = *s; *v && *v != '?'; v++);
  828.     c = *v;
  829.     *v = '\0';
  830.     if (c != '?')
  831.         u = NULL;
  832.     else
  833.         u = v + 1;
  834.     if (**s == 0) {
  835.         *v = c;
  836.         zerr("empty MAILPATH component: %s", *s, 0);
  837.     } else if (stat(*s, &st) == -1) {
  838.         if (errno != ENOENT)
  839.         zerr("%e: %s", *s, errno);
  840.     } else if (S_ISDIR(st.st_mode)) {
  841.         Lklist l;
  842.         DIR *lock = opendir(*s);
  843.         char buf[MAXPATHLEN * 2], **arr, **ap;
  844.         struct dirent *de;
  845.         int ct = 1;
  846.  
  847.         if (lock) {
  848.         pushheap();
  849.         heapalloc();
  850.         l = newlist();
  851.         readdir(lock);
  852.         readdir(lock);
  853.         while ((de = readdir(lock))) {
  854.             if (errflag)
  855.             break;
  856.             if (u)
  857.             sprintf(buf, "%s/%s?%s", *s, de->d_name, u);
  858.             else
  859.             sprintf(buf, "%s/%s", *s, de->d_name);
  860.             addnode(l, dupstring(buf));
  861.             ct++;
  862.         }
  863.         closedir(lock);
  864.         ap = arr = (char **)alloc(ct * sizeof(char *));
  865.  
  866.         while ((*ap++ = (char *)ugetnode(l)));
  867.         checkmailpath(arr);
  868.         popheap();
  869.         }
  870.     } else {
  871.         if (st.st_size && st.st_atime <= st.st_mtime &&
  872.         st.st_mtime > lastmailcheck)
  873.         if (!u) {
  874.             fprintf(stderr, "You have new mail.\n");
  875.             fflush(stderr);
  876.         } else {
  877.             char *z = u;
  878.  
  879.             while (*z)
  880.             if (*z == '$' && z[1] == '_') {
  881.                 fprintf(stderr, "%s", *s);
  882.                 z += 2;
  883.             } else
  884.                 fputc(*z++, stderr);
  885.             fputc('\n', stderr);
  886.             fflush(stderr);
  887.         }
  888.         if (isset(MAILWARNING) && st.st_atime > st.st_mtime &&
  889.         st.st_atime > lastmailcheck && st.st_size) {
  890.         fprintf(stderr, "The mail in %s has been read.\n", *s);
  891.         fflush(stderr);
  892.         }
  893.     }
  894.     *v = c;
  895.     s++;
  896.     }
  897. }
  898.  
  899. void saveoldfuncs(x, y)        /**/
  900. char *x;
  901. Cmdnam y;
  902. {
  903.     Cmdnam cc;
  904.  
  905.     if (y->flags & (SHFUNC | DISABLED)) {
  906.     cc = (Cmdnam) zcalloc(sizeof *cc);
  907.     *cc = *y;
  908.     y->u.list = NULL;
  909.     addhnode(ztrdup(x), cc, cmdnamtab, freecmdnam);
  910.     }
  911. }
  912.  
  913. /* create command hashtable */
  914.  
  915. void newcmdnamtab()
  916. {                /**/
  917.     Hashtab oldcnt;
  918.  
  919.     oldcnt = cmdnamtab;
  920.     permalloc();
  921.     cmdnamtab = newhtable(101);
  922.     addbuiltins();
  923.     if (oldcnt) {
  924.     listhtable(oldcnt, (HFunc) saveoldfuncs);
  925.     freehtab(oldcnt, freecmdnam);
  926.     }
  927.     lastalloc();
  928.     pathchecked = path;
  929. }
  930.  
  931. void freecmdnam(a)        /**/
  932. vptr a;
  933. {
  934.     struct cmdnam *c = (struct cmdnam *)a;
  935.  
  936.     if (c->flags & SHFUNC) {
  937.     if (c->u.list)
  938.         freestruct(c->u.list);
  939.     }
  940.     else if ((c->flags & HASHCMD) == HASHCMD)
  941.     zsfree(c->u.cmd);
  942.  
  943.     zfree(c, sizeof(struct cmdnam));
  944. }
  945.  
  946. void freecompcond(a)        /**/
  947. vptr a;
  948. {
  949.     Compcond cc = (Compcond) a;
  950.     Compcond and, or, c;
  951.     int n;
  952.  
  953.     for (c = cc; c; c = or) {
  954.     or = c->or;
  955.     for (; c; c = and) {
  956.         and = c->and;
  957.         if (c->type == CCT_POS ||
  958.         c->type == CCT_NUMWORDS) {
  959.         free(c->u.r.a);
  960.         free(c->u.r.b);
  961.         } else if (c->type == CCT_CURSUF ||
  962.                c->type == CCT_CURPRE) {
  963.         for (n = 0; n < c->n; n++)
  964.             if (c->u.s.s[n])
  965.             zsfree(c->u.s.s[n]);
  966.         free(c->u.s.s);
  967.         } else if (c->type == CCT_RANGESTR ||
  968.                c->type == CCT_RANGEPAT) {
  969.         for (n = 0; n < c->n; n++)
  970.             if (c->u.l.a[n])
  971.             zsfree(c->u.l.a[n]);
  972.         free(c->u.l.a);
  973.         for (n = 0; n < c->n; n++)
  974.             if (c->u.l.b[n])
  975.             zsfree(c->u.l.b[n]);
  976.         free(c->u.l.b);
  977.         } else {
  978.         for (n = 0; n < c->n; n++)
  979.             if (c->u.s.s[n])
  980.             zsfree(c->u.s.s[n]);
  981.         free(c->u.s.p);
  982.         free(c->u.s.s);
  983.         }
  984.         zfree(c, sizeof(struct compcond));
  985.     }
  986.     }
  987. }
  988.  
  989. void freecompctl(a)        /**/
  990. vptr a;
  991. {
  992.     Compctl cc = (Compctl) a;
  993.  
  994.     if (cc == &cc_default ||
  995.     cc == &cc_compos ||
  996.     --cc->refc > 0)
  997.     return;
  998.  
  999.     zsfree(cc->keyvar);
  1000.     zsfree(cc->glob);
  1001.     zsfree(cc->str);
  1002.     zsfree(cc->func);
  1003.     zsfree(cc->explain);
  1004.     zsfree(cc->prefix);
  1005.     zsfree(cc->suffix);
  1006.     zsfree(cc->hpat);
  1007.     zsfree(cc->subcmd);
  1008.     if (cc->cond)
  1009.     freecompcond(cc->cond);
  1010.     if (cc->ext) {
  1011.     Compctl n, m;
  1012.  
  1013.     n = cc->ext;
  1014.     do {
  1015.         m = (Compctl) (n->next);
  1016.         freecompctl(n);
  1017.         n = m;
  1018.     }
  1019.     while (n);
  1020.     }
  1021.     if (cc->xor && cc->xor != &cc_default)
  1022.     freecompctl(cc->xor);
  1023.     zfree(cc, sizeof(struct compctl));
  1024. }
  1025.  
  1026. void freecompctlp(a)          /**/
  1027. vptr a;
  1028. {
  1029.     Compctlp ccp = (Compctlp) a;
  1030.  
  1031.     freecompctl(ccp->cc);
  1032. }
  1033.  
  1034. void freestr(a)            /**/
  1035. vptr a;
  1036. {
  1037.     zsfree(a);
  1038. }
  1039.  
  1040. void freeanode(a)        /**/
  1041. vptr a;
  1042. {
  1043.     struct alias *c = (struct alias *)a;
  1044.  
  1045.     zsfree(c->text);
  1046.     zfree(c, sizeof(struct alias));
  1047. }
  1048.  
  1049. void freepm(a)            /**/
  1050. vptr a;
  1051. {
  1052.     struct param *pm = (Param) a;
  1053.  
  1054.     zfree(pm, sizeof(struct param));
  1055. }
  1056.  
  1057. void gettyinfo(ti)        /**/
  1058. struct ttyinfo *ti;
  1059. {
  1060.     if (SHTTY != -1) {
  1061. #ifdef HAS_TERMIOS
  1062. #ifdef HAS_TCCRAP
  1063.     if (tcgetattr(SHTTY, &ti->tio) == -1)
  1064. #else
  1065.     if (ioctl(SHTTY, TCGETS, &ti->tio) == -1)
  1066. #endif
  1067.         zerr("bad tcgets: %e", NULL, errno);
  1068. #else
  1069. #ifdef HAS_TERMIO
  1070.     ioctl(SHTTY, TCGETA, &ti->tio);
  1071. #else
  1072.     ioctl(SHTTY, TIOCGETP, &ti->sgttyb);
  1073.     ioctl(SHTTY, TIOCLGET, &ti->lmodes);
  1074.     ioctl(SHTTY, TIOCGETC, &ti->tchars);
  1075.     ioctl(SHTTY, TIOCGLTC, &ti->ltchars);
  1076. #endif
  1077. #endif
  1078. #ifdef TIOCGWINSZ
  1079. /*    if (ioctl(SHTTY, TIOCGWINSZ, &ti->winsize) == -1)
  1080.             zerr("bad tiocgwinsz: %e",NULL,errno);*/
  1081.     ioctl(SHTTY, TIOCGWINSZ, (char *) &ti->winsize);
  1082. #endif
  1083.     }
  1084. }
  1085.  
  1086. void settyinfo(ti)        /**/
  1087. struct ttyinfo *ti;
  1088. {
  1089.     if (SHTTY != -1) {
  1090. #ifdef HAS_TERMIOS
  1091. #ifdef HAS_TCCRAP
  1092. #ifndef TCSADRAIN
  1093. #define TCSADRAIN 1        /* XXX Princeton's include files are screwed up */
  1094. #endif
  1095.     tcsetattr(SHTTY, TCSADRAIN, &ti->tio);
  1096.     /* if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1) */
  1097. #else
  1098.     ioctl(SHTTY, TCSETS, &ti->tio);
  1099.     /* if (ioctl(SHTTY, TCSETS, &ti->tio) == -1) */
  1100. #endif
  1101.         /*    zerr("settyinfo: %e",NULL,errno)*/ ;
  1102. #else
  1103. #ifdef HAS_TERMIO
  1104.     ioctl(SHTTY, TCSETA, &ti->tio);
  1105. #else
  1106.     ioctl(SHTTY, TIOCSETN, &ti->sgttyb);
  1107.     ioctl(SHTTY, TIOCLSET, &ti->lmodes);
  1108.     ioctl(SHTTY, TIOCSETC, &ti->tchars);
  1109.     ioctl(SHTTY, TIOCSLTC, &ti->ltchars);
  1110. #endif
  1111. #endif
  1112.     }
  1113. }
  1114.  
  1115. #ifdef TIOCGWINSZ
  1116. extern winchanged;
  1117.  
  1118. void adjustwinsize()
  1119. {                /**/
  1120.     int oldcols = columns, oldrows = lines;
  1121.  
  1122.     if (SHTTY == -1)
  1123.     return;
  1124.  
  1125.     ioctl(SHTTY, TIOCGWINSZ, (char *) &shttyinfo.winsize);
  1126.     if (shttyinfo.winsize.ws_col)
  1127.     columns = shttyinfo.winsize.ws_col;
  1128.     if (shttyinfo.winsize.ws_row)
  1129.     lines = shttyinfo.winsize.ws_row;
  1130.     if (oldcols != columns) {
  1131.     if (zleactive) {
  1132.         resetneeded = winchanged = 1;
  1133.         refresh();
  1134.     }
  1135.     setintenv("COLUMNS", columns);
  1136.     }
  1137.     if (oldrows != lines)
  1138.     setintenv("LINES", lines);
  1139. }
  1140. #endif
  1141.  
  1142. int zyztem(s, t)        /**/
  1143. char *s;
  1144. char *t;
  1145. {
  1146.     int cj = thisjob;
  1147.  
  1148.     s = tricat(s, " ", t);
  1149.     execstring(s);        /* Depends on recursion condom in execute() */
  1150.     zsfree(s);
  1151.     thisjob = cj;
  1152.     return lastval;
  1153. }
  1154.  
  1155. /* move a fd to a place >= 10 */
  1156.  
  1157. int movefd(fd)            /**/
  1158. int fd;
  1159. {
  1160.     int fe;
  1161.  
  1162.     if (fd == -1)
  1163.     return fd;
  1164. #ifdef F_DUPFD
  1165.     fe = fcntl(fd, F_DUPFD, 10);
  1166. #else
  1167.     if ((fe = dup(fd)) < 10)
  1168.     fe = movefd(fe);
  1169. #endif
  1170.     close(fd);
  1171.     return fe;
  1172. }
  1173.  
  1174. /* move fd x to y */
  1175.  
  1176. void redup(x, y)        /**/
  1177. int x;
  1178. int y;
  1179. {
  1180.     if (x != y) {
  1181.     dup2(x, y);
  1182.     close(x);
  1183.     }
  1184. }
  1185.  
  1186. void settrap(t0, l)        /**/
  1187. int t0;
  1188. List l;
  1189. {
  1190.     Cmd c;
  1191.  
  1192.     if (l) {
  1193.     c = l->left->left->left;
  1194.     if (c->type == SIMPLE && empty(c->args) && empty(c->redir)
  1195.         && empty(c->vars) && !c->flags)
  1196.         l = NULL;
  1197.     }
  1198.     if (t0 == -1)
  1199.     return;
  1200.     if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
  1201.             || t0 == SIGPIPE)) {
  1202.     zerr("can't trap SIG%s in interactive shells", sigs[t0], 0);
  1203.     return;
  1204.     }
  1205.     if (sigfuncs[t0])
  1206.     freestruct(sigfuncs[t0]);
  1207.     if (!l) {
  1208.     sigtrapped[t0] = 2;
  1209.     sigfuncs[t0] = NULL;
  1210.     if (t0 && t0 <= SIGCOUNT &&
  1211. #ifdef SIGWINCH
  1212.         t0 != SIGWINCH &&
  1213. #endif
  1214.         t0 != SIGCHLD)
  1215.         sig_ignore(t0);
  1216.     } else {
  1217.     if (t0 && t0 <= SIGCOUNT &&
  1218. #ifdef SIGWINCH
  1219.         t0 != SIGWINCH &&
  1220. #endif
  1221.         t0 != SIGCHLD)
  1222.         sig_handle(t0);
  1223.     sigtrapped[t0] = 1;
  1224.     permalloc();
  1225.     sigfuncs[t0] = (List) dupstruct(l);
  1226.     heapalloc();
  1227.     }
  1228. }
  1229.  
  1230. void unsettrap(t0)        /**/
  1231. int t0;
  1232. {
  1233.     if (t0 == -1)
  1234.     return;
  1235.     if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
  1236.             || t0 == SIGPIPE)) {
  1237.     return;
  1238.     }
  1239.     sigtrapped[t0] = 0;
  1240.     if (t0 == SIGINT)
  1241.     intr();
  1242.     else if (t0 == SIGHUP)
  1243.     sig_handle(t0);
  1244.     else if (t0 && t0 <= SIGCOUNT &&
  1245. #ifdef SIGWINCH
  1246.          t0 != SIGWINCH &&
  1247. #endif
  1248.          t0 != SIGCHLD)
  1249.     sig_default(t0);
  1250.     if (sigfuncs[t0]) {
  1251.     freestruct(sigfuncs[t0]);
  1252.     sigfuncs[t0] = NULL;
  1253.     }
  1254. }
  1255.  
  1256. void dotrap(sig)        /**/
  1257. int sig;
  1258. {
  1259.     int sav, savval;
  1260.  
  1261.     sav = sigtrapped[sig];
  1262.     savval = lastval;
  1263.     if (sav == 2)
  1264.     return;
  1265.     sigtrapped[sig] = 2;
  1266.     if (sigfuncs[sig]) {
  1267.     Lklist args;
  1268.     char *name, num[4];
  1269.  
  1270.     lexsave();
  1271.     permalloc();
  1272.     args = newlist();
  1273.     name = (char *)zalloc(5 + strlen(sigs[sig]));
  1274.     sprintf(name, "TRAP%s", sigs[sig]);
  1275.     addnode(args, name);
  1276.     sprintf(num, "%d", sig);
  1277.     addnode(args, num);
  1278.     trapreturn = -1;
  1279.     doshfuncnoval(sigfuncs[sig], args, 0);
  1280.     lexrestore();
  1281.     freetable(args, (FFunc) NULL);
  1282.     zsfree(name);
  1283.     if (trapreturn > 0) {
  1284.         breaks = loops;
  1285.         errflag = 1;
  1286.     } else
  1287.         trapreturn = 0;
  1288.     }
  1289.     if (sigtrapped[sig])
  1290.     sigtrapped[sig] = sav;
  1291.     lastval = savval;
  1292. }
  1293.  
  1294. /* copy len chars from t into s, and null terminate */
  1295.  
  1296. void ztrncpy(s, t, len)        /**/
  1297. char *s;
  1298. char *t;
  1299. int len;
  1300. {
  1301.     while (len--)
  1302.     *s++ = *t++;
  1303.     *s = '\0';
  1304. }
  1305.  
  1306. /* copy t into *s and update s */
  1307.  
  1308. void strucpy(s, t)        /**/
  1309. char **s;
  1310. char *t;
  1311. {
  1312.     char *u = *s;
  1313.  
  1314.     while ((*u++ = *t++));
  1315.     *s = u - 1;
  1316. }
  1317.  
  1318. void struncpy(s, t, n)        /**/
  1319. char **s;
  1320. char *t;
  1321. int n;
  1322. {
  1323.     char *u = *s;
  1324.  
  1325.     while (n--)
  1326.     *u++ = *t++;
  1327.     *s = u;
  1328.     *u = '\0';
  1329. }
  1330.  
  1331. int checkrmall(s)        /**/
  1332. char *s;
  1333. {
  1334.     fflush(stdin);
  1335.     if (*s == '/')
  1336.     fprintf(stderr, "zsh: sure you want to delete all the files in %s? ", s);
  1337.     else
  1338.     fprintf(stderr, "zsh: sure you want to delete all the files in %s/%s? ",
  1339.         (pwd[1]) ? pwd : "", s);
  1340.     fflush(stderr);
  1341.     feep();
  1342.     return (getquery() == 'y');
  1343. }
  1344.  
  1345. int getquery()
  1346. {                /**/
  1347.     char c, d;
  1348.     int val, isem = !strcmp(term, "emacs");
  1349.  
  1350.     attachtty(mypgrp);
  1351.     if (!isem)
  1352.     setcbreak();
  1353. #ifdef FIONREAD
  1354.     ioctl(SHTTY, FIONREAD, (char *) &val);
  1355.     if (val) {
  1356.     if (!isem)
  1357.         settyinfo(&shttyinfo);
  1358.     write(2, "n\n", 2);
  1359.     return 'n';
  1360.     }
  1361. #endif
  1362.     if (read(SHTTY, &c, 1) == 1)
  1363.     if (c == 'y' || c == 'Y' || c == '\t')
  1364.         c = 'y';
  1365.     if (isem) {
  1366.     if (c != '\n')
  1367.         while (read(SHTTY, &d, 1) == 1 && d != '\n');
  1368.     }
  1369.     else {
  1370.     settyinfo(&shttyinfo);
  1371.     if (c != '\n')
  1372.         write(2, "\n", 1);
  1373.     }
  1374.     return (int)c;
  1375. }
  1376.  
  1377. static int d;
  1378. static char *guess, *best;
  1379.  
  1380. void spscan(s, junk)        /**/
  1381. char *s;
  1382. char *junk;
  1383. {
  1384.     int nd;
  1385.  
  1386.     nd = spdist(s, guess, (int) strlen(guess) / 4 + 1);
  1387.     if (nd <= d) {
  1388.     best = s;
  1389.     d = nd;
  1390.     }
  1391. }
  1392.  
  1393. /* spellcheck a word */
  1394. /* fix s and s2 ; if s2 is non-null, fix the history list too */
  1395.  
  1396. void spckword(s, s2, tptr, cmd, ask)    /**/
  1397. char **s;
  1398. char **s2;
  1399. char **tptr;
  1400. int cmd;
  1401. int ask;
  1402. {
  1403.     char *t, *u;
  1404.     char firstchar;
  1405.     int x;
  1406.     int pram = 0;
  1407.  
  1408.     if (**s == '-' || **s == '%')
  1409.     return;
  1410.     if (!strcmp(*s, "in"))
  1411.     return;
  1412.     if (!(*s)[0] || !(*s)[1])
  1413.     return;
  1414.     if (gethnode(*s, cmdnamtab) || gethnode(*s, aliastab))
  1415.     return;
  1416.     else if (isset(HASHLISTALL)) {
  1417.     fullhash();
  1418.     if (gethnode(*s, cmdnamtab))
  1419.         return;
  1420.     }
  1421.     t = *s;
  1422.     if (*t == Tilde || *t == Equals || *t == String)
  1423.     t++;
  1424.     for (; *t; t++)
  1425.     if (itok(*t))
  1426.         return;
  1427.     best = NULL;
  1428.     for (t = *s; *t; t++)
  1429.     if (*t == '/')
  1430.         break;
  1431.     if (**s == String) {
  1432.     if (*t)
  1433.         return;
  1434.     pram = 1;
  1435.     guess = *s + 1;
  1436.     while (*guess == '+' || *guess == '^' ||
  1437.            *guess == '#' || *guess == '~' ||
  1438.            *guess == '=')
  1439.         guess++;
  1440.     d = 100;
  1441.     listhtable(paramtab, spscan);
  1442.     } else {
  1443.     if ((u = spname(guess = *s)) != *s)
  1444.         best = u;
  1445.     if (!*t && !cmd) {
  1446.         if (access(*s, F_OK) == 0)
  1447.         return;
  1448.         if (hashcmd(*s, pathchecked))
  1449.         return;
  1450.         guess = *s;
  1451.         d = 100;
  1452.         listhtable(aliastab, spscan);
  1453.         listhtable(cmdnamtab, spscan);
  1454.     }
  1455.     }
  1456.     if (errflag)
  1457.     return;
  1458.     if (best && (int) strlen(best) > 1 && strcmp(best, guess)) {
  1459.     if (ask) {
  1460.         char *pp;
  1461.         int junk;
  1462.  
  1463.         rstring = best;
  1464.         Rstring = guess;
  1465.         firstchar = *guess;
  1466.         if (*guess == Tilde)
  1467.         *guess = '~';
  1468.         else if (*guess == String)
  1469.         *guess = '$';
  1470.         else if (*guess == Equals)
  1471.         *guess = '=';
  1472.         pp = putprompt(sprompt, &junk, 1);
  1473.         *guess = firstchar;
  1474.         fprintf(stderr, "%s", pp);
  1475.         fflush(stderr);
  1476.         feep();
  1477.         x = getquery();
  1478.     } else
  1479.         x = 'y';
  1480.     if (x == 'y' || x == ' ') {
  1481.         if (!pram) {
  1482.         *s = dupstring(best);
  1483.         } else {
  1484.         *s = (char *)alloc(strlen(best) + 2);
  1485.         strcpy(*s + 1, best);
  1486.         **s = String;
  1487.         }
  1488.         if (s2) {
  1489.         if (*tptr && !strcmp(hlastw, *s2) && hlastw < hptr) {
  1490.             char *z;
  1491.  
  1492.             hptr = hlastw;
  1493.             if (pram)
  1494.             hwaddc('$');
  1495.             for (z = best; *z; z++)
  1496.             hwaddc(*z);
  1497.             hwaddc(HISTSPACE);
  1498.             *tptr = hptr - 1;
  1499.             **tptr = '\0';
  1500.         }
  1501.         *s2 = dupstring(best);
  1502.         }
  1503.     } else if (x == 'a') {
  1504.         histdone |= HISTFLAG_NOEXEC;
  1505.     } else if (x == 'e') {
  1506.         histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL;
  1507.     }
  1508.     }
  1509. }
  1510.  
  1511. int ztrftime(buf, bufsize, fmt, tm)    /**/
  1512. char *buf;
  1513. int bufsize;
  1514. char *fmt;
  1515. struct tm *tm;
  1516. {
  1517.     static char *astr[] =
  1518.     {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  1519.     static char *estr[] =
  1520.     {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  1521.      "Aug", "Sep", "Oct", "Nov", "Dec"};
  1522.     static char *lstr[] =
  1523.     {"12", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9",
  1524.      "10", "11"};
  1525.     char tmp[3];
  1526.  
  1527. #ifdef HAS_STRFTIME
  1528.     char *origbuf = buf;
  1529.  
  1530. #endif
  1531.  
  1532.     tmp[0] = '%';
  1533.     tmp[2] = '\0';
  1534.     while (*fmt)
  1535.     if (*fmt == '%') {
  1536.         fmt++;
  1537.         switch (*fmt++) {
  1538.         case 'a':
  1539.         strucpy(&buf, astr[tm->tm_wday]);
  1540.         break;
  1541.         case 'b':
  1542.         strucpy(&buf, estr[tm->tm_mon]);
  1543.         break;
  1544.         case 'd':
  1545.         *buf++ = '0' + tm->tm_mday / 10;
  1546.         *buf++ = '0' + tm->tm_mday % 10;
  1547.         break;
  1548.         case 'e':
  1549.         if (tm->tm_mday > 9)
  1550.             *buf++ = '0' + tm->tm_mday / 10;
  1551.         *buf++ = '0' + tm->tm_mday % 10;
  1552.         break;
  1553.         case 'k':
  1554.         if (tm->tm_hour > 9)
  1555.             *buf++ = '0' + tm->tm_hour / 10;
  1556.         *buf++ = '0' + tm->tm_hour % 10;
  1557.         break;
  1558.         case 'l':
  1559.         strucpy(&buf, lstr[tm->tm_hour % 12]);
  1560.         break;
  1561.         case 'm':
  1562.         *buf++ = '0' + (tm->tm_mon + 1) / 10;
  1563.         *buf++ = '0' + (tm->tm_mon + 1) % 10;
  1564.         break;
  1565.         case 'M':
  1566.         *buf++ = '0' + tm->tm_min / 10;
  1567.         *buf++ = '0' + tm->tm_min % 10;
  1568.         break;
  1569.         case 'p':
  1570.         *buf++ = (tm->tm_hour > 11) ? 'p' : 'a';
  1571.         *buf++ = 'm';
  1572.         break;
  1573.         case 'S':
  1574.         *buf++ = '0' + tm->tm_sec / 10;
  1575.         *buf++ = '0' + tm->tm_sec % 10;
  1576.         break;
  1577.         case 'y':
  1578.         *buf++ = '0' + tm->tm_year / 10;
  1579.         *buf++ = '0' + tm->tm_year % 10;
  1580.         break;
  1581.         default:
  1582. #ifdef HAS_STRFTIME
  1583.         *buf = '\0';
  1584.         tmp[1] = fmt[-1];
  1585.         strftime(buf, bufsize - strlen(origbuf), tmp, tm);
  1586.         buf += strlen(buf);
  1587. #else
  1588.         *buf++ = '%';
  1589.         *buf++ = fmt[-1];
  1590. #endif
  1591.         break;
  1592.         }
  1593.     } else
  1594.         *buf++ = *fmt++;
  1595.     *buf = '\0';
  1596.     return 0;
  1597. }
  1598.  
  1599. char *join(arr, delim)        /**/
  1600. char **arr;
  1601. int delim;
  1602. {
  1603.     int len = 0;
  1604.     char **s, *ret, *ptr;
  1605.     static char *lastmem = NULL;
  1606.  
  1607.     for (s = arr; *s; s++)
  1608.     len += strlen(*s) + 1;
  1609.     if (!len)
  1610.     return "";
  1611.     zsfree(lastmem);
  1612.     lastmem = ptr = ret = (char *)zalloc(len);
  1613.     for (s = arr; *s; s++) {
  1614.     strucpy(&ptr, *s);
  1615.     *ptr++ = delim;
  1616.     }
  1617.     ptr[-1] = '\0';
  1618.     return ret;
  1619. }
  1620.  
  1621. char *spacejoin(s)        /**/
  1622. char **s;
  1623. {
  1624.     return join(s, *ifs);
  1625. }
  1626.  
  1627. char **colonsplit(s)        /**/
  1628. char *s;
  1629. {
  1630.     int ct;
  1631.     char *t, **ret, **ptr;
  1632.  
  1633.     for (t = s, ct = 0; *t; t++)
  1634.     if (*t == ':')
  1635.         ct++;
  1636.     ptr = ret = (char **)zalloc(sizeof(char **) * (ct + 2));
  1637.  
  1638.     t = s;
  1639.     do {
  1640.     for (s = t; *t && *t != ':'; t++);
  1641.     *ptr = (char *)zalloc((t - s) + 1);
  1642.     ztrncpy(*ptr++, s, t - s);
  1643.     }
  1644.     while (*t++);
  1645.     *ptr = NULL;
  1646.     return ret;
  1647. }
  1648.  
  1649. char **spacesplit(s)        /**/
  1650. char *s;
  1651. {
  1652.     int ct;
  1653.     char *t, **ret, **ptr;
  1654.  
  1655.     for (t = s, ct = 0; *t; t++)
  1656.     if (isep(*t))
  1657.         ct++;
  1658.     ptr = ret = (char **)zalloc(sizeof(char **) * (ct + 2));
  1659.  
  1660.     t = s;
  1661.     do {
  1662.     for (s = t; *t && !isep(*t); t++);
  1663.     *ptr = (char *)zalloc((t - s) + 1);
  1664.     ztrncpy(*ptr++, s, t - s);
  1665.     }
  1666.     while (*t++);
  1667.     *ptr = NULL;
  1668.     return ret;
  1669. }
  1670.  
  1671. int findsep(s, sep)        /**/
  1672. char **s;
  1673. char *sep;
  1674. {
  1675.     int i;
  1676.     char *t, *tt;
  1677.  
  1678.     if (!sep) {
  1679.     for (t = *s, i = 1; i && *t;) {
  1680.         for (tt = ifs, i = 1; i && *tt; tt++)
  1681.         if (*tt == *t)
  1682.             i = 0;
  1683.         if (i)
  1684.         t++;
  1685.     }
  1686.     i = t - *s;
  1687.     *s = t;
  1688.     return i;
  1689.     }
  1690.     if (!sep[0]) {
  1691.     i = strlen(*s);
  1692.     *s += i;
  1693.     return i;
  1694.     }
  1695.     for (i = 0; **s; (*s)++, i++) {
  1696.     for (t = sep, tt = *s; *t && *tt && *t == *tt; t++, tt++);
  1697.     if (!*t)
  1698.         return i;
  1699.     }
  1700.     return -1;
  1701. }
  1702.  
  1703. char *findword(s, sep)        /**/
  1704. char **s;
  1705. char *sep;
  1706. {
  1707.     char *r, *t, *tt;
  1708.     int f, sl;
  1709.  
  1710.     if (!**s)
  1711.     return NULL;
  1712.  
  1713.     if (sep) {
  1714.     sl = strlen(sep);
  1715.     r = *s;
  1716.     while (!(f = findsep(s, sep))) {
  1717.         r = *s += sl;
  1718.     }
  1719.     return r;
  1720.     }
  1721.     for (t = *s, f = 1; f && *t;) {
  1722.     for (tt = ifs, f = 0; !f && *tt; tt++)
  1723.         if (*tt == *t)
  1724.         f = 1;
  1725.     if (f)
  1726.         t++;
  1727.     }
  1728.     *s = t;
  1729.     findsep(s, sep);
  1730.     return t;
  1731. }
  1732.  
  1733. int wordcount(s, sep, mul)    /**/
  1734. char *s;
  1735. char *sep;
  1736. int mul;
  1737. {
  1738.     int r = 1, sl, c, cc;
  1739.     char *t = s, *ti;
  1740.  
  1741.     if (sep) {
  1742.     sl = strlen(sep);
  1743.     for (; (c = findsep(&t, sep)) >= 0; t += sl)
  1744.         if ((c && *(t + sl)) || mul)
  1745.         r++;
  1746.     } else {
  1747.     if (!mul)
  1748.         for (c = 1; c && *t;) {
  1749.         for (c = 0, ti = ifs; !c && *ti; ti++)
  1750.             if (*ti == *t)
  1751.             c = 1;
  1752.         if (c)
  1753.             t++;
  1754.         }
  1755.     if (!*t)
  1756.         return 0;
  1757.     for (; *t; t++) {
  1758.         for (c = 0, ti = ifs; !c && *ti; ti++)
  1759.         if (*ti == *t)
  1760.             c = 1;
  1761.         if (c && !mul) {
  1762.         for (cc = 1, t++; cc && *t;) {
  1763.             for (cc = 0, ti = ifs; !cc && *ti; ti++)
  1764.             if (*ti == *t)
  1765.                 cc = 1;
  1766.             if (cc)
  1767.             t++;
  1768.         }
  1769.         if (*t)
  1770.             r++;
  1771.         } else if (c)
  1772.         r++;
  1773.     }
  1774.     }
  1775.     return r;
  1776. }
  1777.  
  1778. char *sepjoin(s, sep)        /**/
  1779. char **s;
  1780. char *sep;
  1781. {
  1782.     char *r, *p, **t;
  1783.     int l, sl, elide = 0;
  1784.     static char *lastmem = NULL;
  1785.     char sepbuf[2];
  1786.  
  1787.     if (!sep) {
  1788.     elide = 1;
  1789.     sep = sepbuf;
  1790.     sepbuf[0] = *ifs;
  1791.     sepbuf[1] = '\0';
  1792.     }
  1793.  
  1794.     sl = strlen(sep);
  1795.     for (t = s, l = 1 - sl; *t; l += strlen(*t) + sl, t++);
  1796.     if (l == 1)
  1797.     return "";
  1798.     zsfree(lastmem);
  1799.     lastmem = r = p = (char *)zalloc(l);
  1800.     t = s;
  1801.     if (elide)
  1802.     while (*t && !**t)
  1803.         t++;
  1804.     for (; *t; t++) {
  1805.     strucpy(&p, *t);
  1806.     if (t[1] && (!elide || t[1][0]))
  1807.         strucpy(&p, sep);
  1808.     }
  1809.     return r;
  1810. }
  1811.  
  1812. char **sepsplit(s, sep)        /**/
  1813. char *s;
  1814. char *sep;
  1815. {
  1816.     int n, sl, f;
  1817.     char *t, *tt, **r, **p;
  1818.  
  1819.     if (!sep)
  1820.     return spacesplit(s);
  1821.  
  1822.     sl = strlen(sep);
  1823.     n = wordcount(s, sep, 1);
  1824.     r = p = (char **)zalloc((n + 1) * sizeof(char *));
  1825.  
  1826.     for (t = s; n--;) {
  1827.     tt = t;
  1828.     f = findsep(&t, sep);/* f set not but not used? ++jhi; */
  1829.     *p = (char *)zalloc(t - tt + 1);
  1830.     strncpy(*p, tt, t - tt);
  1831.     (*p)[t - tt] = '\0';
  1832.     p++;
  1833.     t += sl;
  1834.     }
  1835.     *p = NULL;
  1836.  
  1837.     return r;
  1838. }
  1839.  
  1840. List getshfunc(nam)        /**/
  1841. char *nam;
  1842. {
  1843.     Cmdnam x = (Cmdnam) gethnode(nam, cmdnamtab);
  1844.  
  1845.     if (x && (x->flags & SHFUNC)) {
  1846.     if (x->flags & PMFLAG_u) {
  1847.         List l;
  1848.  
  1849.         if (!(l = getfpfunc(nam))) {
  1850.         zerr("function not found: %s", nam, 0);
  1851.         return NULL;
  1852.         }
  1853.         x->flags &= ~PMFLAG_u;
  1854.         permalloc();
  1855.         x->u.list = (List) dupstruct(l);
  1856.         lastalloc();
  1857.     }
  1858.     return x->u.list;
  1859.     }
  1860.     return NULL;
  1861. }
  1862.  
  1863. /* allocate a tree element */
  1864.  
  1865. static int sizetab[N_COUNT] = {
  1866.     sizeof(struct list),
  1867.     sizeof(struct sublist),
  1868.     sizeof(struct pline),
  1869.     sizeof(struct cmd),
  1870.     sizeof(struct redir),
  1871.     sizeof(struct cond),
  1872.     sizeof(struct forcmd),
  1873.     sizeof(struct casecmd),
  1874.     sizeof(struct ifcmd),
  1875.     sizeof(struct whilecmd),
  1876.     sizeof(struct varasg) };
  1877.  
  1878. static int flagtab[N_COUNT] = {
  1879.     NT_SET(N_LIST, 1, NT_NODE, NT_NODE, 0, 0),
  1880.     NT_SET(N_SUBLIST, 2, NT_NODE, NT_NODE, 0, 0),
  1881.     NT_SET(N_PLINE, 1, NT_NODE, NT_NODE, 0, 0),
  1882.     NT_SET(N_CMD, 2, NT_STR | NT_LIST, NT_NODE, NT_NODE | NT_LIST, NT_NODE | NT_LIST),
  1883.     NT_SET(N_REDIR, 3, NT_STR, 0, 0, 0),
  1884.     NT_SET(N_COND, 1, NT_NODE, NT_NODE, 0, 0),
  1885.     NT_SET(N_FOR, 1, NT_STR, NT_NODE, 0, 0),
  1886.     NT_SET(N_CASE, 0, NT_STR | NT_ARR, NT_NODE | NT_ARR, 0, 0),
  1887.     NT_SET(N_IF, 0, NT_NODE | NT_ARR, NT_NODE | NT_ARR, 0, 0),
  1888.     NT_SET(N_WHILE, 1, NT_NODE, NT_NODE, 0, 0),
  1889.     NT_SET(N_VARASG, 1, NT_STR, NT_STR, NT_STR | NT_LIST, 0) };
  1890.  
  1891. vptr allocnode(type)        /**/
  1892. int type;
  1893. {
  1894.     struct node *n = (struct node *)alloc(sizetab[type]);
  1895.  
  1896.     memset((char *) n, 0, sizetab[type]);
  1897.     n->type = flagtab[type];
  1898.     if (useheap)
  1899.     n->type |= NT_HEAP;
  1900.  
  1901.     return (vptr) n;
  1902. }
  1903.  
  1904. vptr dupstruct(a)        /**/
  1905. vptr a;
  1906. {
  1907.     struct node *n = (struct node *) a, *r;
  1908.  
  1909.     if (!a || ((List) a) == &dummy_list)
  1910.     return (vptr) a;
  1911.  
  1912.     if ((n->type & NT_HEAP) && !useheap) {
  1913.     heapalloc();
  1914.     n = (struct node *) dupstruct2((vptr) n);
  1915.     permalloc();
  1916.     n = simplifystruct(n);
  1917.     }
  1918.  
  1919.     r = (struct node *) dupstruct2((vptr) n);
  1920.  
  1921.     if (!(n->type & NT_HEAP) && useheap)
  1922.     r = expandstruct(r, N_LIST);
  1923.  
  1924.     return (vptr) r;
  1925. }
  1926.  
  1927. struct node *simplifystruct(n)    /**/
  1928. struct node *n;
  1929. {
  1930.     if (!n || ((List) n) == &dummy_list)
  1931.     return n;
  1932.  
  1933.     switch (NT_TYPE(n->type)) {
  1934.     case N_LIST:
  1935.     {
  1936.         List l = (List) n;
  1937.  
  1938.         l->left = (Sublist) simplifystruct((struct node *) l->left);
  1939.         if (l->type == SYNC && !l->right)
  1940.         return (struct node *) l->left;
  1941.     }
  1942.     break;
  1943.     case N_SUBLIST:
  1944.     {
  1945.         Sublist sl = (Sublist) n;
  1946.  
  1947.         sl->left = (Pline) simplifystruct((struct node *) sl->left);
  1948.         if (sl->type == END && !sl->flags && !sl->right)
  1949.         return (struct node *) sl->left;
  1950.     }
  1951.     break;
  1952.     case N_PLINE:
  1953.     {
  1954.         Pline pl = (Pline) n;
  1955.  
  1956.         pl->left = (Cmd) simplifystruct((struct node *) pl->left);
  1957.         if (pl->type == END && !pl->right)
  1958.         return (struct node *) pl->left;
  1959.     }
  1960.     break;
  1961.     case N_CMD:
  1962.     {
  1963.         Cmd c = (Cmd) n;
  1964.         int i = 0;
  1965.  
  1966.         if (empty(c->args))
  1967.         c->args = NULL, i++;
  1968.         if (empty(c->redir))
  1969.         c->redir = NULL, i++;
  1970.         if (empty(c->vars))
  1971.         c->vars = NULL, i++;
  1972.  
  1973.         c->u.list = (List) simplifystruct((struct node *) c->u.list);
  1974.         if (i == 3 && !c->flags &&
  1975.         (c->type == CWHILE || c->type == CIF ||
  1976.          c->type == COND))
  1977.         return (struct node *) c->u.list;
  1978.     }
  1979.     break;
  1980.     case N_FOR:
  1981.     {
  1982.         struct forcmd *f = (struct forcmd *) n;
  1983.  
  1984.         f->list = (List) simplifystruct((struct node *) f->list);
  1985.     }
  1986.     break;
  1987.     case N_CASE:
  1988.     {
  1989.         struct casecmd *c = (struct casecmd *) n;
  1990.         List *l;
  1991.  
  1992.         for (l = c->lists; *l; l++)
  1993.         *l = (List) simplifystruct((struct node *) *l);
  1994.     }
  1995.     break;
  1996.     case N_IF:
  1997.     {
  1998.         struct ifcmd *i = (struct ifcmd *) n;
  1999.         List *l;
  2000.  
  2001.         for (l = i->ifls; *l; l++)
  2002.         *l = (List) simplifystruct((struct node *) *l);
  2003.         for (l = i->thenls; *l; l++)
  2004.         *l = (List) simplifystruct((struct node *) *l);
  2005.     }
  2006.     break;
  2007.     case N_WHILE:
  2008.     {
  2009.         struct whilecmd *w = (struct whilecmd *) n;
  2010.  
  2011.         w->cont = (List) simplifystruct((struct node *) w->cont);
  2012.         w->loop = (List) simplifystruct((struct node *) w->loop); 
  2013.     }
  2014.     }
  2015.  
  2016.     return n;
  2017. }
  2018.  
  2019. struct node *expandstruct(n, exp)    /**/
  2020. struct node *n;
  2021. int exp;
  2022. {
  2023.     struct node *m;
  2024.  
  2025.     if (!n || ((List) n) == &dummy_list)
  2026.     return n;
  2027.  
  2028.     if (exp != N_COUNT && exp != NT_TYPE(n->type)) {
  2029.     switch (exp) {
  2030.     case N_LIST:
  2031.         {
  2032.         List l;
  2033.  
  2034.         m = (struct node *) allocnode(N_LIST);
  2035.         l = (List) m;
  2036.         l->type = SYNC;
  2037.         l->left = (Sublist) expandstruct(n, N_SUBLIST);
  2038.  
  2039.         return (struct node *) l;
  2040.         }
  2041.     case N_SUBLIST:
  2042.         {
  2043.         Sublist sl;
  2044.  
  2045.         m = (struct node *) allocnode(N_SUBLIST);
  2046.         sl = (Sublist) m;
  2047.         sl->type = END;
  2048.         sl->left = (Pline) expandstruct(n, N_PLINE);
  2049.  
  2050.         return (struct node *) sl;
  2051.         }
  2052.     case N_PLINE:
  2053.         {
  2054.         Pline pl;
  2055.  
  2056.         m = (struct node *) allocnode(N_PLINE);
  2057.         pl = (Pline) m;
  2058.         pl->type = END;
  2059.         pl->left = (Cmd) expandstruct(n, N_CMD);
  2060.  
  2061.         return (struct node *) pl;
  2062.         }
  2063.     case N_CMD:
  2064.         {
  2065.         Cmd c;
  2066.  
  2067.         m = (struct node *) allocnode(N_CMD);
  2068.         c = (Cmd) m;
  2069.         switch (NT_TYPE(n->type)) {
  2070.         case N_WHILE:
  2071.             c->type = CWHILE;
  2072.             break;
  2073.         case N_IF:
  2074.             c->type = CIF;
  2075.             break;
  2076.         case N_COND:
  2077.             c->type = COND;
  2078.         }
  2079.         c->u.list = (List) expandstruct(n, NT_TYPE(n->type));
  2080.         c->args = newlist();
  2081.         c->vars = newlist();
  2082.         c->redir = newlist();
  2083.  
  2084.         return (struct node *) c;
  2085.         }
  2086.     }
  2087.     }
  2088.     else
  2089.     switch (NT_TYPE(n->type)) {
  2090.     case N_LIST:
  2091.         {
  2092.         List l = (List) n;
  2093.         
  2094.         l->left = (Sublist) expandstruct((struct node *) l->left, 
  2095.                          N_SUBLIST);
  2096.         l->right = (List) expandstruct((struct node *) l->right,
  2097.                            N_LIST);
  2098.         }
  2099.         break;
  2100.     case N_SUBLIST:
  2101.         {
  2102.         Sublist sl = (Sublist) n;
  2103.  
  2104.         sl->left = (Pline) expandstruct((struct node *) sl->left,
  2105.                         N_PLINE);
  2106.         sl->right = (Sublist) expandstruct((struct node *) sl->right,
  2107.                            N_SUBLIST);
  2108.         }
  2109.         break;
  2110.     case N_PLINE:
  2111.         {
  2112.         Pline pl = (Pline) n;
  2113.  
  2114.         pl->left = (Cmd) expandstruct((struct node *) pl->left,
  2115.                            N_CMD);
  2116.         pl->right = (Pline) expandstruct((struct node *) pl->right,
  2117.                          N_PLINE);
  2118.         }
  2119.         break;
  2120.     case N_CMD:
  2121.         {
  2122.         Cmd c = (Cmd) n;
  2123.  
  2124.         if (!c->args)
  2125.             c->args = newlist();
  2126.         if (!c->vars)
  2127.             c->vars = newlist();
  2128.         if (!c->redir)
  2129.             c->redir = newlist();
  2130.  
  2131.         switch (c->type) {
  2132.         case CFOR:
  2133.         case CSELECT:
  2134.             c->u.list = (List) expandstruct((struct node *) c->u.list,
  2135.                             N_FOR);
  2136.             break;
  2137.         case CWHILE:
  2138.             c->u.list = (List) expandstruct((struct node *) c->u.list,
  2139.                             N_WHILE);
  2140.             break;
  2141.         case CIF:
  2142.             c->u.list = (List) expandstruct((struct node *) c->u.list,
  2143.                             N_IF);
  2144.             break;
  2145.         case CCASE:
  2146.             c->u.list = (List) expandstruct((struct node *) c->u.list,
  2147.                             N_CASE);
  2148.             break;
  2149.         case COND:
  2150.             c->u.list = (List) expandstruct((struct node *) c->u.list,
  2151.                             N_COND);
  2152.             break;
  2153.         case ZCTIME:
  2154.             c->u.list = (List) expandstruct((struct node *) c->u.list,
  2155.                             N_SUBLIST);
  2156.             break;
  2157.         default:
  2158.             c->u.list = (List) expandstruct((struct node *) c->u.list,
  2159.                             N_LIST);
  2160.         }
  2161.         }
  2162.         break;
  2163.     case N_FOR:
  2164.         {
  2165.         struct forcmd *f = (struct forcmd *) n;
  2166.  
  2167.         f->list = (List) expandstruct((struct node *) f->list,
  2168.                           N_LIST);
  2169.         }
  2170.         break;
  2171.     case N_CASE:
  2172.         {
  2173.         struct casecmd *c = (struct casecmd *) n;
  2174.         List *l;
  2175.  
  2176.         for (l = c->lists; *l; l++)
  2177.             *l = (List) expandstruct((struct node *) *l, N_LIST);
  2178.         }
  2179.         break;
  2180.     case N_IF:
  2181.         {
  2182.         struct ifcmd *i = (struct ifcmd *) n;
  2183.         List *l;
  2184.  
  2185.         for (l = i->ifls; *l; l++)
  2186.             *l = (List) expandstruct((struct node *) *l, N_LIST);
  2187.         for (l = i->thenls; *l; l++)
  2188.             *l = (List) expandstruct((struct node *) *l, N_LIST);
  2189.         }
  2190.         break;
  2191.     case N_WHILE:
  2192.         {
  2193.         struct whilecmd *w = (struct whilecmd *) n;
  2194.  
  2195.         w->cont = (List) expandstruct((struct node *) w->cont,
  2196.                           N_LIST);
  2197.         w->loop = (List) expandstruct((struct node *) w->loop,
  2198.                           N_LIST);
  2199.         }
  2200.     }
  2201.  
  2202.     return n;
  2203. }
  2204.  
  2205. /* duplicate a syntax tree node of given type, argument number */
  2206.  
  2207. vptr dupnode(type, a, argnum)        /**/
  2208. int type;
  2209. vptr a;
  2210. int argnum;
  2211. {
  2212.     if (!a)
  2213.     return NULL;
  2214.     switch (NT_N(type, argnum)) {
  2215.         case NT_NODE:
  2216.     return (vptr) dupstruct2(a);
  2217.         case NT_STR:
  2218.     return (useheap) ? ((vptr) dupstring(a)) :
  2219.         ((vptr) ztrdup(a));
  2220.         case NT_LIST | NT_NODE:
  2221.     if (type & NT_HEAP)
  2222.             if (useheap)
  2223.         return (vptr) duplist(a, (VFunc) dupstruct2);
  2224.         else
  2225.         return (vptr) list2arr(a, (VFunc) dupstruct2);
  2226.         else
  2227.             if (useheap)
  2228.         return (vptr) arr2list(a, (VFunc) dupstruct2);
  2229.             else
  2230.         return (vptr) duparray(a, (VFunc) dupstruct2);
  2231.         case NT_LIST | NT_STR:
  2232.     if (type & NT_HEAP)
  2233.             if (useheap)
  2234.         return (vptr) duplist(a, (VFunc) dupstring);
  2235.             else
  2236.         return (vptr) list2arr(a, (VFunc) ztrdup);
  2237.         else
  2238.             if (useheap)
  2239.         return (vptr) arr2list(a, (VFunc) dupstring);
  2240.             else
  2241.         return (vptr) duparray(a, (VFunc) ztrdup);
  2242.     case NT_NODE | NT_ARR:
  2243.     return (vptr) duparray(a, (VFunc) dupstruct2);
  2244.     case NT_STR | NT_ARR:
  2245.     return (vptr) duparray(a, (VFunc) (useheap ? dupstring : ztrdup));
  2246.     default:
  2247.     abort();
  2248.     }
  2249. }
  2250.  
  2251. /* Free a syntax tree node of given type, argument number */
  2252.  
  2253. void freenode(type, a, argnum)        /**/
  2254. int type;
  2255. vptr a;
  2256. int argnum;
  2257. {
  2258.     if (!a)
  2259.     return;
  2260.     switch (NT_N(type, argnum)) {
  2261.     case NT_NODE:
  2262.     freestruct(a);
  2263.         break;
  2264.     case NT_STR:
  2265.     zsfree(a);
  2266.     break;
  2267.     case NT_LIST | NT_NODE:
  2268.         case NT_NODE | NT_ARR:
  2269.     {
  2270.         char **p = (char **) a;
  2271.         
  2272.         while (*p)
  2273.         freestruct(*p++);
  2274.         free(a);
  2275.     }
  2276.         break;
  2277.     case NT_LIST | NT_STR:
  2278.         case NT_STR | NT_ARR:
  2279.     freearray(a);
  2280.     break;
  2281.     default:
  2282.     abort();
  2283.     }
  2284. }
  2285.  
  2286. /* duplicate a syntax tree */
  2287.  
  2288. vptr *dupstruct2(a)        /**/
  2289. vptr a;
  2290. {
  2291.     struct node *n = (struct node *) a, *m;
  2292.     int type;
  2293.     
  2294.     if (!n || ((List) n) == &dummy_list)
  2295.     return a;
  2296.     type = n->type;
  2297.     m = (struct node *)alloc(sizetab[NT_TYPE(type)]);
  2298.     m->type = (type & ~NT_HEAP);
  2299.     if (useheap)
  2300.     m->type |= NT_HEAP;
  2301.     switch (NT_TYPE(type)) {
  2302.     case N_LIST:
  2303.         {
  2304.         List nl = (List) n;
  2305.         List ml = (List) m;
  2306.         
  2307.         ml->type = nl->type;
  2308.         ml->left = (Sublist) dupnode(type, nl->left, 0);
  2309.         ml->right = (List) dupnode(type, nl->right, 1);
  2310.     }
  2311.     break;
  2312.     case N_SUBLIST:
  2313.     {
  2314.         Sublist nsl = (Sublist) n;
  2315.         Sublist msl = (Sublist) m;
  2316.  
  2317.         msl->type = nsl->type;
  2318.         msl->flags = nsl->flags;
  2319.         msl->left = (Pline) dupnode(type, nsl->left, 0);
  2320.         msl->right = (Sublist) dupnode(type, nsl->right, 1);
  2321.     }
  2322.     break;
  2323.     case N_PLINE:
  2324.     {
  2325.         Pline npl = (Pline) n;
  2326.         Pline mpl = (Pline) m;
  2327.  
  2328.         mpl->type = npl->type;
  2329.         mpl->left = (Cmd) dupnode(type, npl->left, 0);
  2330.         mpl->right = (Pline) dupnode(type, npl->right, 1);
  2331.     }
  2332.     break;
  2333.     case N_CMD:
  2334.     {
  2335.         Cmd nc = (Cmd) n;
  2336.         Cmd mc = (Cmd) m;
  2337.  
  2338.         mc->type = nc->type;
  2339.         mc->flags = nc->flags;
  2340.         mc->args = (Lklist) dupnode(type, nc->args, 0);
  2341.         mc->u.generic = (vptr) dupnode(type, nc->u.generic, 1);
  2342.         mc->redir = (Lklist) dupnode(type, nc->redir, 2);
  2343.         mc->vars = (Lklist) dupnode(type, nc->vars, 3);
  2344.     }
  2345.     break;
  2346.     case N_REDIR:
  2347.     {
  2348.         Redir nr = (Redir) n;
  2349.         Redir mr = (Redir) m;
  2350.  
  2351.         mr->type = nr->type;
  2352.         mr->fd1 = nr->fd1;
  2353.         mr->fd2 = nr->fd2;
  2354.         mr->name = (char *) dupnode(type, nr->name, 0);
  2355.     }
  2356.     break;
  2357.     case N_COND:
  2358.     {
  2359.         Cond nco = (Cond) n;
  2360.         Cond mco = (Cond) m;
  2361.  
  2362.         mco->type = nco->type;
  2363.         mco->left = (vptr) dupnode(type, nco->left, 0);
  2364.         mco->right = (vptr) dupnode(type, nco->right, 1);
  2365.     }
  2366.     break;
  2367.     case N_FOR:
  2368.     {
  2369.         struct forcmd *nf = (struct forcmd *) n;
  2370.         struct forcmd *mf = (struct forcmd *) m;
  2371.  
  2372.         mf->inflag = nf->inflag;
  2373.         mf->name = (char *) dupnode(type, nf->name, 0);
  2374.         mf->list = (List) dupnode(type, nf->list, 1);
  2375.     }
  2376.     break;
  2377.     case N_CASE:
  2378.     {
  2379.         struct casecmd *ncc = (struct casecmd *) n;
  2380.         struct casecmd *mcc = (struct casecmd *) m;
  2381.  
  2382.         mcc->pats = (char **) dupnode(type, ncc->pats, 0);
  2383.         mcc->lists = (List *) dupnode(type, ncc->lists, 1);
  2384.     }
  2385.     break;
  2386.     case N_IF:
  2387.     {
  2388.         struct ifcmd *nic = (struct ifcmd *) n;
  2389.         struct ifcmd *mic = (struct ifcmd *) m;
  2390.  
  2391.         mic->ifls = (List *) dupnode(type, nic->ifls, 0);
  2392.         mic->thenls = (List *) dupnode(type, nic->thenls, 1);
  2393.         
  2394.     }
  2395.     break;
  2396.     case N_WHILE:
  2397.     {
  2398.         struct whilecmd *nwc = (struct whilecmd *) n;
  2399.         struct whilecmd *mwc = (struct whilecmd *) m;
  2400.  
  2401.         mwc->cond = nwc->cond;
  2402.         mwc->cont = (List) dupnode(type, nwc->cont, 0);
  2403.         mwc->loop = (List) dupnode(type, nwc->loop, 1);
  2404.     }
  2405.     break;
  2406.     case N_VARASG:
  2407.     {
  2408.         Varasg nva = (Varasg) n;
  2409.         Varasg mva = (Varasg) m;
  2410.  
  2411.         mva->type = nva->type;
  2412.         mva->name = (char *) dupnode(type, nva->name, 0);
  2413.         mva->str = (char *) dupnode(type, nva->str, 1);
  2414.         mva->arr = (Lklist) dupnode(type, nva->arr, 2);
  2415.         }
  2416.     break;
  2417.     }
  2418.     return (vptr *) m;
  2419. }
  2420.  
  2421. /* free a syntax tree */
  2422.  
  2423. void freestruct(a)        /**/
  2424. vptr a;
  2425. {
  2426.     struct node *n = (struct node *)a;
  2427.     int type;
  2428.  
  2429.     if (!n || ((List) n) == &dummy_list)
  2430.     return;
  2431.  
  2432.     type = n->type;
  2433.     switch (NT_TYPE(type)) {
  2434.     case N_LIST:
  2435.         {
  2436.         List nl = (List) n;
  2437.         freenode(type, nl->left, 0);
  2438.         freenode(type, nl->right, 1);
  2439.     }
  2440.         break;
  2441.     case N_SUBLIST:
  2442.     {
  2443.         Sublist nsl = (Sublist) n;
  2444.  
  2445.         freenode(type, nsl->left, 0);
  2446.         freenode(type, nsl->right, 1);
  2447.     }
  2448.         break;
  2449.     case N_PLINE:
  2450.         {
  2451.         Pline npl = (Pline) n;
  2452.  
  2453.         freenode(type, npl->left, 0);
  2454.         freenode(type, npl->right, 1);
  2455.     }
  2456.     break;
  2457.     case N_CMD:
  2458.     {
  2459.         Cmd nc = (Cmd) n;
  2460.  
  2461.         freenode(type, nc->args, 0);
  2462.         freenode(type, nc->u.generic, 1);
  2463.         freenode(type, nc->redir, 2);
  2464.         freenode(type, nc->vars, 3);
  2465.         }
  2466.         break;
  2467.     case N_REDIR:
  2468.     {
  2469.         Redir nr = (Redir) n;
  2470.  
  2471.         freenode(type, nr->name, 0);
  2472.     }
  2473.     break;
  2474.     case N_COND:
  2475.     {
  2476.         Cond nco = (Cond) n;
  2477.  
  2478.         freenode(type, nco->left, 0);
  2479.         freenode(type, nco->right, 1);
  2480.     }
  2481.     break;
  2482.     case N_FOR:
  2483.     {
  2484.         struct forcmd *nf = (struct forcmd *) n;
  2485.  
  2486.         freenode(type, nf->name, 0);
  2487.         freenode(type, nf->list, 1);
  2488.     }
  2489.     break;
  2490.     case N_CASE:
  2491.     {
  2492.         struct casecmd* ncc = (struct casecmd *) n;
  2493.  
  2494.         freenode(type, ncc->pats, 0);
  2495.         freenode(type, ncc->lists, 1);
  2496.     }
  2497.     break;
  2498.     case N_IF:
  2499.     {
  2500.         struct ifcmd *nic = (struct ifcmd *) n;
  2501.  
  2502.         freenode(type, nic->ifls, 0);
  2503.         freenode(type, nic->thenls, 1);
  2504.         
  2505.     }
  2506.     break;
  2507.     case N_WHILE:
  2508.     {
  2509.         struct whilecmd *nwc = (struct whilecmd *) n;
  2510.  
  2511.         freenode(type, nwc->cont, 0);
  2512.         freenode(type, nwc->loop, 1);
  2513.     }
  2514.     break;
  2515.     case N_VARASG:
  2516.     {
  2517.         Varasg nva = (Varasg) n;
  2518.  
  2519.         freenode(type, nva->name, 0);
  2520.         freenode(type, nva->str, 1);
  2521.         freenode(type, nva->arr, 2);
  2522.     }
  2523.         break;
  2524.         }
  2525.     zfree(n, sizetab[NT_TYPE(type)]);
  2526. }
  2527.  
  2528. Lklist duplist(l, func)        /**/
  2529. Lklist l;
  2530. VFunc func;
  2531. {
  2532.     Lklist ret;
  2533.     Lknode node;
  2534.  
  2535.     ret = newlist();
  2536.     for (node = firstnode(l); node; incnode(node))
  2537.     addnode(ret, func(getdata(node)));
  2538.     return ret;
  2539. }
  2540.  
  2541. char **duparray(arr, func)    /**/
  2542. char **arr;
  2543. VFunc func;
  2544. {
  2545.     char **ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *)), **rr;
  2546.  
  2547.     for (rr = ret; *arr;)
  2548.     *rr++ = (char *) func(*arr++);
  2549.     *rr = NULL;
  2550.  
  2551.     return ret;
  2552. }
  2553.  
  2554. char **list2arr(l, func)    /**/
  2555. Lklist l;
  2556. VFunc func;
  2557. {
  2558.     char **arr, **r;
  2559.     Lknode n;
  2560.  
  2561.     arr = r = (char **) alloc((countnodes(l) + 1) * sizeof(char *));
  2562.  
  2563.     for (n = firstnode(l); n; incnode(n))
  2564.     *r++ = (char *) func(getdata(n));
  2565.     *r = NULL;
  2566.  
  2567.     return arr;
  2568. }
  2569.  
  2570. Lklist arr2list(arr, func)    /**/
  2571. char **arr;
  2572. VFunc func;
  2573. {
  2574.     Lklist l = newlist();
  2575.  
  2576.     while (*arr)
  2577.     addnode(l, func(*arr++));
  2578.  
  2579.     return l;
  2580. }
  2581.  
  2582. char **mkarray(s)        /**/
  2583. char *s;
  2584. {
  2585.     char **t = (char **)zalloc((s) ? (2 * sizeof s) : (sizeof s));
  2586.  
  2587.     if ((*t = s))
  2588.     t[1] = NULL;
  2589.     return t;
  2590. }
  2591.  
  2592. void feep()
  2593. {                /**/
  2594.     if (unset(NOBEEP))
  2595.     write(2, "\07", 1);
  2596. }
  2597.  
  2598. void freearray(s)        /**/
  2599. char **s;
  2600. {
  2601.     char **t = s;
  2602.  
  2603.     while (*s)
  2604.     zsfree(*s++);
  2605.     free(t);
  2606. }
  2607.  
  2608. int equalsplit(s, t)        /**/
  2609. char *s;
  2610. char **t;
  2611. {
  2612.     for (; *s && *s != '='; s++);
  2613.     if (*s == '=') {
  2614.     *s++ = '\0';
  2615.     *t = s;
  2616.     return 1;
  2617.     }
  2618.     return 0;
  2619. }
  2620.  
  2621. /* see if the right side of a list is trivial */
  2622.  
  2623. void simplifyright(l)        /**/
  2624. List l;
  2625. {
  2626.     Cmd c;
  2627.  
  2628.     if (l == &dummy_list || !l->right)
  2629.     return;
  2630.     if (l->right->right || l->right->left->right ||
  2631.     l->right->left->flags || l->right->left->left->right ||
  2632.     l->left->flags)
  2633.     return;
  2634.     c = l->left->left->left;
  2635.     if (c->type != SIMPLE || full(c->args) || full(c->redir)
  2636.     || full(c->vars))
  2637.     return;
  2638.     l->right = NULL;
  2639.     return;
  2640. }
  2641.  
  2642. /* initialize the ztypes table */
  2643.  
  2644. void inittyptab()
  2645. {                /**/
  2646.     int t0;
  2647.     char *s;
  2648.  
  2649.     for (t0 = 0; t0 != 256; t0++)
  2650.     typtab[t0] = 0;
  2651.     for (t0 = 0; t0 != 32; t0++)
  2652.     typtab[t0] = typtab[t0 + 128] = ICNTRL;
  2653.     typtab[127] = ICNTRL;
  2654.     for (t0 = '0'; t0 <= '9'; t0++)
  2655.     typtab[t0] = IDIGIT | IALNUM | IWORD | IIDENT | IUSER;
  2656.     for (t0 = 'a'; t0 <= 'z'; t0++)
  2657.     typtab[t0] = typtab[t0 - 'a' + 'A'] = IALPHA | IALNUM | IIDENT | IUSER | IWORD;
  2658.     for (t0 = 0240; t0 != 0400; t0++)
  2659.     typtab[t0] = IALPHA | IALNUM | IIDENT | IUSER | IWORD;
  2660.     typtab['_'] = IIDENT | IUSER;
  2661.     typtab['-'] = IUSER;
  2662.     typtab[' '] |= IBLANK | INBLANK;
  2663.     typtab['\t'] |= IBLANK | INBLANK;
  2664.     typtab['\n'] |= INBLANK;
  2665.     for (t0 = (int)STOUC(ALPOP); t0 <= (int)STOUC(Nularg);
  2666.      t0++)
  2667.     typtab[t0] |= ITOK;
  2668.     for (s = ifs; *s; s++)
  2669.     typtab[(int)(unsigned char)*s] |= ISEP;
  2670.     for (s = wordchars; *s; s++)
  2671.     typtab[(int)(unsigned char)*s] |= IWORD;
  2672.     for (s = SPECCHARS; *s; s++)
  2673.     typtab[(int)(unsigned char)*s] |= ISPECIAL;
  2674. }
  2675.  
  2676. char **arrdup(s)        /**/
  2677. char **s;
  2678. {
  2679.     char **x, **y;
  2680.  
  2681.     y = x = (char **)ncalloc(sizeof(char *) * (arrlen(s) + 1));
  2682.  
  2683.     while ((*x++ = dupstring(*s++)));
  2684.     return y;
  2685. }
  2686.  
  2687. /* next few functions stolen (with changes) from Kernighan & Pike */
  2688. /* "The UNIX Programming Environment" (w/o permission) */
  2689.  
  2690. char *spname(oldname)        /**/
  2691. char *oldname;
  2692. {
  2693.     char *p, spnameguess[MAXPATHLEN + 1], spnamebest[MAXPATHLEN + 1];
  2694.     static char newname[MAXPATHLEN + 1];
  2695.     char *new = newname, *old;
  2696.  
  2697.     if (itok(*oldname)) {
  2698.     singsub(&oldname);
  2699.     if (!oldname)
  2700.         return NULL;
  2701.     }
  2702.     if (access(oldname, F_OK) == 0)
  2703.     return NULL;
  2704.     old = oldname;
  2705.     for (;;) {
  2706.     while (*old == '/')
  2707.         *new++ = *old++;
  2708.     *new = '\0';
  2709.     if (*old == '\0')
  2710.         return newname;
  2711.     p = spnameguess;
  2712.     for (; *old != '/' && *old != '\0'; old++)
  2713.         if (p < spnameguess + MAXPATHLEN)
  2714.         *p++ = *old;
  2715.     *p = '\0';
  2716.     if (mindist(newname, spnameguess, spnamebest) >= 3)
  2717.         return NULL;
  2718.     for (p = spnamebest; (*new = *p++);)
  2719.         new++;
  2720.     }
  2721. }
  2722.  
  2723. int mindist(dir, mindistguess, mindistbest)    /**/
  2724. char *dir;
  2725. char *mindistguess;
  2726. char *mindistbest;
  2727. {
  2728.     int mindistd, nd;
  2729.     DIR *dd;
  2730.     struct dirent *de;
  2731.     char buf[MAXPATHLEN];
  2732.  
  2733.     if (dir[0] == '\0')
  2734.     dir = ".";
  2735.     mindistd = 100;
  2736.     sprintf(buf, "%s/%s", dir, mindistguess);
  2737.     if (access(buf, F_OK) == 0) {
  2738.     strcpy(mindistbest, mindistguess);
  2739.     return 0;
  2740.     }
  2741.     if (!(dd = opendir(dir)))
  2742.     return mindistd;
  2743.     while ((de = readdir(dd))) {
  2744.     nd = spdist(de->d_name, mindistguess, 
  2745.             (int) strlen(mindistguess) / 4 + 1);
  2746.     if (nd <= mindistd) {
  2747.         strcpy(mindistbest, de->d_name);
  2748.         mindistd = nd;
  2749.         if (mindistd == 0)
  2750.         break;
  2751.     }
  2752.     }
  2753.     closedir(dd);
  2754.     return mindistd;
  2755. }
  2756.  
  2757. int spdist(s, t, thresh)    /**/
  2758. char *s;
  2759. char *t;
  2760. int thresh;
  2761. {
  2762.     char *p, *q;
  2763.     char *keymap =
  2764.     "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  2765. \t1234567890-=\t\
  2766. \tqwertyuiop[]\t\
  2767. \tasdfghjkl;'\n\t\
  2768. \tzxcvbnm,./\t\t\t\
  2769. \n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  2770. \t!@#$%^&*()_+\t\
  2771. \tQWERTYUIOP{}\t\
  2772. \tASDFGHJKL:\"\n\t\
  2773. \tZXCVBNM<>?\n\n\t\
  2774. \n\n\n\n\n\n\n\n\n\n\n\n\n\n";
  2775.  
  2776.     if (!strcmp(s, t))
  2777.     return 0;
  2778. /* any number of upper/lower mistakes allowed (dist = 1) */
  2779.     for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++, q++);
  2780.     if (!*p && !*q)
  2781.     return 1;
  2782.     if (!thresh)
  2783.     return 200;
  2784.     for (p = s, q = t; *p && *q; p++, q++)
  2785.     if (*p == *q)
  2786.         continue;        /* don't consider "aa" transposed, ash */
  2787.     else if (p[1] == q[0] && q[1] == p[0])    /* transpositions */
  2788.         return spdist(p + 2, q + 2, thresh - 1) + 1;
  2789.     else if (p[1] == q[0])    /* missing letter */
  2790.         return spdist(p + 1, q + 0, thresh - 1) + 2;
  2791.     else if (p[0] == q[1])    /* missing letter */
  2792.         return spdist(p + 0, q + 1, thresh - 1) + 2;
  2793.     else if (*p != *q)
  2794.         break;
  2795.     if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1))
  2796.     return 2;
  2797.     for (p = s, q = t; *p && *q; p++, q++)
  2798.     if (p[0] != q[0] && p[1] == q[1]) {
  2799.         int t0;
  2800.         char *z;
  2801.  
  2802.     /* mistyped letter */
  2803.  
  2804.         if (!(z = strchr(keymap, p[0])) || *z == '\n' || *z == '\t')
  2805.         return spdist(p + 1, q + 1, thresh - 1) + 1;
  2806.         t0 = z - keymap;
  2807.         if (*q == keymap[t0 - 15] || *q == keymap[t0 - 14] ||
  2808.         *q == keymap[t0 - 13] ||
  2809.         *q == keymap[t0 - 1] || *q == keymap[t0 + 1] ||
  2810.         *q == keymap[t0 + 13] || *q == keymap[t0 + 14] ||
  2811.         *q == keymap[t0 + 15])
  2812.         return spdist(p + 1, q + 1, thresh - 1) + 2;
  2813.         return 200;
  2814.     } else if (*p != *q)
  2815.         break;
  2816.     return 200;
  2817. }
  2818.  
  2819. char *zgetenv(s)        /**/
  2820. char *s;
  2821. {
  2822.     char **av, *p, *q;
  2823.  
  2824.     for (av = environ; *av; av++) {
  2825.     for (p = *av, q = s; *p && *p != '=' && *q && *p == *q; p++, q++);
  2826.     if (*p == '=' && !*q)
  2827.         return p + 1;
  2828.     }
  2829.     return NULL;
  2830. }
  2831.  
  2832. int tulower(c)            /**/
  2833. int c;
  2834. {
  2835.     c &= 0xff;
  2836.     return (isupper(c) ? tolower(c) : c);
  2837. }
  2838.  
  2839. int tuupper(c)            /**/
  2840. int c;
  2841. {
  2842.     c &= 0xff;
  2843.     return (islower(c) ? toupper(c) : c);
  2844. }
  2845.  
  2846. #ifdef SYSV
  2847. #include <sys/utsname.h>
  2848.  
  2849. int gethostname(nameptr, maxlength)
  2850. char *nameptr;
  2851. int maxlength;
  2852. {
  2853.     struct utsname name;
  2854.     int result;
  2855.  
  2856.     result = uname(&name);
  2857.     if (result >= 0) {
  2858.     strncpy(nameptr, name.nodename, maxlength);
  2859.     return 0;
  2860.     } else
  2861.     return -1;
  2862. }
  2863.  
  2864. #endif
  2865.  
  2866. /* set cbreak mode, or the equivalent */
  2867.  
  2868. void setcbreak()
  2869. {                /**/
  2870.     struct ttyinfo ti;
  2871.  
  2872.     ti = shttyinfo;
  2873. #ifdef HAS_TIO
  2874.     ti.tio.c_lflag &= ~ICANON;
  2875.     ti.tio.c_cc[VMIN] = 1;
  2876.     ti.tio.c_cc[VTIME] = 0;
  2877. #else
  2878.     ti.sgttyb.sg_flags |= CBREAK;
  2879. #endif
  2880.     settyinfo(&ti);
  2881. }
  2882.  
  2883. /* give the tty to some process */
  2884.  
  2885. void attachtty(pgrp)        /**/
  2886. long pgrp;
  2887. {
  2888.     static int ep = 0;
  2889.  
  2890.     if (jobbing) {
  2891. #ifdef HAS_TCSETPGRP
  2892.     if (SHTTY != -1 && tcsetpgrp(SHTTY, pgrp) == -1 && !ep)
  2893. #else
  2894. #if ardent
  2895.     if (SHTTY != -1 && setpgrp() == -1 && !ep) 
  2896. #else
  2897.     int arg = pgrp;
  2898.  
  2899.     if (SHTTY != -1 && ioctl(SHTTY, TIOCSPGRP, &arg) == -1 && !ep)
  2900. #endif
  2901. #endif
  2902.     {
  2903.         zerr("can't set tty pgrp: %e", NULL, errno);
  2904.         fflush(stderr);
  2905.         opts[MONITOR] = OPT_UNSET;
  2906.         ep = 1;
  2907.         errflag = 0;
  2908.     }
  2909.     }
  2910. }
  2911.  
  2912. /* get the tty pgrp */
  2913.  
  2914. long gettygrp()
  2915. {                /**/
  2916.     int arg;
  2917.  
  2918.     if (SHTTY == -1)
  2919.     return -1;
  2920. #ifdef HAS_TCSETPGRP
  2921.     arg = tcgetpgrp(SHTTY);
  2922. #else
  2923. #if ardent
  2924.     arg = getpgrp();
  2925. #else
  2926.     ioctl(SHTTY, TIOCGPGRP, &arg);
  2927. #endif
  2928. #endif
  2929.     return arg;
  2930. }
  2931.  
  2932. #if defined(SCO)
  2933. void gettimeofday(struct timeval *tv, struct timezone *tz)
  2934. {
  2935.     tv->tv_usec=0;
  2936.     tv->tv_sec=(long)time((time_t)0);
  2937. }
  2938. #endif
  2939.