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 / subst.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  15KB  |  765 lines

  1. /*
  2.  *
  3.  * subst.c - various substitutions
  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.  
  24. /* do substitutions before fork */
  25.  
  26. void prefork(list) /**/
  27. Lklist list;
  28. {
  29. Lknode node = firstnode(list);
  30. int qt;
  31.  
  32.     while (node)
  33.         {
  34.         char *str,*str3;
  35.         
  36.         str = str3 = getdata(node);
  37.         if ((*str == Inang || *str == Outang || *str == Equals) &&
  38.                 str[1] == Inpar)
  39.             {
  40.             if (*str == Inang)
  41.                 setdata(node,getoutproc(str+2));        /* <(...) */
  42.             else if (*str == Equals)
  43.                 setdata(node,getoutputfile(str+2));    /* =(...) */
  44.             else
  45.                 setdata(node,getinproc(str+2));        /* >(...) */
  46.             if (!getdata(node))
  47.                 {
  48.                 zerr("parse error in process substitution",NULL,0);
  49.                 return;
  50.                 }
  51.             }
  52.         else while (*str)
  53.             {
  54.             if ((qt = *str == Qstring) || *str == String)
  55.                 if (str[1] != Inpar)
  56.                     if (str[1] == Inbrack)
  57.                         {
  58.                         arithsubst((vptr*) &str,&str3);    /* $[...] */
  59.                         setdata(node,str3);
  60.                         str = str3;
  61.                         continue;
  62.                         }
  63.                     else
  64.                         {
  65.                         paramsubst(list,node,str,str3,qt);
  66.                         if (errflag)
  67.                             return;
  68.                         str3 = str = getdata(node);
  69.                         continue;
  70.                         }
  71.             str++;
  72.             if (errflag)
  73.                 return;
  74.             }
  75.         if (*(char *) getdata(node))
  76.             remnulargs(getdata(node));
  77.         if (unset(IGNOREBRACES))
  78.             while (hasbraces(getdata(node)))
  79.                 xpandbraces(list,&node);
  80.         filesub((char **) getaddrdata(node));
  81.         if (errflag)
  82.             return;
  83.         incnode(node);
  84.         }
  85. }
  86.  
  87. void postfork(list,doglob) /**/
  88. Lklist list;int doglob;
  89. {
  90. Lknode node = firstnode(list);
  91. int glb = 1;
  92.  
  93.     badcshglob = 0;
  94.     if (isset(NOGLOBOPT) || !doglob)
  95.         glb = 0;
  96.     while (node)
  97.         {
  98.         char *str3,*str;
  99.         
  100.         str = str3 = getdata(node);
  101.         while (*str)
  102.             {
  103.             if (((*str == String || *str == Qstring) && str[1] == Inpar) ||
  104.                     *str == Tick || *str == Qtick)
  105.                 {
  106.                 Lknode n = prevnode(node);
  107.  
  108.                 commsubst(list,node,str,str3,
  109.                     (*str == Qstring || *str == Qtick));    /* `...`,$(...) */
  110.                 if (errflag)
  111.                     return;
  112.                 str = str3 = getdata(node = nextnode(n));
  113.                 }
  114.             str++;
  115.             }
  116.         if (glb)
  117.             {
  118.             if (haswilds(getdata(node)))
  119.                 glob(list,&node);
  120.             if (errflag)
  121.                 return;
  122.             }
  123.         incnode(node);
  124.         }
  125.     if (badcshglob == 1) zerr("no match",NULL,0);
  126. }
  127.  
  128. /* perform substitution on a single word */
  129.  
  130. void singsub(s) /**/
  131. char **s;
  132. {
  133. Lklist foo;
  134. char *t;
  135.  
  136.     for (t = *s; *t; t++)
  137.         if (*t == String)
  138.             *t = Qstring;
  139.         else if (*t == Tick)
  140.             *t = Qtick;
  141.     foo = newlist();
  142.     addnode(foo,*s);
  143.     prefork(foo);
  144.     if (errflag)
  145.         return;
  146.     postfork(foo,0);
  147.     if (errflag)
  148.         return;
  149.     *s = ugetnode(foo);
  150.     if (firstnode(foo))
  151.         zerr("ambiguous: %s",*s,0);
  152. }
  153.  
  154. /* strdup, but returns "Nularg" if this is a null string */
  155.  
  156. vptr nstrdup(s) /**/
  157. vptr s;
  158. {
  159. char *t = s;
  160. char u[2];
  161.  
  162.     u[0] = Nularg; u[1] = '\0';
  163.     if (!*t)
  164.         return strdup(u);
  165.     return strdup(t);
  166. }
  167.  
  168. char *dynread(stop) /**/
  169. int stop;
  170. {
  171. int bsiz = 256,ct = 0,c;
  172. char *buf = zalloc(bsiz),*ptr;
  173.  
  174.     ptr = buf;
  175.     while ((c = hgetc()) != stop)
  176.         {
  177.         *ptr++ = c;
  178.         if (++ct == bsiz)
  179.             {
  180.             buf = realloc(buf,bsiz *= 2);
  181.             ptr = buf+ct;
  182.             }
  183.         }
  184.     *ptr = 0;
  185.     return buf;
  186. }
  187.  
  188. int filesub(namptr) /**/
  189. char **namptr;
  190. {
  191. char *str = *namptr,*cnam;
  192.  
  193.     if (*str == Tilde && str[1] != '=')
  194.         {
  195.         if (str[1] == '+' && (str[2] == '/' || str[2] == '\0'))
  196.             {
  197.             char *foo = strdup(pwd);    /* ~+ */
  198.  
  199.             str+=2;
  200.             modify(&foo,&str);
  201.             *namptr = dyncat(pwd,str);
  202.             return 1;
  203.             }
  204.         else if (str[1] == '-' && (str[2] == '/' || str[2] == '\0'))
  205.             {
  206.             char *foo;                /* ~- */
  207.  
  208.             if (cnam = oldpwd)
  209.                 foo = cnam;
  210.             else
  211.                 foo = pwd;
  212.             str += 2;
  213.             foo = strdup(foo);
  214.             modify(&foo,&str);
  215.             *namptr = dyncat(foo,str);
  216.             return 1;
  217.             }
  218.         if (ialpha(str[1]))        /* ~foo */
  219.             {
  220.             char *ptr,*hom;
  221.  
  222.             for (ptr = ++str; *ptr && iuser(*ptr); ptr++)
  223.                 if (*ptr == '-')
  224.                     *ptr = '-';
  225.             if (*ptr && *ptr != '/') return 0;
  226.             if (!(hom = gethome(str,ptr-str)))
  227.                 {
  228.                 zerr("user not found: %l",str,ptr-str);
  229.                 errflag = 1;
  230.                 return 0;
  231.                 }
  232.             modify(&hom,&ptr);
  233.             *namptr = dyncat(hom,ptr);
  234.             return 1;
  235.             }
  236.         else if (str[1] == '/')    /* ~/foo */
  237.             {
  238.             *namptr = dyncat(home,str+1);
  239.             return 1;
  240.             }
  241.         else if (!str[1])        /* ~ by itself */
  242.             {
  243.             *namptr = strdup(home);
  244.             return 1;
  245.             }
  246.         }
  247.     if (*str == Equals && iuser(str[1]) && unset(NOEQUALS))
  248.         {
  249.         char *ptr,*s,*ds;
  250.         int val;
  251.         
  252.         if (ialpha(str[1]))        /* =foo */
  253.             {
  254.             char sav,*pp;
  255.  
  256.             for (pp = str+1; *pp && *pp != ':'; pp++);
  257.             sav = *pp;
  258.             *pp = '\0';
  259.             if (!(cnam = findcmd(str+1)))
  260.                 {
  261.                 zerr("%s not found",str+1,0);
  262.                 errflag = 1;
  263.                 return 0;
  264.                 }
  265.             *namptr = cnam;
  266.             if ((*pp = sav) == ':')
  267.                 {
  268.                 modify(namptr,&pp);
  269.                 s = *namptr;
  270.                 *namptr = dyncat(*namptr,pp);
  271.                 }
  272.             return 1;
  273.             }
  274.         if (str[1] == '-')     /* =- */
  275.             {
  276.             val = -1;
  277.             ptr = str+2;
  278.             }
  279.         else
  280.             val = zstrtol(str+1,&ptr,10);    /* =# */
  281.         ds = dstackent(val);
  282.         if (!ds)
  283.             return 1;
  284.         s = strdup(ds);
  285.         modify(&s,&ptr);
  286.         *namptr = dyncat(s,ptr);
  287.         return 1;
  288.         }
  289.     return 0;
  290. }
  291.  
  292. /* get a named directory */
  293.  
  294. char *gethome(user,len) /**/
  295. char *user;int len;
  296. {
  297. char sav,*str;
  298. struct passwd *pw;
  299.  
  300.     if (len == 0)
  301.         return strdup(home);
  302.     sav = user[len];
  303.     user[len] = '\0';
  304.     if ((str = getsparamval(user,len)) && *str == '/')
  305.         {
  306.         str = strdup(str);
  307.         adduserdir(user,str);
  308.         user[len] = sav;
  309.         return str;
  310.         }
  311.     permalloc(); /* fixes iris bug--getpwnam calls strdup! */
  312.     pw = getpwnam(user);
  313.     lastalloc();
  314.     if (!pw) {
  315.         user[len] = sav;
  316.         return NULL;
  317.     }
  318.     str = xsymlink(pw->pw_dir);
  319.     adduserdir(user,str);
  320.     user[len] = sav;
  321.     return str;
  322. }
  323.  
  324. /* `...`, $(...) */
  325.  
  326. void commsubst(l,n,str3,str,qt) /**/
  327. Lklist l;Lknode n;char *str3;char *str;int qt;
  328. {
  329. char *str2;
  330. Lknode where = prevnode(n);
  331. Lklist pl;
  332.  
  333.     if (*str3 == Tick || *str3 == Qtick)
  334.         {
  335.         *str3 = '\0';
  336.         for (str2 = ++str3; *str3 != Tick && *str3 != Qtick; str3++);
  337.         *str3++ = '\0';
  338.         }
  339.     else
  340.         {
  341.         *str3++ = '\0';
  342.         for (str2 = ++str3; *str3 != Outpar; str3++);
  343.         *str3++ = '\0';
  344.         }
  345.     uremnode(l,n);
  346.     if (!(pl = getoutput(str2,qt)))
  347.         {
  348.         zerr("parse error in command substitution",NULL,0);
  349.         errflag = 1;
  350.         return;
  351.         }
  352.     if (full(pl))
  353.         {
  354.         setdata(firstnode(pl),dyncat(str,peekfirst(pl)));
  355.         setdata(lastnode(pl),dyncat(getdata(lastnode(pl)),str3));
  356.         inslist(pl,where,l);
  357.         }
  358.     else
  359.         insnode(l,where,dyncat(str,str3));
  360. }
  361.  
  362. /* parameter substitution */
  363.  
  364. void paramsubst(l,n,aptr,bptr,qt) /**/
  365. Lklist l;Lknode n;char *aptr;char *bptr;int qt;
  366. {
  367. char *s = aptr,*u,*idbeg,*idend,*ostr = bptr;
  368. int brs;            /* != 0 means ${...}, otherwise $... */
  369. int colf;        /* != 0 means we found a colon after the name */
  370. int doub = 0;    /* != 0 means we have %%, not %, or ##, not # */
  371. int isarr = 0;
  372. int wasnularr = 0;
  373. int plan9 = isset(RCEXPANDPARAM);
  374. int getlen = 0;
  375. int vunset = 0;
  376. int spbreak = isset(SHWORDSPLIT) && !qt;
  377. char *val = NULL,**aval = NULL;
  378. int fwidth = 0;
  379. Value v;
  380.  
  381.     *s++ = '\0';
  382.     if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
  383.             *s != '!' && *s != '$' && *s != String && *s != Qstring &&
  384.             *s != '?' && *s != Quest && *s != '_' &&
  385.             *s != '*' && *s != Star && *s != '@' && *s != '{' &&
  386.             *s != Inbrace && *s != '=' && *s != Hat && *s != '^') {
  387.         s[-1] = '$';
  388.         return;
  389.     }
  390.     if (brs = (*s == '{' || *s == Inbrace)) s++;
  391.     for (;;)
  392.         if (*s == '^' || *s == Hat)
  393.             plan9 ^= 1,s++;
  394.         else if (*s == '=')
  395.             spbreak ^= 1,s++;
  396.         else if ((*s == '#' || *s == Pound) && iident(s[1]))
  397.             getlen = 1,s++;
  398.         else
  399.             break;
  400.  
  401.     idbeg = s;
  402.     if (!(v = getvalue(&s,1))) {
  403.         vunset = 1;
  404.         idend = s;
  405.     } else
  406.         if (isarr = v->isarr)
  407.             aval = getarrvalue(v);
  408.         else {
  409.             val = getstrvalue(v);
  410.             fwidth = v->pm->ct;
  411.             switch (v->pm->flags & (PMFLAG_L | PMFLAG_R | PMFLAG_Z)) {
  412.                 char *t;
  413.                 int t0;
  414.  
  415.                 case PMFLAG_L:
  416.                 case PMFLAG_L|PMFLAG_Z:
  417.                     t = val;
  418.                     if (v->pm->flags & PMFLAG_Z)
  419.                         while (*t == '0') t++;
  420.                     else
  421.                         while (isep(*t)) t++;
  422.                     val = ncalloc(fwidth+1);
  423.                     val[fwidth] = '\0';
  424.                     if ((t0 = strlen(t)) > fwidth)
  425.                         t0 = fwidth;
  426.                     memset(val,' ',fwidth);
  427.                     strncpy(val,t,t0);
  428.                     break;
  429.                 case PMFLAG_R:
  430.                 case PMFLAG_Z:
  431.                 case PMFLAG_Z|PMFLAG_R:
  432.                     if (strlen(val) < fwidth) {
  433.                         t = ncalloc(fwidth+1);
  434.                         memset(t,(v->pm->flags & PMFLAG_R) ? ' ' : '0',fwidth);
  435.                         if ((t0 = strlen(val)) > fwidth)
  436.                             t0 = fwidth;
  437.                         strcpy(t+(fwidth-t0),val);
  438.                         val = t;
  439.                     } else {
  440.                         t = ncalloc(fwidth+1);
  441.                         t[fwidth] = '\0';
  442.                         strncpy(t,val+strlen(val)-fwidth,fwidth);
  443.                         val = t;
  444.                     }
  445.                     break;
  446.                 }
  447.             switch (v->pm->flags & (PMFLAG_l | PMFLAG_u)) {
  448.                 char *t;
  449.  
  450.                 case PMFLAG_l:
  451.                     t = val;
  452.                     for (;*t;t++)
  453.                         *t = tulower(*t);
  454.                     break;
  455.                 case PMFLAG_u:
  456.                     t = val;
  457.                     for (;*t;t++)
  458.                         *t = tuupper(*t);
  459.                     break;
  460.             }
  461.         }
  462.     if (colf = *s == ':') s++;
  463.     
  464.     /* check for ${..?...} or ${..=..} or one of those.  Only works
  465.         if the name is in braces. */
  466.  
  467.     if (brs && (*s == '-' || *s == '=' || *s == '?' || *s == '+' || *s == '#' ||
  468.             *s == '%' || *s == Quest || *s == Pound)) {
  469.         if (v && v->isarr && (*s == '%' || *s == '#' || *s == Pound)) {
  470.             zerr("operator requires a scalar",NULL,0);
  471.             return;
  472.         }
  473.         if (*s == s[1]) {
  474.             s++;
  475.             doub = 1;
  476.         }
  477.         u = ++s;
  478.         if (brs) {
  479.             int bct = 1;
  480.  
  481.             for (;;) {
  482.                 if (*s == '{' || *s == Inbrace)
  483.                     bct++;
  484.                 else if (*s == '}' || *s == Outbrace)
  485.                     bct--;
  486.                 if (!bct || !*s)
  487.                     break;
  488.                 s++;
  489.             }
  490.         } else {
  491.             while (*s++);
  492.             s--;
  493.         }
  494.         if (*s) *s++ = '\0';
  495.         if (colf && !vunset)
  496.             vunset = (isarr) ? !*aval : !*val;
  497.         switch ((int)(unsigned char)u[-1]) {
  498.             case '-':
  499.                 if (vunset)
  500.                     val = strdup(u), isarr = 0;
  501.                 break;
  502.             case '=':
  503.                 if (vunset) {
  504.                     char sav = *idend;
  505.  
  506.                     *idend = '\0';
  507.                     setsparam(idbeg,ztrdup(val = strdup(u)));
  508.                     *idend = sav;
  509.                     isarr = 0;
  510.                 }
  511.                 break;
  512.             case '?':
  513.             case (int)(unsigned char)Quest:
  514.                 if (vunset) {
  515.                     zerr("%s",(*u) ? u : "parameter not set",0);
  516.                     if (!interact)
  517.                         exit(1);
  518.                     return;
  519.                 }
  520.                 break;
  521.             case '+':
  522.                 if (vunset)
  523.                     val = strdup("");
  524.                 else
  525.                     val = strdup(u);
  526.                 isarr = 0;
  527.                 break;
  528.             case '#':
  529.             case (int)(unsigned char)Pound:
  530.                 if (vunset)
  531.                     val = strdup("");
  532.                 singsub(&u);
  533.                 getmatch(&val,u,doub);
  534.                 break;
  535.             case '%':
  536.                 if (vunset)
  537.                     val = strdup("");
  538.                 singsub(&u);
  539.                 getmatch(&val,u,doub+2);
  540.                 break;
  541.         }
  542.     } else {        /* no ${...=...} or anything, but possible modifiers. */
  543.         if (vunset) {
  544.             if (isset(NOUNSET)) {
  545.                 zerr("parameter not set",NULL,0);
  546.                 return;
  547.             }
  548.             val = strdup("");
  549.         }
  550.         if (colf) {
  551.             s--;
  552.             if (!isarr) modify(&val,&s);
  553.             else {
  554.                 char *ss = s;
  555.                 char **ap = aval;
  556.                 while (*ap) {
  557.                     ss = s;
  558.                     modify(ap,&ss);
  559.                 }
  560.             }
  561.         }
  562.         if (brs) {
  563.             if (*s != '}' && *s != Outbrace) {
  564.                 zerr("closing brace expected",NULL,0);
  565.                 errflag = 1;
  566.                 return;
  567.             }
  568.             s++;
  569.         }
  570.     }
  571.     if (errflag)
  572.         return;
  573.     if (getlen) {
  574.         long len = 0;
  575.         char buf[14];
  576.  
  577.         if (isarr) {
  578.             char **ctr;
  579.             for (ctr = aval; *ctr; ctr++,len++);
  580.         } else
  581.             len = strlen(val);
  582.         sprintf(buf,"%ld",len);
  583.         val = strdup(buf);
  584.         isarr = 0;
  585.     }
  586.     if (isarr)
  587.         if (!aval || !aval[0]) {
  588.             if (isarr < 0)
  589.                 wasnularr = 1;
  590.             val = strdup("");
  591.             isarr = 0;
  592.         } else if (!aval[1]) {
  593.             val = aval[0];
  594.             isarr = 0;
  595.         }
  596.     if (qt) {
  597.         if (isarr > 0) {
  598.             val = spacejoin(aval);
  599.             isarr = 0;
  600.         }
  601.     } else if (spbreak) {
  602.         if (isarr)
  603.             val = spacejoin(aval);
  604.         isarr = 1;
  605.         aval = spacesplit(val);
  606.         if (!aval || !aval[0]) {
  607.             val = strdup("");
  608.             isarr = 0;
  609.         } else if (!aval[1]) {
  610.             val = aval[0];
  611.             isarr = 0;
  612.         }
  613.         /* if only one member, not really an array */
  614.         if (!aval[1])
  615.             isarr = 0;
  616.     }
  617.     if (isarr)
  618.         if (plan9) {
  619.             int dlen;
  620.             char *y;
  621.  
  622.             y = ncalloc((dlen = (char *) aptr-bptr+strlen(s)+1)+strlen(aval[0]));
  623.             setdata(n,y);
  624.             strcpy(y,ostr);
  625.             strcat(y,aval[0]);
  626.             strcat(y,s);
  627.             while (*++aval) {
  628.                 char *x = ncalloc(dlen+strlen(*aval));
  629.  
  630.                 strcpy(x,ostr);
  631.                 strcat(x,*aval);
  632.                 strcat(x,s);
  633.                 insnode(l,n,x), incnode(n);
  634.             }
  635.         } else {
  636.             char *zz;
  637.  
  638.             zz = ncalloc((char *) aptr-(bptr)+strlen(aval[0])+1);
  639.             setdata(n,zz);
  640.             strcpy(zz,ostr);
  641.             strcat(zz,*aval++);
  642.             while (aval[1])
  643.                 insnode(l,n,*aval++), incnode(n);
  644.             zz = ncalloc(strlen(*aval)+strlen(s)+1);
  645.             strcpy(zz,*aval);
  646.             strcat(zz,s);
  647.             insnode(l,n,zz);
  648.         }
  649.     else {
  650.         bptr = ncalloc((char *) aptr-bptr+strlen(val)+strlen(s)+1);
  651.         setdata(n,bptr);
  652.         strcpy(bptr,ostr);
  653.         strcat(bptr,val);
  654.         strcat(bptr,s);
  655.     }
  656. }
  657.  
  658. /* arithmetic substitution */
  659.  
  660. void arithsubst(aptr,bptr) /**/
  661. vptr *aptr;char **bptr;
  662. {
  663. char *s = *aptr,*t,buf[16];
  664. long v;
  665.  
  666.     *s = '\0';
  667.     for (; *s != Outbrack; s++);
  668.     *s++ = '\0';
  669.     v = matheval((char *) *aptr+2);
  670.     sprintf(buf,"%ld",v);
  671.     t = ncalloc(strlen(*bptr)+strlen(buf)+strlen(s)+1);
  672.     strcpy(t,*bptr);
  673.     strcat(t,buf);
  674.     strcat(t,s);
  675.     *bptr = t;
  676. }
  677.  
  678. void modify(str,ptr) /**/
  679. char **str;char **ptr;
  680. {
  681. char *ptr1,*ptr2,*ptr3,del,*lptr;
  682. int gbal;
  683.  
  684.     if (**ptr == ':')
  685.         *str = strdup(*str);
  686.     while (**ptr == ':')
  687.         {
  688.         lptr = *ptr;
  689.         (*ptr)++;
  690.         gbal = 0;
  691. here:
  692.         switch(*(*ptr)++)
  693.             {
  694.             case 'h': remtpath(str); break;
  695.             case 'r': remtext(str); break;
  696.             case 'e': rembutext(str); break;
  697.             case 't': remlpaths(str); break;
  698.             case 'l': downcase(str); break;
  699.             case 'u': upcase(str); break;
  700.             case 's':
  701.                 if (hsubl)
  702.                     free(hsubl);
  703.                 if (hsubr)
  704.                     free(hsubr);
  705.                 ptr1 = *ptr;
  706.                 del = *ptr1++;
  707.                 for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++);
  708.                 if (!*ptr2)
  709.                     {
  710.                     zerr("bad subtitution",NULL,0);
  711.                     errflag = 1;
  712.                     return;
  713.                     }
  714.                 *ptr2++ = '\0';
  715.                 for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++);
  716.                 if (*ptr3)
  717.                     *ptr3++ = '\0';
  718.                 hsubl = ztrdup(ptr1);
  719.                 hsubr = ztrdup(ptr2);
  720.                 *ptr = ptr3;
  721.             case '&':
  722.                 if (hsubl && hsubr)
  723.                     subst(str,hsubl,hsubr,gbal);
  724.                 break;
  725.             case 'g': gbal = 1; goto here;
  726.             default: *ptr = lptr; return;
  727.             }
  728.         }
  729. }
  730.  
  731. /* get a directory stack entry */
  732.  
  733. char *dstackent(val) /**/
  734. int val;
  735. {
  736. Lknode node;
  737.  
  738.     if ((val < 0 && !firstnode(dirstack)) || !val--)
  739.         return pwd;
  740.     if (val < 0)
  741.         node = lastnode(dirstack);
  742.     else
  743.         for (node = firstnode(dirstack); node && val; val--,incnode(node));
  744.     if (!node)
  745.         {
  746.         zerr("not enough dir stack entries.",NULL,0);
  747.         errflag = 1;
  748.         return NULL;
  749.         }
  750.     return getdata(node);
  751. }
  752.  
  753. /* make an alias hash table node */
  754.  
  755. struct alias *mkanode(txt,cmflag) /**/
  756. char *txt;int cmflag;
  757. {
  758. struct alias *ptr = (Alias) zcalloc(sizeof *ptr);
  759.  
  760.     ptr->text  = txt;
  761.     ptr->cmd = cmflag;
  762.     ptr->inuse = 0;
  763.     return ptr;
  764. }
  765.