home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / params.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-25  |  38.3 KB  |  1,939 lines

  1. /*
  2.  * $Id: params.c,v 2.41 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * params.c - parameters
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #include "zsh.h"
  33.  
  34. static Param argvparam;
  35.  
  36. /* Set up parameter hash table.  This will add predefined  *
  37.  * parameter entries as well as setting up parameter table *
  38.  * entries for environment variables we inherit.           */
  39.  
  40. /**/
  41. void
  42. createparamtable(void)
  43. {
  44.     Param ip, pm;
  45.     char **new_environ, **envp, **envp2, **sigptr, **t;
  46.     char buf[50], *str, *iname;
  47.     int num_env;
  48.  
  49.     paramtab = newhashtable(151);
  50.  
  51.     paramtab->hash        = hasher;
  52.     paramtab->emptytable  = NULL;
  53.     paramtab->filltable   = NULL;
  54.     paramtab->addnode     = addhashnode;
  55.     paramtab->getnode     = gethashnode2;
  56.     paramtab->getnode2    = gethashnode2;
  57.     paramtab->removenode  = removehashnode;
  58.     paramtab->disablenode = NULL;
  59.     paramtab->enablenode  = NULL;
  60.     paramtab->freenode    = freeparamnode;
  61.     paramtab->printnode   = printparamnode;
  62. #ifdef ZSH_HASH_DEBUG
  63.     paramtab->printinfo   = printhashtabinfo;
  64.     paramtab->tablename   = ztrdup("paramtab");
  65. #endif
  66.  
  67.     /* Add the special parameters to the hash table */
  68.     for (ip = special_params; ip->nam; ip++)
  69.     paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
  70.     if (emulation != EMULATE_SH && emulation != EMULATE_KSH)
  71.     while ((++ip)->nam)
  72.         paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
  73.  
  74.     argvparam = (Param) paramtab->getnode(paramtab, "*");
  75.  
  76.     noerrs = 1;
  77.  
  78.     HEAPALLOC {
  79.     int allexp = opts[ALLEXPORT];
  80.  
  81.     opts[ALLEXPORT] = 0;
  82.  
  83.     /* Add the standard non-special parameters which have to    *
  84.      * be initialized before we copy the environment variables. *
  85.      * We don't want to override whatever values the users has  *
  86.      * given them in the environment.                           */
  87.     setiparam("MAILCHECK", 60);
  88.     setiparam("LOGCHECK", 60);
  89.     setiparam("KEYTIMEOUT", 40);
  90.     setiparam("LISTMAX", 100);
  91. #ifdef HAVE_SELECT
  92.     setiparam("BAUD", getbaudrate(&shttyinfo));  /* get the output baudrate */
  93. #endif
  94.     setsparam("FCEDIT", ztrdup(DEFAULT_FCEDIT));
  95.     setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX));
  96.     setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT));
  97.     setsparam("WATCHFMT", ztrdup(DEFAULT_WATCHFMT));
  98.     setsparam("HOST", ztrdup(hostnam));
  99.     setsparam("LOGNAME", ztrdup((str = getlogin()) && *str ? str : cached_username));
  100.  
  101.     /* Copy the environment variables we are inheriting to dynamic *
  102.      * memory, so we can do mallocs and frees on it.               */
  103.     num_env = arrlen(environ);
  104.     new_environ = (char **) zalloc(sizeof(char *) * (num_env + 1));
  105.     *new_environ = NULL;
  106.  
  107.     /* Now incorporate environment variables we are inheriting *
  108.      * into the parameter hash table.                          */
  109.     for (envp = new_environ, envp2 = environ; *envp2; envp2++) {
  110.         for (str = *envp2; *str && *str != '='; str++);
  111.         if (*str == '=') {
  112.         iname = ztrdup(*envp2);
  113.         str = iname + (str - *envp2);
  114.         *str = '\0';
  115.         if (!idigit(*iname) && isident(iname) && !strchr(iname, '[') &&
  116.             !((pm = (Param) paramtab->getnode(paramtab, iname)) &&
  117.               (pm->flags & (PM_DONTIMPORT | PM_EXPORTED))) &&
  118.             (pm = setsparam(iname, metafy(str + 1, -1, META_DUP)))) {
  119.             *str = '=';
  120.             pm->flags |= PM_EXPORTED;
  121.             if (pm->flags & PM_SPECIAL) {
  122.             zsfree(iname);
  123.             iname = mkenvstr(pm->nam, getsparam(pm->nam));
  124.             }
  125.             pm->env = *envp++ = iname;
  126.             *envp = NULL;
  127.         } else
  128.             zsfree(iname);
  129.         }
  130.     }
  131.     environ = new_environ;
  132.  
  133.     pm = (Param) paramtab->getnode(paramtab, "HOME");
  134.     if (!(pm->flags & PM_EXPORTED)) {
  135.         pm->flags |= PM_EXPORTED;
  136.         pm->env = addenv("HOME", home);
  137.     }
  138.     pm = (Param) paramtab->getnode(paramtab, "PWD");
  139.     if (!(pm->flags & PM_EXPORTED)) {
  140.         pm->flags |= PM_EXPORTED;
  141.         pm->env = addenv("PWD", pwd);
  142.     }
  143.     pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
  144.     if (!(pm->flags & PM_EXPORTED)) {
  145.         pm->flags |= PM_EXPORTED;
  146.         pm->env = addenv("LOGNAME", pm->u.str);
  147.     }
  148.     pm = (Param) paramtab->getnode(paramtab, "SHLVL");
  149.     if (!(pm->flags & PM_EXPORTED))
  150.         pm->flags |= PM_EXPORTED;
  151.     sprintf(buf, "%d", (int)++shlvl);
  152.     pm->env = addenv("SHLVL", buf);
  153.  
  154.     /* Add the standard non-special parameters */
  155.     setsparam("MACHTYPE", ztrdup(MACHTYPE));
  156.     setsparam("OSTYPE", ztrdup(OSTYPE));
  157.     setsparam("TTY", ztrdup(ttystrname));
  158.     setsparam("VENDOR", ztrdup(VENDOR));
  159.     setsparam("ZSH_NAME", ztrdup(zsh_name));
  160.     setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION));
  161.     setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));
  162.     for (t = sigs; (*sigptr++ = ztrdup(*t++)); );
  163.     opts[ALLEXPORT] = allexp;
  164.     } LASTALLOC;
  165.  
  166.     noerrs = 0;
  167. }
  168.  
  169. /* Create a new parameter node */
  170.  
  171. /**/
  172. Param
  173. createparam(char *name, int flags)
  174. {
  175.     Param pm, oldpm, altpm;
  176.     int spec;
  177.  
  178.     if (name != nulstring) {
  179.     oldpm = (Param) paramtab->getnode(paramtab, name);
  180.     spec = oldpm && (oldpm->flags & PM_SPECIAL);
  181.  
  182.     if ((oldpm && oldpm->level == locallevel) || spec) {
  183.         if (oldpm && !(oldpm->flags & PM_UNSET))
  184.         return NULL;
  185.         pm = oldpm;
  186.         pm->ct = 0;
  187.         oldpm = pm->old;
  188.         pm->flags = (flags & (PM_EXPORTED | PM_LEFT | PM_RIGHT_B |
  189.                   PM_RIGHT_Z | PM_LOWER | PM_UPPER |
  190.                   PM_READONLY | PM_TAGGED | PM_UNIQUE)) |
  191.         (pm->flags & (PM_SCALAR | PM_INTEGER | PM_ARRAY | PM_SPECIAL));
  192.         if (pm->ename &&
  193.         (altpm = (Param) paramtab->getnode(paramtab, pm->ename))) {
  194.         altpm->flags &= ~(PM_UNSET | PM_UNIQUE | PM_UPPER | PM_LEFT |
  195.                   PM_RIGHT_B | PM_RIGHT_Z | PM_LOWER |
  196.                   PM_READONLY | PM_TAGGED | PM_EXPORTED);
  197.         }
  198.     } else {
  199.         pm = (Param) zcalloc(sizeof *pm);
  200.         if ((pm->old = oldpm)) {
  201.         /* needed to avoid freeing oldpm */
  202.         paramtab->removenode(paramtab, name);
  203.         }
  204.         paramtab->addnode(paramtab, ztrdup(name), pm);
  205.     }
  206.  
  207.     if (isset(ALLEXPORT) && !oldpm)
  208.         pm->flags |= PM_EXPORTED;
  209.     } else {
  210.     pm = (Param) alloc(sizeof *pm);
  211.     spec = 0;
  212.     }
  213.  
  214.     if (!spec) {
  215.     pm->flags = flags;
  216.     switch (PM_TYPE(flags)) {
  217.     case PM_SCALAR:
  218.         pm->sets.cfn = strsetfn;
  219.         pm->gets.cfn = strgetfn;
  220.         break;
  221.     case PM_INTEGER:
  222.         pm->sets.ifn = intsetfn;
  223.         pm->gets.ifn = intgetfn;
  224.         break;
  225.     case PM_ARRAY:
  226.         pm->sets.afn = arrsetfn;
  227.         pm->gets.afn = arrgetfn;
  228.         break;
  229. #ifdef DEBUG
  230.     default:
  231.         DPUTS(1, "oops, tried to create param node without valid flag");
  232.         break;
  233. #endif
  234.     }
  235.     }
  236.     return pm;
  237. }
  238.  
  239. /* Return 1 if the string s is a valid identifier, else return 0. */
  240.  
  241. /**/
  242. int
  243. isident(char *s)
  244. {
  245.     char *ss;
  246.     int ne;
  247.  
  248.     ne = noeval;        /* save the current value of noeval     */
  249.     if (!*s)            /* empty string is definitely not valid */
  250.     return 0;
  251.  
  252.     /* find the first character in `s' not in the iident type table */
  253.     for (ss = s; *ss; ss++)
  254.     if (!iident(*ss))
  255.         break;
  256.  
  257.     /* If this exhaust `s' or the next two characters *
  258.      * are [(, then it is a valid identifier.         */
  259.     if (!*ss || (*ss == '[' && ss[1] == '('))
  260.     return 1;
  261.  
  262.     /* Else if the next character is not [, then it is *
  263.      * definitely not a valid identifier.              */
  264.     if (*ss != '[')
  265.     return 0;
  266.     noeval = 1;
  267.     (void)mathevalarg(++ss, &ss);
  268.     if (*ss == ',')
  269.     (void)mathevalarg(++ss, &ss);
  270.     noeval = ne;        /* restore the value of noeval */
  271.     if (*ss != ']' || ss[1])
  272.     return 0;
  273.     return 1;
  274. }
  275.  
  276. char **garr;
  277.  
  278. /**/
  279. long
  280. getarg(char **str, int *inv, Value v, int a2, long *w)
  281. {
  282.     int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i;
  283.     char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt;
  284.     long r = 0;
  285.     Comp c;
  286.  
  287.     /* first parse any subscription flags */
  288.     if (*s == '(' || *s == Inpar) {
  289.     int escapes = 0;
  290.     int waste;
  291.     for (s++; *s != ')' && *s != Outpar && s != *str; s++) {
  292.         switch (*s) {
  293.         case 'r':
  294.         rev = 1;
  295.         down = ind = 0;
  296.         break;
  297.         case 'R':
  298.         rev = down = 1;
  299.         ind = 0;
  300.         break;
  301.         case 'i':
  302.         rev = ind = 1;
  303.         down = 0;
  304.         break;
  305.         case 'I':
  306.         rev = ind = down = 1;
  307.         break;
  308.         case 'w':
  309.         /* If the parameter is a scalar, then make subscription *
  310.          * work on a per-word basis instead of characters.      */
  311.         word = 1;
  312.         break;
  313.         case 'f':
  314.         word = 1;
  315.         sep = "\n";
  316.         break;
  317.         case 'e':
  318.         /* obsolate compatibility flag without any real effect */
  319.         break;
  320.         case 'n':
  321.         t = get_strarg(++s);
  322.         if (!*t)
  323.             goto flagerr;
  324.         sav = *t;
  325.         *t = '\0';
  326.         num = mathevalarg(s + 1, &d);
  327.         if (!num)
  328.             num = 1;
  329.         *t = sav;
  330.         s = t;
  331.         break;
  332.         case 'p':
  333.         escapes = 1;
  334.         break;
  335.         case 's':
  336.         /* This gives the string that separates words *
  337.          * (for use with the `w' flag.                */
  338.         t = get_strarg(++s);
  339.         if (!*t)
  340.             goto flagerr;
  341.         sav = *t;
  342.         *t = '\0';
  343.         sep = escapes ? getkeystring(s + 1, &waste, 1, &waste) :
  344.                 dupstring(s + 1);
  345.         *t = sav;
  346.         s = t;
  347.         break;
  348.         default:
  349.           flagerr:
  350.         num = 1;
  351.         word = rev = ind = down = 0;
  352.         sep = NULL;
  353.         s = *str - 1;
  354.         }
  355.     }
  356.     if (s != *str)
  357.         s++;
  358.     }
  359.     if (num < 0) {
  360.     down = !down;
  361.     num = -num;
  362.     }
  363.     *inv = ind;
  364.  
  365.     for (t=s, i=0; *t && ((*t != ']' && *t != Outbrack && *t != ',') || i); t++)
  366.     if (*t == '[' || *t == Inbrack)
  367.         i++;
  368.     else if (*t == ']' || *t == Outbrack)
  369.         i--;
  370.  
  371.     if (!*t)
  372.     return 0;
  373.     s = dupstrpfx(s, t - s);
  374.     *str = tt = t;
  375.     if (parsestr(s))
  376.     return 0;
  377.     singsub(&s);
  378.  
  379.     if (!rev) {
  380.     if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0))
  381.         r++;
  382.     if (word && !v->isarr) {
  383.         s = t = getstrvalue(v);
  384.         i = wordcount(s, sep, 0);
  385.         if (r < 0)
  386.         r += i + 1;
  387.         if (r < 1)
  388.         r = 1;
  389.         if (r > i)
  390.         r = i;
  391.         if (!s || !*s)
  392.         return 0;
  393.         while ((d = findword(&s, sep)) && --r);
  394.         if (!d)
  395.         return 0;
  396.  
  397.         if (!a2 && *tt != ',')
  398.         *w = (long)(s - t) - 1;
  399.  
  400.         return (a2 ? s : d + 1) - t;
  401.     } else if (!v->isarr && !word) {
  402.         s = getstrvalue(v);
  403.         if (r > 0) {
  404.         for (t = s + r - 1; *s && s < t;)
  405.             if (*s++ == Meta)
  406.             s++, t++, r++;
  407.         } else {
  408.         r += ztrlen(s);
  409.         for (t = s + r; *s && s < t; r--)
  410.             if (*s++ == Meta)
  411.             t++, r++;
  412.         r -= strlen(s);
  413.         }
  414.     }
  415.     } else {
  416.     if (!v->isarr && !word) {
  417.         l = strlen(s);
  418.         if (a2) {
  419.         if (!l || *s != '*') {
  420.             d = (char *) ncalloc(l + 2);
  421.             *d = '*';
  422.             strcpy(d + 1, s);
  423.             s = d;
  424.         }
  425.         } else {
  426.         if (!l || s[l - 1] != '*') {
  427.             d = (char *) ncalloc(l + 2);
  428.             strcpy(d, s);
  429.             strcat(d, "*");
  430.             s = d;
  431.         }
  432.         }
  433.     }
  434.     tokenize(s);
  435.  
  436.     if ((c = parsereg(s))) {
  437.         if (v->isarr) {
  438.         ta = getarrvalue(v);
  439.         if (!ta || !*ta)
  440.             return 0;
  441.         if (down)
  442.             for (r = -1, p = ta + arrlen(ta) - 1; p >= ta; r--, p--) {
  443.             if (domatch(*p, c, 0) && !--num)
  444.                 return r;
  445.         } else
  446.             for (r = 1, p = ta; *p; r++, p++)
  447.             if (domatch(*p, c, 0) && !--num)
  448.                 return r;
  449.         } else if (word) {
  450.         ta = sepsplit(d = s = getstrvalue(v), sep, 1);
  451.         if (down) {
  452.             for (p = ta + (r = arrlen(ta)) - 1; p >= ta; p--, r--)
  453.             if (domatch(*p, c, 0) && !--num)
  454.                 break;
  455.             if (p < ta)
  456.             return 0;
  457.         } else {
  458.             for (r = 1, p = ta; *p; r++, p++)
  459.             if (domatch(*p, c, 0) && !--num)
  460.                 break;
  461.             if (!*p)
  462.             return 0;
  463.         }
  464.         if (a2)
  465.             r++;
  466.         for (i = 0; (t = findword(&d, sep)) && *t; i++)
  467.             if (!--r) {
  468.             r = (long)(t - s + (a2 ? -1 : 1));
  469.             if (!a2 && *tt != ',')
  470.                 *w = r + strlen(ta[i]) - 2;
  471.             return r;
  472.             }
  473.         return a2 ? -1 : 0;
  474.         } else {
  475.         d = getstrvalue(v);
  476.         if (!d || !*d)
  477.             return 0;
  478.         if (a2) {
  479.             if (down)
  480.             for (r = -2, t = d + strlen(d) - 1; t >= d; r--, t--) {
  481.                 sav = *t;
  482.                 *t = '\0';
  483.                 if (domatch(d, c, 0) && !--num) {
  484.                 *t = sav;
  485.                 return r;
  486.                 }
  487.                 *t = sav;
  488.             } else
  489.             for (r = 0, t = d; *t; r++, t++) {
  490.                 sav = *t;
  491.                 *t = '\0';
  492.                 if (domatch(d, c, 0) && !--num) {
  493.                 *t = sav;
  494.                 return r;
  495.                 }
  496.                 *t = sav;
  497.             }
  498.         } else {
  499.             if (down)
  500.             for (r = -1, t = d + strlen(d) - 1; t >= d; r--, t--) {
  501.                 if (domatch(t, c, 0) && !--num)
  502.                 return r;
  503.             } else
  504.             for (r = 1, t = d; *t; r++, t++)
  505.                 if (domatch(t, c, 0) && !--num)
  506.                 return r;
  507.         }
  508.         return 0;
  509.         }
  510.     }
  511.     }
  512.     return r;
  513. }
  514.  
  515. /**/
  516. int
  517. getindex(char **pptr, Value v)
  518. {
  519.     int a, b, inv = 0;
  520.     char *s = *pptr, *tbrack;
  521.  
  522.     *s++ = '[';
  523.     for (tbrack = s; *tbrack && *tbrack != ']' && *tbrack != Outbrack; tbrack++)
  524.     if (itok(*tbrack))
  525.         *tbrack = ztokens[*tbrack - Pound];
  526.     if (*tbrack == Outbrack)
  527.     *tbrack = ']';
  528.     if ((s[0] == '*' || s[0] == '@') && s[1] == ']') {
  529.     if (v->isarr)
  530.         v->isarr = (s[0] == '*') ? 1 : -1;
  531.     v->a = 0;
  532.     v->b = -1;
  533.     s += 2;
  534.     } else {
  535.     long we = 0, dummy;
  536.  
  537.     a = getarg(&s, &inv, v, 0, &we);
  538.  
  539.     if (inv) {
  540.         if (!v->isarr && a != 0) {
  541.         char *t, *p;
  542.         t = getstrvalue(v);
  543.         if (a > 0) {
  544.             for (p = t + a - 1; p-- > t; )
  545.             if (*p == Meta)
  546.                 a--;
  547.         } else
  548.             a = -ztrlen(t + a + strlen(t));
  549.         }
  550.         if (a > 0 && isset(KSHARRAYS))
  551.         a--;
  552.         v->inv = 1;
  553.         v->isarr = 0;
  554.         v->a = v->b = a;
  555.         if (*s == ',') {
  556.         zerr("invalid subscript", NULL, 0);
  557.         while (*s != ']' && *s != Outbrack)
  558.             s++;
  559.         *pptr = s;
  560.         return 1;
  561.         }
  562.         if (*s == ']' || *s == Outbrack)
  563.         s++;
  564.     } else {
  565.         if (a > 0)
  566.         a--;
  567.         if (*s == ',') {
  568.         s++;
  569.         b = getarg(&s, &inv, v, 1, &dummy);
  570.         if (b > 0)
  571.             b--;
  572.         } else {
  573.         b = we ? we : a;
  574.         }
  575.         if (*s == ']' || *s == Outbrack) {
  576.         s++;
  577.         if (v->isarr && a == b)
  578.             v->isarr = 0;
  579.         v->a = a;
  580.         v->b = b;
  581.         } else
  582.         s = *pptr;
  583.     }
  584.     }
  585.     *pptr = s;
  586.     return 0;
  587. }
  588.  
  589.  
  590. /**/
  591. Value
  592. getvalue(char **pptr, int bracks)
  593. {
  594.     char *s, *t;
  595.     char sav;
  596.     Value v;
  597.     int ppar = 0;
  598.  
  599.     s = t = *pptr;
  600.     garr = NULL;
  601.  
  602.     if (idigit(*s))
  603.     if (bracks >= 0)
  604.         ppar = zstrtol(s, &s, 10);
  605.     else
  606.         ppar = *s++ - '0';
  607.     else if (iident(*s))
  608.     while (iident(*s))
  609.         s++;
  610.     else if (*s == Quest)
  611.     *s++ = '?';
  612.     else if (*s == Pound)
  613.     *s++ = '#';
  614.     else if (*s == String)
  615.     *s++ = '$';
  616.     else if (*s == Qstring)
  617.     *s++ = '$';
  618.     else if (*s == Star)
  619.     *s++ = '*';
  620.     else if (*s == '#' || *s == '-' || *s == '?' || *s == '$' ||
  621.          *s == '_' || *s == '!' || *s == '@' || *s == '*')
  622.     s++;
  623.     else
  624.     return NULL;
  625.  
  626.     if ((sav = *s))
  627.     *s = '\0';
  628.     if (ppar) {
  629.     v = (Value) hcalloc(sizeof *v);
  630.     v->pm = argvparam;
  631.     v->inv = 0;
  632.     v->a = v->b = ppar - 1;
  633.     if (sav)
  634.         *s = sav;
  635.     } else {
  636.     Param pm;
  637.     int isvarat;
  638.  
  639.         isvarat = !strcmp(t, "@");
  640.     pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
  641.     if (sav)
  642.         *s = sav;
  643.     *pptr = s;
  644.     if (!pm || (pm->flags & PM_UNSET))
  645.         return NULL;
  646.     v = (Value) hcalloc(sizeof *v);
  647.     if (PM_TYPE(pm->flags) == PM_ARRAY)
  648.         v->isarr = isvarat ? -1 : 1;
  649.     v->pm = pm;
  650.     v->inv = 0;
  651.     v->a = 0;
  652.     v->b = -1;
  653.     if (bracks > 0 && (*s == '[' || *s == Inbrack)) {
  654.         if (getindex(&s, v)) {
  655.         *pptr = s;
  656.         return v;
  657.         }
  658.     } else if (v->isarr && iident(*t) && isset(KSHARRAYS))
  659.         v->b = 0, v->isarr = 0;
  660.     }
  661.     if (!bracks && *s)
  662.     return NULL;
  663.     *pptr = s;
  664.     if (v->a > MAX_ARRLEN ||
  665.     v->a < -MAX_ARRLEN) {
  666.     zerr("subscript to %s: %d", (v->a < 0) ? "small" : "big", v->a);
  667.     return NULL;
  668.     }
  669.     if (v->b > MAX_ARRLEN ||
  670.     v->b < -MAX_ARRLEN) {
  671.     zerr("subscript to %s: %d", (v->b < 0) ? "small" : "big", v->b);
  672.     return NULL;
  673.     }
  674.     return v;
  675. }
  676.  
  677. /**/
  678. char *
  679. getstrvalue(Value v)
  680. {
  681.     char *s, **ss;
  682.     static char buf[(SIZEOF_LONG * 8) + 4];
  683.  
  684.     if (!v)
  685.     return hcalloc(1);
  686.     HEAPALLOC {
  687.     if (v->inv) {
  688.         sprintf(buf, "%d", v->a);
  689.         s = dupstring(buf);
  690.         LASTALLOC_RETURN s;
  691.     }
  692.  
  693.     switch(PM_TYPE(v->pm->flags)) {
  694.     case PM_ARRAY:
  695.         if (v->isarr)
  696.         s = sepjoin(v->pm->gets.afn(v->pm), NULL);
  697.         else {
  698.         ss = v->pm->gets.afn(v->pm);
  699.         if (v->a < 0)
  700.             v->a += arrlen(ss);
  701.         s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a];
  702.         }
  703.         LASTALLOC_RETURN s;
  704.     case PM_INTEGER:
  705.         convbase(s = buf, v->pm->gets.ifn(v->pm), v->pm->ct);
  706.         break;
  707.     case PM_SCALAR:
  708.         s = v->pm->gets.cfn(v->pm);
  709.         break;
  710.     default:
  711.         s = NULL;
  712.         DPUTS(1, "oops, param node without valid type");
  713.         break;
  714.     }
  715.  
  716.     if (v->a == 0 && v->b == -1)
  717.         LASTALLOC_RETURN s;
  718.     if (v->a < 0)
  719.         v->a += strlen(s);
  720.     if (v->b < 0)
  721.         v->b += strlen(s);
  722.     s = (v->a > (int)strlen(s)) ? dupstring("") : dupstring(s + v->a);
  723.     if (v->b < v->a)
  724.         s[0] = '\0';
  725.     else if (v->b - v->a < (int)strlen(s))
  726.         s[v->b - v->a + 1 + (s[v->b - v->a] == Meta)] = '\0';
  727.     } LASTALLOC;
  728.     return s;
  729. }
  730.  
  731. static char *nular[] = {"", NULL};
  732.  
  733. /**/
  734. char **
  735. getarrvalue(Value v)
  736. {
  737.     char **s;
  738.  
  739.     if (!v)
  740.     return arrdup(nular);
  741.     if (v->inv) {
  742.     char buf[DIGBUFSIZE];
  743.  
  744.     s = arrdup(nular);
  745.     sprintf(buf, "%d", v->a);
  746.     s[0] = dupstring(buf);
  747.     return s;
  748.     }
  749.     s = v->pm->gets.afn(v->pm);
  750.     if (v->a == 0 && v->b == -1)
  751.     return s;
  752.     if (v->a < 0)
  753.     v->a += arrlen(s);
  754.     if (v->b < 0)
  755.     v->b += arrlen(s);
  756.     if (v->a > arrlen(s) || v->a < 0)
  757.     s = arrdup(nular);
  758.     else
  759.     s = arrdup(s) + v->a;
  760.     if (v->b < v->a)
  761.     s[0] = NULL;
  762.     else if (v->b - v->a < arrlen(s))
  763.     s[v->b - v->a + 1] = NULL;
  764.     return s;
  765. }
  766.  
  767. /**/
  768. long
  769. getintvalue(Value v)
  770. {
  771.     if (!v || v->isarr)
  772.     return 0;
  773.     if (v->inv)
  774.     return v->a;
  775.     if (PM_TYPE(v->pm->flags) == PM_INTEGER)
  776.     return v->pm->gets.ifn(v->pm);
  777.     return matheval(getstrvalue(v));
  778. }
  779.  
  780. /**/
  781. void
  782. setstrvalue(Value v, char *val)
  783. {
  784.     char buf[(SIZEOF_LONG * 8) + 4];
  785.  
  786.     if (v->pm->flags & PM_READONLY) {
  787.     zerr("read-only variable: %s", v->pm->nam, 0);
  788.     zsfree(val);
  789.     return;
  790.     }
  791.     switch (PM_TYPE(v->pm->flags)) {
  792.     case PM_SCALAR:
  793.     MUSTUSEHEAP("setstrvalue");
  794.     if (v->a == 0 && v->b == -1) {
  795.         (v->pm->sets.cfn) (v->pm, val);
  796.         if (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z) && !v->pm->ct)
  797.         v->pm->ct = strlen(val);
  798.     } else {
  799.         char *z, *x;
  800.         int zlen;
  801.  
  802.         z = dupstring((v->pm->gets.cfn) (v->pm));
  803.         zlen = strlen(z);
  804.         if (v->inv && unset(KSHARRAYS))
  805.         v->a--, v->b--;
  806.         if (v->a < 0) {
  807.         v->a += zlen;
  808.         if (v->a < 0)
  809.             v->a = 0;
  810.         }
  811.         if (v->a > zlen)
  812.         v->a = zlen;
  813.         if (v->b < 0)
  814.         v->b += zlen;
  815.         if (v->b > zlen - 1)
  816.         v->b = zlen - 1;
  817.         x = (char *) zalloc(v->a + strlen(val) + zlen - v->b);
  818.         strncpy(x, z, v->a);
  819.         strcpy(x + v->a, val);
  820.         strcat(x + v->a, z + v->b + 1);
  821.         (v->pm->sets.cfn) (v->pm, x);
  822.         zsfree(val);
  823.     }
  824.     break;
  825.     case PM_INTEGER:
  826.     if (val) {
  827.         (v->pm->sets.ifn) (v->pm, matheval(val));
  828.         zsfree(val);
  829.     }
  830.     if (!v->pm->ct && lastbase != -1)
  831.         v->pm->ct = lastbase;
  832.     break;
  833.     case PM_ARRAY:
  834.     MUSTUSEHEAP("setstrvalue");
  835.     {
  836.         char **ss = (char **) zalloc(2 * sizeof(char *));
  837.  
  838.         ss[0] = val;
  839.         ss[1] = NULL;
  840.         setarrvalue(v, ss);
  841.     }
  842.     break;
  843.     }
  844.     if ((!v->pm->env && !(v->pm->flags & PM_EXPORTED) &&
  845.      !(isset(ALLEXPORT) && !v->pm->old)) ||
  846.     (v->pm->flags & PM_ARRAY) || v->pm->ename)
  847.     return;
  848.     if (PM_TYPE(v->pm->flags) == PM_INTEGER)
  849.     convbase(val = buf, v->pm->gets.ifn(v->pm), v->pm->ct);
  850.     else
  851.     val = v->pm->gets.cfn(v->pm);
  852.     if (v->pm->env)
  853.     v->pm->env = replenv(v->pm->env, val);
  854.     else {
  855.     v->pm->flags |= PM_EXPORTED;
  856.     v->pm->env = addenv(v->pm->nam, val);
  857.     }
  858. }
  859.  
  860. /**/
  861. void
  862. setintvalue(Value v, long val)
  863. {
  864.     char buf[DIGBUFSIZE];
  865.  
  866.     if (v->pm->flags & PM_READONLY) {
  867.     zerr("read-only variable: %s", v->pm->nam, 0);
  868.     return;
  869.     }
  870.     switch (PM_TYPE(v->pm->flags)) {
  871.     case PM_SCALAR:
  872.     case PM_ARRAY:
  873.     sprintf(buf, "%ld", val);
  874.     setstrvalue(v, ztrdup(buf));
  875.     break;
  876.     case PM_INTEGER:
  877.     (v->pm->sets.ifn) (v->pm, val);
  878.     setstrvalue(v, NULL);
  879.     break;
  880.     }
  881. }
  882.  
  883. /**/
  884. void
  885. setarrvalue(Value v, char **val)
  886. {
  887.     if (v->pm->flags & PM_READONLY) {
  888.     zerr("read-only variable: %s", v->pm->nam, 0);
  889.     freearray(val);
  890.     return;
  891.     }
  892.     if (PM_TYPE(v->pm->flags) != PM_ARRAY) {
  893.     freearray(val);
  894.     zerr("attempt to assign array value to non-array", NULL, 0);
  895.     return;
  896.     }
  897.     if (v->a == 0 && v->b == -1)
  898.     (v->pm->sets.afn) (v->pm, val);
  899.     else {
  900.     char **old, **new, **p, **q, **r;
  901.     int n, ll, i;
  902.  
  903.     if (v->inv && unset(KSHARRAYS))
  904.         v->a--, v->b--;
  905.     q = old = v->pm->gets.afn(v->pm);
  906.     n = arrlen(old);
  907.     if (v->a < 0)
  908.         v->a += n;
  909.     if (v->b < 0)
  910.         v->b += n;
  911.     if (v->a < 0)
  912.         v->a = 0;
  913.     if (v->b < 0)
  914.         v->b = 0;
  915.  
  916.     ll = v->a + arrlen(val);
  917.     if (v->b < n)
  918.         ll += n - v->b;
  919.  
  920.     p = new = (char **) zcalloc(sizeof(char *) * (ll + 1));
  921.  
  922.     for (i = 0; i < v->a; i++)
  923.         *p++ = i < n ? ztrdup(*q++) : ztrdup("");
  924.     for (r = val; *r;)
  925.         *p++ = ztrdup(*r++);
  926.     if (v->b + 1 < n)
  927.         for (q = old + v->b + 1; *q;)
  928.         *p++ = ztrdup(*q++);
  929.     *p = NULL;
  930.  
  931.     (v->pm->sets.afn) (v->pm, new);
  932.     freearray(val);
  933.     }
  934. }
  935.  
  936. /* Retrieve an integer parameter */
  937.  
  938. /**/
  939. long
  940. getiparam(char *s)
  941. {
  942.     Value v;
  943.  
  944.     if (!(v = getvalue(&s, 1)))
  945.     return 0;
  946.     return getintvalue(v);
  947. }
  948.  
  949. /* Retrieve a scalar (string) parameter */
  950.  
  951. /**/
  952. char *
  953. getsparam(char *s)
  954. {
  955.     Value v;
  956.  
  957.     if (!(v = getvalue(&s, 0)))
  958.     return NULL;
  959.     return getstrvalue(v);
  960. }
  961.  
  962. /* Retrieve an array parameter */
  963.  
  964. /**/
  965. char **
  966. getaparam(char *s)
  967. {
  968.     Value v;
  969.  
  970.     if (!idigit(*s) && (v = getvalue(&s, 0)) &&
  971.     PM_TYPE(v->pm->flags) == PM_ARRAY)
  972.     return v->pm->gets.afn(v->pm);
  973.     return NULL;
  974. }
  975.  
  976. /**/
  977. Param
  978. setsparam(char *s, char *val)
  979. {
  980.     Value v;
  981.     char *t = s;
  982.     char *ss;
  983.  
  984.     if (!isident(s)) {
  985.     zerr("not an identifier: %s", s, 0);
  986.     zsfree(val);
  987.     errflag = 1;
  988.     return NULL;
  989.     }
  990.     if ((ss = strchr(s, '['))) {
  991.     *ss = '\0';
  992.     if (!(v = getvalue(&s, 1)))
  993.         createparam(t, PM_ARRAY);
  994.     *ss = '[';
  995.     v = NULL;
  996.     } else {
  997.     if (!(v = getvalue(&s, 1)))
  998.         createparam(t, PM_SCALAR);
  999.     else if (PM_TYPE(v->pm->flags) == PM_ARRAY &&
  1000.          !(v->pm->flags & PM_SPECIAL) && unset(KSHARRAYS)) {
  1001.         unsetparam(t);
  1002.         createparam(t, PM_SCALAR);
  1003.         v = NULL;
  1004.     }
  1005.     }
  1006.     if (!v && !(v = getvalue(&t, 1))) {
  1007.     zsfree(val);
  1008.     return NULL;
  1009.     }
  1010.     setstrvalue(v, val);
  1011.     return v->pm;
  1012. }
  1013.  
  1014. /**/
  1015. Param
  1016. setaparam(char *s, char **val)
  1017. {
  1018.     Value v;
  1019.     char *t = s;
  1020.     char *ss;
  1021.  
  1022.     if (!isident(s)) {
  1023.     zerr("not an identifier: %s", s, 0);
  1024.     freearray(val);
  1025.     errflag = 1;
  1026.     return NULL;
  1027.     }
  1028.     if ((ss = strchr(s, '['))) {
  1029.     *ss = '\0';
  1030.     if (!(v = getvalue(&s, 1)))
  1031.         createparam(t, PM_ARRAY);
  1032.     *ss = '[';
  1033.     v = NULL;
  1034.     } else {
  1035.     if (!(v = getvalue(&s, 1)))
  1036.         createparam(t, PM_ARRAY);
  1037.     else if (PM_TYPE(v->pm->flags) != PM_ARRAY &&
  1038.          !(v->pm->flags & PM_SPECIAL)) {
  1039.         int uniq = v->pm->flags & PM_UNIQUE;
  1040.         unsetparam(t);
  1041.         createparam(t, PM_ARRAY | uniq);
  1042.         v = NULL;
  1043.     }
  1044.     }
  1045.     if (!v)
  1046.     if (!(v = getvalue(&t, 1)))
  1047.         return NULL;
  1048.     if (isset(KSHARRAYS) && !ss)
  1049.     /* the whole array should be set instead of only the first element */
  1050.     v->b = -1;
  1051.     setarrvalue(v, val);
  1052.     return v->pm;
  1053. }
  1054.  
  1055. /**/
  1056. Param
  1057. setiparam(char *s, long val)
  1058. {
  1059.     Value v;
  1060.     char *t = s;
  1061.     Param pm;
  1062.  
  1063.     if (!isident(s)) {
  1064.     zerr("not an identifier: %s", s, 0);
  1065.     errflag = 1;
  1066.     return NULL;
  1067.     }
  1068.     if (!(v = getvalue(&s, 1))) {
  1069.     pm = createparam(t, PM_INTEGER);
  1070.     DPUTS(!pm, "BUG: parameter not created");
  1071.     pm->u.val = val;
  1072.     return pm;
  1073.     }
  1074.     setintvalue(v, val);
  1075.     return v->pm;
  1076. }
  1077.  
  1078. /* Unset a parameter */
  1079.  
  1080. /**/
  1081. void
  1082. unsetparam(char *s)
  1083. {
  1084.     Param pm;
  1085.  
  1086.     if ((pm = (Param) paramtab->getnode(paramtab, s)))
  1087.     unsetparam_pm(pm, 0);
  1088. }
  1089.  
  1090. /* Unset a parameter */
  1091.  
  1092. /**/
  1093. void
  1094. unsetparam_pm(Param pm, int altflag)
  1095. {
  1096.     Param oldpm, altpm;
  1097.     int spec;
  1098.  
  1099.     if ((pm->flags & PM_READONLY) && pm->level <= locallevel) {
  1100.     zerr("read-only variable: %s", pm->nam, 0);
  1101.     return;
  1102.     }
  1103.     spec = (pm->flags & PM_SPECIAL) && !pm->level;
  1104.     switch (PM_TYPE(pm->flags)) {
  1105.     case PM_SCALAR:
  1106.     (pm->sets.cfn) (pm, NULL);
  1107.     break;
  1108.     case PM_ARRAY:
  1109.     (pm->sets.afn) (pm, NULL);
  1110.     break;
  1111.     }
  1112.     if ((pm->flags & PM_EXPORTED) && pm->env) {
  1113.     delenv(pm->env);
  1114.     zsfree(pm->env);
  1115.     pm->env = NULL;
  1116.     }
  1117.  
  1118.     /* remove it under its alternate name if necessary */
  1119.     if (pm->ename && !altflag) {
  1120.     altpm = (Param) paramtab->getnode(paramtab, pm->ename);
  1121.     unsetparam_pm(altpm, 1);
  1122.     }
  1123.  
  1124.     if ((locallevel && locallevel == pm->level) || spec) {
  1125.     pm->flags |= PM_UNSET;
  1126.     return;
  1127.     }
  1128.  
  1129.     paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */
  1130.  
  1131.     if (pm->old) {
  1132.     oldpm = pm->old;
  1133.     paramtab->addnode(paramtab, oldpm->nam, oldpm);
  1134.     if ((PM_TYPE(oldpm->flags) == PM_SCALAR) && oldpm->sets.cfn == strsetfn)
  1135.         adduserdir(oldpm->nam, oldpm->u.str, 0, 0);
  1136.     }
  1137.  
  1138.     paramtab->freenode((HashNode) pm); /* free parameter node */
  1139. }
  1140.  
  1141. /* Function to get value of an integer parameter */
  1142.  
  1143. /**/
  1144. long
  1145. intgetfn(Param pm)
  1146. {
  1147.     return pm->u.val;
  1148. }
  1149.  
  1150. /* Function to set value of an integer parameter */
  1151.  
  1152. /**/
  1153. void
  1154. intsetfn(Param pm, long x)
  1155. {
  1156.     pm->u.val = x;
  1157. }
  1158.  
  1159. /* Function to get value of a scalar (string) parameter */
  1160.  
  1161. /**/
  1162. char *
  1163. strgetfn(Param pm)
  1164. {
  1165.     return pm->u.str ? pm->u.str : (char *) hcalloc(1);
  1166. }
  1167.  
  1168. /* Function to set value of a scalar (string) parameter */
  1169.  
  1170. /**/
  1171. void
  1172. strsetfn(Param pm, char *x)
  1173. {
  1174.     zsfree(pm->u.str);
  1175.     pm->u.str = x;
  1176.     adduserdir(pm->nam, x, 0, 0);
  1177. }
  1178.  
  1179. /* Function to get value of an array parameter */
  1180.  
  1181. /**/
  1182. char **
  1183. arrgetfn(Param pm)
  1184. {
  1185.     static char *nullarray = NULL;
  1186.  
  1187.     return pm->u.arr ? pm->u.arr : &nullarray;
  1188. }
  1189.  
  1190. /* Function to set value of an array parameter */
  1191.  
  1192. /**/
  1193. void
  1194. arrsetfn(Param pm, char **x)
  1195. {
  1196.     if (pm->u.arr && pm->u.arr != x)
  1197.     freearray(pm->u.arr);
  1198.     if (pm->flags & PM_UNIQUE)
  1199.     uniqarray(x);
  1200.     pm->u.arr = x;
  1201. }
  1202.  
  1203. /* This function is used as the set function for      *
  1204.  * special parameters that cannot be set by the user. */
  1205.  
  1206. /**/
  1207. void
  1208. nullsetfn(Param pm, char *x)
  1209. {
  1210.     zsfree(x);
  1211. }
  1212.  
  1213. /* Function to get value of generic special integer *
  1214.  * parameter.  data is pointer to global variable   *
  1215.  * containing the integer value.                    */
  1216.  
  1217. /**/
  1218. long
  1219. intvargetfn(Param pm)
  1220. {
  1221.     return *((long *)pm->data);
  1222. }
  1223.  
  1224. /* Function to set value of generic special integer *
  1225.  * parameter.  data is pointer to global variable   *
  1226.  * where the value is to be stored.                 */
  1227.  
  1228. /**/
  1229. void
  1230. intvarsetfn(Param pm, long x)
  1231. {
  1232.     *((long *)pm->data) = x;
  1233. }
  1234.  
  1235. /* Function to set value of any ZLE-related integer *
  1236.  * parameter.  data is pointer to global variable   *
  1237.  * where the value is to be stored.                 */
  1238.  
  1239. /**/
  1240. void
  1241. zlevarsetfn(Param pm, long x)
  1242. {
  1243.     long *p = (long *)pm->data;
  1244.  
  1245.     *p = x;
  1246.     if (p == &lines || p == &columns)
  1247.     adjustwinsize(2 + (p == &columns));
  1248. }
  1249.  
  1250. /* Function to set value of generic special scalar    *
  1251.  * parameter.  data is pointer to a character pointer *
  1252.  * representing the scalar (string).                  */
  1253.  
  1254. /**/
  1255. void
  1256. strvarsetfn(Param pm, char *x)
  1257. {
  1258.     char **q = ((char **)pm->data);
  1259.  
  1260.     zsfree(*q);
  1261.     *q = x;
  1262. }
  1263.  
  1264. /* Function to get value of generic special scalar    *
  1265.  * parameter.  data is pointer to a character pointer *
  1266.  * representing the scalar (string).                  */
  1267.  
  1268. /**/
  1269. char *
  1270. strvargetfn(Param pm)
  1271. {
  1272.     char *s = *((char **)pm->data);
  1273.  
  1274.     if (!s)
  1275.     return hcalloc(1);
  1276.     return s;
  1277. }
  1278.  
  1279. /* Function to get value of generic special array  *
  1280.  * parameter.  data is a pointer to the pointer to *
  1281.  * a pointer (a pointer to a variable length array *
  1282.  * of pointers).                                   */
  1283.  
  1284. /**/
  1285. char **
  1286. arrvargetfn(Param pm)
  1287. {
  1288.     return *((char ***)pm->data);
  1289. }
  1290.  
  1291. /* Function to set value of generic special array parameter.    *
  1292.  * data is pointer to a variable length array of pointers which *
  1293.  * represents this array of scalars (strings).  If pm->ename is *
  1294.  * non NULL, then it is a colon separated environment variable  *
  1295.  * version of this array which will need to be updated.         */
  1296.  
  1297. /**/
  1298. void
  1299. arrvarsetfn(Param pm, char **x)
  1300. {
  1301.     char ***dptr = (char ***)pm->data;
  1302.  
  1303.     if (*dptr != x)
  1304.     freearray(*dptr);
  1305.     if (pm->flags & PM_UNIQUE)
  1306.     uniqarray(x);
  1307.     *dptr = x ? x : mkarray(NULL);
  1308.     if (pm->ename && x)
  1309.     arrfixenv(pm->ename, x);
  1310. }
  1311.  
  1312. /**/
  1313. char *
  1314. colonarrgetfn(Param pm)
  1315. {
  1316.     return zjoin(*(char ***)pm->data, ':');
  1317. }
  1318.  
  1319. /**/
  1320. void
  1321. colonarrsetfn(Param pm, char *x)
  1322. {
  1323.     char ***dptr = (char ***)pm->data;
  1324.  
  1325.     freearray(*dptr);
  1326.     *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : mkarray(NULL);
  1327.     zsfree(x);
  1328.     if (pm->ename)
  1329.     arrfixenv(pm->nam, *dptr);
  1330. }
  1331.  
  1332. /**/
  1333. int
  1334. uniqarray(char **x)
  1335. {
  1336.     int changes = 0;
  1337.     char **t, **p = x;
  1338.  
  1339.     if (!x || !*x)
  1340.     return 0;
  1341.     while (*++p)
  1342.     for (t = x; t < p; t++)
  1343.         if (!strcmp(*p, *t)) {
  1344.         zsfree(*p);
  1345.         for (t = p--; (*t = t[1]) != NULL; t++);
  1346.         changes++;
  1347.         break;
  1348.         }
  1349.     return changes;
  1350. }
  1351.  
  1352. /* Function to get value of special parameter `#' and `ARGC' */
  1353.  
  1354. /**/
  1355. long
  1356. poundgetfn(Param pm)
  1357. {
  1358.     return arrlen(pparams);
  1359. }
  1360.  
  1361. /* Function to get value for special parameter `RANDOM' */
  1362.  
  1363. /**/
  1364. long
  1365. randomgetfn(Param pm)
  1366. {
  1367.     return rand() & 0x7fff;
  1368. }
  1369.  
  1370. /* Function to set value of special parameter `RANDOM' */
  1371.  
  1372. /**/
  1373. void
  1374. randomsetfn(Param pm, long v)
  1375. {
  1376.     srand((unsigned int)v);
  1377. }
  1378.  
  1379. /* Function to get value for special parameter `SECONDS' */
  1380.  
  1381. /**/
  1382. long
  1383. secondsgetfn(Param pm)
  1384. {
  1385.     return time(NULL) - shtimer.tv_sec;
  1386. }
  1387.  
  1388. /* Function to set value of special parameter `SECONDS' */
  1389.  
  1390. /**/
  1391. void
  1392. secondssetfn(Param pm, long x)
  1393. {
  1394.     shtimer.tv_sec = time(NULL) - x;
  1395.     shtimer.tv_usec = 0;
  1396. }
  1397.  
  1398. /* Function to get value for special parameter `USERNAME' */
  1399.  
  1400. /**/
  1401. char *
  1402. usernamegetfn(Param pm)
  1403. {
  1404.     return get_username();
  1405. }
  1406.  
  1407. /* Function to set value of special parameter `USERNAME' */
  1408.  
  1409. /**/
  1410. void
  1411. usernamesetfn(Param pm, char *x)
  1412. {
  1413. #ifdef HAVE_SETUID
  1414.     struct passwd *pswd;
  1415.  
  1416.     if (x && (pswd = getpwnam(x)) && (pswd->pw_uid != cached_uid)) {
  1417. #ifdef HAVE_INITGROUPS
  1418.     initgroups(x, pswd->pw_gid);
  1419. #endif
  1420.     if(!setgid(pswd->pw_gid) && !setuid(pswd->pw_uid)) {
  1421.         zsfree(cached_username);
  1422.         cached_username = x;
  1423.         cached_uid = pswd->pw_uid;
  1424.         return;
  1425.     }
  1426.     }
  1427.     zsfree(x);
  1428. #endif
  1429. }
  1430.  
  1431. /* Function to get value for special parameter `UID' */
  1432.  
  1433. /**/
  1434. long
  1435. uidgetfn(Param pm)
  1436. {
  1437.     return getuid();
  1438. }
  1439.  
  1440. /* Function to set value of special parameter `UID' */
  1441.  
  1442. /**/
  1443. void
  1444. uidsetfn(Param pm, uid_t x)
  1445. {
  1446. #ifdef HAVE_SETUID
  1447.     setuid(x);
  1448. #endif
  1449. }
  1450.  
  1451. /* Function to get value for special parameter `EUID' */
  1452.  
  1453. /**/
  1454. long
  1455. euidgetfn(Param pm)
  1456. {
  1457.     return geteuid();
  1458. }
  1459.  
  1460. /* Function to set value of special parameter `EUID' */
  1461.  
  1462. /**/
  1463. void
  1464. euidsetfn(Param pm, uid_t x)
  1465. {
  1466. #ifdef HAVE_SETEUID
  1467.     seteuid(x);
  1468. #endif
  1469. }
  1470.  
  1471. /* Function to get value for special parameter `GID' */
  1472.  
  1473. /**/
  1474. long
  1475. gidgetfn(Param pm)
  1476. {
  1477.     return getgid();
  1478. }
  1479.  
  1480. /* Function to set value of special parameter `GID' */
  1481.  
  1482. /**/
  1483. void
  1484. gidsetfn(Param pm, gid_t x)
  1485. {
  1486. #ifdef HAVE_SETUID
  1487.     setgid(x);
  1488. #endif
  1489. }
  1490.  
  1491. /* Function to get value for special parameter `EGID' */
  1492.  
  1493. /**/
  1494. long
  1495. egidgetfn(Param pm)
  1496. {
  1497.     return getegid();
  1498. }
  1499.  
  1500. /* Function to set value of special parameter `EGID' */
  1501.  
  1502. /**/
  1503. void
  1504. egidsetfn(Param pm, gid_t x)
  1505. {
  1506. #ifdef HAVE_SETEUID
  1507.     setegid(x);
  1508. #endif
  1509. }
  1510.  
  1511. /**/
  1512. long
  1513. ttyidlegetfn(Param pm)
  1514. {
  1515.     struct stat ttystat;
  1516.  
  1517.     if (SHTTY == -1 || fstat(SHTTY, &ttystat))
  1518.     return -1;
  1519.     return time(NULL) - ttystat.st_atime;
  1520. }
  1521.  
  1522. /* Function to get value for special parameter `IFS' */
  1523.  
  1524. /**/
  1525. char *
  1526. ifsgetfn(Param pm)
  1527. {
  1528.     return ifs;
  1529. }
  1530.  
  1531. /* Function to set value of special parameter `IFS' */
  1532.  
  1533. /**/
  1534. void
  1535. ifssetfn(Param pm, char *x)
  1536. {
  1537.     zsfree(ifs);
  1538.     ifs = x;
  1539.     inittyptab();
  1540. }
  1541.  
  1542. /* Functions to set value of special parameters `LANG' and `LC_*' */
  1543.  
  1544. #ifdef LC_ALL
  1545. static struct localename {
  1546.     char *name;
  1547.     int category;
  1548. } lc_names[] = {
  1549. #ifdef LC_COLLATE
  1550.     {"LC_COLLATE", LC_COLLATE},
  1551. #endif
  1552. #ifdef LC_CTYPE
  1553.     {"LC_CTYPE", LC_CTYPE},
  1554. #endif
  1555. #ifdef LC_MESSAGES
  1556.     {"LC_MESSAGES", LC_MESSAGES},
  1557. #endif
  1558. #ifdef LC_TIME
  1559.     {"LC_TIME", LC_TIME},
  1560. #endif
  1561.     {NULL, 0}
  1562. };
  1563.  
  1564. /**/
  1565. void
  1566. setlang(char *x)
  1567. {
  1568.     struct localename *ln;
  1569.  
  1570.     setlocale(LC_ALL, x ? x : "");
  1571.     for (ln = lc_names; ln->name; ln++)
  1572.     if ((x = getsparam(ln->name)))
  1573.         setlocale(ln->category, x);
  1574. }
  1575.  
  1576. /**/
  1577. void
  1578. lc_allsetfn(Param pm, char *x)
  1579. {
  1580.     strsetfn(pm, x);
  1581.     if (!x)
  1582.     setlang(getsparam("LANG"));
  1583.     else
  1584.     setlocale(LC_ALL, x);
  1585. }
  1586.  
  1587. /**/
  1588. void
  1589. langsetfn(Param pm, char *x)
  1590. {
  1591.     strsetfn(pm, x);
  1592.     setlang(x);
  1593. }
  1594.  
  1595. /**/
  1596. void
  1597. lcsetfn(Param pm, char *x)
  1598. {
  1599.     strsetfn(pm, x);
  1600.     if (getsparam("LC_ALL"))
  1601.     return;
  1602.     if (!x)
  1603.     x = getsparam("LANG");
  1604.     setlocale((int) pm->data, x ? x : "");
  1605. }
  1606. #endif
  1607.  
  1608. /* Function to get value for special parameter `HISTSIZE' */
  1609.  
  1610. /**/
  1611. long
  1612. histsizegetfn(Param pm)
  1613. {
  1614.     return histsiz;
  1615. }
  1616.  
  1617. /* Function to set value of special parameter `HISTSIZE' */
  1618.  
  1619. /**/
  1620. void
  1621. histsizesetfn(Param pm, long v)
  1622. {
  1623.     if ((histsiz = v) <= 2)
  1624.     histsiz = 2;
  1625.     resizehistents();
  1626. }
  1627.  
  1628. /* Function to get value for special parameter `ERRNO' */
  1629.  
  1630. /**/
  1631. long
  1632. errnogetfn(Param pm)
  1633. {
  1634.     return errno;
  1635. }
  1636.  
  1637. /* Function to get value for special parameter `-' */
  1638.  
  1639. /**/
  1640. char *
  1641. dashgetfn(Param pm)
  1642. {
  1643.     static char buf[63];
  1644.     char *val = buf;
  1645.     int optno;
  1646.  
  1647.     for(optno = 1; optno < OPT_SIZE; optno++)
  1648.     if(optid(optns[optno]) &&
  1649.         opts[optno] == !(optid(optns[optno]) & OPT_REV))
  1650.         *val++ = optid(optns[optno]) & ~OPT_REV;
  1651.     *val = '\0';
  1652.     return buf;
  1653. }
  1654.  
  1655. /* Function to get value for special parameter `histchar' */
  1656.  
  1657. /**/
  1658. char *
  1659. histcharsgetfn(Param pm)
  1660. {
  1661.     static char buf[4];
  1662.  
  1663.     buf[0] = bangchar;
  1664.     buf[1] = hatchar;
  1665.     buf[2] = hashchar;
  1666.     buf[3] = '\0';
  1667.     return buf;
  1668. }
  1669.  
  1670. /* Function to set value of special parameter `histchar' */
  1671.  
  1672. /**/
  1673. void
  1674. histcharssetfn(Param pm, char *x)
  1675. {
  1676.     if (x) {
  1677.     bangchar = x[0];
  1678.     hatchar = (bangchar) ? x[1] : '\0';
  1679.     hashchar = (hatchar) ? x[2] : '\0';
  1680.     zsfree(x);
  1681.     } else {
  1682.     bangchar = '!';
  1683.     hashchar = '#';
  1684.     hatchar = '^';
  1685.     }
  1686.     inittyptab();
  1687. }
  1688.  
  1689. /* Function to get value for special parameter `HOME' */
  1690.  
  1691. /**/
  1692. char *
  1693. homegetfn(Param pm)
  1694. {
  1695.     return home;
  1696. }
  1697.  
  1698. /* Function to set value of special parameter `HOME' */
  1699.  
  1700. /**/
  1701. void
  1702. homesetfn(Param pm, char *x)
  1703. {
  1704.     zsfree(home);
  1705.     if (x && isset(CHASELINKS) && (home = xsymlink(x)))
  1706.     zsfree(x);
  1707.     else
  1708.     home = x ? x : ztrdup("");
  1709.     finddir(NULL);
  1710. }
  1711.  
  1712. /* Function to get value for special parameter `WORDCHARS' */
  1713.  
  1714. /**/
  1715. char *
  1716. wordcharsgetfn(Param pm)
  1717. {
  1718.     return wordchars;
  1719. }
  1720.  
  1721. /* Function to set value of special parameter `WORDCHARS' */
  1722.  
  1723. /**/
  1724. void
  1725. wordcharssetfn(Param pm, char *x)
  1726. {
  1727.     zsfree(wordchars);
  1728.     wordchars = x;
  1729.     inittyptab();
  1730. }
  1731.  
  1732. /* Function to get value for special parameter `_' */
  1733.  
  1734. /**/
  1735. char *
  1736. underscoregetfn(Param pm)
  1737. {
  1738.     return underscore;
  1739. }
  1740.  
  1741. /* Function to get value for special parameter `TERM' */
  1742.  
  1743. /**/
  1744. char *
  1745. termgetfn(Param pm)
  1746. {
  1747.     return term;
  1748. }
  1749.  
  1750. /* Function to set value of special parameter `TERM' */
  1751.  
  1752. /**/
  1753. void
  1754. termsetfn(Param pm, char *x)
  1755. {
  1756.     zsfree(term);
  1757.     term = x ? x : ztrdup("");
  1758.  
  1759.     /* If non-interactive, delay setting up term till we need it. */
  1760.     if (unset(INTERACTIVE) || !*term)
  1761.     termflags |= TERM_UNKNOWN;
  1762.     else 
  1763.     init_term();
  1764. }
  1765.  
  1766. /* We could probably replace the replenv with the actual code to *
  1767.  * do the replacing, since we've already scanned for the string. */
  1768.  
  1769. /**/
  1770. void
  1771. arrfixenv(char *s, char **t)
  1772. {
  1773.     char **ep, *u;
  1774.     int len_s;
  1775.     Param pm;
  1776.  
  1777.     MUSTUSEHEAP("arrfixenv");
  1778.     if (t == path)
  1779.     cmdnamtab->emptytable(cmdnamtab);
  1780.     u = zjoin(t, ':');
  1781.     len_s = strlen(s);
  1782.     pm = (Param) paramtab->getnode(paramtab, s);
  1783.     if (isset(ALLEXPORT))
  1784.     pm->flags |= PM_EXPORTED;
  1785.     if (pm->flags & PM_EXPORTED) {
  1786.     for (ep = environ; *ep; ep++)
  1787.         if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') {
  1788.         pm->env = replenv(*ep, u);
  1789.         return;
  1790.         }
  1791.     pm->env = addenv(s, u);
  1792.     }
  1793. }
  1794.  
  1795. /* Given *name = "foo", it searchs the environment for string *
  1796.  * "foo=bar", and returns a pointer to the beginning of "bar" */
  1797.  
  1798. /**/
  1799. char *
  1800. zgetenv(char *name)
  1801. {
  1802.     char **ep, *s, *t;
  1803.  
  1804.     for (ep = environ; *ep; ep++) {
  1805.     for (s = *ep, t = name; *s && *s == *t; s++, t++);
  1806.     if (*s == '=' && !*t)
  1807.         return s + 1;
  1808.     }
  1809.     return NULL;
  1810. }
  1811.  
  1812. /* Change the value of an existing environment variable */
  1813.  
  1814. /**/
  1815. char *
  1816. replenv(char *e, char *value)
  1817. {
  1818.     char **ep, *s;
  1819.     int len_value;
  1820.  
  1821.     for (ep = environ; *ep; ep++)
  1822.     if (*ep == e) {
  1823.         for (len_value = 0, s = value;
  1824.          *s && (*s++ != Meta || *s++ != 32); len_value++);
  1825.         s = e;
  1826.         while (*s++ != '=');
  1827.         *ep = (char *) zrealloc(e, s - e + len_value + 1);
  1828.         s = s - e + *ep - 1;
  1829.         while (*s++)
  1830.         if ((*s = *value++) == Meta)
  1831.             *s = *value++ ^ 32;
  1832.         return *ep;
  1833.     }
  1834.     return NULL;
  1835. }
  1836.  
  1837. /* Given strings *name = "foo", *value = "bar", *
  1838.  * return a new string *str = "foo=bar".        */
  1839.  
  1840. /**/
  1841. char *
  1842. mkenvstr(char *name, char *value)
  1843. {
  1844.     char *str, *s;
  1845.     int len_name, len_value;
  1846.  
  1847.     len_name = strlen(name);
  1848.     for (len_value = 0, s = value;
  1849.      *s && (*s++ != Meta || *s++ != 32); len_value++);
  1850.     s = str = (char *) zalloc(len_name + len_value + 2);
  1851.     strcpy(s, name);
  1852.     s += len_name;
  1853.     *s = '=';
  1854.     while (*s++)
  1855.     if ((*s = *value++) == Meta)
  1856.         *s = *value++ ^ 32;
  1857.     return str;
  1858. }
  1859.  
  1860. /* Given *name = "foo", *value = "bar", add the    *
  1861.  * string "foo=bar" to the environment.  Return a  *
  1862.  * pointer to the location of this new environment *
  1863.  * string.                                         */
  1864.  
  1865. /**/
  1866. char *
  1867. addenv(char *name, char *value)
  1868. {
  1869.     char **ep, *s, *t;
  1870.     int num_env;
  1871.  
  1872.     /* First check if there is already an environment *
  1873.      * variable matching string `name'.               */
  1874.     for (ep = environ; *ep; ep++) {
  1875.     for (s = *ep, t = name; *s && *s == *t; s++, t++);
  1876.     if (*s == '=' && !*t) {
  1877.         zsfree(*ep);
  1878.         return *ep = mkenvstr(name, value);
  1879.     }
  1880.     }
  1881.  
  1882.     /* Else we have to make room and add it */
  1883.     num_env = arrlen(environ);
  1884.     environ = (char **) zrealloc(environ, (sizeof(char *)) * (num_env + 2));
  1885.  
  1886.     /* Now add it at the end */
  1887.     ep = environ + num_env;
  1888.     *ep = mkenvstr(name, value);
  1889.     *(ep + 1) = NULL;
  1890.     return *ep;
  1891. }
  1892.  
  1893. /* Delete a pointer from the list of pointers to environment *
  1894.  * variables by shifting all the other pointers up one slot. */
  1895.  
  1896. /**/
  1897. void
  1898. delenv(char *x)
  1899. {
  1900.     char **ep;
  1901.  
  1902.     for (ep = environ; *ep; ep++) {
  1903.     if (*ep == x)
  1904.         break;
  1905.     }
  1906.     if (*ep)
  1907.     for (; (ep[0] = ep[1]); ep++);
  1908. }
  1909.  
  1910. /**/
  1911. void
  1912. convbase(char *s, long v, int base)
  1913. {
  1914.     int digs = 0;
  1915.     unsigned long x;
  1916.  
  1917.     if (v < 0)
  1918.     *s++ = '-', v = -v;
  1919.     if (base <= 1)
  1920.     base = 10;
  1921.  
  1922.     if (base != 10) {
  1923.     sprintf(s, "%d#", base);
  1924.     s += strlen(s);
  1925.     }
  1926.     for (x = v; x; digs++)
  1927.     x /= base;
  1928.     if (!digs)
  1929.     digs = 1;
  1930.     s[digs--] = '\0';
  1931.     x = v;
  1932.     while (digs >= 0) {
  1933.     int dig = x % base;
  1934.  
  1935.     s[digs--] = (dig < 10) ? '0' + dig : dig - 10 + 'A';
  1936.     x /= base;
  1937.     }
  1938. }
  1939.