home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / pdksh-4.9-src.tgz / tar.out / contrib / pdksh / sh / var.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  14KB  |  667 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: var.c,v 1.4 93/05/05 21:17:17 sjg Exp $";
  3. #endif
  4.  
  5. #include "stdh.h"
  6. #include <errno.h>
  7. #include <setjmp.h>
  8. #include <time.h>
  9. #include "sh.h"
  10. #include "expand.h"
  11.  
  12. /*
  13.  * Variables
  14.  *
  15.  * WARNING: unreadable code, needs a rewrite
  16.  *
  17.  * if (flag&INTEGER), val.i contains integer value, and type contains base.
  18.  * otherwise, (val.s + type) contains string value.
  19.  * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
  20.  */
  21. char    null []    = "";
  22. static    struct tbl vtemp;
  23. static void     export      ARGS((struct tbl *vp, char *val));
  24. static int      special     ARGS((char *name));
  25. static void     getspec     ARGS((struct tbl *vp));
  26. static void     setspec     ARGS((struct tbl *vp));
  27.  
  28. /*
  29.  * create a new block for function calls and simple commands
  30.  * assume caller has allocated and set up e.loc
  31.  */
  32. void
  33. newblock()
  34. {
  35.     register struct block *l = e.loc;
  36.     static char *empty[] = {""};
  37.  
  38.     ainit(&l->area);
  39.     l->argc = 0;
  40.     l->argv = empty;
  41.     l->exit = l->error = NULL;
  42.     tinit(&l->vars, &l->area);
  43.     tinit(&l->funs, &l->area);
  44. }
  45.  
  46. /*
  47.  * pop a block handling special variables
  48.  */
  49. void
  50. popblock()
  51. {
  52.     register struct block *l = e.loc;
  53.     register struct tbl *vp, **vpp = l->vars.tbls;
  54.     register int i;
  55.  
  56.     e.loc = l->next;    /* pop block */
  57.     for (i = l->vars.size; --i >= 0; )
  58.         if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
  59.             setspec(global(vp->name));
  60.     afreeall(&l->area);
  61. }
  62.  
  63. /*
  64.  * Search for variable, if not found create globally.
  65.  */
  66. struct tbl *
  67. global(n)
  68.     register char *n;
  69. {
  70.     register struct block *l = e.loc;
  71.     register struct tbl *vp;
  72.     register int c;
  73.     unsigned h = hash(n);
  74.  
  75.     c = n[0];
  76.     if (digit(c)) {
  77.         vp = &vtemp;
  78.         lastarea = ATEMP;
  79.         vp->flag = (DEFINED|RDONLY);
  80.         vp->type = 0;
  81.         *vp->name = c;    /* should strncpy */
  82.         for (c = 0; digit(*n) && c < 1000; n++)
  83.             c = c*10 + *n-'0';
  84.         if (c <= l->argc)
  85.             setstr(vp, l->argv[c]);
  86.         return vp;
  87.     } else
  88.     if (!letter(c)) {
  89.         vp = &vtemp;
  90.         lastarea = ATEMP;
  91.         vp->flag = (DEFINED|RDONLY);
  92.         vp->type = 0;
  93.         *vp->name = c;
  94.         if (n[1] != '\0')
  95.             return vp;
  96.         vp->flag |= ISSET|INTEGER;
  97.         switch (c) {
  98.           case '$':
  99.             vp->val.i = kshpid;
  100.             break;
  101.           case '!':
  102.             vp->val.i = async;
  103.             break;
  104.           case '?':
  105.             vp->val.i = exstat;
  106.             break;
  107.           case '#':
  108.             vp->val.i = l->argc;
  109.             break;
  110.           case '-':
  111.             vp->flag &= ~ INTEGER;
  112.             vp->val.s = getoptions();
  113.             break;
  114.           default:
  115.             vp->flag &= ~(ISSET|INTEGER);
  116.         }
  117.         return vp;
  118.     }
  119.     for (l = e.loc; l != NULL; l = l->next) {
  120.         vp = tsearch(&l->vars, n, h);
  121.         lastarea = &l->area;
  122.         if (vp != NULL)
  123.             return vp;
  124.         if (l->next == NULL)
  125.             break;
  126.     }
  127.     vp = tenter(&l->vars, n, h);
  128.     vp->flag |= DEFINED;
  129.     if (special(n))
  130.         vp->flag |= SPECIAL;
  131.     return vp;
  132. }
  133.  
  134. /*
  135.  * Search for local variable, if not found create locally.
  136.  */
  137. struct tbl *
  138. local(n)
  139.     register char *n;
  140. {
  141.     register struct block *l = e.loc;
  142.     register struct tbl *vp;
  143.     unsigned h = hash(n);
  144.  
  145.     if (!letter(*n)) {
  146.         vp = &vtemp;
  147.         lastarea = ATEMP;
  148.         vp->flag = (DEFINED|RDONLY);
  149.         vp->type = 0;
  150.         return vp;
  151.     }
  152.     vp = tenter(&l->vars, n, h);
  153.     lastarea = &l->area;
  154.     vp->flag |= DEFINED;
  155.     if (special(n))
  156.         vp->flag |= SPECIAL;
  157.     return vp;
  158. }
  159.  
  160. /* get variable string value */
  161. char *
  162. strval(vp)
  163.     register struct tbl *vp;
  164. {
  165.     register char *s;
  166.     static char strbuf[40];
  167.  
  168.     if ((vp->flag&SPECIAL))
  169.         getspec(vp);
  170.     if (!(vp->flag&ISSET))
  171.         return null;    /* special to dollar() */
  172.     if (!(vp->flag&INTEGER))    /* string source */
  173.         s = vp->val.s + vp->type;
  174.     else {                /* integer source */
  175.         register unsigned long n;
  176.         register int base;
  177.  
  178.         s = strbuf + sizeof(strbuf);
  179.         n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
  180.         base = (vp->type == 0) ? 10 : vp->type;
  181.  
  182.         *--s = '\0';
  183.         do {
  184.             *--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
  185.             n /= base;
  186.         } while (n != 0);
  187.         /* todo: should we output base# ? */
  188.         if (vp->val.i < 0)
  189.             *--s = '-';
  190.     }
  191.     return s;
  192. }
  193.  
  194. /* get variable integer value */
  195. long
  196. intval(vp)
  197.     register struct tbl *vp;
  198. {
  199.     register struct tbl *vq;
  200.  
  201.     if ((vp->flag&SPECIAL))
  202.         getspec(vp);
  203.     if ((vp->flag&INTEGER))
  204.         return vp->val.i;
  205.     vq = &vtemp;
  206.     vq->flag = (INTEGER);
  207.     vq->type = 0;
  208.     if (strint(vq, vp) == NULL)
  209.         errorf("%s: bad number\n", vp->val.s);
  210.     return vq->val.i;
  211. }
  212.  
  213. /* set variable to string value */
  214. void
  215. setstr(vq, s)
  216.     register struct tbl *vq;
  217.     char *s;
  218. {
  219.     if (!(vq->flag&INTEGER)) { /* string dest */
  220.         if ((vq->flag&ALLOC))
  221.             afree((void*)vq->val.s, lastarea);
  222.         vq->flag &= ~ (ISSET|ALLOC);
  223.         vq->type = 0;
  224.         if ((vq->flag&EXPORT))
  225.             export(vq, s);
  226.         else
  227.             vq->val.s = strsave(s, lastarea);
  228.         vq->flag |= ALLOC;
  229.     } else {        /* integer dest */
  230.         register struct tbl *vp = &vtemp;    
  231.         vp->flag = (DEFINED|ISSET);
  232.         vp->type = 0;
  233.         vp->val.s = s;
  234.         if (strint(vq, vp) == NULL)
  235.             errorf("%s: bad number\n", s);
  236.     }
  237.     vq->flag |= ISSET;
  238.     if ((vq->flag&SPECIAL))
  239.         setspec(vq);
  240. }
  241.     
  242. /* convert variable to integer variable */
  243. struct tbl *
  244. strint(vq, vp)
  245.     register struct tbl *vq, *vp;
  246. {
  247.     register char *s = vp->val.s + vp->type;
  248.     register int c;
  249.     int base, neg = 0;
  250.     
  251.     vq->flag |= INTEGER;
  252.     if (!(vp->flag&ISSET) || (s == NULL && !(vp->flag&INTEGER))) {
  253.         vq->flag &= ~ ISSET;
  254.         return NULL;
  255.     }
  256.     if ((vp->flag&INTEGER)) {
  257.         vq->val.i = vp->val.i;
  258.         return vq;
  259.     }
  260.     vq->val.i = 0;
  261.     base = 10;
  262.     for (c = *s++; c ; c = *s++)
  263.         if (c == '-') {
  264.             neg++;
  265.         } else if (c == '#') {
  266.             base = vq->type = vq->val.i;
  267.             vq->val.i = 0;
  268.         } else if (letnum(c)) {
  269.             if ('0' <= c && c <= '9')
  270.                 c -= '0';
  271.             else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
  272.                 c -= 'a'-10;
  273.             else if ('A' <= c && c <= 'Z')
  274.                 c -= 'A'-10;
  275.             if (c < 0 || c >= base) {
  276.                 vq->flag &= ~ ISSET;
  277.                 return NULL;
  278.             }
  279.             vq->val.i = (vq->val.i*base) + c;
  280.         } else
  281.             break;
  282.     if (neg)
  283.         vq->val.i = -vq->val.i;
  284.     if (vq->type < 2 || vq->type > 36)
  285.         vq->type = 0;    /* default base (10) */
  286.     return vq;
  287. }
  288.  
  289. /* set variable to integer */
  290. void
  291. setint(vq, n)
  292.     register struct tbl *vq;
  293.     long n;
  294. {
  295.     if (!(vq->flag&INTEGER)) {
  296.         register struct tbl *vp = &vtemp;
  297.         vp->flag = (ISSET|INTEGER);
  298.         vp->type = 0;
  299.         vp->val.i = n;
  300.         setstr(vq, strval(vp));    /* ? */
  301.     } else
  302.         vq->val.i = n;
  303.     vq->flag |= ISSET;
  304.     if ((vq->flag&SPECIAL))
  305.         setspec(vq);
  306. }
  307.  
  308. /* set variable from enviroment */
  309. import(thing)
  310.     char *thing;
  311. {
  312.     register struct tbl *vp;
  313.     register char *val;
  314.  
  315.     val = strchr(thing, '=');
  316.     if (val == NULL)
  317.         return 0;
  318.     *val = '\0';
  319.     vp = local(thing);
  320.     *val++ = '=';
  321.     vp->flag |= DEFINED|ISSET|EXPORT;
  322.     vp->val.s = thing;
  323.     vp->type = val - thing;
  324.     if ((vp->flag&SPECIAL))
  325.         setspec(vp);
  326.     return 1;
  327. }
  328.  
  329. /*
  330.  * make vp->val.s be "name=value" for quick exporting.
  331.  */
  332. static void
  333. export(vp, val)
  334.     register struct tbl *vp;
  335.     char *val;
  336. {
  337.     register char *cp, *xp;
  338.     char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
  339.  
  340.     xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
  341.     vp->flag |= ALLOC;
  342.     vp->val.s = xp;
  343.     for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
  344.         ;
  345.     *xp++ = '=';
  346.     vp->type = xp - vp->val.s; /* offset to value */
  347.     for (cp = val; (*xp++ = *cp++) != '\0'; )
  348.         ;
  349.     if (op != NULL)
  350.         afree((void*)op, lastarea);
  351. }
  352.  
  353. /*
  354.  * lookup variable (according to (set&LOCAL)),
  355.  * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
  356.  * and optionally set its value if an assignment.
  357.  */
  358. struct tbl *
  359. typeset(var, set, clr)
  360.     register char *var;
  361.     int clr, set;
  362. {
  363.     register struct tbl *vp;
  364.     register char *val;
  365.  
  366.     /* check for valid variable name, search for value */
  367.     val = var;
  368.     if (!letter(*val))
  369.         return NULL;
  370.     for (val++; *val != '\0'; val++)
  371.         if (*val == '=')
  372.             break;
  373.         else if (letnum(*val))
  374.             ;
  375.         else
  376.             return NULL;
  377.     if (*val == '=')
  378.         *val = '\0';
  379.     else
  380.         val = NULL;
  381.     vp = (set&LOCAL) ? local(var) : global(var);
  382.     set &= ~ LOCAL;
  383.     if (val != NULL)
  384.         *val++ = '=';
  385.  
  386.     if (!(vp->flag&ISSET))
  387.         vp->flag = (vp->flag & ~clr) | set;
  388.     else
  389.         if (!(vp->flag&INTEGER) && (set&INTEGER)) {
  390.         /* string to integer */
  391.         vtemp.flag = (ISSET);
  392.         vtemp.type = 0;
  393.         vtemp.val.s = vp->val.s + vp->type;
  394.         if ((vp->flag&ALLOC))
  395.             afree((void*)vp->val.s, lastarea); /* dangerous, used later */
  396.         vp->flag &= ~ ALLOC;
  397.         vp->flag |= INTEGER;
  398.         vp->type = 0;
  399.         if (val == NULL && strint(vp, &vtemp) == NULL) {
  400.             vp->flag &= ~ ISSET;
  401.             errorf("%s: bad number\n", vtemp.val.s);
  402.         }
  403.         } else
  404.         if ((clr&INTEGER) && (vp->flag&INTEGER)) {
  405.         /* integer to string */
  406.         vtemp.val.s = strval(vp);
  407.         vp->flag &= ~ INTEGER;
  408.         setstr(vp, vtemp.val.s);
  409.         }
  410.  
  411.     vp->flag = (vp->flag & ~clr) | set;
  412.  
  413.     if (val != NULL) {
  414.         if ((vp->flag&RDONLY))
  415.             errorf("cannot set readonly %s\n", var);
  416.         if ((vp->flag&INTEGER))
  417.             /* setstr should be able to handle this */
  418.             (void)evaluate(var);
  419.         else
  420.             setstr(vp, val);
  421.     }
  422.  
  423.     if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
  424.         export(vp, (vp->flag&ISSET) ? vp->val.s : null);
  425.  
  426.     return vp;
  427. }
  428.  
  429. void
  430. unset(vp)
  431.     register struct tbl *vp;
  432. {
  433.     if ((vp->flag&ALLOC))
  434.         afree((void*)vp->val.s, lastarea);
  435.     vp->flag &= SPECIAL;    /* Should ``unspecial'' some vars */
  436. }
  437.  
  438. int
  439. isassign(s)
  440.     register char *s;
  441. {
  442.     if (!letter(*s))
  443.         return (0);
  444.     for (s++; *s != '='; s++)
  445.         if (*s == 0 || !letnum(*s))
  446.             return (0);
  447.     return (1);
  448. }
  449.  
  450. /*
  451.  * Make the exported environment from the exported names in the dictionary.
  452.  */
  453. char **
  454. makenv()
  455. {
  456.     struct block *l = e.loc;
  457.     XPtrV env;
  458.     register struct tbl *vp, **vpp;
  459.     register int i;
  460.  
  461.     XPinit(env, 64);
  462.     for (l = e.loc; l != NULL; l = l->next)
  463.         for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
  464.             if ((vp = *vpp++) != NULL
  465.                 && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
  466.                 register struct block *l2;
  467.                 register struct tbl *vp2;
  468.                 unsigned h = hash(vp->name);
  469.  
  470.                 lastarea = &l->area;
  471.  
  472.                 /* unexport any redefined instances */
  473.                 for (l2 = l->next; l2 != NULL; l2 = l2->next) {
  474.                     vp2 = tsearch(&l2->vars, vp->name, h);
  475.                     if (vp2 != NULL)
  476.                         vp2->flag &= ~ EXPORT;
  477.                 }
  478.                 if ((vp->flag&INTEGER)) {
  479.                     /* integer to string */
  480.                     char *val;
  481.                     val = strval(vp);
  482.                     vp->flag &= ~ INTEGER;
  483.                     setstr(vp, val);
  484.                 }
  485.                 XPput(env, vp->val.s);
  486.             }
  487.     XPput(env, NULL);
  488.     return (char **) XPclose(env);
  489. }
  490.  
  491. /*
  492.  * handle special variables with side effects - PATH, SECONDS.
  493.  */
  494. #define STREQ(a, b) ((*a) == (*b) && strcmp((a), (b)) == 0)
  495. static int
  496. special(name)
  497.     register char * name;
  498. {
  499.     if (STREQ("PATH", name))
  500.         return V_PATH;
  501.     if (STREQ("IFS", name))
  502.         return V_IFS;
  503.     if (STREQ("SECONDS", name))
  504.         return V_SECONDS;
  505.     if (STREQ("OPTIND", name))
  506.         return V_OPTIND;
  507.     if (STREQ("MAIL", name))
  508.         return V_MAIL;
  509.     if (STREQ("MAILPATH", name))
  510.         return V_MAILPATH;
  511.     if (STREQ("RANDOM", name))
  512.         return V_RANDOM;
  513. #ifndef EASY_HISTORY
  514.     if (STREQ("HISTSIZE", name))
  515.         return V_HISTSIZE;
  516.     if (STREQ("HISTFILE", name))
  517.         return V_HISTFILE;
  518. #endif
  519.     if (STREQ("FCEDIT", name))
  520.         return V_FCEDIT;
  521.     if (STREQ("COLUMNS", name))
  522.         return V_COLUMNS;
  523.     return V_NONE;
  524. }
  525.  
  526. extern    time_t time();
  527. static    time_t    seconds;        /* time SECONDS last set */
  528. #ifdef NOSTDHDRS
  529. extern    int    rand();
  530. extern    void    srand();
  531. #endif
  532.  
  533. static void
  534. getspec(vp)
  535.     register struct tbl *vp;
  536. {
  537.     switch (special(vp->name)) {
  538.     case V_SECONDS:
  539.         vp->flag &= ~ SPECIAL;
  540.         setint(vp, time((time_t *)0) - seconds);
  541.         vp->flag |= SPECIAL;
  542.         break;
  543.     case V_RANDOM:
  544.         vp->flag &= ~ SPECIAL;
  545.         setint(vp, (rand() & 0x7fff));
  546.         vp->flag |= SPECIAL;
  547.         break;
  548. #ifndef EASY_HISTORY
  549.     case V_HISTSIZE:
  550.         vp->flag &= ~ SPECIAL;
  551.         setint(vp, histsize);
  552.         vp->flag |= SPECIAL;
  553.         break;
  554. #endif
  555.     }
  556. }
  557.  
  558. #ifdef amigaos
  559. /* have to copy stuff lacking real fork () (vfork is a bitch..) */
  560.  
  561. /* assume e already set up for new block, so we use ATEMP for storage */
  562. void
  563. blk_copy (struct block *src)
  564. {
  565.   struct block *l;
  566.   char **tw, **rw;
  567.   static char *empty[] = {""};
  568.  
  569.   /* this is the deepest nested block, also called `globals' */
  570.   if (! src->next)
  571.     {
  572.       /* note: taking &globals yields another address in the child
  573.                than src, since src points to the parents &globals. The
  574.                child has relocated global data, but not malloc space */
  575.  
  576.       l = &globals;
  577.       bzero (l, sizeof (*l));
  578.       e.loc = l;
  579.     }
  580.   else
  581.     {
  582.       blk_copy (src->next);
  583.       l = (struct block*) alloc(sizeof(struct block), ATEMP);
  584.       l->next = e.loc; e.loc = l;
  585.     }
  586.  
  587.   newblock();
  588.  
  589.   l->argc = src->argc;
  590.  
  591.   if (l->argc)
  592.     {
  593.       /* copy the argument vector */
  594.       for (tw = src->argv; *tw++ != NULL; ) ;
  595.       rw = l->argv = (char **) alloc((int)(tw - src->argv) * sizeof(*tw), 
  596.                           & l->area);
  597.       for (tw = src->argv; *tw != NULL; )
  598.          *rw++ = wdcopy(*tw++, & l->area);
  599.       *rw = NULL;
  600.     }
  601.   else
  602.     l->argv = empty;
  603.  
  604.   tbl_copy (& src->vars, & l->vars, & l->area);
  605.   tbl_copy (& src->funs, & l->funs, & l->area);
  606.  
  607.   /* they're not used anyway (ie. always 0), but something like this
  608.      will have to be done when they ARE used. Perhaps it will be ATEMP
  609.      instead of APERM? */
  610.   l->error = src->error ? strsave (src->error, APERM) : 0;
  611.   l->exit  = src->exit ? strsave (src->exit, APERM) : 0;
  612. }
  613.  
  614. #endif
  615. static void
  616. setspec(vp)
  617.     register struct tbl *vp;
  618. {
  619.     extern void    mbset(), mpset();
  620.  
  621.     switch (special(vp->name)) {
  622.       case V_PATH:
  623.         path = strval(vp);
  624.         flushcom(1);    /* clear tracked aliases */
  625.         break;
  626.       case V_IFS:
  627.         setctypes(strval(vp), C_IFS);
  628.         break;
  629.       case V_SECONDS:
  630.         seconds = time((time_t *)0);
  631.         break;
  632.       case V_OPTIND:
  633.         if (intval(vp) == 1)
  634.             resetopts();
  635.         break;
  636.       case V_MAIL:
  637.         mbset(strval(vp));
  638.         break;
  639.       case V_MAILPATH:
  640.         mpset(strval(vp));
  641.         break;
  642.       case V_RANDOM:
  643.         vp->flag &= ~ SPECIAL;
  644.         srand((unsigned int)intval(vp));
  645.         vp->flag |= SPECIAL;
  646.         break;
  647. #ifndef EASY_HISTORY
  648.       case V_HISTSIZE:
  649.         vp->flag &= ~ SPECIAL;
  650.         sethistsize(intval(vp));
  651.         vp->flag |= SPECIAL;
  652.         break;
  653.       case V_HISTFILE:
  654.         sethistfile(strval(vp));
  655.         break;
  656. #endif
  657.       case V_FCEDIT:
  658.         set_editmode(strval(vp));
  659.         break;
  660.       case V_COLUMNS:
  661.         if ((x_cols = intval(vp)) <= 0)
  662.           x_cols=80;
  663.         break;
  664.     }
  665. }
  666.  
  667.