home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / pdksh-src.lha / src / amiga / pdksh / sh / var.c < prev    next >
C/C++ Source or Header  |  1993-12-01  |  13KB  |  633 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: var.c,v 1.2 1992/04/25 08:33:28 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.  
  495. static int
  496. special(name)
  497.     register char * name;
  498. {
  499.     if (strcmp("PATH", name) == 0)
  500.         return V_PATH;
  501.     if (strcmp("IFS", name) == 0)
  502.         return V_IFS;
  503.     if (strcmp("SECONDS", name) == 0)
  504.         return V_SECONDS;
  505.     if (strcmp("OPTIND", name) == 0)
  506.         return V_OPTIND;
  507.     if (strcmp("MAIL", name) == 0)
  508.         return V_MAIL;
  509.     if (strcmp("MAILPATH", name) == 0)
  510.         return V_MAILPATH;
  511.     if (strcmp("RANDOM", name) == 0)
  512.         return V_RANDOM;
  513.     return V_NONE;
  514. }
  515.  
  516. extern    time_t time();
  517. static    time_t    seconds;        /* time SECONDS last set */
  518. #ifdef NOSTDHDRS
  519. extern    int    rand();
  520. extern    void    srand();
  521. #endif
  522.  
  523. static void
  524. getspec(vp)
  525.     register struct tbl *vp;
  526. {
  527.     switch (special(vp->name)) {
  528.     case V_SECONDS:
  529.         vp->flag &= ~ SPECIAL;
  530.         setint(vp, time((time_t *)0) - seconds);
  531.         vp->flag |= SPECIAL;
  532.         break;
  533.     case V_RANDOM:
  534.         vp->flag &= ~ SPECIAL;
  535.         setint(vp, (rand() & 0x7fff));
  536.         vp->flag |= SPECIAL;
  537.         break;
  538.     }
  539. }
  540.  
  541. static void
  542. setspec(vp)
  543.     register struct tbl *vp;
  544. {
  545.     extern void    mbset(), mpset();
  546.  
  547.     switch (special(vp->name)) {
  548.       case V_PATH:
  549.         path = strval(vp);
  550.         flushcom(1);    /* clear tracked aliases */
  551.         break;
  552.       case V_IFS:
  553.         setctypes(strval(vp), C_IFS);
  554.         break;
  555.       case V_SECONDS:
  556.         seconds = time((time_t *)0);
  557.         break;
  558.       case V_OPTIND:
  559.         if (intval(vp) == 1)
  560.             resetopts();
  561.         break;
  562.       case V_MAIL:
  563.         mbset(strval(vp));
  564.         break;
  565.       case V_MAILPATH:
  566.         mpset(strval(vp));
  567.         break;
  568.       case V_RANDOM:
  569.         vp->flag &= ~ SPECIAL;
  570.         srand((unsigned int)intval(vp));
  571.         vp->flag |= SPECIAL;
  572.         break;
  573.     }
  574. }
  575.  
  576. #ifdef amigados
  577. /* have to copy stuff lacking real fork () (vfork is a bitch..) */
  578.  
  579. /* assume e already set up for new block, so we use ATEMP for storage */
  580. void
  581. blk_copy (struct block *src)
  582. {
  583.   struct block *l;
  584.   char **tw, **rw;
  585.   static char *empty[] = {""};
  586.  
  587.   /* this is the deepest nested block, also called `globals' */
  588.   if (! src->next)
  589.     {
  590.       /* note: taking &globals yields another address in the child
  591.                than src, since src points to the parents &globals. The
  592.                child has relocated global data, but not malloc space */
  593.  
  594.       l = &globals;
  595.       bzero (l, sizeof (*l));
  596.       e.loc = l;
  597.     }
  598.   else
  599.     {
  600.       blk_copy (src->next);
  601.       l = (struct block*) alloc(sizeof(struct block), ATEMP);
  602.       l->next = e.loc; e.loc = l;
  603.     }
  604.  
  605.   newblock();
  606.  
  607.   l->argc = src->argc;
  608.  
  609.   if (l->argc)
  610.     {
  611.       /* copy the argument vector */
  612.       for (tw = src->argv; *tw++ != NULL; ) ;
  613.       rw = l->argv = (char **) alloc((int)(tw - src->argv) * sizeof(*tw), 
  614.                           & l->area);
  615.       for (tw = src->argv; *tw != NULL; )
  616.          *rw++ = wdcopy(*tw++, & l->area);
  617.       *rw = NULL;
  618.     }
  619.   else
  620.     l->argv = empty;
  621.  
  622.   tbl_copy (& src->vars, & l->vars, & l->area);
  623.   tbl_copy (& src->funs, & l->funs, & l->area);
  624.  
  625.   /* they're not used anyway (ie. always 0), but something like this
  626.      will have to be done when they ARE used. Perhaps it will be ATEMP
  627.      instead of APERM? */
  628.   l->error = src->error ? strsave (src->error, APERM) : 0;
  629.   l->exit  = src->exit ? strsave (src->exit, APERM) : 0;
  630. }
  631.  
  632. #endif
  633.