home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume35 / zsh / part01 / src / params.c
Encoding:
C/C++ Source or Header  |  1993-02-20  |  25.7 KB  |  1,393 lines

  1. /*
  2.  *
  3.  * params.c - parameters
  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 "version.h"
  23. #include <pwd.h>
  24.  
  25. #define new(X) (X=(vptr)alloc(sizeof(*(X))))
  26.  
  27. static Param argvparam;
  28.  
  29. struct iparam {
  30.     struct hashnode *next; int canfree; char *nam; /* hash data */
  31.     vptr value;
  32.     int (*func1)(); /* set func */
  33.     int (*func2)(); /* get func */
  34.     int ct;                /* output base or field width */
  35.     int flags;
  36.     vptr data;            /* used by getfns */
  37.     char *env;            /* location in environment, if exported */
  38.     char *ename;        /* name of corresponding environment var */
  39.     };
  40.  
  41. #define IFN(X) ((int (*)())(X))
  42.  
  43. /* put predefined params in hash table */
  44.  
  45. void setupparams() /**/
  46. {
  47. static struct iparam pinit[] = {
  48. #define IPDEF1(A,B,C,D) {NULL,0,A,NULL,IFN(C),IFN(B),10,\
  49.         PMFLAG_i|PMFLAG_SPECIAL|D,NULL,NULL,NULL}
  50.     IPDEF1("#",poundgetfn,IFN(nullsetfn),PMFLAG_r),
  51.     IPDEF1("ARGC",poundgetfn,IFN(nullsetfn),PMFLAG_r),
  52.     IPDEF1("ERRNO",errnogetfn,IFN(nullsetfn),PMFLAG_r),
  53.     IPDEF1("GID",gidgetfn,IFN(nullsetfn),PMFLAG_r),
  54.     IPDEF1("HISTSIZE",histsizegetfn,histsizesetfn,0),
  55.     IPDEF1("LITHISTSIZE",lithistsizegetfn,lithistsizesetfn,0),
  56.     IPDEF1("RANDOM",randomgetfn,randomsetfn,0),
  57.     IPDEF1("SECONDS",secondsgetfn,secondssetfn,0),
  58.     IPDEF1("UID",uidgetfn,IFN(nullsetfn),PMFLAG_r),
  59.  
  60. #define IPDEF2(A,B,C,D) {NULL,0,A,NULL,IFN(C),IFN(B),0,\
  61.         PMFLAG_SPECIAL|D,NULL,NULL,NULL}
  62.     IPDEF2("-",dashgetfn,IFN(nullsetfn),PMFLAG_r),
  63.     IPDEF2("HISTCHARS",histcharsgetfn,histcharssetfn,0),
  64.     IPDEF2("HOME",homegetfn,homesetfn,0),
  65.     IPDEF2("TERM",termgetfn,termsetfn,0),
  66.     IPDEF2("WORDCHARS",wordcharsgetfn,wordcharssetfn,0),
  67.     IPDEF2("IFS",ifsgetfn,ifssetfn,0),
  68.     IPDEF2("_",underscoregetfn,IFN(nullsetfn),PMFLAG_r),
  69.  
  70. #define IPDEF3(A) {NULL,0,A,NULL,IFN(nullsetfn),IFN(strconstgetfn),0,PMFLAG_r|\
  71.         PMFLAG_SPECIAL,NULL,NULL,NULL}
  72.     IPDEF3("HOSTTYPE"),
  73.     IPDEF3("VERSION"),
  74.  
  75. #define IPDEF4(A,B) {NULL,0,A,NULL,IFN(nullsetfn),IFN(intvargetfn),10,\
  76.         PMFLAG_r|PMFLAG_i|PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
  77.     IPDEF4("!",&lastpid),
  78.     IPDEF4("$",&mypid),
  79.     IPDEF4("?",&lastval),
  80.     IPDEF4("status",&lastval),
  81.     IPDEF4("LINENO",&lineno),
  82.     IPDEF4("PPID",&ppid),
  83.  
  84. #define IPDEF5(A,B) {NULL,0,A,NULL,IFN(intvarsetfn),IFN(intvargetfn),10,\
  85.         PMFLAG_i|PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
  86.     IPDEF5("BAUD",&baud),
  87.     IPDEF5("COLUMNS",&columns),
  88.     IPDEF5("DIRSTACKSIZE",&dirstacksize),
  89.     IPDEF5("LINES",&lines),
  90.     IPDEF5("LISTMAX",&listmax),
  91.     IPDEF5("LOGCHECK",&logcheck),
  92.     IPDEF5("MAILCHECK",&mailcheck),
  93.     IPDEF5("OPTIND",&zoptind),
  94.     IPDEF5("PERIOD",&period),
  95.     IPDEF5("REPORTTIME",&reporttime),
  96.     IPDEF5("SAVEHIST",&savehist),
  97.     IPDEF5("SHLVL",&shlvl),
  98.     IPDEF5("TMOUT",&tmout),
  99.  
  100. #define IPDEF6(A,B) {NULL,0,A,NULL,IFN(nullsetfn),IFN(strvargetfn),0,\
  101.         PMFLAG_r|PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
  102.     IPDEF6("LOGNAME",&logname),
  103.     IPDEF6("PWD",&pwd),
  104.     IPDEF6("TTY",&ttystrname),
  105.     IPDEF6("USERNAME",&username),
  106.  
  107. #define IPDEF7(A,B) {NULL,0,A,NULL,IFN(strvarsetfn),IFN(strvargetfn),0,\
  108.         PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
  109.     IPDEF7("FCEDIT",&fceditparam),
  110.     IPDEF7("HOST",&hostnam),
  111.     IPDEF7("OLDPWD",&oldpwd),
  112.     IPDEF7("OPTARG",&optarg),
  113.     IPDEF7("MAIL",&mailfile),
  114.     IPDEF7("NULLCMD",&nullcmd),
  115.     IPDEF7("POSTEDIT",&postedit),
  116.     IPDEF7("prompt",&prompt),
  117.     IPDEF7("PROMPT",&prompt),
  118.     IPDEF7("PROMPT2",&prompt2),
  119.     IPDEF7("PROMPT3",&prompt3),
  120.     IPDEF7("PROMPT4",&prompt4),
  121.     IPDEF7("READNULLCMD",&readnullcmd),
  122.     IPDEF7("RPROMPT",&rprompt),
  123.     IPDEF7("PS1",&prompt),
  124.     IPDEF7("PS2",&prompt2),
  125.     IPDEF7("PS3",&prompt3),
  126.     IPDEF7("PS4",&prompt4),
  127.     IPDEF7("RPS1",&rprompt),
  128.     IPDEF7("SPROMPT",&sprompt),
  129.     IPDEF7("TIMEFMT",&timefmt),
  130.     IPDEF7("TMPPREFIX",&tmpprefix),
  131.     IPDEF7("WATCHFMT",&watchfmt),
  132.     IPDEF7("0",&argzero),
  133.  
  134. #define IPDEF8(A,B,C) {NULL,0,A,NULL,IFN(colonarrsetfn),IFN(colonarrgetfn),0,\
  135.         PMFLAG_SPECIAL,(vptr)C,NULL,B}
  136.     IPDEF8("CDPATH","cdpath",&cdpath),
  137.     IPDEF8("FIGNORE","fignore",&fignore),
  138.     IPDEF8("FPATH","fpath",&fpath),
  139.     IPDEF8("MAILPATH","mailpath",&mailpath),
  140.     IPDEF8("MANPATH","manpath",&manpath),
  141.     IPDEF8("WATCH","watch",&watch),
  142.     IPDEF8("HOSTS","hosts",&hosts),
  143.     IPDEF8("PSVAR","psvar",&psvar),
  144.     IPDEF8("PATH",NULL,NULL),
  145.  
  146. #define IPDEF9(A,B,C,D) {NULL,0,A,NULL,IFN(arrvarsetfn),IFN(arrvargetfn),0,\
  147.         PMFLAG_A|PMFLAG_SPECIAL|C,(vptr)B,NULL,D}
  148.     IPDEF9("cdpath",&cdpath,0,"CDPATH"),
  149.     IPDEF9("fignore",&fignore,0,"FIGNORE"),
  150.     IPDEF9("fpath",&fpath,0,"FPATH"),
  151.     IPDEF9("mailpath",&mailpath,0,"MAILPATH"),
  152.     IPDEF9("manpath",&manpath,0,"MANPATH"),
  153.     IPDEF9("watch",&watch,0,"WATCH"),
  154.     IPDEF9("hosts",&hosts,0,"HOSTS"),
  155.     IPDEF9("psvar",&psvar,0,"PSVAR"),
  156.     IPDEF9("signals",&sigptr,PMFLAG_r,NULL),
  157.     IPDEF9("argv",&pparams,0,NULL),
  158.     IPDEF9("*",&pparams,0,NULL),
  159.     IPDEF9("@",&pparams,0,NULL),
  160.  
  161. #define IPDEF10(A,C,D) {NULL,0,A,NULL,IFN(D),IFN(C),0,\
  162.         PMFLAG_A|PMFLAG_SPECIAL,NULL,NULL,NULL}
  163.     IPDEF10("path",pathgetfn,pathsetfn),
  164.     IPDEF10("hostcmds",nullgetfn,hostcmdssetfn),
  165.     IPDEF10("optcmds",nullgetfn,optcmdssetfn),
  166.     IPDEF10("bindcmds",nullgetfn,bindcmdssetfn),
  167.     IPDEF10("varcmds",nullgetfn,varcmdssetfn),
  168.     {NULL,}
  169.     };
  170. struct iparam *ip;
  171.  
  172.     for (ip = pinit; ip->nam; ip++) addhperm(ip->nam,ip,paramtab,(FFunc) 0);
  173.     argvparam = gethnode("argv",paramtab);
  174.  
  175.     ((struct iparam *)gethnode("HOSTTYPE", paramtab))->data = ztrdup(HOSTTYPE);
  176.     ((struct iparam *)gethnode("VERSION", paramtab))->data = ztrdup(VERSIONSTR);
  177. }
  178.  
  179. static int unsetflag;
  180.  
  181. struct param *createparam(name,value,flags) /**/
  182. char *name;vptr value;int flags;
  183. {
  184. struct param *pm;
  185. char buf[20];
  186.  
  187.     pm = zcalloc(sizeof *pm);
  188.     if (isset(ALLEXPORT))
  189.         flags |= PMFLAG_x;
  190.     pm->flags = flags;
  191.     if ((flags & PMTYPE) == PMFLAG_s) {
  192.         pm->u.str = value;
  193.         pm->sets.cfn = strsetfn;
  194.         pm->gets.cfn = strgetfn;
  195.     } else if ((flags & PMTYPE) == PMFLAG_A) {
  196.         pm->u.arr = value;
  197.         pm->sets.afn = arrsetfn;
  198.         pm->gets.afn = arrgetfn;
  199.     } else {
  200.         pm->u.val = (value) ? matheval(value) : 0;
  201.         pm->sets.ifn = intsetfn;
  202.         pm->gets.ifn = intgetfn;
  203.         sprintf(buf,"%ld",pm->u.val);
  204.         value = buf;
  205.     }
  206.     if (flags & PMFLAG_x)
  207.         pm->env = addenv(name,value);
  208.     addhnode(ztrdup(name),pm,paramtab,freepm);
  209.     return pm;
  210. }
  211.  
  212. int isident(s) /**/
  213. char *s;
  214. {
  215. char *ss;
  216.  
  217.     for (ss = s; *ss; ss++) if (!iident(*ss)) break;
  218.     if (!*ss) return 1;
  219.     if (*ss != '[') return 0;
  220.     (void) mathevalarg(++ss, &ss);
  221.     if(*ss == ',' || *ss == Comma)
  222.         (void) mathevalarg(++ss,&ss);
  223.     if(*ss != ']' || ss[1]) return 0;
  224.     return 1;
  225. }
  226.  
  227. Value getvalue(pptr,bracks) /**/
  228. char **pptr;int bracks;
  229. {
  230. char *s = *pptr,*t = *pptr;
  231. char sav;
  232. Value v;
  233.  
  234.     if (idigit(*s)) while (idigit(*s)) s++;
  235.     else if (iident(*s)) while (iident(*s)) s++;
  236.     else if (*s == Quest) *s++ = '?';
  237.     else if (*s == Pound) *s++ = '#';
  238.     else if (*s == String) *s++ = '$';
  239.     else if (*s == Qstring) *s++ = '$';
  240.     else if (*s == Star) *s++ = '*';
  241.     else if (*s == '#' || *s == '-' || *s == '?' || *s == '$' ||
  242.                 *s == '_' || *s == '!' || *s == '@' || *s == '*') s++;
  243.     else return NULL;
  244.     if (sav = *s) *s = '\0';
  245.     if (idigit(*t) && *t != '0') {
  246.         v = (Value) hcalloc(sizeof *v);
  247.         v->pm = argvparam;
  248.         v->a = v->b = atoi(t)-1;
  249.         if (sav)
  250.             *s = sav;
  251.     } else {
  252.         struct param *pm;
  253.         int isvarat = !strcmp(t, "@");
  254.  
  255.         pm = gethnode(t,paramtab);
  256.         if (sav)
  257.             *s = sav;
  258.         *pptr = s;
  259.         if (!pm)
  260.             return NULL;
  261.         v = hcalloc(sizeof *v);
  262.         if (pmtype(pm) == PMFLAG_A)
  263.             v->isarr = isvarat ? -1 : 1;
  264.         v->pm = pm;
  265.         v->a = 0; v->b = -1;
  266.         if (bracks && (*s == '[' || *s == Inbrack)) {
  267.             int a,b;
  268.             char *olds = s,*t;
  269.  
  270.             *s++ = '[';
  271.             for (t = s; *t && *t != ']' && *t != Outbrack; t++)
  272.                 if (itok(*t))
  273.                     *t = ztokens[*t-Pound];
  274.             if (*t == Outbrack)
  275.                 *t = ']';
  276.             if ((s[0] == '*' || s[0] == '@')  && s[1] == ']') {
  277.                 if (v->isarr) v->isarr = (s[0] == '*') ? 1 : -1;
  278.                 v->a = 0;
  279.                 v->b = -1;
  280.                 s += 2;
  281.             } else {
  282.                 a = mathevalarg(s,&s);
  283.                 if (a > 0) a--;
  284.                 if (*s == ',' || *s == Comma) {
  285.                     s++;
  286.                     b = mathevalarg(s,&s);
  287.                     if (b > 0) b--;
  288.                 } else
  289.                     b = a;
  290.                 if (*s == ']') {
  291.                     s++;
  292.                     if (v->isarr && a == b)
  293.                         v->isarr = 0;
  294.                     v->a = a;
  295.                     v->b = b;
  296.                 } else
  297.                     s = olds;
  298.             }
  299.         }
  300.     }
  301.     if (!bracks && *s)
  302.         return NULL;
  303.     *pptr = s;
  304.     return v;
  305. }
  306.  
  307. char *getstrvalue(v) /**/
  308. Value v;
  309. {
  310. char *s,**ss;
  311. static char buf[20];
  312.  
  313.     if (!v)
  314.         return "";
  315.     if (pmtype(v->pm) != PMFLAG_A) {
  316.         if ((pmtype(v->pm) == PMFLAG_i))
  317.             convbase(s = buf,v->pm->gets.ifn(v->pm),v->pm->ct);
  318.         else
  319.             s = v->pm->gets.cfn(v->pm);
  320.         if (v->a == 0 && v->b == -1) return s;
  321.         if (v->a < 0) v->a += strlen(s);
  322.         if (v->b < 0) v->b += strlen(s);
  323.         s = (v->a > strlen(s)) ? strdup("") : strdup(s+v->a);
  324.         if (v->b < v->a) s[0] = '\0';
  325.         else if (v->b-v->a < strlen(s)) s[v->b-v->a+1] = '\0';
  326.         return s;
  327.     }
  328.     if (v->isarr) return spacejoin(v->pm->gets.afn(v->pm));
  329.  
  330.     ss = v->pm->gets.afn(v->pm);
  331.     if (v->a < 0) v->a += arrlen(ss);
  332.     s = (v->a >= arrlen(ss) || v->a < 0) ? "" : ss[v->a];
  333.     return s;
  334. }
  335.  
  336. char **getarrvalue(v) /**/
  337. Value v;
  338. {
  339. char **s;
  340. static char *nular[] = { "", NULL };
  341.  
  342.     if (!v)
  343.         return arrdup(nular);
  344.     s = v->pm->gets.afn(v->pm);
  345.     if (v->a == 0 && v->b == -1) return s;
  346.     if (v->a < 0) v->a += arrlen(s);
  347.     if (v->b < 0) v->b += arrlen(s);
  348.     if (v->a > arrlen(s) || v->a < 0)
  349.         s = arrdup(nular);
  350.     else
  351.         s = arrdup(s)+v->a;
  352.     if (v->b < v->a) s[0] = NULL;
  353.     else if (v->b-v->a < arrlen(s)) s[v->b-v->a+1] = NULL;
  354.     return s;
  355. }
  356.  
  357. long getintvalue(v) /**/
  358. Value v;
  359. {
  360. char **ss;
  361.  
  362.     if (!v || v->isarr)
  363.         return 0;
  364.     if (pmtype(v->pm) != PMFLAG_A) {
  365.         if (pmtype(v->pm) == PMFLAG_i)
  366.             return v->pm->gets.ifn(v->pm);
  367.         return atol(v->pm->gets.cfn(v->pm));
  368.     }
  369.     ss = v->pm->gets.afn(v->pm);
  370.     if (v->a < 0) v->a += arrlen(ss);
  371.     if (v->a < 0 || v->a >= arrlen(ss)) return 0;
  372.     return atol(ss[v->a]);
  373. }
  374.  
  375. void setstrvalue(v,val) /**/
  376. Value v;char *val;
  377. {
  378.     if (v->pm->flags & PMFLAG_r) {
  379.         free(val);
  380.         return;
  381.     }
  382.     if (v->pm->env)
  383.         v->pm->env = replenv(v->pm->env,val);
  384.     else if (isset(ALLEXPORT)) {
  385.         v->pm->flags |= PMFLAG_x;
  386.         v->pm->env = addenv(v->pm->nam,val);
  387.     }
  388.     switch (pmtype(v->pm)) {
  389.         case PMFLAG_s:
  390.             if (v->a == 0 && v->b == -1)
  391.                 (v->pm->sets.cfn)(v->pm,val);
  392.             else {
  393.                 char *z,*y,*x;
  394.  
  395.                 z = strdup((v->pm->gets.cfn)(v->pm));
  396.                 if (v->a < 0) {
  397.                     v->a += strlen(z);
  398.                     if (v->a < 0) v->a = 0;
  399.                 }
  400.                 if (v->a > strlen(z)) v->a = strlen(z);
  401.                 if (v->b < 0) v->b += strlen(z);
  402.                 if (v->b < v->a) v->b = v->a;
  403.                 z[v->a] = '\0';
  404.                 y = z+v->b+1;
  405.                 x = zalloc(strlen(z)+strlen(y)+strlen(val)+1);
  406.                 strcpy(x,z);
  407.                 strcat(x,val);
  408.                 strcat(x,y);
  409.                 (v->pm->sets.cfn)(v->pm,x);
  410.             }
  411.             if (v->pm->flags & (PMFLAG_L|PMFLAG_R|PMFLAG_Z) && !v->pm->ct)
  412.                 v->pm->ct = strlen(val);
  413.             break;
  414.         case PMFLAG_i:
  415.             (v->pm->sets.ifn)(v->pm,matheval(val));
  416.             if (!v->pm->ct && lastbase != 1)
  417.                 v->pm->ct = lastbase;
  418.             free(val);
  419.             break;
  420.         case PMFLAG_A:
  421.             if (v->a != v->b)
  422.                 zerr("illegal array assignment",NULL,0);
  423.             else {
  424.                 char **ss = (v->pm->gets.afn)(v->pm);
  425.                 int ac,ad,t0;
  426.  
  427.                 ac = arrlen(ss);
  428.                 if (v->a < 0) {
  429.                     v->a += ac;
  430.                     if (v->a < 0) v->a = 0;
  431.                 }
  432.                 if (v->a >= ac) {
  433.                     char **st = ss;
  434.  
  435.                     ad = v->a+1;
  436.                     ss = zalloc((ad+1)*sizeof *ss);
  437.                     for (t0 = 0; t0 != ac; t0++)
  438.                         ss[t0] = ztrdup(st[t0]);
  439.                     while (ac < ad)
  440.                         ss[ac++] = ztrdup("");
  441.                     ss[ac] = NULL;
  442.                 }
  443.                 if (ss[v->a]) free(ss[v->a]);
  444.                 ss[v->a] = val;
  445.                 (v->pm->sets.afn)(v->pm,ss);
  446.             }
  447.             break;
  448.     }
  449. }
  450.  
  451. void setintvalue(v,val) /**/
  452. Value v;long val;
  453. {
  454. char buf[20];
  455.  
  456.     if (v->pm->flags & PMFLAG_r)
  457.         return;
  458.     sprintf(buf,"%ld",val);
  459.     if (v->pm->env) {
  460.         v->pm->env = replenv(v->pm->env,buf);
  461.     }
  462.     else if (isset(ALLEXPORT)) {
  463.         v->pm->flags |= PMFLAG_x;
  464.         v->pm->env = addenv(v->pm->nam,buf);
  465.     }
  466.     switch (pmtype(v->pm))
  467.         {
  468.         case PMFLAG_s:
  469.             (v->pm->sets.cfn)(v->pm,ztrdup(buf));
  470.             break;
  471.         case PMFLAG_i:
  472.             (v->pm->sets.ifn)(v->pm,val);
  473.             if (!v->pm->ct && lastbase != -1)
  474.                 v->pm->ct = lastbase;
  475.             break;
  476.         case PMFLAG_A:
  477.             zerr("attempt to assign integer to array",NULL,0);
  478.             break;
  479.         }
  480. }
  481.  
  482. void setintenv(s,val) /**/
  483. char *s; long val;
  484. {
  485. Param pm;
  486. char buf[20];
  487.  
  488.     if ((pm = gethnode(s,paramtab)) && pm->env) {
  489.         sprintf(buf,"%ld",val);
  490.         pm->env = replenv(pm->env,buf);
  491.     }
  492. }
  493.  
  494. void setarrvalue(v,val) /**/
  495. Value v;char **val;
  496. {
  497.     if (v->pm->flags & PMFLAG_r) {
  498.         freearray(val);
  499.         return;
  500.     }
  501.     if (pmtype(v->pm) != PMFLAG_A)
  502.         {
  503.         freearray(val);
  504.         zerr("attempt to assign array value to non-array",NULL,0);
  505.         return;
  506.         }
  507.     if (v->a == 0 && v->b == -1)
  508.         (v->pm->sets.afn)(v->pm,val);
  509.     else {
  510.         char **ss = (v->pm->gets.afn)(v->pm);
  511.         int ac,ad,t0;
  512.  
  513.         ac = arrlen(ss);
  514.         if (v->a < 0) {
  515.             v->a += ac;
  516.             if (v->a < 0) v->a = 0;
  517.         }
  518.         if (v->b < 0) v->b += ac;
  519.         if (v->b < v->a) v->b = v->a;
  520.         t0 = arrlen(val) - (v->b - v->a + 1);
  521.         if (v->b >= ac || t0 != 0) {
  522.             char **st = ss;
  523.  
  524.             ad = (v->b > (ac - 1) ? v->b : (ac - 1)) + t0 + 1;
  525.             ss = zalloc((ad+1)*sizeof *ss);
  526.             for (t0 = 0; t0 < v->a; t0++)
  527.                 ss[t0] = ztrdup(t0 < ac ? st[t0] : "");
  528.             while (*val) ss[t0++] = *val++;
  529.             while (++v->b < ac) ss[t0++] = ztrdup(st[v->b]);
  530.             ss[t0] = NULL;
  531.         } else {
  532.             for (t0 = v->a; t0 <= v->b; t0++) {
  533.                 if (ss[t0]) free(ss[t0]);
  534.                 ss[t0] = val[t0];
  535.             }
  536.         }
  537.         (v->pm->sets.afn)(v->pm,ss);
  538.     }
  539. }
  540.  
  541. int getparamtype(s,l) /**/
  542. char *s;int l;
  543. {
  544. char sav,*t = s;
  545. Value v;
  546.  
  547.     sav = t[l];
  548.     t[l] = '\0';
  549.  
  550.     if (!(v = getvalue(&s,0)))
  551.         return -1;
  552.  
  553.     t[l] = sav;
  554.     return (pmtype(v->pm));
  555. }
  556.  
  557. char *getsparamval(s,l) /**/
  558. char *s;int l;
  559. {
  560. char sav,*t = s;
  561. Value v;
  562.  
  563.     sav = t[l];
  564.     t[l] = '\0';
  565.     
  566.     if (!(v = getvalue(&s,0)))
  567.         return NULL;
  568.     t[l] = sav;
  569.     t = getstrvalue(v);
  570.     return t;
  571. }
  572.  
  573. long getiparam(s) /**/
  574. char *s;
  575. {
  576. Value v;
  577.  
  578.     if (!(v = getvalue(&s,0)))
  579.         return 0;
  580.     return getintvalue(v);
  581. }
  582.  
  583. char *getsparam(s) /**/
  584. char *s;
  585. {
  586. Value v;
  587.  
  588.     if (!(v = getvalue(&s,0)))
  589.         return NULL;
  590.     return getstrvalue(v);
  591. }
  592.  
  593. char **getaparam(s) /**/
  594. char *s;
  595. {
  596. Value v;
  597.  
  598.     if (!((v = getvalue(&s,0)) && v->isarr))
  599.         return NULL;
  600.     return getarrvalue(v);
  601. }
  602.  
  603. Param setsparam(s,val) /**/
  604. char *s;char *val;
  605. {
  606. Value v;
  607. char *t = s;
  608. char *ss;
  609.  
  610.     if (!isident(s)) {
  611.         zerr("not an identifier: %s",s,0);
  612.         free(val);
  613.         return NULL;
  614.     }
  615.     if (ss = strchr(s, '[')) {
  616.         *ss = '\0';
  617.         if (!(v = getvalue(&s,1)))
  618.             createparam(t,zcalloc(sizeof val),PMFLAG_A);
  619.         *ss = '[';
  620.         v = getvalue(&t,1);
  621.     } else {
  622.         if (!(v = getvalue(&s,1)))
  623.             return createparam(t,val,PMFLAG_s);
  624.         if ((v->pm->flags & PMTYPE) != PMFLAG_s &&
  625.                 !(v->pm->flags & PMFLAG_SPECIAL)) {
  626.             unsetparam(t);
  627.             return createparam(t,val,PMFLAG_s);
  628.         }
  629.     }
  630.     setstrvalue(v,val);
  631.     return v->pm;
  632. }
  633.  
  634. Param setaparam(s,val) /**/
  635. char *s;char **val;
  636. {
  637. Value v;
  638. char *t = s;
  639. char *ss;
  640.  
  641.     if (!isident(s))
  642.         {
  643.         zerr("not an identifier: %s",s,0);
  644.         freearray(val);
  645.         return NULL;
  646.         }
  647.     if(ss = strchr(s, '[')) {
  648.         *ss = '\0';
  649.         if (!(v = getvalue(&s,1)))
  650.             createparam(t,zcalloc(sizeof val),PMFLAG_A);
  651.         *ss = '[';
  652.         v = getvalue(&t,1);
  653.     } else {
  654.         if (!(v = getvalue(&s,1)))
  655.             return createparam(t,val,PMFLAG_A);
  656.         if ((v->pm->flags & PMTYPE) != PMFLAG_A &&
  657.                 !(v->pm->flags & PMFLAG_SPECIAL)) {
  658.             unsetparam(t);
  659.             return createparam(t,val,PMFLAG_A);
  660.         }
  661.     }
  662.     setarrvalue(v,val);
  663.     return v->pm;
  664. }
  665.  
  666. Param setiparam(s,val) /**/
  667. char *s;long val;
  668. {
  669. Value v;
  670. char *t = s;
  671. Param pm;
  672.  
  673.     if (!isident(s))
  674.         {
  675.         zerr("not an identifier: %s",s,0);
  676.         return NULL;
  677.         }
  678.     if (!(v = getvalue(&s,0)))
  679.         {
  680.         pm = createparam(t,NULL,PMFLAG_i);
  681.         pm->u.val = val;
  682.         return pm;
  683.         }
  684.     setintvalue(v,val);
  685.     return v->pm;
  686. }
  687.  
  688. void unsetparam(s) /**/
  689. char *s;
  690. {
  691. Param pm;
  692.  
  693.     if (!(pm = gethnode(s,paramtab)))
  694.         return;
  695.     if (pm->flags & PMFLAG_r)
  696.         return;
  697.     unsetflag = 1;
  698.     switch (pmtype(pm))
  699.         {
  700.         case 0:
  701.             (pm->sets.cfn)(pm,ztrdup(""));
  702.             break;
  703.         case PMFLAG_i:
  704.             (pm->sets.ifn)(pm,0);
  705.             break;
  706.         case PMFLAG_A:
  707.             (pm->sets.afn)(pm,mkarray(NULL));
  708.             break;
  709.         }
  710.     if (pmtype(pm) == PMFLAG_s && (pm->flags & PMFLAG_x)) {
  711.         delenv(pm->env);
  712.         free(pm->env);
  713.         if (pm->flags & PMFLAG_SPECIAL)
  714.             pm->env = NULL;
  715.     }
  716.     if (!(pm->flags & PMFLAG_SPECIAL))
  717.         freepm(remhnode(s,paramtab));
  718.     unsetflag = 0;
  719. }
  720.  
  721. void intsetfn(pm,x) /**/
  722. Param pm;long x;
  723. {
  724.     pm->u.val = x;
  725. }
  726.  
  727. long intgetfn(pm) /**/
  728. Param pm;
  729. {
  730.     return pm->u.val;
  731. }
  732.  
  733. void strsetfn(pm,x) /**/
  734. Param pm;char *x;
  735. {
  736.     if (x) 
  737.         {
  738.         if (pm->u.str)
  739.             free(pm->u.str);
  740.         pm->u.str = x;
  741.         }
  742. }
  743.  
  744. char *strgetfn(pm) /**/
  745. Param pm;
  746. {
  747.     return pm->u.str;
  748. }
  749.  
  750. void nullsetfn(pm,x) /**/
  751. Param pm; char *x;
  752. {
  753.     free(x);
  754. }
  755.  
  756. void arrsetfn(pm,x) /**/
  757. Param pm;char **x;
  758. {
  759. int ct;
  760.  
  761.     if (x)
  762.         {
  763.         if (pm->u.arr && pm->u.arr != x)
  764.             freearray(pm->u.arr);
  765.         pm->u.arr = x;
  766.         for (ct = 0; *x; x++,ct++);
  767.         pm->ct = ct;
  768.         }
  769. }
  770.  
  771. char **arrgetfn(pm) /**/
  772. Param pm;
  773. {
  774.     return pm->u.arr;
  775. }
  776.  
  777. void intvarsetfn(pm,x) /**/
  778. Param pm;long x;
  779. {
  780.     *((long *) pm->data) = x;
  781. }
  782.  
  783. long intvargetfn(pm) /**/
  784. Param pm;
  785. {
  786.     return *((long *) pm->data);
  787. }
  788.  
  789. void strvarsetfn(pm,x) /**/
  790. Param pm;char *x;
  791. {
  792. char **q = ((char **) pm->data);
  793.  
  794.     if (*q) free(*q);
  795.     *q = x;
  796. }
  797.  
  798. void strvarnonullsetfn(pm,x) /**/
  799. Param pm;char *x;
  800. {
  801. char **q = ((char **) pm->data);
  802.  
  803.     if (*q) free(*q);
  804.     *q = (x) ? x : ztrdup("");
  805. }
  806.  
  807. char *strvargetfn(pm) /**/
  808. Param pm;
  809. {
  810. char *s;
  811.  
  812.     s = *((char **) pm->data);
  813.     if (!s) return "";
  814.     return s;
  815. }
  816.  
  817. char *strconstgetfn(pm) /**/
  818. Param pm;
  819. {
  820.     return (char *) pm->data;
  821. }
  822.  
  823. void colonarrsetfn(pm,x) /**/
  824. Param pm;char *x;
  825. {
  826. char **s,**t,*u,*up;
  827.  
  828.     s = colonsplit(x);
  829.     free(x);
  830.     if (pm->data != &fignore)
  831.         for (t = s; *t; t++) {
  832.             u = *t;
  833.             if (*u == '~') *u = Tilde;
  834.             if (*u == '=') *u = Equals;
  835.             up = hcalloc(strlen(u)+1);
  836.             strcpy(up,u);
  837.             u = up;
  838.             filesub(&u);
  839.             if (!*u) u = ".";
  840.             free(*t);
  841.             *t = ztrdup(u);
  842.         }
  843.     if (pm->data) {
  844.         freearray(*((char ***) pm->data));
  845.         *((char ***) pm->data) = s;
  846.         if (pm->ename)
  847.             arrfixenv(pm->ename,s);
  848.     } else {
  849.         freearray(path);
  850.         path = s;
  851.         newcmdnamtab();
  852.         arrfixenv("PATH",s);
  853.     }
  854. }
  855.  
  856. char *colonarrgetfn(pm) /**/
  857. Param pm;
  858. {
  859.     if ((char **) pm->data)
  860.         return colonjoin(*(char ***) pm->data);
  861.     else
  862.         return colonjoin(path);
  863. }
  864.  
  865. char **arrvargetfn(pm) /**/
  866. Param pm;
  867. {
  868.     return *((char ***) pm->data);
  869. }
  870.  
  871. void arrvarsetfn(pm,x) /**/
  872. Param pm;char **x;
  873. {
  874.     if ((*(char ***) pm->data) != x)
  875.         freearray(*(char ***) pm->data);
  876.     *((char ***) pm->data) = x;
  877.     if (pm->ename)
  878.         arrfixenv(pm->ename,x);
  879. }
  880.  
  881. char **pathgetfn(pm) /**/
  882. Param pm;
  883. {
  884.     return path;
  885. }
  886.  
  887. void pathsetfn(pm,x) /**/
  888. Param pm;char **x;
  889. {
  890.     if (path != x) freearray(path);
  891.     path = x;
  892.     newcmdnamtab();
  893.     arrfixenv("PATH",x);
  894. }
  895.  
  896. void hostcmdssetfn(pm,x) /**/
  897. Param pm;char **x;
  898. {
  899.     compctl_process(x,CC_HOSTS,NULL);
  900.     freearray(x);
  901. }
  902.  
  903. void optcmdssetfn(pm,x) /**/
  904. Param pm;char **x;
  905. {
  906.     compctl_process(x,CC_OPTIONS,NULL);
  907.     freearray(x);
  908. }
  909.  
  910. void bindcmdssetfn(pm,x) /**/
  911. Param pm;char **x;
  912. {
  913.     compctl_process(x,CC_BINDINGS,NULL);
  914.     freearray(x);
  915. }
  916.  
  917. void varcmdssetfn(pm,x) /**/
  918. Param pm;char **x;
  919. {
  920.     compctl_process(x,CC_VARS,NULL);
  921.     freearray(x);
  922. }
  923.  
  924. char **nullgetfn(pm) /**/
  925. Param pm;
  926. {
  927. static char *nl = NULL; return &nl;
  928. }
  929.  
  930. void unsettablesetfn(pm,x) /**/
  931. Param pm;char *x;
  932. { ; }
  933.  
  934. long poundgetfn(pm) /**/
  935. Param pm;
  936. {
  937.     return arrlen(pparams);
  938. }
  939.  
  940. long randomgetfn(pm) /**/
  941. Param pm;
  942. {
  943.     return rand() & 0x7fff;
  944. }
  945.  
  946. void randomsetfn(pm,v) /**/
  947. Param pm;long v;
  948. {
  949.     srand((unsigned int) v);
  950. }
  951.  
  952. long secondsgetfn(pm) /**/
  953. Param pm;
  954. {
  955.     return time(NULL)-shtimer;
  956. }
  957.  
  958. void secondssetfn(pm,x) /**/
  959. Param pm;long x;
  960. {
  961.     shtimer = time(NULL)-x;
  962. }
  963.  
  964. long uidgetfn(pm) /**/
  965. Param pm;
  966. {
  967.     return getuid();
  968. }
  969.  
  970. long gidgetfn(pm) /**/
  971. Param pm;
  972. {
  973.     return getegid();
  974. }
  975.  
  976. char *usernamegetfn(pm) /**/
  977. Param pm;
  978. {
  979. struct passwd *pwd;
  980.  
  981.     pwd = getpwuid(getuid());
  982.     return pwd->pw_name;
  983. }
  984.  
  985. char *hostgetfn(pm) /**/
  986. Param pm;
  987. {
  988. static char hostnam[65];
  989. static int got = 0;
  990.  
  991.     if (!got)
  992.         {
  993.         gethostname(hostnam,64);
  994.         hostnam[64] = '\0';
  995.         got = 1;
  996.         }
  997.     return hostnam;
  998. }
  999.  
  1000. char *ifsgetfn(pm) /**/
  1001. Param pm;
  1002. {
  1003.     return ifs;
  1004. }
  1005.  
  1006. void ifssetfn(pm,x) /**/
  1007. Param pm;char *x;
  1008. {
  1009.     if (x) { free(ifs); ifs = x; }
  1010.     inittyptab();
  1011. }
  1012.  
  1013. void histsizesetfn(pm,v) /**/
  1014. Param pm;long v;
  1015. {
  1016.     if ((histsiz = v) <= 2) histsiz = 2;
  1017.     resizehistents();
  1018. }
  1019.  
  1020. long histsizegetfn(pm) /**/
  1021. Param pm;
  1022. {
  1023.     return histsiz;
  1024. }
  1025.  
  1026. void lithistsizesetfn(pm,v) /**/
  1027. Param pm;long v;
  1028. {
  1029.     if ((lithistsiz = v) <= 2) lithistsiz = 2;
  1030.     resizehistents();
  1031. }
  1032.  
  1033. long lithistsizegetfn(pm) /**/
  1034. Param pm;
  1035. {
  1036.     return lithistsiz;
  1037. }
  1038.  
  1039. void mailchecksetfn(pm,x) /**/
  1040. Param pm;long x;
  1041. {
  1042.     mailcheck = (unsetflag) ? 600 : x;
  1043. }
  1044.  
  1045. void pathasetfn(pm,x) /**/
  1046. Param pm;char **x;
  1047. {
  1048.     freearray(path);
  1049.     path = x;
  1050.     newcmdnamtab();
  1051. }
  1052.  
  1053. char **pathagetfn(pm) /**/
  1054. Param pm;
  1055. {
  1056.     return path;
  1057. }
  1058.  
  1059. long errnogetfn(pm) /**/
  1060. Param pm;
  1061. {
  1062.     return errno;
  1063. }
  1064.  
  1065. char *dashgetfn(pm) /**/
  1066. Param pm;
  1067. {
  1068. static char buf[100];
  1069. char *val;
  1070. int t0;
  1071.  
  1072.     for (val = buf, t0 = ' ';t0 <= 'z'; t0++)
  1073.         if (isset(t0))
  1074.             *val++ = t0;
  1075.     *val = '\0';
  1076.     return buf;
  1077. }
  1078.  
  1079. void histcharssetfn(pm,x) /**/
  1080. Param pm;char *x;
  1081. {
  1082.     if (x) {
  1083.         bangchar = x[0];
  1084.         hatchar = (bangchar) ? x[1] : '\0';
  1085.         hashchar = (hatchar) ? x[2] : '\0';
  1086.         free(x);
  1087.     }
  1088. }
  1089.  
  1090. char *histcharsgetfn(pm) /**/
  1091. Param pm;
  1092. {
  1093. static char buf[4];
  1094.  
  1095.     buf[0] = bangchar;
  1096.     buf[1] = hatchar;
  1097.     buf[2] = hashchar;
  1098.     buf[3] = '\0';
  1099.     return buf;
  1100. }
  1101.  
  1102. char *homegetfn(pm) /**/
  1103. Param pm;
  1104. {
  1105.     return home;
  1106. }
  1107.  
  1108. void homesetfn(pm,x) /**/
  1109. Param pm;char *x;
  1110. {
  1111.     free(home);
  1112.     if (isset(CHASELINKS) && (home = xsymlink(x))) free(x);
  1113.     else home = x;
  1114. }
  1115.  
  1116. char *wordcharsgetfn(pm) /**/
  1117. Param pm;
  1118. {
  1119.     return wordchars;
  1120. }
  1121.  
  1122. void wordcharssetfn(pm,x) /**/
  1123. Param pm;char *x;
  1124. {
  1125.     free(wordchars);
  1126.     if (x) wordchars = x;
  1127.     else wordchars = ztrdup(DEFWORDCHARS);
  1128.     inittyptab();
  1129. }
  1130.  
  1131. char *underscoregetfn(pm) /**/
  1132. Param pm;
  1133. {
  1134. char *s,*t;
  1135.  
  1136.     if (!(s = qgetevent(curhist-1)))
  1137.         return "";
  1138.     for (t = s+strlen(s); t > s; t--)
  1139.         if (*t == HISTSPACE)
  1140.             break;
  1141.     if (t != s)
  1142.         t++;
  1143.     return t;
  1144. }
  1145.  
  1146. char *termgetfn(pm) /**/
  1147. Param pm;
  1148. {
  1149.     return term;
  1150. }
  1151.  
  1152. void termsetfn(pm,x) /**/
  1153. Param pm;char *x;
  1154. {
  1155.     if (term) free(term);
  1156.     term = x;
  1157.     if (!interact || unset(USEZLE))
  1158.         return;
  1159.     if (tgetent(termbuf,term) != 1)
  1160.         {
  1161.         zerr("can't find termcap info for %s",term,0);
  1162.         errflag = 0;
  1163.         termok = 0;
  1164.         }
  1165.     else
  1166.         {
  1167.         char tbuf[1024],*pp;
  1168.         int t0;
  1169.  
  1170.         termok = 1;
  1171.         for (t0 = 0; t0 != TC_COUNT; t0++)
  1172.             {
  1173.             pp = tbuf;
  1174.             if (tcstr[t0])
  1175.                 free(tcstr[t0]);
  1176.             /* AIX tgetstr() ignores second argument */
  1177.             if (!(pp = tgetstr(tccapnams[t0],&pp)))
  1178.                 tcstr[t0] = NULL, tclen[t0] = 0;
  1179.             else
  1180.                 {
  1181.                 tcstr[t0] = zalloc(tclen[t0] = strlen(pp)+1);
  1182.                 memcpy(tcstr[t0],pp,tclen[t0]);
  1183.                 }
  1184.             }
  1185.  
  1186. /* if there's no termcap entry for cursor left, use \b. */
  1187.  
  1188.         if (!tccan(TCLEFT))
  1189.             {
  1190.             tcstr[TCLEFT] = ztrdup("\b");
  1191.             tclen[TCLEFT] = 1;
  1192.             }
  1193.  
  1194. /* if there's no termcap entry for clear, use ^L. */
  1195.  
  1196.         if (!tccan(TCCLEARSCREEN))
  1197.             {
  1198.             tcstr[TCCLEARSCREEN] = ztrdup("\14");
  1199.             tclen[TCCLEARSCREEN] = 1;
  1200.             }
  1201.  
  1202. /* if the termcap entry for down is \n, don't use it. */
  1203.  
  1204.         if (tccan(TCDOWN) && tcstr[TCDOWN][0] == '\n')
  1205.             {
  1206.             tclen[TCDOWN] = 0;
  1207.             free(tcstr[TCDOWN]);
  1208.             tcstr[TCDOWN] = NULL;
  1209.             }
  1210.  
  1211. /* if there's no termcap entry for cursor up, forget it.
  1212.     Use single line mode. */
  1213.  
  1214.         if (!tccan(TCUP))
  1215.             termok = 0;
  1216.         }
  1217. }
  1218.  
  1219. void setparams() /**/
  1220. {
  1221. char **envp,**envp2,**envp3,*str;
  1222. char buf[50];
  1223. struct param *pm;
  1224. int ct;
  1225.  
  1226.     noerrs = 1;
  1227.     for (envp = environ, ct = 2; *envp; envp++,ct++);
  1228.     envp = environ;
  1229.     envp2 = envp3 = (char **) zalloc(sizeof(char *)*ct);
  1230.     for (; *envp; envp++)
  1231.         *envp2++ = ztrdup(*envp);
  1232.     *envp2 = NULL;
  1233.     envp = environ;
  1234.     environ = envp2 = envp3;
  1235.     for (; *envp; envp++,envp2++) {
  1236.         for (str = *envp; *str && *str != '='; str++);
  1237.         if (*str == '=') {
  1238.             char *iname = NULL;
  1239.  
  1240.             *str = '\0';
  1241.             pm = (isident(*envp) && !strchr(*envp, '[')) ?
  1242.                 setsparam(iname = *envp,ztrdup(str+1)) : NULL;
  1243.             if (pm) {
  1244.                 pm->flags |= PMFLAG_x;
  1245.                 pm->env = *envp2;
  1246.                 if (pm->flags & PMFLAG_SPECIAL)
  1247.                     pm->env = replenv(pm->env,getsparam(iname));
  1248.             }
  1249.             *str = '=';
  1250.         }
  1251.     }
  1252.     pm = gethnode("HOME",paramtab);
  1253.     if (!(pm->flags & PMFLAG_x)) {
  1254.         pm->flags |= PMFLAG_x;
  1255.         pm->env = addenv("HOME",home);
  1256.     }
  1257.     pm = gethnode("PWD",paramtab);
  1258.     if (!(pm->flags & PMFLAG_x)) {
  1259.         pm->flags |= PMFLAG_x;
  1260.         pm->env = addenv("PWD",pwd);
  1261.     }
  1262.     pm = gethnode("LOGNAME",paramtab);
  1263.     if (!(pm->flags & PMFLAG_x)) {
  1264.         pm->flags |= PMFLAG_x;
  1265.         pm->env = addenv("LOGNAME",logname);
  1266.     }
  1267.     pm = gethnode("SHLVL",paramtab);
  1268.     if (!(pm->flags & PMFLAG_x))
  1269.         pm->flags |= PMFLAG_x;
  1270.     sprintf(buf,"%d",++shlvl);
  1271.     pm->env = addenv("SHLVL",buf);
  1272.     noerrs = 0;
  1273. }
  1274.  
  1275. char *mkenvstr(x,y) /**/
  1276. char *x;char *y;
  1277. {
  1278. char *z;
  1279. int xl = strlen(x),yl = strlen(y);
  1280.  
  1281.     z = zalloc(xl+yl+2);
  1282.     strcpy(z,x);
  1283.     z[xl] = '=';
  1284.     strcpy(z+xl+1,y);
  1285.     z[xl+yl+1] = '\0';
  1286.     return z;
  1287. }
  1288.  
  1289. void arrfixenv(s,t) /**/
  1290. char *s;char **t;
  1291. {
  1292. char **ep;
  1293. int sl = strlen(s);
  1294.  
  1295.     for (ep = environ; *ep; ep++)
  1296.         if (!strncmp(*ep,s,sl) && (*ep)[sl] == '=') {
  1297.             char *u = colonjoin(t);
  1298.             replenv(*ep,u);
  1299.             break;
  1300.         }
  1301. }
  1302.  
  1303. char *replenv(e,value) /**/
  1304. char *e;char *value;
  1305. {
  1306. char **ep;
  1307.  
  1308.     for (ep = environ; *ep; ep++)
  1309.         if (*ep == e)
  1310.             {
  1311.             char *s = e;
  1312.  
  1313.             while (*s++ != '=');
  1314.             *s = '\0';
  1315.             *ep = zalloc(strlen(e)+strlen(value)+2);
  1316.             strcpy(*ep,e);
  1317.             strcat(*ep,value);
  1318.             free(e);
  1319.             return *ep;
  1320.             }
  1321.     return NULL;
  1322. }
  1323.  
  1324. char *addenv(name,value) /**/
  1325. char *name;char *value;
  1326. {
  1327. char **ep,**ep2,**ep3;
  1328. int envct;
  1329.  
  1330.     for (ep = environ; *ep; ep++)
  1331.         {
  1332.         char *s = *ep,*t = name;
  1333.  
  1334.         while (*s && *s == *t) s++,t++;
  1335.         if (*s == '=' && !*t)
  1336.             {
  1337.             free(*ep);
  1338.             return *ep = mkenvstr(name,value);
  1339.             }
  1340.         }
  1341.     envct = arrlen(environ);
  1342.     ep = ep2 = (char **) zalloc((sizeof (char *))*(envct+3));
  1343.     for (ep3 = environ; *ep2 = *ep3; ep3++,ep2++);
  1344.     *ep2 = mkenvstr(name,value);
  1345.     ep2[1] = NULL;
  1346.     free(environ);
  1347.     environ = ep;
  1348.     return *ep2;
  1349. }
  1350.  
  1351. void delenv(x) /**/
  1352. char *x;
  1353. {
  1354. char **ep;
  1355.  
  1356.     ep = environ;
  1357.     for (; *ep; ep++)
  1358.         if (*ep == x)
  1359.             break;
  1360.     if (*ep)
  1361.         for (; ep[0] = ep[1]; ep++);
  1362. }
  1363.  
  1364. void convbase(s,v,base) /**/
  1365. char *s;long v;int base;
  1366. {
  1367. int digs = 0;
  1368. long x;
  1369.  
  1370.     if (base <= 1)
  1371.         base = 10;
  1372.     x = v;
  1373.     if (x < 0)
  1374.         {
  1375.         x = -x;
  1376.         digs++;
  1377.         }
  1378.     for (; x; digs++)
  1379.         x /= base;
  1380.     if (!digs)
  1381.         digs = 1;
  1382.     s[digs--] = '\0';
  1383.     x = (v < 0) ? -v : v;
  1384.     while (digs >= 0)
  1385.         {
  1386.         int dig = x%base;
  1387.         s[digs--] = (dig < 10) ? '0'+dig : dig-10+'A';
  1388.         x /= base;
  1389.         }
  1390.     if (v < 0)
  1391.         s[0] = '-';
  1392. }
  1393.