home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / z / zsh220.zip / zsh2.2 / src / utils.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  32KB  |  1,804 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. #ifdef __hpux
  25. #include <ndir.h>
  26. #else
  27. #ifndef SYSV
  28. #include <sys/dir.h>
  29. #endif
  30. #endif
  31. #include <fcntl.h>
  32.  
  33. #ifdef SYSV
  34. #define direct dirent
  35. #undef TIOCGWINSZ
  36. int readlink(s,t,z)
  37. char *s;char *t;int z;
  38. {
  39. return -1;
  40. }
  41. #endif
  42.  
  43. /* source a file */
  44.  
  45. int source(s) /**/
  46. char *s;
  47. {
  48. int fd,cj = thisjob;
  49. int oldlineno = lineno,oldshst;
  50. FILE *obshin = bshin;
  51.  
  52.     fd = SHIN;
  53.     lineno = 0;
  54.     oldshst = opts[SHINSTDIN];
  55.     opts[SHINSTDIN] = OPT_UNSET;
  56.     if ((SHIN = movefd(open(s,O_RDONLY))) == -1)
  57.         {
  58.         SHIN = fd;
  59.         thisjob = cj;
  60.         opts[SHINSTDIN] = oldshst;
  61.         return 1;
  62.         }
  63.     bshin = fdopen(SHIN,"r");
  64.     loop();
  65.     fclose(bshin);
  66.     bshin = obshin;
  67.     opts[SHINSTDIN] = oldshst;
  68.     SHIN = fd;
  69.     thisjob = cj;
  70.     errflag = 0;
  71.     retflag = 0;
  72.     lineno = oldlineno;
  73.     return 0;
  74. }
  75.  
  76. /* try to source a file in the home directory */
  77.  
  78. void sourcehome(s) /**/
  79. char *s;
  80. {
  81. char buf[MAXPATHLEN];
  82. char *h;
  83.  
  84.     if (!(h = getsparam("ZDOTDIR")))
  85.         h = home;
  86.     sprintf(buf,"%s/%s",h,s);
  87.     (void) source(buf);
  88. }
  89.  
  90. /* print an error */
  91.  
  92. void zerrnam(cmd,fmt,str,num) /**/
  93. char *cmd; char *fmt; char *str;int num;
  94. {
  95.     if (cmd)
  96.         {
  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.             {
  109.             fmt++;
  110.             switch(*fmt++)
  111.                 {
  112.                 case 's':
  113.                     while (*str)
  114.                         niceputc(*str++,stderr);
  115.                     break;
  116.                 case 'l':
  117.                     while (num--)
  118.                         niceputc(*str++,stderr);
  119.                     break;
  120.                 case 'd':
  121.                     fprintf(stderr,"%d",num);
  122.                     break;
  123.                 case '%':
  124.                     putc('%',stderr);
  125.                     break;
  126.                 case 'c':
  127.                     niceputc(num,stderr);
  128.                     break;
  129.                 case 'e':
  130.                     if (num == EINTR)
  131.                         {
  132.                         fputs("interrupt\n",stderr);
  133.                         errflag = 1;
  134.                         return;
  135.                         }
  136.                     if (num == EIO)
  137.                         fputs(sys_errlist[num],stderr);
  138.                     else
  139.                         {
  140.                         fputc(tulower(sys_errlist[num][0]),stderr);
  141.                         fputs(sys_errlist[num]+1,stderr);
  142.                         }
  143.                     break;
  144.                 }
  145.             }
  146.         else
  147.             putc(*fmt++,stderr);
  148.     if (unset(SHINSTDIN) && lineno)
  149.         fprintf(stderr," [%ld]\n",lineno);
  150.     else
  151.         putc('\n',stderr);
  152.     fflush(stderr);
  153. }
  154.  
  155. void zerr(fmt,str,num) /**/
  156. char *fmt; char *str;int num;
  157. {
  158.     if (errflag || noerrs)
  159.         return;
  160.     errflag = 1;
  161.     trashzle();
  162.     fprintf(stderr,"%s: ",(isset(SHINSTDIN)) ? "zsh" : argzero);
  163.     zerrnam(NULL,fmt,str,num);
  164. }
  165.  
  166. void niceputc(c,f) /**/
  167. int c;FILE *f;
  168. {
  169.     if (itok(c))
  170.         {
  171.         if (c >= Pound && c <= Comma)
  172.             putc(ztokens[c-Pound],f);
  173.         return;
  174.         }
  175.     c &= 0xff;
  176.     if (isprint(c))
  177.         putc(c,f);
  178.     else if (c == '\n')
  179.         {
  180.         putc('\\',f);
  181.         putc('n',f);
  182.         }
  183.     else
  184.         {
  185.         putc('^',f);
  186.         putc(c|'@',f);
  187.         }
  188. }
  189.  
  190. /* enable ^C interrupts */
  191.  
  192. void intr() /**/
  193. {
  194. #ifdef SV_INTERRUPT
  195. static struct sigvec vec = { handler,sigmask(SIGINT),SV_INTERRUPT };
  196.  
  197.     if (interact)
  198.         sigvec(SIGINT,&vec,NULL);
  199. #else
  200.     if (interact)
  201.         signal(SIGINT,handler);
  202. #endif
  203. }
  204.  
  205. void noholdintr() /**/
  206. {
  207.     intr();
  208. }
  209.  
  210. void holdintr() /**/
  211. {
  212. #ifdef SV_INTERRUPT
  213. static struct sigvec vec = { handler,sigmask(SIGINT),0 };
  214.  
  215.     if (interact) sigvec(SIGINT,&vec,NULL);
  216. #else
  217.     if (interact) signal(SIGINT,SIG_IGN);
  218. #endif
  219. }
  220.  
  221. char *fgetline(buf,len,in) /**/
  222. char *buf;int len;FILE *in;
  223. {
  224.     if (!fgets(buf,len,in))
  225.         return NULL;
  226.     buf[len] = '\0';
  227.     buf[strlen(buf)-1] = '\0';
  228.     return buf;
  229. }
  230.  
  231. /* get a symlink-free pathname for s relative to PWD */
  232.  
  233. char *findpwd(s) /**/
  234. char *s;
  235. {
  236. char *t;
  237.  
  238.     if (*s == '/')
  239.         return xsymlink(s);
  240.     s = tricat((pwd[1]) ? pwd : "","/",s);
  241.     t = xsymlink(s);
  242.     free(s);
  243.     return t;
  244. }
  245.  
  246. static char xbuf[MAXPATHLEN];
  247.  
  248. #if 0
  249. char *fixpwd(s) /**/
  250. char *s;
  251. {
  252. struct stat sbuf,tbuf;
  253. char *t;
  254.  
  255.     strcpy(xbuf,"");
  256.     if (*s == '/')
  257.         t = ztrdup(s);
  258.     else
  259.         t = tricat((pwd[1]) ? pwd : "","/",s);
  260.     (void) xsymlinks(t+1,0); 
  261.     free(t);
  262.     if (!*xbuf)
  263.         strcpy(xbuf,"/");
  264.     if (stat(xbuf,&sbuf) == 0 && stat(".",&tbuf) == 0)
  265.         if (!(sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino))
  266.             chdir(xbuf);
  267.     return ztrdup(xbuf);
  268. }
  269. #endif
  270.  
  271. int ispwd(s) /**/
  272. char *s;
  273. {
  274. struct stat sbuf,tbuf;
  275.  
  276.     if (stat(s,&sbuf) == 0 && stat(".",&tbuf) == 0)
  277.         if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
  278.             return 1;
  279.     return 0;
  280. }
  281.  
  282. /* expand symlinks in s, and remove other weird things */
  283.  
  284. char *xsymlink(s) /**/
  285. char *s;
  286. {
  287.     if (unset(CHASELINKS))
  288.         return ztrdup(s);
  289.     if (*s != '/')
  290.         return NULL;
  291.     strcpy(xbuf,"");
  292.     if (xsymlinks(s+1,1))
  293.         return ztrdup(s);
  294.     if (!*xbuf)
  295.         return ztrdup("/");
  296.     return ztrdup(xbuf);
  297. }
  298.  
  299. char **slashsplit(s) /**/
  300. char *s;
  301. {
  302. char *t,**r,**q;
  303. int t0;
  304.  
  305.     if (!*s)
  306.         return (char **) zcalloc(sizeof(char **));
  307.     for (t = s, t0 = 0; *t; t++)
  308.         if (*t == '/')
  309.             t0++;
  310.     q  = r = (char **) zalloc(sizeof(char **)*(t0+2));
  311.     while (t = strchr(s,'/'))
  312.         {
  313.         *t = '\0';
  314.         *q++ = ztrdup(s);
  315.         *t = '/';
  316.         while (*t == '/')
  317.             t++;
  318.         if (!*t)
  319.             {
  320.             *q = NULL;
  321.             return r;
  322.             }
  323.         s = t;
  324.         }
  325.     *q++ = ztrdup(s);
  326.     *q = NULL;
  327.     return r;
  328. }
  329.  
  330. int islink(s) /**/
  331. char *s;
  332. {
  333.     return readlink(s,NULL,0) == 0;
  334. }
  335.  
  336. /* expands symlinks and .. or . expressions */
  337. /* if flag = 0, only expand .. and . expressions */
  338.  
  339. int xsymlinks(s,flag) /**/
  340. char *s;int flag;
  341. {
  342. char **pp,**opp;
  343. char xbuf2[MAXPATHLEN],xbuf3[MAXPATHLEN];
  344. int t0;
  345.  
  346.     opp = pp = slashsplit(s);
  347.     for (; *pp; pp++)
  348.         {
  349.         if (!strcmp(*pp,"."))
  350.             {
  351.             free(*pp);
  352.             continue;
  353.             }
  354.         if (!strcmp(*pp,".."))
  355.             {
  356.             char *p;
  357.  
  358.             free(*pp);
  359.             if (!strcmp(xbuf,"/"))
  360.                 continue;
  361.             p = xbuf+strlen(xbuf);
  362.             while (*--p != '/');
  363.             *p = '\0';
  364.             continue;
  365.             }
  366.         if (unset(CHASELINKS))
  367.             {
  368.             strcat(xbuf,"/");
  369.             strcat(xbuf,*pp);
  370.             free(*pp);
  371.             continue;
  372.             }
  373.         sprintf(xbuf2,"%s/%s",xbuf,*pp);
  374.         t0 = readlink(xbuf2,xbuf3,MAXPATHLEN);
  375.         if (t0 == -1 || !flag)
  376.             {
  377.             strcat(xbuf,"/");
  378.             strcat(xbuf,*pp);
  379.             free(*pp);
  380.             }
  381.         else
  382.             {
  383.             xbuf3[t0] = '\0'; /* STUPID */
  384.             if (*xbuf3 == '/')
  385.                 {
  386.                 strcpy(xbuf,"");
  387.                 if (xsymlinks(xbuf3+1,flag))
  388.                     return 1;
  389.                 }
  390.             else
  391.                 if (xsymlinks(xbuf3,flag))
  392.                     return 1;
  393.             free(*pp);
  394.             }
  395.         }
  396.     free(opp);
  397.     return 0;
  398. }
  399.  
  400. /* print a directory */
  401.  
  402. void fprintdir(s, f) /**/
  403. char *s; FILE *f;
  404. {
  405. int t0;
  406.  
  407.     t0 = finddir(s);
  408.     if (t0 == -1)
  409.         {
  410.         if (!strncmp(s,home,t0 = strlen(home)) && t0 > 1)
  411.             {
  412.             putc('~', f);
  413.             fputs(s+t0,f);
  414.             }
  415.         else
  416.             fputs(s,f);
  417.         }
  418.     else
  419.         {
  420.         putc('~', f);
  421.         fputs(usernames[t0],f);
  422.         fputs(s+strlen(userdirs[t0]),f);
  423.         }
  424. }
  425.  
  426. void printdir(s) /**/
  427. char *s;
  428. {
  429.     fprintdir(s, stdout);
  430. }
  431.  
  432. void printdircr(s) /**/
  433. char *s;
  434. {
  435.     fprintdir(s, stdout);
  436.     putchar('\n');
  437. }
  438.  
  439. /* see if a path has a named directory as its prefix */
  440.  
  441. int finddir(s) /**/
  442. char *s;
  443. {
  444. int t0,t1,step;
  445.  
  446.     if (userdirsz)
  447.         {
  448.         step = t0 = userdirsz/2;
  449.         for(;;)
  450.             {
  451.             t1 = (userdirs[t0]) ? dircmp(userdirs[t0],s) : 1;
  452.             if (!t1)
  453.                 {
  454.                 while (t0 != userdirsz-1 && userdirs[t0+1] && 
  455.                         !dircmp(userdirs[t0+1],s)) 
  456.                     t0++;
  457.                 return t0;
  458.                 }
  459.             if (!step)
  460.                 break;
  461.             if (t1 > 0)
  462.                 t0 = t0-step+step/2;
  463.             else
  464.                 t0 += step/2;
  465.             step /= 2;
  466.             }
  467.         }
  468.     return -1;
  469. }
  470.  
  471. /* add a named directory */
  472.  
  473. void adduserdir(s,t) /**/
  474. char *s;char *t;
  475. {
  476. int t0,t1;
  477.  
  478.     if (!interact || ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0])))
  479.         return;
  480.     if (!strcmp(t,"/"))
  481.         return;
  482.     if ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0]))
  483.         return;
  484.     if (userdirsz == userdirct)
  485.         {
  486.         userdirsz *= 2;
  487.         userdirs = (char **) realloc((char *) userdirs,
  488.             sizeof(char **)*userdirsz);
  489.         usernames = (char **) realloc((char *) usernames,
  490.             sizeof(char **)*userdirsz);
  491.         for (t0 = userdirct; t0 != userdirsz; t0++)
  492.             userdirs[t0] = usernames[t0] = NULL;
  493.         }
  494.     for (t0 = 0; t0 != userdirct; t0++)
  495.         if (strcmp(userdirs[t0],t) > 0)
  496.             break;
  497.     for (t1 = userdirct-1; t1 >= t0; t1--)
  498.         {
  499.         userdirs[t1+1] = userdirs[t1];
  500.         usernames[t1+1] = usernames[t1];
  501.         }
  502.     userdirs[t0] = ztrdup(t);
  503.     usernames[t0] = ztrdup(s);
  504.     userdirct++;
  505. }
  506.  
  507. int dircmp(s,t) /**/
  508. char *s;char *t;
  509. {
  510.     for (; *s && *t; s++,t++)
  511.         if (*s != *t)
  512.             return *s-*t;
  513.     if (!*s && (!*t || *t == '/'))
  514.         return 0;
  515.     return *s-*t;
  516. }
  517.  
  518. int ddifftime(t1,t2) /**/
  519. time_t t1;time_t t2;
  520. {
  521.     return ((long) t2-(long) t1);
  522. }
  523.  
  524. /* see if jobs need printing */
  525.  
  526. void scanjobs() /**/
  527. {
  528. int t0;
  529.  
  530.     for (t0 = 1; t0 != MAXJOB; t0++)
  531.         if (jobtab[t0].stat & STAT_CHANGED)
  532.             printjob(jobtab+t0,0);
  533. }
  534.  
  535. /* do pre-prompt stuff */
  536.  
  537. void preprompt() /**/
  538. {
  539. int diff;
  540. List list;
  541. struct schedcmd *sch,*schl;
  542.  
  543.     if (unset(NOTIFY))
  544.         scanjobs();
  545.     if (errflag)
  546.         return;
  547.     if (list = getshfunc("precmd")) doshfuncnoval(list,NULL,0);
  548.     if (errflag)
  549.         return;
  550.     if (period && (time(NULL) > lastperiod+period) &&
  551.             (list = getshfunc("periodic"))) {
  552.         doshfuncnoval(list,NULL,0);
  553.         lastperiod = time(NULL);
  554.     }
  555.     if (errflag)
  556.         return;
  557.     if (watch)
  558.         {
  559.         diff = (int) ddifftime(lastwatch,time(NULL));
  560.         if (diff > logcheck)
  561.             {
  562.             dowatch();
  563.             lastwatch = time(NULL);
  564.             }
  565.         }
  566.     if (errflag)
  567.         return;
  568.     diff = (int) ddifftime(lastmailcheck,time(NULL));
  569.     if (diff > mailcheck)
  570.         {
  571.         if (mailpath && *mailpath)
  572.             checkmailpath(mailpath);
  573.         else if (mailfile)
  574.             {
  575.             char *x[2];
  576.  
  577.             x[0] = mailfile;
  578.             x[1] = NULL;
  579.             checkmailpath(x);
  580.             }
  581.         lastmailcheck = time(NULL);
  582.         }
  583.     for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds; sch;
  584.             sch = (schl = sch)->next)
  585.         {
  586.         if (sch->time < time(NULL))
  587.             {
  588.             execstring(sch->cmd);
  589.             schl->next = sch->next;
  590.             free(sch->cmd);
  591.             free(sch);
  592.             }
  593.         if (errflag)
  594.             return;
  595.         }
  596. }
  597.  
  598. int arrlen(s) /**/
  599. char **s;
  600. {
  601. int t0;
  602.  
  603.     for (t0 = 0; *s; s++,t0++);
  604.     return t0;
  605. }
  606.  
  607. void checkmailpath(s) /**/
  608. char **s;
  609. {
  610. struct stat st;
  611. char *v,*u,c;
  612.  
  613.     while (*s)
  614.         {
  615.         for (v = *s; *v && *v != '?'; v++);
  616.         c = *v;
  617.         *v = '\0';
  618.         if (c != '?')
  619.             u = NULL;
  620.         else
  621.             u = v+1;
  622.         if (stat(*s,&st) == -1)
  623.             {
  624.             if (errno != ENOENT)
  625.                 zerr("%e: %s",*s,errno);
  626.             }
  627.         else if (S_ISDIR(st.st_mode))
  628.             {
  629.             Lklist l;
  630.             DIR *lock = opendir(*s);
  631.             char buf[MAXPATHLEN*2],**arr,**ap;
  632.             struct direct *de;
  633.             int ct = 1;
  634.  
  635.             if (lock)
  636.                 {
  637.                 pushheap();
  638.                 heapalloc();
  639.                 l = newlist();
  640.                 readdir(lock); readdir(lock);
  641.                 while (de = readdir(lock))
  642.                     {
  643.                     if (errflag)
  644.                         break;
  645.                     if (u)
  646.                         sprintf(buf,"%s/%s?%s",*s,de->d_name,u);
  647.                     else
  648.                         sprintf(buf,"%s/%s",*s,de->d_name);
  649.                     addnode(l,strdup(buf));
  650.                     ct++;
  651.                     }
  652.                 closedir(lock);
  653.                 ap = arr = (char **) alloc(ct*sizeof(char *));
  654.                 while (*ap++ = ugetnode(l));
  655.                 checkmailpath(arr);
  656.                 popheap();
  657.                 }
  658.             }
  659.         else
  660.             {
  661.             if (st.st_size && st.st_atime <= st.st_mtime &&
  662.                     st.st_mtime > lastmailcheck)
  663.                 if (!u)
  664.                     {
  665.                     fprintf(stderr,"You have new mail.\n",*s);
  666.                     fflush(stderr);
  667.                     }
  668.                 else
  669.                     {
  670.                     char *z = u;
  671.  
  672.                     while (*z)
  673.                         if (*z == '$' && z[1] == '_')
  674.                             {
  675.                             fprintf(stderr,"%s",*s);
  676.                             z += 2;
  677.                             }
  678.                         else
  679.                             fputc(*z++,stderr);
  680.                     fputc('\n',stderr);
  681.                     fflush(stderr);
  682.                     }
  683.             if (isset(MAILWARNING) && st.st_atime > st.st_mtime &&
  684.                     st.st_atime > lastmailcheck && st.st_size)
  685.                 {
  686.                 fprintf(stderr,"The mail in %s has been read.\n",*s);
  687.                 fflush(stderr);
  688.                 }
  689.             }
  690.         *v = c;
  691.         s++;
  692.         }
  693. }
  694.  
  695. void saveoldfuncs(x,y) /**/
  696. char *x;Cmdnam y;
  697. {
  698. Cmdnam cc;
  699.  
  700.     if (y->type == SHFUNC || y->type == DISABLED)
  701.         {
  702.         cc = (Cmdnam) zcalloc(sizeof *cc);
  703.         *cc = *y;
  704.         y->u.list = NULL;
  705.         addhnode(ztrdup(x),cc,cmdnamtab,freecmdnam);
  706.         }
  707. }
  708.  
  709. /* create command hashtable */
  710.  
  711. void newcmdnamtab() /**/
  712. {
  713. Hashtab oldcnt;
  714.  
  715.     oldcnt = cmdnamtab;
  716.     permalloc();
  717.     cmdnamtab = newhtable(101);
  718.     addbuiltins();
  719.     if (oldcnt) {
  720.         listhtable(oldcnt,(HFunc) saveoldfuncs);
  721.         freehtab(oldcnt,freecmdnam);
  722.     }
  723.     lastalloc();
  724.     pathchecked = path;
  725. }
  726.  
  727. void freecmdnam(a) /**/
  728. vptr a;
  729. {
  730. struct cmdnam *c = (struct cmdnam *) a;
  731.  
  732.     if (c->type == SHFUNC) {
  733.         if (c->u.list)
  734.             freestruct(c->u.list);
  735.     } else if (c->type != BUILTIN && c->type != DISABLED)
  736.         free(c->u.nam);
  737.     free(c);
  738. }
  739.  
  740. void freecompctl(a) /**/
  741. vptr a;
  742. {
  743. Compctl cc = (Compctl) a;
  744.  
  745.     free(cc);
  746. }
  747.  
  748. void freestr(a) /**/
  749. vptr a;
  750. {
  751.     free(a);
  752. }
  753.  
  754. void freeanode(a) /**/
  755. vptr a;
  756. {
  757. struct alias *c = (struct alias *) a;
  758.  
  759.     free(c->text);
  760.     free(c);
  761. }
  762.  
  763. void freepm(a) /**/
  764. vptr a;
  765. {
  766. struct param *pm = (Param) a;
  767.  
  768.     free(pm);
  769. }
  770.  
  771. void restoretty() /**/
  772. {
  773.     settyinfo(&shttyinfo);
  774. }
  775.  
  776. void gettyinfo(ti) /**/
  777. struct ttyinfo *ti;
  778. {
  779.     if (SHTTY != -1)
  780.         {
  781. #ifdef TERMIOS
  782. #ifdef HAS_TCCRAP
  783.         if (tcgetattr(SHTTY,&ti->tio) == -1)
  784. #else
  785.         if (ioctl(SHTTY,TCGETS,&ti->tio) == -1)
  786. #endif
  787.             zerr("bad tcgets: %e",NULL,errno);
  788. #else
  789. #ifdef TERMIO
  790.         ioctl(SHTTY,TCGETA,&ti->tio);
  791. #else
  792.         ioctl(SHTTY,TIOCGETP,&ti->sgttyb);
  793.         ioctl(SHTTY,TIOCLGET,&ti->lmodes);
  794.         ioctl(SHTTY,TIOCGETC,&ti->tchars);
  795.         ioctl(SHTTY,TIOCGLTC,&ti->ltchars);
  796. #endif
  797. #endif
  798. #ifdef TIOCGWINSZ
  799.         if (ioctl(SHTTY,TIOCGWINSZ,&ti->winsize) == -1)
  800.         /*    zerr("bad tiocgwinsz: %e",NULL,errno)*/;
  801. #endif
  802.         }
  803. }
  804.  
  805. void settyinfo(ti) /**/
  806. struct ttyinfo *ti;
  807. {
  808.     if (SHTTY != -1)
  809.         {
  810. #ifdef TERMIOS
  811. #ifdef HAS_TCCRAP
  812. #ifndef TCSADRAIN
  813. #define TCSADRAIN 1   /* XXX Princeton's include files are screwed up */
  814. #endif
  815.         if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1)
  816. #else
  817.         if (ioctl(SHTTY,TCSETS,&ti->tio) == -1)
  818. #endif
  819.         /*    zerr("settyinfo: %e",NULL,errno)*/;
  820. #else
  821. #ifdef TERMIO
  822.         ioctl(SHTTY,TCSETA,&ti->tio);
  823. #else
  824.         ioctl(SHTTY,TIOCSETN,&ti->sgttyb);
  825.         ioctl(SHTTY,TIOCLSET,&ti->lmodes);
  826.         ioctl(SHTTY,TIOCSETC,&ti->tchars);
  827.         ioctl(SHTTY,TIOCSLTC,&ti->ltchars);
  828. #endif
  829. #endif
  830. #ifdef TIOCGWINSZ
  831.         signal(SIGWINCH,SIG_IGN);
  832.         if (ioctl(SHTTY,TIOCSWINSZ,&ti->winsize) == -1)
  833.         /*    zerr("settyinfo: %e",NULL,errno)*/;
  834.         signal(SIGWINCH,handler);
  835. #endif
  836.         }
  837. }
  838.  
  839. #define SANEKEY(X) \
  840.     if (ti->X == -1 && savedttyinfo.X != -1) ti->X = savedttyinfo.X;
  841.  
  842. void sanetty(ti) /**/
  843. struct ttyinfo *ti;
  844. {
  845. int t0;
  846.  
  847. #ifdef TIO
  848.     ti->tio.c_lflag |= ICANON|ECHO;
  849. #ifdef FLUSHO
  850.     ti->tio.c_lflag &= ~FLUSHO;
  851. #endif
  852.     for (t0 = 0; t0 !=
  853. #ifdef NCCS
  854.     NCCS
  855. #else
  856.     NCC
  857. #endif
  858.     ; t0++)
  859.         if (ti->tio.c_cc[t0] == VDISABLEVAL &&
  860.                 savedttyinfo.tio.c_cc[t0] != VDISABLEVAL)
  861.             ti->tio.c_cc[t0] = savedttyinfo.tio.c_cc[t0];
  862. #else
  863.     ti->sgttyb.sg_flags = (ti->sgttyb.sg_flags & ~CBREAK) | ECHO;
  864.     ti->lmodes &= ~LFLUSHO;
  865.     SANEKEY(tchars.t_quitc);
  866.     SANEKEY(tchars.t_startc);
  867.     SANEKEY(tchars.t_stopc);
  868.     SANEKEY(ltchars.t_suspc);
  869.     SANEKEY(ltchars.t_dsuspc);
  870.     SANEKEY(ltchars.t_lnextc);
  871.     SANEKEY(ltchars.t_flushc);
  872. #endif
  873. }
  874.  
  875. void adjustwinsize() /**/
  876. {
  877. #ifdef TIOCGWINSZ
  878.     ioctl(SHTTY,TIOCGWINSZ,&shttyinfo.winsize);
  879.     if (!(columns = shttyinfo.winsize.ws_col)) columns = 80;
  880.     lines = shttyinfo.winsize.ws_row;
  881.     setintenv("COLUMNS",columns);
  882.     setintenv("LINES",lines);
  883.     if (zleactive) refresh();
  884. #endif
  885. }
  886.  
  887. int zyztem(s,t) /**/
  888. char *s;char *t;
  889. {
  890. #ifdef WAITPID
  891. int pid,statusp;
  892.  
  893.     if (!(pid = fork()))
  894.         {
  895.         s = tricat(s," ",t);
  896.         execl("/bin/sh","sh","-c",s,(char *) 0);
  897.         _exit(1);
  898.         }
  899.     while (waitpid(pid,&statusp,WUNTRACED) == -1 && errno == EINTR);
  900.     if (WIFEXITED(statusp))
  901.         return WEXITSTATUS(statusp);
  902.     return 1;
  903. #else
  904.     if (!waitfork())
  905.         {
  906.         s = tricat(s," ",t);
  907.         execl("/bin/sh","sh","-c",s,(char *) 0);
  908.         _exit(1);
  909.         }
  910.     return 0;
  911. #endif
  912. }
  913.  
  914. #ifndef WAITPID
  915.  
  916. /* fork a process and wait for it to complete without confusing
  917.     the SIGCHLD handler */
  918.  
  919. int waitfork() /**/
  920. {
  921. int pipes[2];
  922. char x;
  923.  
  924.     pipe(pipes);
  925.     if (!fork())
  926.         {
  927.         close(pipes[0]);
  928.         signal(SIGCHLD,SIG_DFL);
  929.         if (!fork())
  930.             return 0;
  931.         wait(NULL);
  932.         _exit(0);
  933.         }
  934.     close(pipes[1]);
  935.     read(pipes[0],&x,1);
  936.     close(pipes[0]);
  937.     return 1;
  938. }
  939.  
  940. #endif
  941.  
  942. /* move a fd to a place >= 10 */
  943.  
  944. int movefd(fd) /**/
  945. int fd;
  946. {
  947. int fe;
  948.  
  949.     if (fd == -1)
  950.         return fd;
  951. #ifdef F_DUPFD
  952.     fe = fcntl(fd,F_DUPFD,10);
  953. #else
  954.     if ((fe = dup(fd)) < 10)
  955.         fe = movefd(fe);
  956. #endif
  957.     close(fd);
  958.     return fe;
  959. }
  960.  
  961. /* move fd x to y */
  962.  
  963. void redup(x,y) /**/
  964. int x;int y;
  965. {
  966.     if (x != y)
  967.         {
  968.         dup2(x,y);
  969.         close(x);
  970.         }
  971. }
  972.  
  973. void settrap(t0,l) /**/
  974. int t0;List l;
  975. {
  976. Cmd c;
  977.  
  978.     if (l)
  979.         {
  980.         c = l->left->left->left;
  981.         if (c->type == SIMPLE && !full(c->args) && !full(c->redir)
  982.                 && !full(c->vars) && !c->flags)
  983.             l = NULL;
  984.         }
  985.     if (t0 == -1)
  986.         return;
  987.     if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
  988.             || t0 == SIGPIPE))
  989.         {
  990.         zerr("can't trap SIG%s in interactive shells",sigs[t0-1],0);
  991.         return;
  992.         }
  993.     if (!l)
  994.         {
  995.         sigtrapped[t0] = 2;
  996.         if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD)
  997.             {
  998.             signal(t0,SIG_IGN);
  999.             sigtrapped[t0] = 2;
  1000.             }
  1001.         }
  1002.     else
  1003.         {
  1004.         if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD)
  1005.             signal(t0,handler);
  1006.         sigtrapped[t0] = 1;
  1007.         permalloc();
  1008.         sigfuncs[t0] = (List) dupstruct(l);
  1009.         heapalloc();
  1010.         }
  1011. }
  1012.  
  1013. void unsettrap(t0) /**/
  1014. int t0;
  1015. {
  1016.     if (t0 == -1)
  1017.         return;
  1018.     if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
  1019.             || t0 == SIGPIPE)) {
  1020.         return;
  1021.     }
  1022.     sigtrapped[t0] = 0;
  1023.     if (t0 == SIGINT) intr();
  1024.     else if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD) signal(t0,SIG_DFL);
  1025.     if (sigfuncs[t0]) freestruct(sigfuncs[t0]);
  1026. }
  1027.  
  1028. void dotrap(sig) /**/
  1029. int sig;
  1030. {
  1031. int sav,savval;
  1032.  
  1033.     sav = sigtrapped[sig];
  1034.     savval = lastval;
  1035.     if (sav == 2)
  1036.         return;
  1037.     sigtrapped[sig] = 2;
  1038.     if (sigfuncs[sig]) {
  1039.         lexsave();
  1040.         doshfuncnoval(sigfuncs[sig],NULL,0);
  1041.         lexrestore();
  1042.     }
  1043.     sigtrapped[sig] = sav;
  1044.     lastval = savval;
  1045. }
  1046.  
  1047. /* copy len chars from t into s, and null terminate */
  1048.  
  1049. void ztrncpy(s,t,len) /**/
  1050. char *s;char *t;int len;
  1051. {
  1052.     while (len--) *s++ = *t++;
  1053.     *s = '\0';
  1054. }
  1055.  
  1056. /* copy t into *s and update s */
  1057.  
  1058. void strucpy(s,t) /**/
  1059. char **s;char *t;
  1060. {
  1061. char *u = *s;
  1062.  
  1063.     while (*u++ = *t++);
  1064.     *s = u-1;
  1065. }
  1066.  
  1067. void struncpy(s,t,n) /**/
  1068. char **s;char *t;int n;
  1069. {
  1070. char *u = *s;
  1071.  
  1072.     while (n--)
  1073.         *u++ = *t++;
  1074.     *s = u;
  1075.     *u = '\0';
  1076. }
  1077.  
  1078. void checkrmall(s) /**/
  1079. char *s;
  1080. {
  1081.     fflush(stdin);
  1082.     if (*s == '/')
  1083.         fprintf(stderr,"zsh: sure you want to delete all the files in %s? ",s);
  1084.     else
  1085.         fprintf(stderr,"zsh: sure you want to delete all the files in %s/%s? ",
  1086.             (pwd[1]) ? pwd : "",s);
  1087.     fflush(stderr);
  1088.     feep();
  1089.     errflag |= (getquery() != 'y');
  1090. }
  1091.  
  1092. int getquery() /**/
  1093. {
  1094. char c;
  1095. long val;
  1096.  
  1097.     setcbreak();
  1098. #ifdef FIONREAD
  1099.     ioctl(SHTTY,FIONREAD,&val);
  1100.     if (val) { unsetcbreak(); write(2,"n\n",2); return 'n'; }
  1101. #endif
  1102.     if (read(SHTTY,&c,1) == 1)
  1103.         if (c == 'y' || c == 'Y' || c == '\t') c = 'y';
  1104.     unsetcbreak();
  1105.     if (c != '\n')
  1106.         write(2,"\n",1);
  1107.     return (int) c;
  1108. }
  1109.  
  1110. static int d;
  1111. static char *guess,*best;
  1112.  
  1113. void spscannodis(s,cn) /**/
  1114. char *s;char *cn;
  1115. {
  1116.     if (((Cmdnam) cn)->type != DISABLED)
  1117.         spscan(s,NULL);
  1118. }
  1119.  
  1120. void spscan(s,junk) /**/
  1121. char *s;char *junk;
  1122. {
  1123. int nd;
  1124.  
  1125.     nd = spdist(s,guess,strlen(guess)/4+1);
  1126.     if (nd <= d) {
  1127.         best = s;
  1128.         d = nd;
  1129.     }
  1130. }
  1131.  
  1132. /* spellcheck a word */
  1133. /* fix s and s2 ; if s2 is non-null, fix the history list too */
  1134.  
  1135. void spckword(s,s2,tptr,cmd,ask) /**/
  1136. char **s;char **s2;char **tptr;int cmd;int ask;
  1137. {
  1138. char *t,*u;
  1139. char firstchar;
  1140. int x;
  1141. int pram = 0;
  1142.  
  1143.     if (**s == '-' || **s == '%')
  1144.         return;
  1145.     if (!strcmp(*s,"in"))
  1146.         return;
  1147.     if (!(*s)[0] || !(*s)[1]) return;
  1148.     if (gethnode(*s,cmdnamtab) || gethnode(*s,aliastab)) return;
  1149.     t = *s;
  1150.     if (*t == Tilde || *t == Equals || *t == String) t++;
  1151.     for (; *t; t++) if (itok(*t)) return;
  1152.     best = NULL;
  1153.     for (t = *s; *t; t++) if (*t == '/') break;
  1154.     if (**s == String) {
  1155.         if (*t) return;
  1156.         pram = 1;
  1157.         guess = *s+1;
  1158.         d = 100;
  1159.         listhtable(paramtab,spscan);
  1160.     } else {
  1161.         if ((u = spname(guess = *s)) != *s)
  1162.             best = u;
  1163.         if (!*t && !cmd) {
  1164.             if (access(*s,F_OK) == 0) return;
  1165.             if (hashcmd(*s,pathchecked)) return;
  1166.             guess = *s;
  1167.             d = 100;
  1168.             listhtable(aliastab,spscan);
  1169.             listhtable(cmdnamtab,spscan);
  1170.         }
  1171.     }
  1172.     if (errflag) return;
  1173.     if (best && strlen(best) > 1 && strcmp(best,guess)) {
  1174.         if (ask) {
  1175.             char *pp;
  1176.             int junk;
  1177.  
  1178.             rstring = best; Rstring = guess;
  1179.             firstchar = *guess;
  1180.             if (*guess == Tilde) *guess = '~';
  1181.             else if (*guess == String) *guess = '$';
  1182.             else if (*guess == Equals) *guess = '=';
  1183.             pp = putprompt(sprompt,&junk);
  1184.             *guess = firstchar;
  1185.             fprintf(stderr,"%s",pp);
  1186.             fflush(stderr);
  1187.             feep();
  1188.             x = getquery();
  1189.         } else
  1190.             x = 'y';
  1191.         if (x == 'y') {
  1192.             if (!pram) {
  1193.                 *s = strdup(best);
  1194.             } else {
  1195.                 *s = alloc(strlen(best)+2);
  1196.                 strcpy(*s+1,best);
  1197.                 **s = String;
  1198.             }
  1199.             if (s2) {
  1200.                 if (*tptr && !strcmp(hlastw,*s2) && hlastw < hptr) {
  1201.                     char *z;
  1202.                     hptr = hlastw;
  1203.                     if (pram) hwaddc('$');
  1204.                     for (z = best; *z; z++) hwaddc(*z);
  1205.                     hwaddc(HISTSPACE);
  1206.                     *tptr = hptr-1;
  1207.                     **tptr = '\0';
  1208.                 }
  1209.                 *s2 = strdup(best);
  1210.             }
  1211.         } else if (x == 'a') {
  1212.             histdone |= HISTFLAG_NOEXEC;
  1213.         } else if (x == 'e') {
  1214.             histdone |= HISTFLAG_NOEXEC|HISTFLAG_RECALL;
  1215.         }
  1216.     }
  1217. }
  1218.  
  1219. int ztrftime(buf,bufsize,fmt,tm) /**/
  1220. char *buf;int bufsize;char *fmt;struct tm *tm;
  1221. {
  1222. static char *astr[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  1223. static char *estr[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
  1224.     "Aug","Sep","Oct","Nov","Dec"};
  1225. static char *lstr[] = {"12"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9",
  1226.     "10","11"};
  1227. char tmp[3];
  1228. #ifdef HAS_STRFTIME
  1229. char *origbuf = buf;
  1230. #endif
  1231.  
  1232.     tmp[0] = '%'; tmp[2] = '\0';
  1233.     while (*fmt)
  1234.         if (*fmt == '%')
  1235.             {
  1236.             fmt++;
  1237.             switch(*fmt++)
  1238.                 {
  1239.                 case 'a':
  1240.                     strucpy(&buf,astr[tm->tm_wday]);
  1241.                     break;
  1242.                 case 'b':
  1243.                     strucpy(&buf,estr[tm->tm_mon]);
  1244.                     break;
  1245.                 case 'd':
  1246.                     *buf++ = '0'+tm->tm_mday/10;
  1247.                     *buf++ = '0'+tm->tm_mday%10;
  1248.                     break;
  1249.                 case 'e':
  1250.                     if (tm->tm_mday > 9)
  1251.                         *buf++ = '0'+tm->tm_mday/10;
  1252.                     *buf++ = '0'+tm->tm_mday%10;
  1253.                     break;
  1254.                 case 'k':
  1255.                     if (tm->tm_hour > 9)
  1256.                         *buf++ = '0'+tm->tm_hour/10;
  1257.                     *buf++ = '0'+tm->tm_hour%10;
  1258.                     break;
  1259.                 case 'l':
  1260.                     strucpy(&buf,lstr[tm->tm_hour%12]);
  1261.                     break;
  1262.                 case 'm':
  1263.                     *buf++ = '0'+(tm->tm_mon+1)/10;
  1264.                     *buf++ = '0'+(tm->tm_mon+1)%10;
  1265.                     break;
  1266.                 case 'M':
  1267.                     *buf++ = '0'+tm->tm_min/10;
  1268.                     *buf++ = '0'+tm->tm_min%10;
  1269.                     break;
  1270.                 case 'p':
  1271.                     *buf++ = (tm->tm_hour > 11) ? 'p' : 'a';
  1272.                     *buf++ = 'm';
  1273.                     break;
  1274.                 case 'S':
  1275.                     *buf++ = '0'+tm->tm_sec/10;
  1276.                     *buf++ = '0'+tm->tm_sec%10;
  1277.                     break;
  1278.                 case 'y':
  1279.                     *buf++ = '0'+tm->tm_year/10;
  1280.                     *buf++ = '0'+tm->tm_year%10;
  1281.                     break;
  1282.                 default:
  1283. #ifdef HAS_STRFTIME
  1284.                     *buf = '\0';
  1285.                     tmp[1] = fmt[-1];
  1286.                     strftime(buf,bufsize-strlen(origbuf),tmp,tm);
  1287.                     buf += strlen(buf);
  1288. #else
  1289.                     *buf++ = '%';
  1290.                     *buf++ = fmt[-1];
  1291. #endif
  1292.                     break;
  1293.                 }
  1294.             }
  1295.         else
  1296.             *buf++ = *fmt++;
  1297.     *buf = '\0';
  1298.     return 0;
  1299. }
  1300.  
  1301. char *join(arr,delim) /**/
  1302. char **arr;int delim;
  1303. {
  1304. int len = 0;
  1305. char **s,*ret,*ptr;
  1306. static char *lastmem = NULL;
  1307.  
  1308.     for (s = arr; *s; s++)
  1309.         len += strlen(*s)+1;
  1310.     if (!len) return "";
  1311.     if (lastmem) free(lastmem);
  1312.     lastmem = ptr = ret = zalloc(len);
  1313.     for (s = arr; *s; s++) {
  1314.         strucpy(&ptr,*s);
  1315.         *ptr++ = delim;
  1316.     }
  1317.     ptr[-1] = '\0';
  1318.     return ret;
  1319. }
  1320.  
  1321. char *spacejoin(s) /**/
  1322. char **s;
  1323. {
  1324.     return join(s,*ifs);
  1325. }
  1326.  
  1327. char *colonjoin(s) /**/
  1328. char **s;
  1329. {
  1330.     return join(s,':');
  1331. }
  1332.  
  1333. char **colonsplit(s) /**/
  1334. char *s;
  1335. {
  1336. int ct;
  1337. char *t,**ret,**ptr;
  1338. char **lastmem = NULL;
  1339.  
  1340.     for (t = s, ct = 0; *t; t++) if (*t == ':') ct++;
  1341.     if (lastmem) freearray(lastmem);
  1342.     lastmem = ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
  1343.     t = s;
  1344.     do {
  1345.         for (s = t; *t && *t != ':'; t++);
  1346.         *ptr = zalloc((t-s)+1);
  1347.         ztrncpy(*ptr++,s,t-s);
  1348.     }
  1349.     while (*t++);
  1350.     *ptr = NULL;
  1351.     return ret;
  1352. }
  1353.  
  1354. char **spacesplit(s) /**/
  1355. char *s;
  1356. {
  1357. int ct;
  1358. char *t,**ret,**ptr;
  1359.  
  1360.     for (t = s, ct = 0; *t; t++)
  1361.         if (isep(*t)) ct++;
  1362.     ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
  1363.     t = s;
  1364.     do {
  1365.         for (s = t; *t && !isep(*t); t++);
  1366.         *ptr = zalloc((t-s)+1);
  1367.         ztrncpy(*ptr++,s,t-s);
  1368.     } while (*t++);
  1369.     *ptr = NULL;
  1370.     return ret;
  1371. }
  1372.  
  1373. List getshfunc(nam) /**/
  1374. char *nam;
  1375. {
  1376. Cmdnam x = (Cmdnam) gethnode(nam,cmdnamtab);
  1377.  
  1378.     return (x && x->type == SHFUNC) ? x->u.list : NULL;
  1379. }
  1380.  
  1381. /* allocate a tree element */
  1382.  
  1383. vptr allocnode(type) /**/
  1384. int type;
  1385. {
  1386. int t0;
  1387. struct node *n = (struct node *) alloc(sizeof *n);
  1388. static int typetab[N_COUNT][4] = {
  1389.     NT_NODE,NT_NODE,0,0,
  1390.     NT_NODE,NT_NODE,0,0,
  1391.     NT_NODE,NT_NODE,0,0,
  1392.     NT_STR|NT_LIST,NT_NODE,NT_NODE|NT_LIST,NT_NODE|NT_LIST,
  1393.     NT_STR,0,0,0,
  1394.     NT_NODE,NT_NODE,0,0,
  1395.     NT_STR,NT_NODE,0,0,
  1396.     NT_NODE,NT_STR,NT_NODE,0,
  1397.     NT_NODE,NT_NODE,NT_NODE,0,
  1398.     NT_NODE,NT_NODE,0,0,
  1399.     NT_STR,NT_STR,NT_STR|NT_LIST,0
  1400.     };
  1401.  
  1402.     n->type = type;
  1403.     for (t0 = 0; t0 != 4; t0++)
  1404.         n->types[t0] = typetab[type][t0];
  1405.     return (vptr) n;
  1406. }
  1407.  
  1408. /* duplicate a syntax tree */
  1409.  
  1410. vptr dupstruct(a) /**/
  1411. vptr a;
  1412. {
  1413. struct node *n = a,*m;
  1414. int t0;
  1415.  
  1416.     if (!a) return NULL;
  1417.     m = alloc(sizeof *m);
  1418.     *m = *n;
  1419.     for (t0 = 0; t0 != 4; t0++)
  1420.         if (m->ptrs[t0])
  1421.             switch(m->types[t0])
  1422.                 {
  1423.                 case NT_NODE: m->ptrs[t0] = dupstruct(m->ptrs[t0]); break;
  1424.                 case NT_STR: m->ptrs[t0] =
  1425.                     (useheap) ? strdup(m->ptrs[t0]) : ztrdup(m->ptrs[t0]); break;
  1426.                 case NT_LIST|NT_NODE:
  1427.                     m->ptrs[t0] = duplist(m->ptrs[t0],dupstruct); break;
  1428.                 case NT_LIST|NT_STR:
  1429.                     m->ptrs[t0] = duplist(m->ptrs[t0],(VFunc)
  1430.                         ((useheap) ? strdup : ztrdup));
  1431.                     break;
  1432.                 }
  1433.     return (vptr) m;
  1434. }
  1435.  
  1436. /* free a syntax tree */
  1437.  
  1438. void freestruct(a) /**/
  1439. vptr a;
  1440. {
  1441. struct node *n = (struct node *) a;
  1442. int t0;
  1443.  
  1444.     for (t0 = 0; t0 != 4; t0++)
  1445.         if (n->ptrs[t0])
  1446.             switch(n->types[t0])
  1447.                 {
  1448.                 case NT_NODE: freestruct(n->ptrs[t0]); break;
  1449.                 case NT_STR: free(n->ptrs[t0]); break;
  1450.                 case NT_LIST|NT_STR: freetable(n->ptrs[t0],freestr); break;
  1451.                 case NT_LIST|NT_NODE: freetable(n->ptrs[t0],freestruct); break;
  1452.                 }
  1453.     free(n);
  1454. }
  1455.  
  1456. Lklist duplist(l,func) /**/
  1457. Lklist l;VFunc func;
  1458. {
  1459. Lklist ret;
  1460. Lknode node;
  1461.  
  1462.     ret = newlist();
  1463.     for (node = firstnode(l); node; incnode(node))
  1464.         addnode(ret,func(getdata(node)));
  1465.     return ret;
  1466. }
  1467.  
  1468. char **mkarray(s) /**/
  1469. char *s;
  1470. {
  1471. char **t = (char **) zalloc((s) ? (2*sizeof s) : (sizeof s));
  1472.  
  1473.     if (*t = s) t[1] = NULL;
  1474.     return t;
  1475. }
  1476.  
  1477. void feep() /**/
  1478. {
  1479.     if (unset(NOBEEP))
  1480.         write(2,"\07",1);
  1481. }
  1482.  
  1483. void freearray(s) /**/
  1484. char **s;
  1485. {
  1486. char **t = s;
  1487.  
  1488.     while (*s)
  1489.         free(*s++);
  1490.     free(t);
  1491. }
  1492.  
  1493. int equalsplit(s,t) /**/
  1494. char *s;char **t;
  1495. {
  1496.     for (; *s && *s != '='; s++);
  1497.     if (*s == '=')
  1498.         {
  1499.         *s++ = '\0';
  1500.         *t = s;
  1501.         return 1;
  1502.         }
  1503.     return 0;
  1504. }
  1505.  
  1506. /* see if the right side of a list is trivial */
  1507.  
  1508. void simplifyright(l) /**/
  1509. List l;
  1510. {
  1511. Cmd c;
  1512.  
  1513.     if (!l->right)
  1514.         return;
  1515.     if (l->right->right || l->right->left->right ||
  1516.             l->right->left->left->right)
  1517.         return;
  1518.     c = l->left->left->left;
  1519.     if (c->type != SIMPLE || full(c->args) || full(c->redir)
  1520.             || full(c->vars))
  1521.         return;
  1522.     l->right = NULL;
  1523.     return;
  1524. }
  1525.  
  1526. /* initialize the ztypes table */
  1527.  
  1528. void inittyptab() /**/
  1529. {
  1530. int t0;
  1531. char *s;
  1532.  
  1533.     for (t0 = 0; t0 != 256; t0++)
  1534.         typtab[t0] = 0;
  1535.     for (t0 = 0; t0 != 32; t0++)
  1536.         typtab[t0] = typtab[t0+128] = ICNTRL;
  1537.     typtab[127] = ICNTRL;
  1538.     for (t0 = '0'; t0 <= '9'; t0++)
  1539.         typtab[t0] = IDIGIT|IALNUM|IWORD|IIDENT|IUSER;
  1540.     for (t0 = 'a'; t0 <= 'z'; t0++)
  1541.         typtab[t0] = typtab[t0-'a'+'A'] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
  1542.     for (t0 = 0240; t0 != 0400; t0++)
  1543.         typtab[t0] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
  1544.     typtab['_'] = IIDENT|IUSER;
  1545.     typtab['-'] = IUSER;
  1546.     typtab[' '] |= IBLANK|INBLANK;
  1547.     typtab['\t'] |= IBLANK|INBLANK;
  1548.     typtab['\n'] |= INBLANK;
  1549.     for (t0 = (int) (unsigned char) ALPOP; t0 <= (int) (unsigned char) Nularg;
  1550.             t0++)
  1551.         typtab[t0] |= ITOK;
  1552.     for (s = ifs; *s; s++)
  1553.         typtab[(int) (unsigned char) *s] |= ISEP;
  1554.     for (s = wordchars; *s; s++)
  1555.         typtab[(int) (unsigned char) *s] |= IWORD;
  1556.     for (s = SPECCHARS; *s; s++)
  1557.         typtab[(int) (unsigned char) *s] |= ISPECIAL;
  1558. }
  1559.  
  1560. char **arrdup(s) /**/
  1561. char **s;
  1562. {
  1563. char **x,**y;
  1564.  
  1565.     y = x = (char **) ncalloc(sizeof(char *)*(arrlen(s)+1));
  1566.     while (*x++ = strdup(*s++));
  1567.     return y;
  1568. }
  1569.  
  1570. /* next few functions stolen (with changes) from Kernighan & Pike */
  1571. /* "The UNIX Programming Environment" (w/o permission) */
  1572.  
  1573. char *spname (oldname) /**/
  1574. char *oldname;
  1575. {
  1576.     char *p,guess[MAXPATHLEN+1],best[MAXPATHLEN+1];
  1577.     static char newname[MAXPATHLEN+1];
  1578.     char *new = newname, *old;
  1579.  
  1580.     if (itok(*oldname)) {
  1581.         singsub(&oldname);
  1582.         if (!oldname) return NULL;
  1583.     }
  1584.     if (access(oldname,F_OK) == 0) return NULL;
  1585.     old = oldname;
  1586.     for (;;) {
  1587.         while (*old == '/') *new++ = *old++;
  1588.         *new = '\0';
  1589.         if (*old == '\0') return newname;
  1590.         p = guess;
  1591.         for (; *old != '/' && *old != '\0'; old++)
  1592.             if (p < guess+MAXPATHLEN) *p++ = *old;
  1593.         *p = '\0';
  1594.         if (mindist(newname,guess,best) >= 3) return NULL;
  1595.         for (p = best; *new = *p++; ) new++;
  1596.     }
  1597. }
  1598.  
  1599. int mindist(dir,guess,best) /**/
  1600. char *dir;char *guess;char *best;
  1601. {
  1602.     int d,nd;
  1603.     DIR *dd;
  1604.     struct direct *de;
  1605.     char buf[MAXPATHLEN];
  1606.  
  1607.     if (dir[0] == '\0')
  1608.         dir = ".";
  1609.     d = 100;
  1610.     sprintf(buf,"%s/%s",dir,guess);
  1611.     if (access(buf,F_OK) == 0) { strcpy(best,guess); return 0; }
  1612.     if (!(dd = opendir(dir))) return d;
  1613.     while (de = readdir(dd)) {
  1614.         nd = spdist(de->d_name,guess,strlen(guess)/4+1);
  1615.         if (nd <= d) {
  1616.             strcpy(best,de->d_name);
  1617.             d = nd;
  1618.             if (d == 0) break;
  1619.         }
  1620.     }
  1621.     closedir(dd);
  1622.     return d;
  1623. }
  1624.  
  1625. int spdist(s,t,thresh) /**/
  1626. char *s;char *t;int thresh;
  1627. {
  1628. char *p,*q;
  1629. char *keymap =
  1630. "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  1631. \t1234567890-=\t\
  1632. \tqwertyuiop[]\t\
  1633. \tasdfghjkl;'\n\t\
  1634. \tzxcvbnm,./\t\t\t\
  1635. \n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  1636. \t!@#$%^&*()_+\t\
  1637. \tQWERTYUIOP{}\t\
  1638. \tASDFGHJKL:\"\n\t\
  1639. \tZXCVBNM<>?\n\n\t\
  1640. \n\n\n\n\n\n\n\n\n\n\n\n\n\n";
  1641.  
  1642.     if (!strcmp(s,t))
  1643.         return 0;
  1644.     /* any number of upper/lower mistakes allowed (dist = 1) */
  1645.     for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++,q++);
  1646.     if (!*p && !*q)
  1647.         return 1;
  1648.     if (!thresh)
  1649.         return 200;
  1650.     for (p = s, q = t; *p && *q; p++,q++)
  1651.         if (*p == *q) continue;    /* don't consider "aa" transposed, ash */
  1652.         else if (p[1] == q[0] && q[1] == p[0])  /* transpositions */
  1653.             return spdist(p+2,q+2,thresh-1)+1;
  1654.         else if (p[1] == q[0])    /* missing letter */
  1655.             return spdist(p+1,q+0,thresh-1)+2;
  1656.         else if (p[0] == q[1])    /* missing letter */
  1657.             return spdist(p+0,q+1,thresh-1)+2;
  1658.         else if (*p != *q)
  1659.             break;
  1660.     if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1))
  1661.         return 2;
  1662.     for (p = s, q = t; *p && *q; p++,q++)
  1663.         if (p[0] != q[0] && p[1] == q[1])
  1664.             {
  1665.             int t0;
  1666.             char *z;
  1667.  
  1668.             /* mistyped letter */
  1669.  
  1670.             if (!(z = strchr(keymap,p[0])) || *z == '\n' || *z == '\t')
  1671.                 return spdist(p+1,q+1,thresh-1)+1;
  1672.             t0 = z-keymap;
  1673.             if (*q == keymap[t0-15] || *q == keymap[t0-14] ||
  1674.                     *q == keymap[t0-13] ||
  1675.                     *q == keymap[t0-1] || *q == keymap[t0+1] ||
  1676.                     *q == keymap[t0+13] || *q == keymap[t0+14] ||
  1677.                     *q == keymap[t0+15])
  1678.                 return spdist(p+1,q+1,thresh-1)+2;
  1679.             return 200;
  1680.             }
  1681.         else if (*p != *q)
  1682.             break;
  1683.     return 200;
  1684. }
  1685.  
  1686. char *zgetenv(s) /**/
  1687. char *s;
  1688. {
  1689. char **av,*p,*q;
  1690.  
  1691.     for (av = environ; *av; av++)
  1692.         {
  1693.         for (p = *av, q = s; *p && *p != '=' && *q && *p == *q; p++,q++);
  1694.         if (*p == '=' && !*q)
  1695.             return p+1;
  1696.         }
  1697.     return NULL;
  1698. }
  1699.  
  1700. int tulower(c) /**/
  1701. int c;
  1702. {
  1703.     c &= 0xff;
  1704.     return (isupper(c) ? tolower(c) : c);
  1705. }
  1706.  
  1707. int tuupper(c) /**/
  1708. int c;
  1709. {
  1710.     c &= 0xff;
  1711.     return (islower(c) ? toupper(c) : c);
  1712. }
  1713.  
  1714. #ifdef SYSV
  1715. #include <sys/utsname.h>
  1716.  
  1717. int gethostname(nameptr, maxlength)
  1718. char *nameptr;
  1719. int maxlength;
  1720. {
  1721. struct utsname *name;
  1722. int result;
  1723.  
  1724.     result = uname(name);
  1725.     if (result >= 0) {
  1726.         strcpy(nameptr,name->sysname);
  1727.         return 0;
  1728.     } else return -1;
  1729. }
  1730. #endif
  1731.  
  1732. /* set cbreak mode, or the equivalent */
  1733.  
  1734. void setcbreak() /**/
  1735. {
  1736. struct ttyinfo ti;
  1737.  
  1738.     ti = shttyinfo;
  1739. #ifdef TIO
  1740.     ti.tio.c_lflag &= ~ICANON;
  1741.     ti.tio.c_cc[VMIN] = 1;
  1742.     ti.tio.c_cc[VTIME] = 0;
  1743. #else
  1744.     ti.sgttyb.sg_flags |= CBREAK;
  1745. #endif
  1746.     settyinfo(&ti);
  1747. }
  1748.  
  1749. int getlineleng() /**/
  1750. {
  1751. int z;
  1752.  
  1753. #ifdef TIOCSWINSZ
  1754.     z = shttyinfo.winsize.ws_col;
  1755.     return (z) ? z : 80;
  1756. #else
  1757.     return 80;
  1758. #endif
  1759. }
  1760.  
  1761. void unsetcbreak() /**/
  1762. {
  1763.     settyinfo(&shttyinfo);
  1764. }
  1765.  
  1766. /* give the tty to some process */
  1767.  
  1768. void attachtty(pgrp) /**/
  1769. long pgrp;
  1770. {
  1771. static int ep = 0;
  1772.  
  1773.     if (jobbing) {
  1774. #ifdef HAS_TCSETPGRP
  1775.         if (SHTTY != -1 && tcsetpgrp(SHTTY,pgrp) == -1 && !ep)
  1776. #else
  1777.         int arg = pgrp;
  1778.         if (SHTTY != -1 && ioctl(SHTTY,TIOCSPGRP,&arg) == -1 && !ep)
  1779. #endif
  1780.             {
  1781.             zerr("can't set tty pgrp: %e",NULL,errno);
  1782.             fflush(stderr);
  1783.             opts[MONITOR] = OPT_UNSET;
  1784.             ep =1;
  1785.             errflag = 0;
  1786.             }
  1787.     }
  1788. }
  1789.  
  1790. /* get the tty pgrp */
  1791.  
  1792. long gettygrp() /**/
  1793. {
  1794. int arg = -1;
  1795.  
  1796.     if (SHTTY == -1) return -1;
  1797. #ifdef HAS_TCSETPGRP
  1798.     arg = tcgetpgrp(SHTTY);
  1799. #else
  1800.     ioctl(SHTTY,TIOCGPGRP,&arg);
  1801. #endif
  1802.     return arg;
  1803. }
  1804.