home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / k / ksh48.zip / sh / var.c < prev    next >
C/C++ Source or Header  |  1992-08-25  |  13KB  |  611 lines

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