home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / subst.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  29.8 KB  |  1,495 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, flags)    /**/
  27. Lklist list;
  28. int flags;
  29. {
  30.     Lknode node = firstnode(list);
  31.     int qt;
  32.  
  33.     /* bits 0 and 1 of flags are flags to filesub (treat as assignment)
  34.      * bit 2 is a flag to paramsubst (single word sub)
  35.      */
  36.     while (node) {
  37.     char *str, *str3;
  38.     int keep = 1;
  39.  
  40.     str = str3 = (char *)getdata(node);
  41.     if ((*str == Inang || *str == Outang || *str == Equals) &&
  42.         str[1] == Inpar) {
  43.         if (*str == Inang)
  44.         setdata(node, (vptr) getoutproc(str + 2));    /* <(...) */
  45.         else if (*str == Equals)
  46.         setdata(node, (vptr) getoutputfile(str + 2));    /* =(...) */
  47.         else
  48.         setdata(node, (vptr) getinproc(str + 2));    /* >(...) */
  49.         if (!getdata(node)) {
  50.         zerr("parse error in process substitution", NULL, 0);
  51.         return;
  52.         }
  53.     } else
  54.         while (*str) {
  55.         if ((qt = *str == Qstring) || *str == String)
  56.             if (str[1] != Inpar)
  57.             if (str[1] == Inbrack) {
  58.                 arithsubst((vptr *) & str, &str3);    /* $[...] */
  59.                 setdata(node, (vptr) str3);
  60.                 str = str3;
  61.                 continue;
  62.             } else {
  63.                 if (!paramsubst(list, node, str, str3,
  64.                         qt | (flags & 4), !(flags & 010)))
  65.                 keep = 0;
  66.                 if (errflag)
  67.                 return;
  68.                 if (!keep)
  69.                 break;
  70.                 str3 = str = (char *)getdata(node);
  71.                 continue;
  72.             }
  73.         str++;
  74.         if (errflag)
  75.             return;
  76.         }
  77.     if (keep) {
  78.         if (*(char *)getdata(node))
  79.         remnulargs(getdata(node));
  80.         if (unset(IGNOREBRACES))
  81.         while (hasbraces(getdata(node)))
  82.             xpandbraces(list, &node);
  83.         filesub((char **)getaddrdata(node), flags & 3);
  84.         if (errflag)
  85.         return;
  86.         incnode(node);
  87.     } else {
  88.         Lknode zapnode;
  89.  
  90.         zapnode = node;
  91.         incnode(node);
  92.         uremnode(list, zapnode);
  93.     }
  94.     }
  95. }
  96.  
  97. void postfork(list, flags)    /**/
  98. Lklist list;
  99. int flags;
  100. {
  101.     Lknode node = firstnode(list);
  102.     int glb = 1;
  103.  
  104.     /* bit 0 of flags is to do glob, bit 1 is flag for single substitution */
  105.     badcshglob = 0;
  106.     if (isset(NOGLOBOPT) || !(flags & 1))
  107.     glb = 0;
  108.     while (node) {
  109.     char *str3, *str;
  110.  
  111.     str = str3 = (char *)getdata(node);
  112.     while (*str) {
  113.         if (((*str == String || *str == Qstring) && str[1] == Inpar) ||
  114.         *str == Tick || *str == Qtick) {
  115.         Lknode n = prevnode(node);
  116.  
  117.         /* `...`,$(...) */
  118.         commsubst(list, node, str, str3,
  119.               (*str == Qstring || *str == Qtick || flags > 1));
  120.         if (errflag)
  121.             return;
  122.         if (!(node = nextnode(n)))
  123.             return;
  124.         str = str3 = (char *)getdata(node);
  125.         continue;
  126.         }
  127.         str++;
  128.     }
  129.     if (glb) {
  130.         if (haswilds(getdata(node)))
  131.         glob(list, &node);
  132.         if (errflag)
  133.         return;
  134.     }
  135.     incnode(node);
  136.     }
  137.     if (badcshglob == 1)
  138.     zerr("no match", NULL, 0);
  139. }
  140.  
  141. /* perform substitution on a single word */
  142.  
  143. void singsub(s)            /**/
  144. char **s;
  145. {
  146.     Lklist foo;
  147.  
  148.     foo = newlist();
  149.     addnode(foo, *s);
  150.     prefork(foo, 014);
  151.     if (errflag)
  152.     return;
  153.     postfork(foo, 010);
  154.     if (errflag)
  155.     return;
  156.     *s = (char *)ugetnode(foo);
  157.     remnulargs(*s);
  158.     if (firstnode(foo))
  159.     zerr("ambiguous: %s", *s, 0);
  160. }
  161.  
  162. /* ~, = subs: assign = 2 => typeset; assign = 1 => something that looks
  163.     like an assignment but may not be; assign = 3 => normal assignment */
  164.  
  165. void filesub(namptr, assign)    /**/
  166. char **namptr;
  167. int assign;
  168. {
  169.     char *sub = (char *)NULL, *str, *ptr;
  170.     int len;
  171.  
  172.     filesubstr(namptr, assign);
  173.  
  174.     if (!assign)
  175.     return;
  176.  
  177.     if (assign < 3)
  178.     if ((*namptr)[1] && (sub = strchr(*namptr + 1, Equals))) {
  179.         if (assign == 1)
  180.         for (ptr = *namptr; ptr != sub; ptr++)
  181.             if (!iident(*ptr) && !INULL(*ptr))
  182.             return;
  183.         *sub = Equals;
  184.         str = sub + 1;
  185.         if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) {
  186.         sub[1] = '\0';
  187.         *namptr = dyncat(*namptr, str);
  188.         }
  189.     } else
  190.         return;
  191.  
  192.     ptr = *namptr;
  193.     while ((sub = strchr(ptr, ':'))) {
  194.     str = sub + 1;
  195.     len = sub - *namptr;
  196.     if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) {
  197.         sub[1] = '\0';
  198.         *namptr = dyncat(*namptr, str);
  199.     }
  200.     ptr = *namptr + len + 1;
  201.     }
  202. }
  203.  
  204. int filesubstr(namptr, assign)    /**/
  205. char **namptr;
  206. int assign;
  207. {
  208.     char *str = *namptr, *cnam;
  209.  
  210.     if (*str == Tilde && str[1] != '=' && str[1] != Equals) {
  211.     if (str[1] == '+' && (str[2] == '/' || str[2] == Inpar ||
  212.                   (assign && str[2] == ':') || !str[2])) {
  213.         *namptr = dyncat(pwd, str + 2);    /* ~+ */
  214.         return 1;
  215.     } else if (str[1] == '-' && (str[2] == '/' || str[2] == Inpar ||
  216.                      (assign && str[2] == ':') || !str[2])) {
  217.         *namptr = dyncat((cnam = oldpwd) ? cnam : pwd, str + 2);    /* ~- */
  218.         return 1;
  219.     } else if (ialpha(str[1])) {    /* ~foo */
  220.         char *ptr, *hom;
  221.  
  222.         for (ptr = ++str; *ptr && iuser(*ptr); ptr++);
  223.         if (*ptr && *ptr != '/' && *ptr != Inpar &&
  224.         (!assign || *ptr != ':'))
  225.         return 0;
  226.         if (!(hom = getnamedir(str, ptr - str))) {
  227.         if (!isset(NONOMATCH))
  228.             zerr("user not found: %l", str, ptr - str);
  229.         return 0;
  230.         }
  231.         *namptr = dyncat(hom, ptr);
  232.         return 1;
  233.     } else if (str[1] == '/' || str[1] == Inpar ||
  234.            (assign && str[1] == ':')) {    /* ~/foo */
  235.         *namptr = dyncat(home, str + 1);
  236.         return 1;
  237.     } else if (!str[1]) {    /* ~ by itself */
  238.         *namptr = dupstring(home);
  239.         return 1;
  240.     }
  241.     } else if (*str == Equals && unset(NOEQUALS) && str[1]) {
  242.     char *ptr, *ds;
  243.     int val;
  244.  
  245.     if (str[1] == '-') {    /* =- */
  246.         val = -1;
  247.         ptr = str + 2;
  248.     } else if (idigit(str[1]))
  249.         val = zstrtol(str + 1, &ptr, 10);    /* =# */
  250.     else
  251.     /* =foo */
  252.     {
  253.         char sav, *pp;
  254.  
  255.         for (pp = str + 1; *pp && *pp != Inpar && (!assign || *pp != ':');
  256.          pp++);
  257.         sav = *pp;
  258.         *pp = '\0';
  259.         if (!(cnam = findcmd(str + 1))) {
  260.         if (!isset(NONOMATCH))
  261.             zerr("%s not found", str + 1, 0);
  262.         return 0;
  263.         }
  264.         *namptr = dupstring(cnam);
  265.         zsfree(cnam);
  266.         if (sav) {
  267.         *pp = sav;
  268.         *namptr = dyncat(*namptr, pp);
  269.         }
  270.         return 1;
  271.     }
  272.     ds = dstackent(val);
  273.     if (!ds)
  274.         return 1;
  275.     *namptr = dyncat(ds, ptr);
  276.     return 1;
  277.     }
  278.     return 0;
  279. }
  280.  
  281. /* get a named directory */
  282.  
  283. char *getnamedir(user, len)    /**/
  284. char *user;
  285. int len;
  286. {
  287.     char sav, *str, *ret_val = NULL;
  288.     struct passwd *pw;
  289.     int t0;
  290.     struct param *pm;
  291.  
  292.     if (len == 0)
  293.     return dupstring(home);
  294.     sav = user[len];
  295.     user[len] = '\0';
  296.     if ((t0 = findname(user)) != -1)
  297.     ret_val = dupstring(namdirs[t0].dir);
  298.     else if ((pm = (struct param *) gethnode(user, paramtab)) &&
  299.          !(pm->flags & (PMFLAG_i | PMFLAG_A)) &&
  300.          (str = getsparam(user)) && *str == '/') {
  301.     adduserdir(user, str, 0, 1);
  302.     ret_val = str;
  303.     }
  304.     else if ((pw = getpwnam(user))) {
  305.     str = xsymlink(pw->pw_dir);
  306.     adduserdir(user, str, 1, 1);
  307.     ret_val = dupstring(str);
  308.     zsfree(str);
  309.     }     
  310.     user[len] = sav;
  311.     return ret_val;
  312. }
  313.  
  314. /* `...`, $(...) */
  315.  
  316. void commsubst(l, n, str3, str, qt)    /**/
  317. Lklist l;
  318. Lknode n;
  319. char *str3;
  320. char *str;
  321. int qt;
  322. {
  323.     char *str2;
  324.     Lknode where = prevnode(n);
  325.     Lklist pl;
  326.  
  327.     if (*str3 == Tick || *str3 == Qtick) {
  328.     *str3 = '\0';
  329.     for (str2 = ++str3; *str3 && *str3 != Tick && *str3 != Qtick; str3++);
  330.     *str3++ = '\0';
  331.     } else {
  332.     *str3++ = '\0';
  333.     for (str2 = ++str3; *str3 && *str3 != Outpar; str3++);
  334.     *str3++ = '\0';
  335.     }
  336.     uremnode(l, n);
  337.     if (!(pl = getoutput(str2, qt))) {
  338.     if (!errflag)
  339.         zerr("parse error in command substitution", NULL, 0);
  340.     return;
  341.     }
  342.     if (full(pl)) {
  343.     setdata(firstnode(pl), (vptr) dyncat(str, peekfirst(pl)));
  344.     setdata(lastnode(pl), (vptr) dyncat(getdata(lastnode(pl)), str3));
  345.     inslist(pl, where, l);
  346.     } else
  347.     insnode(l, where, dyncat(str, str3));
  348. }
  349.  
  350. void strcatsub(dest, src, cshtilde)    /**/
  351. char *dest;
  352. char *src;
  353. int cshtilde;
  354. {
  355.     if (!cshtilde) {
  356.     strcat(dest, src);
  357.     return;
  358.     }
  359.     while (*dest)
  360.     dest++;
  361.     do {
  362.     *dest++ = (*src == '~') ? Tilde : (*src == '=') ? Equals : *src;
  363.     }
  364.     while (*src++);
  365. }
  366.  
  367. int strpcmp(a, b)        /**/
  368. const void *a;
  369. const void *b;
  370. {
  371.     return strcmp(*(char **)a, *(char **)b);
  372. }
  373.  
  374. int invstrpcmp(a, b)        /**/
  375. const void *a;
  376. const void *b;
  377. {
  378.     return -strcmp(*(char **)a, *(char **)b);
  379. }
  380.  
  381. int cstrpcmp(a, b)        /**/
  382. const void *a;
  383. const void *b;
  384. {
  385.     char *c = *(char **)a, *d = *(char **)b;
  386.  
  387.     for (; *c && tulower(*c) == tulower(*d); c++, d++);
  388.  
  389.     return (int)(unsigned char)tulower(*c) - (int)(unsigned char)tulower(*d);
  390. }
  391.  
  392. int invcstrpcmp(a, b)        /**/
  393. const void *a;
  394. const void *b;
  395. {
  396.     char *c = *(char **)a, *d = *(char **)b;
  397.  
  398.     for (; *c && tulower(*c) == tulower(*d); c++, d++);
  399.  
  400.     return (int)(unsigned char)tulower(*d) - (int)(unsigned char)tulower(*c);
  401. }
  402.  
  403. char *dopadding(str, prenum, postnum, preone, postone, premul, postmul)    /**/
  404. char *str;
  405. int prenum;
  406. int postnum;
  407. char *preone;
  408. char *postone;
  409. char *premul;
  410. char *postmul;
  411. {
  412.     char def[2], *ret, *t, *r;
  413.     int ls, ls2, lpreone, lpostone, lpremul, lpostmul, lr, f, m, c, cc;
  414.  
  415.     def[0] = ifs[0];
  416.     def[1] = '\0';
  417.     if (preone && !*preone)
  418.     preone = def;
  419.     if (postone && !*postone)
  420.     postone = def;
  421.     if (!premul || !*premul)
  422.     premul = def;
  423.     if (!postmul || !*postmul)
  424.     postmul = def;
  425.  
  426.     ls = strlen(str);
  427.     lpreone = preone ? strlen(preone) : 0;
  428.     lpostone = postone ? strlen(postone) : 0;
  429.     lpremul = strlen(premul);
  430.     lpostmul = strlen(postmul);
  431.  
  432.     lr = prenum + postnum;
  433.  
  434.     if (lr == ls)
  435.     return str;
  436.  
  437.     r = ret = (char *) halloc(lr + 1);
  438.  
  439.     if (prenum) {
  440.     if (postnum) {
  441.         ls2 = ls / 2;
  442.  
  443.         f = prenum - ls2;
  444.         if (f <= 0)
  445.         for (str -= f, c = prenum; c--; *r++ = *str++);
  446.         else {
  447.         if (f <= lpreone)
  448.             for (c = f, t = preone + lpreone - f; c--; *r++ = *t++);
  449.         else {
  450.             f -= lpreone;
  451.             if ((m = f % lpremul))
  452.             for (c = m, t = premul + lpremul - m; c--; *r++ = *t++);
  453.             for (cc = f / lpremul; cc--;)
  454.             for (c = lpremul, t = premul; c--; *r++ = *t++);
  455.             for (c = lpreone; c--; *r++ = *preone++);
  456.         }
  457.         for (c = ls2; c--; *r++ = *str++);
  458.         }
  459.         ls2 = ls - ls2;
  460.         f = postnum - ls2;
  461.         if (f <= 0)
  462.         for (c = postnum; c--; *r++ = *str++);
  463.         else {
  464.         for (c = ls2; c--; *r++ = *str++);
  465.         if (f <= lpostone)
  466.             for (c = f; c--; *r++ = *postone++);
  467.         else {
  468.             f -= lpostone;
  469.             for (c = lpostone; c--; *r++ = *postone++);
  470.             for (cc = f / lpostmul; cc--;)
  471.             for (c = lpostmul, t = postmul; c--; *r++ = *t++);
  472.             if ((m = f % lpostmul))
  473.             for (; m--; *r++ = *postmul++);
  474.         }
  475.         }
  476.     } else {
  477.         f = prenum - ls;
  478.         if (f <= 0)
  479.         for (c = prenum, str -= f; c--; *r++ = *str++);
  480.         else {
  481.         if (f <= lpreone)
  482.             for (c = f, t = preone + lpreone - f; c--; *r++ = *t++);
  483.         else {
  484.             f -= lpreone;
  485.             if ((m = f % lpremul))
  486.             for (c = m, t = premul + lpremul - m; c--; *r++ = *t++);
  487.             for (cc = f / lpremul; cc--;)
  488.             for (c = lpremul, t = premul; c--; *r++ = *t++);
  489.             for (c = lpreone; c--; *r++ = *preone++);
  490.         }
  491.         for (c = ls; c--; *r++ = *str++);
  492.         }
  493.     }
  494.     } else if (postnum) {
  495.     f = postnum - ls;
  496.     if (f <= 0)
  497.         for (c = postnum; c--; *r++ = *str++);
  498.     else {
  499.         for (c = ls; c--; *r++ = *str++);
  500.         if (f <= lpostone)
  501.         for (c = f; c--; *r++ = *postone++);
  502.         else {
  503.         f -= lpostone;
  504.         for (c = lpostone; c--; *r++ = *postone++);
  505.         for (cc = f / lpostmul; cc--;)
  506.             for (c = lpostmul, t = postmul; c--; *r++ = *t++);
  507.         if ((m = f % lpostmul))
  508.             for (; m--; *r++ = *postmul++);
  509.         }
  510.     }
  511.     }
  512.     *r = '\0';
  513.  
  514.     return ret;
  515. }
  516.  
  517. char *get_strarg(s)        /**/
  518. char *s;
  519. {
  520.     char t = *s++;
  521.  
  522.     if (!t)
  523.     return s - 1;
  524.  
  525.     switch (t) {
  526.     case '(':
  527.     t = ')';
  528.     break;
  529.     case '[':
  530.     t = ']';
  531.     break;
  532.     case '{':
  533.     t = '}';
  534.     break;
  535.     case '<':
  536.     t = '>';
  537.     break;
  538.     case Inpar:
  539.     t = Outpar;
  540.     break;
  541.     case Inang:
  542.     t = Outang;
  543.     break;
  544.     case Inbrace:
  545.     t = Outbrace;
  546.     break;
  547.     case Inbrack:
  548.     t = Outbrack;
  549.     break;
  550.     }
  551.  
  552.     while (*s && *s != t)
  553.     s++;
  554.  
  555.     return s;
  556. }
  557.  
  558. /* parameter substitution */
  559.  
  560. #define    isstring(c)    (c == '$' || c == String || c == Qstring)
  561. #define    isbrace(c)    (c == '{' || c == Inbrace)
  562.  
  563. int paramsubst(l, n, aptr, bptr, qt, sp)    /**/
  564. Lklist l;
  565. Lknode n;
  566. char *aptr;
  567. char *bptr;
  568. int qt;  /* if bit 0 set, real quote, else single word substitution */
  569. int sp;
  570. {
  571.     char *s = aptr, *u, *uu, *idbeg, *idend, *ostr = bptr;
  572.     int brs;            /* != 0 means ${...}, otherwise $... */
  573.     int colf;            /* != 0 means we found a colon after the name */
  574.     int doub = 0;        /* != 0 means we have %%, not %, or ##, not # */
  575.     int isarr = 0;
  576.     int plan9 = isset(RCEXPANDPARAM);
  577.     int cshtilde = isset(CSHJUNKIETILDE);
  578.     int getlen = 0;
  579.     int whichlen = 0;
  580.     int chkset = 0;
  581.     int vunset = 0;
  582.     int spbreak = isset(SHWORDSPLIT) && sp && !qt;
  583.     char *val = NULL, **aval = NULL;
  584.     int fwidth = 0;
  585.     Value v;
  586.     int flags = 0;
  587.     int flnum = 0;
  588.     int substr = 0;
  589.     int sortit = 0, casind = 0;
  590.     int casmod = 0;
  591.     char *sep = NULL, *spsep = NULL;
  592.     char *premul = NULL, *postmul = NULL, *preone = NULL, *postone = NULL;
  593.     long prenum = 0, postnum = 0;
  594.     int copied = 0;
  595.  
  596.     *s++ = '\0';
  597.     if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
  598.     *s != '!' && *s != '$' && *s != String && *s != Qstring &&
  599.     *s != '?' && *s != Quest && *s != '_' &&
  600.     *s != '*' && *s != Star && *s != '@' && *s != '{' &&
  601.     *s != Inbrace && *s != '=' && *s != Equals && *s != Hat &&
  602.     *s != '^' &&
  603.     *s != '+') {
  604.     s[-1] = '$';
  605.     return 1;
  606.     }
  607.     if ((brs = (*s == '{' || *s == Inbrace))) {
  608.     s++;
  609.  
  610.     if (*s == '(' || *s == Inpar) {
  611.         char *t, sav, *d;
  612.         int tt = 0;
  613.         long num;
  614.  
  615.         for (s++; *s != ')' && *s != Outpar; s++, tt = 0) {
  616.         switch (*s) {
  617.         case ')':
  618.         case Outpar:
  619.             break;
  620.         case 'M':
  621.             flags |= 8;
  622.             break;
  623.         case 'R':
  624.             flags |= 16;
  625.             break;
  626.         case 'B':
  627.             flags |= 32;
  628.             break;
  629.         case 'E':
  630.             flags |= 64;
  631.             break;
  632.         case 'N':
  633.             flags |= 128;
  634.             break;
  635.         case 'S':
  636.             substr = 1;
  637.             break;
  638.         case 'I':
  639.             flnum = 0;
  640.             t = get_strarg(++s);
  641.             if (*t) {
  642.             sav = *t;
  643.             *t = '\0';
  644.             d = dupstring(s + 1);
  645.             untokenize(d);
  646.             if ((flnum = mathevalarg(s + 1, &d)) < 0)
  647.                 flnum = -flnum;
  648.             *t = sav;
  649.             s = t;
  650.             } else
  651.             goto flagerr;
  652.             break;
  653.  
  654.         case 'L':
  655.             casmod = 2;
  656.             break;
  657.         case 'U':
  658.             casmod = 1;
  659.             break;
  660.         case 'C':
  661.             casmod = 3;
  662.             break;
  663.  
  664.         case 'o':
  665.             sortit = 1;
  666.             break;
  667.         case 'O':
  668.             sortit = 2;
  669.             break;
  670.         case 'i':
  671.             casind = 1;
  672.             break;
  673.  
  674.         case 'c':
  675.             whichlen = 1;
  676.             break;
  677.         case 'w':
  678.             whichlen = 2;
  679.             break;
  680.  
  681.         case 's':
  682.             tt = 1;
  683.         /* fall through */
  684.         case 'j':
  685.             t = get_strarg(++s);
  686.             if (*t) {
  687.             sav = *t;
  688.             *t = '\0';
  689.             if (tt)
  690.                 spsep = dupstring(s + 1);
  691.             else
  692.                 sep = dupstring(s + 1);
  693.             *t = sav;
  694.             s = t;
  695.             } else
  696.             goto flagerr;
  697.             break;
  698.  
  699.         case 'l':
  700.             tt = 1;
  701.         /* fall through */
  702.         case 'r':
  703.             t = get_strarg(++s);
  704.             if (!*t)
  705.             goto flagerr;
  706.             sav = *t;
  707.             *t = '\0';
  708.             d = dupstring(s + 1);
  709.             untokenize(d);
  710.             if ((num = mathevalarg(d, &d)) < 0)
  711.             num = -num;
  712.             if (tt)
  713.             prenum = num;
  714.             else
  715.             postnum = num;
  716.             *t = sav;
  717.             sav = *s;
  718.             s = t + 1;
  719.             if (*s != sav) {
  720.             s--;
  721.             break;
  722.             }
  723.             t = get_strarg(s);
  724.             if (!*t)
  725.             goto flagerr;
  726.             sav = *t;
  727.             *t = '\0';
  728.             if (tt)
  729.             premul = dupstring(s + 1);
  730.             else
  731.             postmul = dupstring(s + 1);
  732.             *t = sav;
  733.             sav = *s;
  734.             s = t + 1;
  735.             if (*s != sav) {
  736.             s--;
  737.             break;
  738.             }
  739.             t = get_strarg(s);
  740.             if (!*t)
  741.             goto flagerr;
  742.             sav = *t;
  743.             *t = '\0';
  744.             if (tt)
  745.             preone = dupstring(s + 1);
  746.             else
  747.             postone = dupstring(s + 1);
  748.             *t = sav;
  749.             s = t;
  750.             break;
  751.  
  752.         default:
  753.           flagerr:
  754.             zerr("error in flags", NULL, 0);
  755.             return 1;
  756.         }
  757.         }
  758.         s++;
  759.     }
  760.     }
  761.     if (sortit && casind)
  762.     sortit |= (casind << 1);
  763.  
  764.     if (!premul)
  765.     premul = " ";
  766.     if (!postmul)
  767.     postmul = " ";
  768.  
  769.     for (;;) {
  770.     if (*s == '^' || *s == Hat)
  771.         plan9 ^= 1, s++;
  772.     else if (*s == '=' || *s == Equals)
  773.         spbreak ^= 1, s++;
  774.     else if ((*s == '#' || *s == Pound) && (iident(s[1])
  775.                         || s[1] == '*' || s[1] == Star || s[1] == '@'
  776.                         || (isstring(s[1]) && isbrace(s[2]) && iident(s[3]))))
  777.         getlen = 1 + whichlen, s++;
  778.     else if (*s == '~' || *s == Tilde)
  779.         cshtilde ^= 1, s++;
  780.     else if (*s == '+' && iident(s[1]))
  781.         chkset = 1, s++;
  782.     else
  783.         break;
  784.     }
  785.     cshtilde = cshtilde && !(qt & 1);
  786.  
  787.     idbeg = s;
  788.     if (isstring(*s) && isbrace(s[1])) {
  789.     int bct, sav;
  790.  
  791.     val = s;
  792.     for (bct = 1, s += 2; *s && bct; ++s)
  793.         if (*s == Inbrace || *s == '{')
  794.         ++bct;
  795.         else if (*s == Outbrace || *s == '}')
  796.         --bct;
  797.     sav = *s;
  798.     *s = 0;
  799.     singsub(&val);
  800.     *s = sav;
  801.     isarr = 0;
  802.     v = (Value) NULL;
  803.     } else if (!(v = getvalue(&s, 1))) {
  804.     vunset = 1;
  805.     } else if ((isarr = v->isarr)) {
  806.     aval = getarrvalue(v);
  807.     if (qt && ((qt & 1) || !getlen) && isarr > 0) {
  808.         val = sepjoin(aval,sep);
  809.         isarr = 0;
  810.     }
  811.     } else {
  812.     if (v->pm->flags & PMFLAG_A) {
  813.         int tmplen = arrlen(v->pm->gets.afn(v->pm));
  814.         if (v->a < 0)
  815.         v->a += tmplen + v->inv;
  816.         if (!v->inv && (v->a >= tmplen || v->a < 0))
  817.         vunset = 1;
  818.     }
  819.     if (!vunset) {
  820.         val = getstrvalue(v);
  821.         fwidth = v->pm->ct ? v->pm->ct : strlen(val);
  822.         switch (v->pm->flags & (PMFLAG_L | PMFLAG_R | PMFLAG_Z)) {
  823.         char *t;
  824.         int t0;
  825.  
  826.         case PMFLAG_L:
  827.         case PMFLAG_L | PMFLAG_Z:
  828.         t = val;
  829.         if (v->pm->flags & PMFLAG_Z)
  830.             while (*t == '0')
  831.             t++;
  832.         else
  833.             while (isep(*t))
  834.             t++;
  835.         val = (char *)ncalloc(fwidth + 1);
  836.         val[fwidth] = '\0';
  837.         if ((t0 = strlen(t)) > fwidth)
  838.             t0 = fwidth;
  839.         memset(val, ' ', fwidth);
  840.         strncpy(val, t, t0);
  841.         break;
  842.         case PMFLAG_R:
  843.         case PMFLAG_Z:
  844.         case PMFLAG_Z | PMFLAG_R:
  845.         if (strlen(val) < fwidth) {
  846.             t = (char *)ncalloc(fwidth + 1);
  847.             memset(t, (v->pm->flags & PMFLAG_R) ? ' ' : '0', fwidth);
  848.             if ((t0 = strlen(val)) > fwidth)
  849.             t0 = fwidth;
  850.             strcpy(t + (fwidth - t0), val);
  851.             val = t;
  852.         } else {
  853.             t = (char *)ncalloc(fwidth + 1);
  854.             t[fwidth] = '\0';
  855.             strncpy(t, val + strlen(val) - fwidth, fwidth);
  856.             val = t;
  857.         }
  858.         break;
  859.         }
  860.         switch (v->pm->flags & (PMFLAG_l | PMFLAG_u)) {
  861.         char *t;
  862.  
  863.         case PMFLAG_l:
  864.         t = val;
  865.         for (; *t; t++)
  866.             *t = tulower(*t);
  867.         break;
  868.         case PMFLAG_u:
  869.         t = val;
  870.         for (; *t; t++)
  871.             *t = tuupper(*t);
  872.         break;
  873.         }
  874.     }
  875.     }
  876.     idend = s;
  877.     if ((colf = *s == ':'))
  878.     s++;
  879.  
  880. /* check for ${..?...} or ${..=..} or one of those.  Only works
  881.         if the name is in braces. */
  882.  
  883.     if (brs && (*s == '-' || *s == '=' || *s == Equals || *s == '?' ||
  884.         *s == '+' || *s == '#' || *s == '%' || *s == Quest || *s == Pound)) {
  885.  
  886.     if (!flnum)
  887.         flnum++;
  888.     if (*s == '%')
  889.         flags |= 1;
  890.  
  891.     if ((*s == '%' || *s == '#' || *s == Pound) && *s == s[1]) {
  892.         s++;
  893.         doub = 1;
  894.     }
  895.  
  896.     u = ++s;
  897.  
  898.     flags |= (doub | (substr << 1)) << 1;
  899.     if (!(flags & 0xf8))
  900.         flags |= 16;
  901.  
  902.     if (brs) {
  903.         int bct = 1;
  904.  
  905.         for (;;) {
  906.         if (*s == '{' || *s == Inbrace)
  907.             bct++;
  908.         else if (*s == '}' || *s == Outbrace)
  909.             bct--;
  910.         if (!bct || !*s)
  911.             break;
  912.         s++;
  913.         }
  914.     } else {
  915.         while (*s++);
  916.         s--;
  917.     }
  918.     if (*s)
  919.         *s++ = '\0';
  920.     if (colf && !vunset)
  921.         vunset = (isarr) ? !*aval : !*val;
  922.  
  923.     switch ((int)(unsigned char)u[-1]) {
  924.     case '-':
  925.         if (vunset)
  926.         val = dupstring(u), isarr = 0;
  927.         break;
  928.     case '=':
  929.     case (int)STOUC(Equals):
  930.         if (vunset) {
  931.         char sav = *idend;
  932.  
  933.         *idend = '\0';
  934.         val = dupstring(u);
  935.         filesub(&val, 3);
  936.         setsparam(idbeg, ztrdup(val));
  937.         *idend = sav;
  938.         isarr = 0;
  939.         }
  940.         break;
  941.     case '?':
  942.     case (int)STOUC(Quest):
  943.         if (vunset) {
  944.         char *msg;
  945.         *idend = '\0';
  946.         msg = tricat(idbeg, ": ", *u ? u : "parameter not set");
  947.         zerr("%s", msg, 0);
  948.         zsfree(msg);
  949.         if (!interact)
  950.             exit(1);
  951.         return 1;
  952.         }
  953.         break;
  954.     case '+':
  955.         if (vunset)
  956.         val = dupstring("");
  957.         else
  958.         val = dupstring(u);
  959.         isarr = 0;
  960.         break;
  961.     case '%':
  962.     case '#':
  963.     case (int)STOUC(Pound):
  964.         if (qt & 1)
  965.         tokenize(u);
  966.  
  967.         if (!vunset && v && v->isarr) {
  968.         char **ap = aval;
  969.         char **pp = aval = (char **)ncalloc(sizeof(char *) * (arrlen(aval) + 1));
  970.  
  971.         singsub(&u);
  972.         while ((*pp = *ap++)) {
  973.             getmatch(pp, u, flags, flnum);
  974.             pp++;
  975.         }
  976.         if (!isarr)
  977.             val = sepjoin(aval,sep);
  978.         } else {
  979.         if (vunset)
  980.             val = dupstring("");
  981.         singsub(&u);
  982.         getmatch(&val, u, flags, flnum);
  983.         }
  984.         break;
  985.     }
  986.     } else {            /* no ${...=...} or anything, but possible modifiers. */
  987.     if (chkset) {
  988.         val = dupstring(vunset ? "0" : "1");
  989.         isarr = 0;
  990.     } else if (vunset) {
  991.         if (isset(NOUNSET)) {
  992.         *idend = '\0';
  993.         zerr("%s: parameter not set", idbeg, 0);
  994.         return 1;
  995.         }
  996.         val = dupstring("");
  997.     }
  998.     if (colf) {
  999.         s--;
  1000.         if (!isarr)
  1001.         modify(&val, &s);
  1002.         else {
  1003.         char *ss = s;
  1004.         char **ap = aval;
  1005.         char **pp = aval = (char **)ncalloc(sizeof(char *) * (arrlen(aval) + 1));
  1006.  
  1007.         while ((*pp = *ap++)) {
  1008.             ss = s;
  1009.             modify(pp++, &ss);
  1010.         }
  1011.         s = ss;
  1012.         }
  1013.     }
  1014.     if (brs) {
  1015.         if (*s != '}' && *s != Outbrace) {
  1016.         zerr("closing brace expected", NULL, 0);
  1017.         return 1;
  1018.         }
  1019.         s++;
  1020.     }
  1021.     }
  1022.     if (errflag)
  1023.     return 1;
  1024.     if (getlen) {
  1025.     long len = 0;
  1026.     char buf[14];
  1027.  
  1028.     if (isarr) {
  1029.         char **ctr;
  1030.         int sl = sep ? strlen(sep) : 1;
  1031.  
  1032.         if (getlen == 1)
  1033.         for (ctr = aval; *ctr; ctr++, len++);
  1034.         else if (getlen == 2)
  1035.         for (len = -sl, ctr = aval; *ctr; len += sl + strlen(*ctr), ctr++);
  1036.         else
  1037.         for (ctr = aval;
  1038.              *ctr;
  1039.              len += wordcount(*ctr, sep, getlen > 3), ctr++);
  1040.     } else {
  1041.         if (getlen < 3)
  1042.         len = strlen(val);
  1043.         else
  1044.         len = wordcount(val, sep, getlen > 3);
  1045.     }
  1046.  
  1047.     sprintf(buf, "%ld", len);
  1048.     val = dupstring(buf);
  1049.     isarr = 0;
  1050.     }
  1051.     if (isarr > 0 && !plan9 && (!aval || !aval[0])) {
  1052.     val = dupstring("");
  1053.     isarr = 0;
  1054.     } else if (isarr && aval && aval[0] && !aval[1]) {
  1055.     val = aval[0];
  1056.     isarr = 0;
  1057.     }
  1058.     if (!qt && (spbreak || spsep || sep)) {
  1059.     if (isarr)
  1060.         val = sepjoin(aval, sep);
  1061.     if (spbreak || spsep) {
  1062.         isarr = 1;
  1063.         aval = sepsplit(val, spsep);
  1064.         if (!aval || !aval[0]) {
  1065.         val = dupstring("");
  1066.         isarr = 0;
  1067.         } else if (!aval[1]) {
  1068.         val = aval[0];
  1069.         isarr = 0;
  1070.         }
  1071.     } else
  1072.         isarr = 0;
  1073.     }
  1074.     if (casmod) {
  1075.     if (isarr) {
  1076.         char **ap;
  1077.  
  1078.         ap = aval = arrdup(aval);
  1079.         copied = 1;
  1080.  
  1081.         if (casmod == 1)
  1082.         for (; *ap; ap++)
  1083.             makeuppercase(ap);
  1084.         else if (casmod == 2)
  1085.         for (; *ap; ap++)
  1086.             makelowercase(ap);
  1087.         else
  1088.         for (; *ap; ap++)
  1089.             makecapitals(ap);
  1090.  
  1091.     } else {
  1092.         val = dupstring(val);
  1093.         copied = 1;
  1094.         if (casmod == 1)
  1095.         makeuppercase(&val);
  1096.         else if (casmod == 2)
  1097.         makelowercase(&val);
  1098.         else
  1099.         makecapitals(&val);
  1100.     }
  1101.     }
  1102.     if (isarr) {
  1103.     char *x;
  1104.     char *y;
  1105.     int xlen;
  1106.     int i;
  1107.  
  1108.     if (!aval[0]) {
  1109.         if (plan9)
  1110.         return 0;
  1111.         y = (char *) ncalloc((aptr - bptr) + strlen(s) + 1);
  1112.         strcpy(y, ostr);
  1113.         strcat(y, s);
  1114.         remnulargs(y);
  1115.         if (INULL(*y))
  1116.         return 0;
  1117.         else {
  1118.         setdata(n, (vptr) y);
  1119.         return 1;
  1120.         }
  1121.     }
  1122.  
  1123.     if (sortit && !copied)
  1124.         aval = arrdup(aval);
  1125.     if (sortit == 1)
  1126.         qsort(aval, arrlen(aval), sizeof(char *), (int (*)()) strpcmp);
  1127.     else if (sortit == 2)
  1128.         qsort(aval, arrlen(aval), sizeof(char *), (int (*)()) invstrpcmp);
  1129.     else if (sortit == 3)
  1130.         qsort(aval, arrlen(aval), sizeof(char *), (int (*)()) cstrpcmp);
  1131.     else if (sortit)
  1132.         qsort(aval, arrlen(aval), sizeof(char *), (int (*)()) invcstrpcmp);
  1133.  
  1134.       if (plan9) {
  1135.           int dlen;
  1136.   
  1137.         dlen = (aptr - bptr) + strlen(s) + 1;
  1138.         i = 0;
  1139.         while (aval[i]) {
  1140.         x = aval[i++];
  1141.         if (prenum || postnum)
  1142.             x = dopadding(x, prenum, postnum, preone, postone,
  1143.                   premul, postmul);
  1144.         if (qt && !*x) {
  1145.             x = nulstring;
  1146.             xlen = nulstrlen;
  1147.         } else
  1148.             xlen = strlen(x);
  1149.         y = (char *) ncalloc(dlen + xlen);
  1150.         strcpy(y, ostr);
  1151.         strcatsub(y, x, cshtilde);
  1152.         strcat(y, s);
  1153.         if (i == 1)
  1154.             setdata(n, (vptr) y);
  1155.         else
  1156.             insnode(l, n, (vptr) y), incnode(n);
  1157.         }
  1158.     } else {
  1159.         x = aval[0];
  1160.         if (prenum || postnum)
  1161.         x = dopadding(x, prenum, postnum, preone, postone, 
  1162.                   premul, postmul);
  1163.         if (qt && !*x) {
  1164.         x = nulstring;
  1165.         xlen = nulstrlen;
  1166.         } else
  1167.         xlen = strlen(x);
  1168.         y = (char *) ncalloc((aptr - bptr) + xlen + 1);
  1169.         strcpy(y, ostr);
  1170.         strcatsub(y, x, cshtilde);
  1171.         setdata(n, (vptr) y);
  1172.  
  1173.         i = 1;
  1174.         while (aval[i] && aval[i + 1]) {
  1175.         x = aval[i++];
  1176.         if (prenum || postnum)
  1177.             x = dopadding(x, prenum, postnum, preone, postone,
  1178.                   premul, postmul);
  1179.         if (qt && !*x)
  1180.             y = dupstring(nulstring);
  1181.         else if (cshtilde) {
  1182.             y = (char *) ncalloc(strlen(x) + 1);
  1183.             *y = '\0';
  1184.             strcatsub(y, x, 1);
  1185.         } else
  1186.             y = x;
  1187.         insnode(l, n, (vptr) y), incnode(n);
  1188.         }
  1189.  
  1190.         x = aval[i];
  1191.         if (prenum || postnum)
  1192.         x = dopadding(x, prenum, postnum, preone, postone, 
  1193.                   premul, postmul);
  1194.         if (qt && !*x) {
  1195.         x = nulstring;
  1196.         xlen = nulstrlen;
  1197.         } else
  1198.         xlen = strlen(x);
  1199.         y = (char *) ncalloc(xlen + strlen(s) + 1);
  1200.         strcpy(y, x);
  1201.         strcat(y, s);
  1202.         insnode(l, n, (vptr) y);
  1203.     }
  1204.     } else {
  1205.     int xlen;
  1206.     char *x;
  1207.     char *y;
  1208.  
  1209.     x = val;
  1210.     if (prenum || postnum)
  1211.         x = dopadding(x, prenum, postnum, preone, postone,
  1212.               premul, postmul);
  1213.     if (qt && !*x) {
  1214.         x = nulstring;
  1215.         xlen = nulstrlen;
  1216.     } else
  1217.         xlen = strlen(x);
  1218.     y = (char *) ncalloc((aptr - bptr) + xlen + strlen(s) + 1);
  1219.     strcpy(y, ostr);
  1220.     strcatsub(y, x, cshtilde);
  1221.     strcat(y, s);
  1222.     setdata(n, (vptr) y);
  1223.     }
  1224.  
  1225.     return 1;
  1226. }
  1227.  
  1228. /* arithmetic substitution */
  1229.  
  1230. void arithsubst(aptr, bptr)    /**/
  1231. vptr *aptr;
  1232. char **bptr;
  1233. {
  1234.     char *s = (char *)*aptr, *t, buf[16];
  1235.     long v;
  1236.  
  1237.     *s = '\0';
  1238.     for (; *s != Outbrack; s++);
  1239.     *s++ = '\0';
  1240.     v = matheval((char *)*aptr + 2);
  1241.     sprintf(buf, "%ld", v);
  1242.     t = (char *)ncalloc(strlen(*bptr) + strlen(buf) + strlen(s) + 1);
  1243.     strcpy(t, *bptr);
  1244.     strcat(t, buf);
  1245.     strcat(t, s);
  1246.     *bptr = t;
  1247. }
  1248.  
  1249. void modify(str, ptr)        /**/
  1250. char **str;
  1251. char **ptr;
  1252. {
  1253.     char *ptr1, *ptr2, *ptr3, del, *lptr, c, *test, *sep, *t, *tt, tc, *e;
  1254.     char *copy, *all, *tmp, sav;
  1255.     int gbal, wall, rec, al, nl;
  1256.  
  1257.     test = NULL;
  1258.  
  1259.     if (**ptr == ':')
  1260.     *str = dupstring(*str);
  1261.  
  1262.     while (**ptr == ':') {
  1263.     lptr = *ptr;
  1264.     (*ptr)++;
  1265.     wall = gbal = 0;
  1266.     rec = 1;
  1267.     c = '\0';
  1268.     sep = NULL;
  1269.  
  1270.     for (; !c && **ptr;) {
  1271.         switch (**ptr) {
  1272.         case 'h':
  1273.         case 'r':
  1274.         case 'e':
  1275.         case 't':
  1276.         case 'l':
  1277.         case 'u':
  1278.         c = **ptr;
  1279.         break;
  1280.  
  1281.         case 's':
  1282.         c = **ptr;
  1283.         (*ptr)++;
  1284.         zsfree(hsubl);
  1285.         zsfree(hsubr);
  1286.         ptr1 = *ptr;
  1287.         del = *ptr1++;
  1288.         for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++);
  1289.         if (!*ptr2) {
  1290.             zerr("bad subtitution", NULL, 0);
  1291.             return;
  1292.         }
  1293.         *ptr2++ = '\0';
  1294.         for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++);
  1295.         if ((sav = *ptr3))
  1296.             *ptr3++ = '\0';
  1297.         for (tt = hsubl = ztrdup(ptr1); *tt; tt++)
  1298.             if (INULL(*tt))
  1299.             chuck(tt);
  1300.         for (tt = hsubr = ztrdup(ptr2); *tt; tt++)
  1301.             if (INULL(*tt))
  1302.             chuck(tt);
  1303.         ptr2[-1] = del;
  1304.         if (sav)
  1305.             ptr3[-1] = sav;
  1306.         *ptr = ptr3 - 1;
  1307.         break;
  1308.  
  1309.         case '&':
  1310.         c = 's';
  1311.         break;
  1312.  
  1313.         case 'g':
  1314.         (*ptr)++;
  1315.         gbal = 1;
  1316.         break;
  1317.  
  1318.         case 'w':
  1319.         wall = 1;
  1320.         (*ptr)++;
  1321.         break;
  1322.         case 'W':
  1323.         wall = 1;
  1324.         (*ptr)++;
  1325.         ptr1 = get_strarg(ptr2 = *ptr);
  1326.         if ((sav = *ptr1))
  1327.             *ptr1 = '\0';
  1328.         sep = dupstring(ptr2 + 1);
  1329.         if (sav)
  1330.             *ptr1 = sav;
  1331.         *ptr = ptr1 + 1;
  1332.         c = '\0';
  1333.         break;
  1334.  
  1335.         case 'f':
  1336.         rec = -1;
  1337.         (*ptr)++;
  1338.         break;
  1339.         case 'F':
  1340.         rec = -1;
  1341.         (*ptr)++;
  1342.         ptr1 = get_strarg(ptr2 = *ptr);
  1343.         if ((sav = *ptr1))
  1344.             *ptr1 = '\0';
  1345.         ptr2 = dupstring(ptr2 + 1);
  1346.         if (sav)
  1347.             *ptr1 = sav;
  1348.         untokenize(ptr2);
  1349.         rec = mathevalarg(ptr2, &ptr2);
  1350.         *ptr = ptr1 + 1;
  1351.         c = '\0';
  1352.         break;
  1353.         default:
  1354.         *ptr = lptr;
  1355.         return;
  1356.         }
  1357.     }
  1358.     (*ptr)++;
  1359.     if (!c) {
  1360.         *ptr = lptr;
  1361.         return;
  1362.     }
  1363.     if (rec < 0)
  1364.         test = dupstring(*str);
  1365.  
  1366.     while (rec--) {
  1367.         if (wall) {
  1368.         al = 0;
  1369.         all = NULL;
  1370.         for (t = e = *str; (tt = findword(&e, sep));) {
  1371.             tc = *e;
  1372.             *e = '\0';
  1373.             copy = dupstring(tt);
  1374.             *e = tc;
  1375.             switch (c) {
  1376.             case 'h':
  1377.             remtpath(©);
  1378.             break;
  1379.             case 'r':
  1380.             remtext(©);
  1381.             break;
  1382.             case 'e':
  1383.             rembutext(©);
  1384.             break;
  1385.             case 't':
  1386.             remlpaths(©);
  1387.             break;
  1388.             case 'l':
  1389.             downcase(©);
  1390.             break;
  1391.             case 'u':
  1392.             upcase(©);
  1393.             break;
  1394.             case 's':
  1395.             if (hsubl && hsubr)
  1396.                 subst(©, hsubl, hsubr, gbal);
  1397.             break;
  1398.             }
  1399.             tc = *tt;
  1400.             *tt = '\0';
  1401.             nl = al + strlen(t) + strlen(copy);
  1402.             ptr1 = tmp = (char *) halloc(nl + 1);
  1403.             if (all)
  1404.             for (ptr2 = all; *ptr2;)
  1405.                 *ptr1++ = *ptr2++;
  1406.             for (ptr2 = t; *ptr2;)
  1407.             *ptr1++ = *ptr2++;
  1408.             *tt = tc;
  1409.             for (ptr2 = copy; *ptr2;)
  1410.             *ptr1++ = *ptr2++;
  1411.             *ptr1 = '\0';
  1412.             al = nl;
  1413.             all = tmp;
  1414.             t = e;
  1415.         }
  1416.         *str = all;
  1417.  
  1418.         } else {
  1419.         switch (c) {
  1420.         case 'h':
  1421.             remtpath(str);
  1422.             break;
  1423.         case 'r':
  1424.             remtext(str);
  1425.             break;
  1426.         case 'e':
  1427.             rembutext(str);
  1428.             break;
  1429.         case 't':
  1430.             remlpaths(str);
  1431.             break;
  1432.         case 'l':
  1433.             downcase(str);
  1434.             break;
  1435.         case 'u':
  1436.             upcase(str);
  1437.             break;
  1438.         case 's':
  1439.             if (hsubl && hsubr) {
  1440.             char *oldstr = *str;
  1441.  
  1442.             subst(str, hsubl, hsubr, gbal);
  1443.             if (*str != oldstr) {
  1444.                 *str = dupstring(oldstr = *str);
  1445.                 zsfree(oldstr);
  1446.             }
  1447.             }
  1448.             break;
  1449.         }
  1450.         }
  1451.         if (rec < 0) {
  1452.         if (!strcmp(test, *str))
  1453.             rec = 0;
  1454.         else
  1455.             test = dupstring(*str);
  1456.         }
  1457.     }
  1458.     }
  1459. }
  1460.  
  1461. /* get a directory stack entry */
  1462.  
  1463. char *dstackent(val)        /**/
  1464. int val;
  1465. {
  1466.     Lknode node;
  1467.  
  1468.     if ((val < 0 && !firstnode(dirstack)) || !val--)
  1469.     return pwd;
  1470.     if (val < 0)
  1471.     node = lastnode(dirstack);
  1472.     else
  1473.     for (node = firstnode(dirstack); node && val; val--, incnode(node));
  1474.     if (!node) {
  1475.     if (!isset(NONOMATCH))
  1476.         zerr("not enough dir stack entries.", NULL, 0);
  1477.     return NULL;
  1478.     }
  1479.     return (char *)getdata(node);
  1480. }
  1481.  
  1482. /* make an alias hash table node */
  1483.  
  1484. struct alias *mkanode(txt, cmflag)    /**/
  1485. char *txt;
  1486. int cmflag;
  1487. {
  1488.     struct alias *ptr = (Alias) zcalloc(sizeof *ptr);
  1489.  
  1490.     ptr->text = txt;
  1491.     ptr->cmd = cmflag;
  1492.     ptr->inuse = 0;
  1493.     return ptr;
  1494. }
  1495.