Category : OS/2 Files
Archive   : KSH48.ZIP
Filename : VAR.C

 
Output of file : VAR.C contained in archive : KSH48.ZIP
#ifndef lint
static char *RCSid = "$Id: var.c,v 1.3 1992/08/10 12:03:25 sjg Exp $";
#endif

#include "stdh.h"
#include
#include
#include
#include
#include "sh.h"
#include "expand.h"

/*
* Variables
*
* WARNING: unreadable code, needs a rewrite
*
* if (flag&INTEGER), val.i contains integer value, and type contains base.
* otherwise, (val.s + type) contains string value.
* if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
*/
char null [] = "";
static struct tbl vtemp;
static void export ARGS((struct tbl *vp, char *val));
static int special ARGS((char *name));
static void getspec ARGS((struct tbl *vp));
static void setspec ARGS((struct tbl *vp));

/*
* create a new block for function calls and simple commands
* assume caller has allocated and set up e.loc
*/
void
newblock()
{
register struct block *l = e.loc;
static char *empty[] = {""};

ainit(&l->area);
l->argc = 0;
l->argv = empty;
l->exit = l->error = NULL;
tinit(&l->vars, &l->area);
tinit(&l->funs, &l->area);
}

/*
* pop a block handling special variables
*/
void
popblock()
{
register struct block *l = e.loc;
register struct tbl *vp, **vpp = l->vars.tbls;
register int i;

e.loc = l->next; /* pop block */
for (i = l->vars.size; --i >= 0; )
if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
setspec(global(vp->name));
afreeall(&l->area);
}

/*
* Search for variable, if not found create globally.
*/
struct tbl *
global(n)
register char *n;
{
register struct block *l = e.loc;
register struct tbl *vp;
register int c;
unsigned h = hash(n);

c = n[0];
if (digit(c)) {
vp = &vtemp;
lastarea = ATEMP;
vp->flag = (DEFINED|RDONLY);
vp->type = 0;
*vp->name = c; /* should strncpy */
for (c = 0; digit(*n) && c < 1000; n++)
c = c*10 + *n-'0';
if (c <= l->argc)
setstr(vp, l->argv[c]);
return vp;
} else
if (!letter(c)) {
vp = &vtemp;
lastarea = ATEMP;
vp->flag = (DEFINED|RDONLY);
vp->type = 0;
*vp->name = c;
if (n[1] != '\0')
return vp;
vp->flag |= ISSET|INTEGER;
switch (c) {
case '$':
vp->val.i = kshpid;
break;
case '!':
vp->val.i = async;
break;
case '?':
vp->val.i = exstat;
break;
case '#':
vp->val.i = l->argc;
break;
case '-':
vp->flag &= ~ INTEGER;
vp->val.s = getoptions();
break;
default:
vp->flag &= ~(ISSET|INTEGER);
}
return vp;
}
for (l = e.loc; l != NULL; l = l->next) {
vp = tsearch(&l->vars, n, h);
lastarea = &l->area;
if (vp != NULL)
return vp;
if (l->next == NULL)
break;
}
vp = tenter(&l->vars, n, h);
vp->flag |= DEFINED;
if (special(n))
vp->flag |= SPECIAL;
return vp;
}

/*
* Search for local variable, if not found create locally.
*/
struct tbl *
local(n)
register char *n;
{
register struct block *l = e.loc;
register struct tbl *vp;
unsigned h = hash(n);

if (!letter(*n)) {
vp = &vtemp;
lastarea = ATEMP;
vp->flag = (DEFINED|RDONLY);
vp->type = 0;
return vp;
}
vp = tenter(&l->vars, n, h);
lastarea = &l->area;
vp->flag |= DEFINED;
if (special(n))
vp->flag |= SPECIAL;
return vp;
}

/* get variable string value */
char *
strval(vp)
register struct tbl *vp;
{
register char *s;
static char strbuf[40];

if ((vp->flag&SPECIAL))
getspec(vp);
if (!(vp->flag&ISSET))
return null; /* special to dollar() */
if (!(vp->flag&INTEGER)) /* string source */
s = vp->val.s + vp->type;
else { /* integer source */
register unsigned long n;
register int base;

s = strbuf + sizeof(strbuf);
n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
base = (vp->type == 0) ? 10 : vp->type;

*--s = '\0';
do {
*--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
n /= base;
} while (n != 0);
/* todo: should we output base# ? */
if (vp->val.i < 0)
*--s = '-';
}
return s;
}

/* get variable integer value */
long
intval(vp)
register struct tbl *vp;
{
register struct tbl *vq;

if ((vp->flag&SPECIAL))
getspec(vp);
if ((vp->flag&INTEGER))
return vp->val.i;
vq = &vtemp;
vq->flag = (INTEGER);
vq->type = 0;
if (strint(vq, vp) == NULL)
errorf("%s: bad number\n", vp->val.s);
return vq->val.i;
}

/* set variable to string value */
void
setstr(vq, s)
register struct tbl *vq;
char *s;
{
if (!(vq->flag&INTEGER)) { /* string dest */
if ((vq->flag&ALLOC))
afree((void*)vq->val.s, lastarea);
vq->flag &= ~ (ISSET|ALLOC);
vq->type = 0;
if ((vq->flag&EXPORT))
export(vq, s);
else
vq->val.s = strsave(s, lastarea);
vq->flag |= ALLOC;
} else { /* integer dest */
register struct tbl *vp = &vtemp;
vp->flag = (DEFINED|ISSET);
vp->type = 0;
vp->val.s = s;
if (strint(vq, vp) == NULL)
errorf("%s: bad number\n", s);
}
vq->flag |= ISSET;
if ((vq->flag&SPECIAL))
setspec(vq);
}

/* convert variable to integer variable */
struct tbl *
strint(vq, vp)
register struct tbl *vq, *vp;
{
register char *s = vp->val.s + vp->type;
register int c;
int base, neg = 0;

vq->flag |= INTEGER;
if (!(vp->flag&ISSET) || (s == NULL && !(vp->flag&INTEGER))) {
vq->flag &= ~ ISSET;
return NULL;
}
if ((vp->flag&INTEGER)) {
vq->val.i = vp->val.i;
return vq;
}
vq->val.i = 0;
base = 10;
for (c = *s++; c ; c = *s++)
if (c == '-') {
neg++;
} else if (c == '#') {
base = vq->type = vq->val.i;
vq->val.i = 0;
} else if (letnum(c)) {
if ('0' <= c && c <= '9')
c -= '0';
else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
c -= 'a'-10;
else if ('A' <= c && c <= 'Z')
c -= 'A'-10;
if (c < 0 || c >= base) {
vq->flag &= ~ ISSET;
return NULL;
}
vq->val.i = (vq->val.i*base) + c;
} else
break;
if (neg)
vq->val.i = -vq->val.i;
if (vq->type < 2 || vq->type > 36)
vq->type = 0; /* default base (10) */
return vq;
}

/* set variable to integer */
void
setint(vq, n)
register struct tbl *vq;
long n;
{
if (!(vq->flag&INTEGER)) {
register struct tbl *vp = &vtemp;
vp->flag = (ISSET|INTEGER);
vp->type = 0;
vp->val.i = n;
setstr(vq, strval(vp)); /* ? */
} else
vq->val.i = n;
vq->flag |= ISSET;
if ((vq->flag&SPECIAL))
setspec(vq);
}

/* set variable from enviroment */
import(thing)
char *thing;
{
register struct tbl *vp;
register char *val;

val = strchr(thing, '=');
if (val == NULL)
return 0;
*val = '\0';
vp = local(thing);
*val++ = '=';
vp->flag |= DEFINED|ISSET|EXPORT;
vp->val.s = thing;
vp->type = val - thing;
if ((vp->flag&SPECIAL))
setspec(vp);
return 1;
}

/*
* make vp->val.s be "name=value" for quick exporting.
*/
static void
export(vp, val)
register struct tbl *vp;
char *val;
{
register char *cp, *xp;
char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;

xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
vp->flag |= ALLOC;
vp->val.s = xp;
for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
;
*xp++ = '=';
vp->type = xp - vp->val.s; /* offset to value */
for (cp = val; (*xp++ = *cp++) != '\0'; )
;
if (op != NULL)
afree((void*)op, lastarea);
}

/*
* lookup variable (according to (set&LOCAL)),
* set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
* and optionally set its value if an assignment.
*/
struct tbl *
typeset(var, set, clr)
register char *var;
int clr, set;
{
register struct tbl *vp;
register char *val;

/* check for valid variable name, search for value */
val = var;
if (!letter(*val))
return NULL;
for (val++; *val != '\0'; val++)
if (*val == '=')
break;
else if (letnum(*val))
;
else
return NULL;
if (*val == '=')
*val = '\0';
else
val = NULL;
vp = (set&LOCAL) ? local(var) : global(var);
set &= ~ LOCAL;
if (val != NULL)
*val++ = '=';

if (!(vp->flag&ISSET))
vp->flag = (vp->flag & ~clr) | set;
else
if (!(vp->flag&INTEGER) && (set&INTEGER)) {
/* string to integer */
vtemp.flag = (ISSET);
vtemp.type = 0;
vtemp.val.s = vp->val.s + vp->type;
if ((vp->flag&ALLOC))
afree((void*)vp->val.s, lastarea); /* dangerous, used later */
vp->flag &= ~ ALLOC;
vp->flag |= INTEGER;
vp->type = 0;
if (val == NULL && strint(vp, &vtemp) == NULL) {
vp->flag &= ~ ISSET;
errorf("%s: bad number\n", vtemp.val.s);
}
} else
if ((clr&INTEGER) && (vp->flag&INTEGER)) {
/* integer to string */
vtemp.val.s = strval(vp);
vp->flag &= ~ INTEGER;
setstr(vp, vtemp.val.s);
}

vp->flag = (vp->flag & ~clr) | set;

if (val != NULL) {
if ((vp->flag&RDONLY))
errorf("cannot set readonly %s\n", var);
if ((vp->flag&INTEGER))
/* setstr should be able to handle this */
(void)evaluate(var);
else
setstr(vp, val);
}

if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
export(vp, (vp->flag&ISSET) ? vp->val.s : null);

return vp;
}

void
unset(vp)
register struct tbl *vp;
{
if ((vp->flag&ALLOC))
afree((void*)vp->val.s, lastarea);
vp->flag &= SPECIAL; /* Should ``unspecial'' some vars */
}

int
isassign(s)
register char *s;
{
if (!letter(*s))
return (0);
for (s++; *s != '='; s++)
if (*s == 0 || !letnum(*s))
return (0);
return (1);
}

/*
* Make the exported environment from the exported names in the dictionary.
*/
char **
makenv()
{
struct block *l = e.loc;
XPtrV env;
register struct tbl *vp, **vpp;
register int i;

XPinit(env, 64);
for (l = e.loc; l != NULL; l = l->next)
for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
if ((vp = *vpp++) != NULL
&& (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
register struct block *l2;
register struct tbl *vp2;
unsigned h = hash(vp->name);

lastarea = &l->area;

/* unexport any redefined instances */
for (l2 = l->next; l2 != NULL; l2 = l2->next) {
vp2 = tsearch(&l2->vars, vp->name, h);
if (vp2 != NULL)
vp2->flag &= ~ EXPORT;
}
if ((vp->flag&INTEGER)) {
/* integer to string */
char *val;
val = strval(vp);
vp->flag &= ~ INTEGER;
setstr(vp, val);
}
XPput(env, vp->val.s);
}
XPput(env, NULL);
return (char **) XPclose(env);
}

/*
* handle special variables with side effects - PATH, SECONDS.
*/
#define STREQ(a, b) ((*a) == (*b) && strcmp((a), (b)) == 0)
static int
special(name)
register char * name;
{
if (STREQ("PATH", name))
return V_PATH;
if (STREQ("IFS", name))
return V_IFS;
if (STREQ("SECONDS", name))
return V_SECONDS;
if (STREQ("OPTIND", name))
return V_OPTIND;
if (STREQ("MAIL", name))
return V_MAIL;
if (STREQ("MAILPATH", name))
return V_MAILPATH;
if (STREQ("RANDOM", name))
return V_RANDOM;
#ifndef EASY_HISTORY
if (STREQ("HISTSIZE", name))
return V_HISTSIZE;
if (STREQ("HISTFILE", name))
return V_HISTFILE;
#endif
if (STREQ("FCEDIT", name))
return V_FCEDIT;
if (STREQ("COLUMNS", name))
return V_COLUMNS;
return V_NONE;
}

extern time_t time();
static time_t seconds; /* time SECONDS last set */
#ifdef NOSTDHDRS
extern int rand();
extern void srand();
#endif

static void
getspec(vp)
register struct tbl *vp;
{
switch (special(vp->name)) {
case V_SECONDS:
vp->flag &= ~ SPECIAL;
setint(vp, time((time_t *)0) - seconds);
vp->flag |= SPECIAL;
break;
case V_RANDOM:
vp->flag &= ~ SPECIAL;
setint(vp, (rand() & 0x7fff));
vp->flag |= SPECIAL;
break;
#ifndef EASY_HISTORY
case V_HISTSIZE:
vp->flag &= ~ SPECIAL;
setint(vp, histsize);
vp->flag |= SPECIAL;
break;
#endif
}
}

static void
setspec(vp)
register struct tbl *vp;
{
extern void mbset(), mpset();

switch (special(vp->name)) {
case V_PATH:
path = strval(vp);
flushcom(1); /* clear tracked aliases */
break;
case V_IFS:
setctypes(strval(vp), C_IFS);
break;
case V_SECONDS:
seconds = time((time_t *)0);
break;
case V_OPTIND:
if (intval(vp) == 1)
resetopts();
break;
case V_MAIL:
mbset(strval(vp));
break;
case V_MAILPATH:
mpset(strval(vp));
break;
case V_RANDOM:
vp->flag &= ~ SPECIAL;
srand((unsigned int)intval(vp));
vp->flag |= SPECIAL;
break;
#ifndef EASY_HISTORY
case V_HISTSIZE:
vp->flag &= ~ SPECIAL;
sethistsize(intval(vp));
vp->flag |= SPECIAL;
break;
case V_HISTFILE:
sethistfile(strval(vp));
break;
#endif
case V_FCEDIT:
set_editmode(strval(vp));
break;
case V_COLUMNS:
if ((x_cols = intval(vp)) <= 0)
x_cols=80;
break;
}
}



  3 Responses to “Category : OS/2 Files
Archive   : KSH48.ZIP
Filename : VAR.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/