home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 4 / AUCD4.iso / acorn / riscos / riscix / bootstrap_ / GMA-ports / ksh-alpha_ / ksh-alpha.t / ksh-alpha / var.c < prev    next >
C/C++ Source or Header  |  1989-03-11  |  10KB  |  534 lines

  1. static char *RCSid = "$Header: var.c,v 3.1 88/11/03 09:18:22 egisin Exp $";
  2.  
  3. #include <stddef.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <setjmp.h>
  7. #include <time.h>
  8. #include "sh.h"
  9. #include "table.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 getspec(), setspec();
  24. static    void export ARGS((struct tbl *, char *val));
  25. static    int special ARGS ((char *name));
  26.  
  27. /*
  28.  * create a new block for function calls and simple commands
  29.  * assume caller has allocated and set up e.loc
  30.  */
  31. void
  32. newblock()
  33. {
  34.     register struct block *l = e.loc;
  35.     static char *empty[] = {""};
  36.  
  37.     ainit(&l->area);
  38.     l->argc = 0;
  39.     l->argv = empty;
  40.     l->exit = l->error = NULL;
  41.     tinit(&l->vars, &l->area);
  42.     tinit(&l->funs, &l->area);
  43. }
  44.  
  45. /*
  46.  * pop a block handling special variables
  47.  */
  48. void
  49. popblock()
  50. {
  51.     register struct block *l = e.loc;
  52.     register struct tbl *vp, **vpp = l->vars.tbls;
  53.     register int i;
  54.  
  55.     e.loc = l->next;    /* pop block */
  56.     for (i = l->vars.size; --i >= 0; )
  57.         if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
  58.             setspec(global(vp->name));
  59.     afreeall(&l->area);
  60. }
  61.  
  62. /*
  63.  * Search for variable, if not found create globally.
  64.  */
  65. struct tbl *
  66. global(n)
  67.     register char *n;
  68. {
  69.     register struct block *l = e.loc;
  70.     register struct tbl *vp;
  71.     register int c;
  72.     unsigned h = hash(n);
  73.  
  74.     c = n[0];
  75.     if (digit(c)) {
  76.         vp = &vtemp;
  77.         lastarea = ATEMP;
  78.         vp->flag = (DEFINED|RDONLY);
  79.         vp->type = 0;
  80.         *vp->name = c;    /* should strncpy */
  81.         for (c = 0; digit(*n) && c < 1000; n++)
  82.             c = c*10 + *n-'0';
  83.         if (c <= l->argc)
  84.             setstr(vp, l->argv[c]);
  85.         return vp;
  86.     } else
  87.     if (!letter(c)) {
  88.         vp = &vtemp;
  89.         lastarea = ATEMP;
  90.         vp->flag = (DEFINED|RDONLY);
  91.         vp->type = 0;
  92.         *vp->name = c;
  93.         if (n[1] != '\0')
  94.             return vp;
  95.         vp->flag |= ISSET|INTEGER;
  96.         switch (c) {
  97.           case '$':
  98.             vp->val.i = getpid();
  99.             break;
  100.           case '!':
  101.             vp->val.i = async;
  102.             break;
  103.           case '?':
  104.             vp->val.i = exstat;
  105.             break;
  106.           case '#':
  107.             vp->val.i = l->argc;
  108.             break;
  109.           case '-':
  110.             vp->flag &= ~ INTEGER;
  111.             vp->val.s = getoptions();
  112.             break;
  113.           default:
  114.             vp->flag &= ~(ISSET|INTEGER);
  115.         }
  116.         return vp;
  117.     }
  118.     for (l = e.loc; l != NULL; l = l->next) {
  119.         vp = tsearch(&l->vars, n, h);
  120.         lastarea = &l->area;
  121.         if (vp != NULL)
  122.             return vp;
  123.         if (l->next == NULL)
  124.             break;
  125.     }
  126.     vp = tenter(&l->vars, n, h);
  127.     vp->flag |= DEFINED;
  128.     if (special(n))
  129.         vp->flag |= SPECIAL;
  130.     return vp;
  131. }
  132.  
  133. /*
  134.  * Search for local variable, if not found create locally.
  135.  */
  136. struct tbl *
  137. local(n)
  138.     register char *n;
  139. {
  140.     register struct block *l = e.loc;
  141.     register struct tbl *vp;
  142.     unsigned h = hash(n);
  143.  
  144.     if (!letter(*n)) {
  145.         vp = &vtemp;
  146.         lastarea = ATEMP;
  147.         vp->flag = (DEFINED|RDONLY);
  148.         vp->type = 0;
  149.         return vp;
  150.     }
  151.     vp = tenter(&l->vars, n, h);
  152.     lastarea = &l->area;
  153.     vp->flag |= DEFINED;
  154.     if (special(n))
  155.         vp->flag |= SPECIAL;
  156.     return vp;
  157. }
  158.  
  159. /* get variable string value */
  160. char *
  161. strval(vp)
  162.     register struct tbl *vp;
  163. {
  164.     register char *s;
  165.     static char strbuf[40];
  166.  
  167.     if ((vp->flag&SPECIAL))
  168.         getspec(vp);
  169.     if (!(vp->flag&ISSET))
  170.         return null;    /* special to dollar() */
  171.     if (!(vp->flag&INTEGER))    /* string source */
  172.         s = vp->val.s + vp->type;
  173.     else {                /* integer source */
  174.         register unsigned long n;
  175.         register int base;
  176.  
  177.         s = strbuf + sizeof(strbuf);
  178.         n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
  179.         base = (vp->type == 0) ? 10 : vp->type;
  180.  
  181.         *--s = '\0';
  182.         do {
  183.             *--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
  184.             n /= base;
  185.         } while (n != 0);
  186.         /* todo: should we output base# ? */
  187.         if (vp->val.i < 0)
  188.             *--s = '-';
  189.     }
  190.     return s;
  191. }
  192.  
  193. /* get variable integer value */
  194. long
  195. intval(vp)
  196.     register struct tbl *vp;
  197. {
  198.     register struct tbl *vq;
  199.  
  200.     if ((vp->flag&SPECIAL))
  201.         getspec(vp);
  202.     if ((vp->flag&INTEGER))
  203.         return vp->val.i;
  204.     vq = &vtemp;
  205.     vq->flag = (INTEGER);
  206.     vq->type = 0;
  207.     strint(vq, vp);
  208.     return vq->val.i;
  209. }
  210.  
  211. /* set variable to string value */
  212. void
  213. setstr(vq, s)
  214.     register struct tbl *vq;
  215.     char *s;
  216. {
  217.     if (!(vq->flag&INTEGER)) { /* string dest */
  218.         if ((vq->flag&ALLOC))
  219.             afree((Void*)vq->val.s, lastarea);
  220.         vq->flag &= ~ (ISSET|ALLOC);
  221.         vq->type = 0;
  222.         if ((vq->flag&EXPORT))
  223.             export(vq, s);
  224.         else
  225.             vq->val.s = strsave(s, lastarea);
  226.         vq->flag |= ALLOC;
  227.     } else {        /* integer dest */
  228.         register struct tbl *vp = &vtemp;    
  229.         vp->flag = (DEFINED|ISSET);
  230.         vp->type = 0;
  231.         vp->val.s = s;
  232.         strint(vq, vp);
  233.     }
  234.     vq->flag |= ISSET;
  235.     if ((vq->flag&SPECIAL))
  236.         setspec(vq);
  237. }
  238.     
  239. /* convert variable to integer variable */
  240. struct tbl *
  241. strint(vq, vp)
  242.     register struct tbl *vq, *vp;
  243. {
  244.     register char *s = vp->val.s + vp->type;
  245.     register int c;
  246.     int base, neg = 0;
  247.     
  248.     vq->flag |= INTEGER;
  249.     if ((vp->flag&INTEGER)) {
  250.         vq->val.i = vp->val.i;
  251.         return vq;
  252.     }
  253.     vq->val.i = 0;
  254.     base = 10;
  255.     for (c = *s++; c ; c = *s++)
  256.         if (c == '-') {
  257.             neg++;
  258.         } else if (c == '#') {
  259.             base = vq->type = vq->val.i;
  260.             vq->val.i = 0;
  261.         } else if (letnum(c)) {
  262.             if ('0' <= c && c <= '9')
  263.                 c -= '0';
  264.             else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
  265.                 c -= 'a'-10;
  266.             else if ('A' <= c && c <= 'Z')
  267.                 c -= 'A'-10;
  268.             vq->val.i = (vq->val.i*base) + c;
  269.         } else
  270.             break;
  271.     if (neg)
  272.         vq->val.i = -vq->val.i;
  273.     if (vq->type < 2 || vq->type > 36)
  274.         vq->type = 0;    /* default base (10) */
  275.     return vq;
  276. }
  277.  
  278. /* set variable to integer */
  279. void
  280. setint(vq, n)
  281.     register struct tbl *vq;
  282.     long n;
  283. {
  284.     if (!(vq->flag&INTEGER)) {
  285.         register struct tbl *vp = &vtemp;
  286.         vp->flag = (ISSET|INTEGER);
  287.         vp->type = 0;
  288.         vp->val.i = n;
  289.         setstr(vq, strval(vp));    /* ? */
  290.     } else
  291.         vq->val.i = n;
  292.     vq->flag |= ISSET;
  293.     if ((vq->flag&SPECIAL))
  294.         setspec(vq);
  295. }
  296.  
  297. /* set variable from enviroment */
  298. import(thing)
  299.     char *thing;
  300. {
  301.     register struct tbl *vp;
  302.     register char *val;
  303.  
  304.     val = strchr(thing, '=');
  305.     if (val == NULL)
  306.         return 0;
  307.     *val = '\0';
  308.     vp = local(thing);
  309.     *val++ = '=';
  310.     vp->flag |= DEFINED|ISSET|EXPORT;
  311.     vp->val.s = thing;
  312.     vp->type = val - thing;
  313.     if ((vp->flag&SPECIAL))
  314.         setspec(vp);
  315.     return 1;
  316. }
  317.  
  318. /*
  319.  * make vp->val.s be "name=value" for quick exporting.
  320.  */
  321. static void
  322. export(vp, val)
  323.     register struct tbl *vp;
  324.     char *val;
  325. {
  326.     register char *cp, *xp;
  327.     char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
  328.  
  329.     xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
  330.     vp->flag |= ALLOC;
  331.     vp->val.s = xp;
  332.     for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
  333.         ;
  334.     *xp++ = '=';
  335.     vp->type = xp - vp->val.s; /* offset to value */
  336.     for (cp = val; (*xp++ = *cp++) != '\0'; )
  337.         ;
  338.     if (op != NULL)
  339.         afree((Void*)op, lastarea);
  340. }
  341.  
  342. /*
  343.  * lookup variable (according to (set&LOCAL)),
  344.  * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
  345.  * and optionally set its value if an assignment.
  346.  */
  347. struct tbl *
  348. typeset(var, set, clr)
  349.     register char *var;
  350.     int clr, set;
  351. {
  352.     register struct tbl *vp;
  353.     register char *val;
  354.  
  355.     /* check for valid variable name, search for value */
  356.     val = var;
  357.     if (!letter(*val))
  358.         return NULL;
  359.     for (val++; *val != '\0'; val++)
  360.         if (*val == '=')
  361.             break;
  362.         else if (letnum(*val))
  363.             ;
  364.         else
  365.             return NULL;
  366.     if (*val == '=')
  367.         *val = '\0';
  368.     else
  369.         val = NULL;
  370.     vp = (set&LOCAL) ? local(var) : global(var);
  371.     set &= ~ LOCAL;
  372.     if (val != NULL)
  373.         *val++ = '=';
  374.  
  375.     if (!(vp->flag&ISSET))
  376.         vp->flag = vp->flag & ~clr | set;
  377.     else
  378.         if (!(vp->flag&INTEGER) && (set&INTEGER)) {
  379.         /* string to integer */
  380.         vtemp.flag = (ISSET);
  381.         vtemp.type = 0;
  382.         vtemp.val.s = vp->val.s + vp->type;
  383.         if ((vp->flag&ALLOC))
  384.             afree((Void*)vp->val.s, lastarea); /* dangerous, used later */
  385.         vp->flag &= ~ ALLOC;
  386.         vp->flag |= INTEGER;
  387.         vp->type = 0;
  388.         strint(vp, &vtemp);
  389.         } else
  390.         if ((clr&INTEGER) && (vp->flag&INTEGER)) {
  391.         /* integer to string */
  392.         vtemp.val.s = strval(vp);
  393.         vp->flag &= ~ INTEGER;
  394.         setstr(vp, vtemp.val.s);
  395.         }
  396.  
  397.     vp->flag = vp->flag & ~clr | set;
  398.  
  399.     if (val != NULL) {
  400.         if ((vp->flag&RDONLY))
  401.             errorf("cannot set readonly %s\n", var);
  402.         if ((vp->flag&INTEGER))
  403.             /* setstr should be able to handle this */
  404.             (void)evaluate(var);
  405.         else
  406.             setstr(vp, val);
  407.     }
  408.  
  409.     if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
  410.         export(vp, (vp->flag&ISSET) ? vp->val.s : null);
  411.  
  412.     return vp;
  413. }
  414.  
  415. void
  416. unset(vp)
  417.     register struct tbl *vp;
  418. {
  419.     if ((vp->flag&ALLOC))
  420.         afree((Void*)vp->val.s, lastarea);
  421.     vp->flag &= ~ (ALLOC|ISSET);
  422. }
  423.  
  424. int
  425. isassign(s)
  426.     register char *s;
  427. {
  428.     if (!letter(*s))
  429.         return (0);
  430.     for (s++; *s != '='; s++)
  431.         if (*s == 0 || !letnum(*s))
  432.             return (0);
  433.     return (1);
  434. }
  435.  
  436. /*
  437.  * Make the exported environment from the exported names in the dictionary.
  438.  */
  439. char **
  440. makenv()
  441. {
  442.     struct block *l = e.loc;
  443.     XPtrV env;
  444.     register struct tbl *vp, **vpp;
  445.     register int i;
  446.  
  447.     XPinit(env, 64);
  448.     for (l = e.loc; l != NULL; l = l->next)
  449.         for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
  450.             if ((vp = *vpp++) != NULL
  451.                 && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
  452.                 register struct block *l2;
  453.                 register struct tbl *vp2;
  454.                 unsigned h = hash(vp->name);
  455.  
  456.                 lastarea = &l->area;
  457.  
  458.                 /* unexport any redefined instances */
  459.                 for (l2 = l->next; l2 != NULL; l2 = l2->next) {
  460.                     vp2 = tsearch(&l2->vars, vp->name, h);
  461.                     if (vp2 != NULL)
  462.                         vp2->flag &= ~ EXPORT;
  463.                 }
  464.                 if ((vp->flag&INTEGER)) {
  465.                     /* integer to string */
  466.                     char *val;
  467.                     val = strval(vp);
  468.                     vp->flag &= ~ INTEGER;
  469.                     setstr(vp, val);
  470.                 }
  471.                 XPput(env, vp->val.s);
  472.             }
  473.     XPput(env, NULL);
  474.     return (char **) XPclose(env);
  475. }
  476.  
  477. /*
  478.  * handle special variables with side effects - PATH, SECONDS.
  479.  */
  480.  
  481. static int
  482. special(name)
  483.     register char * name;
  484. {
  485.     if (strcmp("PATH", name) == 0)
  486.         return V_PATH;
  487.     if (strcmp("IFS", name) == 0)
  488.         return V_IFS;
  489.     if (strcmp("SECONDS", name) == 0)
  490.         return V_SECONDS;
  491.     if (strcmp("OPTIND", name) == 0)
  492.         return V_OPTIND;
  493.     return V_NONE;
  494. }
  495.  
  496. extern    time_t time();
  497. static    time_t    seconds;        /* time SECONDS last set */
  498.  
  499. static void
  500. getspec(vp)
  501.     register struct tbl *vp;
  502. {
  503.     switch (special(vp->name)) {
  504.     case V_SECONDS:
  505.         vp->flag &= ~ SPECIAL;
  506.         setint(vp, time((time_t *)0) - seconds);
  507.         vp->flag |= SPECIAL;
  508.         break;
  509.     }
  510. }
  511.  
  512. static void
  513. setspec(vp)
  514.     register struct tbl *vp;
  515. {
  516.     switch (special(vp->name)) {
  517.       case V_PATH:
  518.         path = strval(vp);
  519.         flushcom(1);    /* clear tracked aliases */
  520.         break;
  521.       case V_IFS:
  522.         setctypes(strval(vp), C_IFS);
  523.         break;
  524.       case V_SECONDS:
  525.         seconds = time((time_t *)0);
  526.         break;
  527.       case V_OPTIND:
  528.         if (intval(vp) == 1)
  529.             resetopts();
  530.         break;
  531.     }
  532. }
  533.  
  534.