Yet Another Shell (part 11 of 11)

Dave Clemans dclemans.falcon at mntgfx.mentor.com
Thu Mar 16 08:42:56 AEST 1989


With all the talk about shells that has been going on recently...

Here's an early pre-release of a "Korn"-like shell for anyone
who might want to experiment.  It is definitely NOT complete,
but it starting to be usable.  It does use some GNU code (for
expression evaluation), so it presumably comes under their
"copyleft".

It basically runs on BSD/USG Unix systems, and on the Atari ST.
I'm currently working on a port to the Amiga.  It is NOT yet
bug free; I am VERY interested in fixes; enhancements, etc.

dgc

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 11 (of 11)."
# Contents:  var.c
# Wrapped by dclemans at dclemans on Wed Mar 15 14:04:02 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'var.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'var.c'\"
else
echo shar: Extracting \"'var.c'\" \(50361 characters\)
sed "s/^X//" >'var.c' <<'END_OF_FILE'
X/*
X * Command Input Shell
X * Dave Clemans
X * 12/88-1/89
X *
X * "spiritually" based on Bourne, Korn shells
X *
X * Handle shell variables
X *
X * $Id: var.c,v 1.12 89/03/07 19:35:06 dclemans Exp $
X *
X * $Log:	var.c,v $
X * Revision 1.12  89/03/07  19:35:06  dclemans
X * fix typo in GEMDOS code
X * 
X * Revision 1.11  89/03/07  19:05:53  dclemans
X * portability fixes
X * 
X * Revision 1.10  89/02/25  17:40:24  dclemans
X * miscellaneous bug fixes/speedups
X * 
X * Revision 1.9  89/02/22  21:32:07  dclemans
X * Implement simple background job monitoring facility
X * 
X * Revision 1.8  89/02/22  13:18:53  dclemans
X * Implement $!
X * 
X * Revision 1.7  89/02/22  08:17:18  dclemans
X * implement left-justified, right-justified, etc. parameter attributes
X * 
X * Revision 1.6  89/02/21  21:47:22  dclemans
X * Fix bugs in % and %% variable expansions
X * 
X * Revision 1.5  89/02/21  19:40:13  dclemans
X * Implement RANDOM and SECONDS variables
X * 
X * Revision 1.4  89/02/20  20:07:19  dclemans
X * Add RCS identifiers
X * 
X */
X#include <stdio.h>
X#include "shell.h"
X#include <time.h>
Xextern unsigned long time();
X#ifdef  LINED
X#include "reader\history.h"
X#endif  /* LINED */
X#ifdef  GEMDOS
X#include <basepage.h>
X#endif  /* GEMDOS */
X
X/*
X * Positional arguments
X */
Xchar    *var_arg0;
Xint     var_argc;
Xchar    **var_argv;
X
X/*
X * Initial values of variables
X */
Xchar    *var_init[] =
X{
X    "PS1",      "$ ",
X    "PS2",      "> ",
X    "PS3",      "#? ",
X    "PS4",      "+ ",
X    "IFS",      " \t",
X#ifdef  GEMDOS
X    "PATH",     ",c:\\bin",
X    "SUFF",     ".ttp,.tos,.prg,.app,,.sh",
X    "TMPDIR",   "",
X    "COLUMNS",  "80",
X    "LINES",    "24",
X#else
X    "PATH",     ":/bin:/usr/bin",
X#endif  /* GEMDOS */
X    (char *)NULL,   (char *)NULL
X};
X
X/*
X * Set up "reserved"/special handling variables
X */
X#define VAR_CDPATH      0
X#define VAR_COLUMNS     1
X#define VAR_ENV         2
X#define VAR_HISTSIZE    3
X#define VAR_HOME        4
X#define VAR_IFS         5
X#define VAR_LINES       6
X#define VAR_PATH        7
X#define VAR_PS1         8
X#define VAR_PS2         9
X#define VAR_PS3         10
X#define VAR_PS4         11
X#define VAR_PWD         12
X#define VAR_SHELL       13
X#ifdef  GEMDOS
X#define VAR_SUFF        14
X#define VAR_TMPDIR      15
X#endif  /* GEMDOS */
Xstruct {
X    char    *name;
X    int     flag;
X} reserved_names[] =
X{   /* keep this list sorted... */
X    { "CDPATH",     VAR_CDPATH },
X    { "COLUMNS",    VAR_COLUMNS },
X    { "ENV",        VAR_ENV },
X    { "HISTSIZE",   VAR_HISTSIZE },
X    { "HOME",       VAR_HOME },
X    { "IFS",        VAR_IFS },
X    { "LINES",      VAR_LINES },
X    { "PATH",       VAR_PATH },
X    { "PS1",        VAR_PS1 },
X    { "PS2",        VAR_PS2 },
X    { "PS3",        VAR_PS3 },
X    { "PS4",        VAR_PS4 },
X    { "PWD",        VAR_PWD },
X    { "SHELL",      VAR_SHELL },
X#ifdef  GEMDOS
X    { "SUFF",       VAR_SUFF },
X    { "TMPDIR",     VAR_TMPDIR },
X#endif  /* GEMDOS */
X    { (char *)NULL, -1 }
X};  /* end of reserved_names */
X
Xint var_namecmp(n1,n2)
Xchar *n1;
Xchar *n2;
X{
X    int i1,i2,rc;
X    char *p1,*p2;
X    register char *p,*q;
X    char buffer[BUFSIZ];
X
X    p = strchr(n1,'[');
X    if (p == (char *)NULL)
X        q = p;
X    else q = strrchr(n1,']');
X    if (p == (char *)NULL || q == (char *)NULL)
X    {   /* not an indexed variable? */
X        p1 = n1;
X        i1 = 0;
X    }
X    else
X    {   /* indexed variable */
X        strncpy(buffer,&p[1],(int)(q-p)-1);
X        buffer[(int)(q-p)-1] = '\0';
X        i1 = parse_c_expression(buffer,0);
X        strncpy(buffer,n1,(int)(p-n1));
X        p1 = strcopy(buffer);
X    }
X    p = strchr(n2,'[');
X    if (p == (char *)NULL)
X        q = p;
X    else q = strrchr(n2,']');
X    if (p == (char *)NULL || q == (char *)NULL)
X    {   /* not an indexed variable? */
X        p2 = n2;
X        i2 = 0;
X    }
X    else
X    {   /* indexed variable */
X        strncpy(buffer,&p[1],(int)(q-p)-1);
X        buffer[(int)(q-p)-1] = '\0';
X        i2 = parse_c_expression(buffer,0);
X        strncpy(buffer,n2,(int)(p-n2));
X        p2 = strcopy(buffer);
X    }
X    rc = strcmp(p1,p2);
X    if (p1 != n1)
X        free(p1);
X    if (p2 != n2)
X        free(p2);
X    if (rc != 0)
X        return rc;
X    if (i1 < i2)
X        return -1;
X    if (i1 > i2)
X        return 1;
X    return 0;
X}   /* end of var_namecmp */
X
Xchar *var_subeval(name,side_effects)
Xregister char *name;
Xint side_effects;
X{
X    int temp;
X    register char *p,*q;
X    char buffer[BUFSIZ];
X
X    p = strchr(name,'[');
X    if (p == (char *)NULL)
X        return (char *)NULL;
X    q = strrchr(name,']');
X    if (q == (char *)NULL)
X        return (char *)NULL;
X    strncpy(buffer,&p[1],(int)(q-p)-1);
X    buffer[(int)(q-p)-1] = '\0';
X    temp = 1;
X    for (q = buffer; *q; q++)
X        if (!isdigit(*q))
X            temp = 0;
X    if (temp)
X    {   /* if doesn't really need evaluation */
X        return (char *)NULL;
X    }
X    temp = parse_c_expression(buffer,side_effects);
X    strncpy(buffer,name,(int)(p-name));
X    sprintf(&buffer[(int)(p-name)],"[%d]",temp);
X    return strcopy(buffer);
X}   /* end of var_subeval */
X
Xstatic void dump_var(vp,flag)
Xregister struct variable *vp;
Xint flag;
X{
X    long temp;
X    char buffer[32];
X#ifndef GEMDOS
X#ifndef USG
X    extern long random();
X#else
X#endif  /* USG */
X#endif  /* GEMDOS */
X
X    io_writestring(0,vp->name);
X    if (flag)
X    {   /* also write out value */
X        io_writestring(0,"=");
X        if (vp->type & TYPE_FUNCTION)
X        {   /* a "special" variable? */
X            if (strcmp(vp->name,"RANDOM") == 0)
X            {   /* return a random number */
X#ifndef GEMDOS
X#ifndef USG
X                temp = random();
X#else
X                temp = rand();
X#endif  /* USG */
X#else
X                temp = Random();
X#endif  /* GEMDOS */
X                sprintf(buffer,"%ld",temp);
X                io_writestring(0,buffer);
X            }
X            else if (strcmp(vp->name,"SECONDS") == 0)
X            {   /* how long have we been running? */
X                temp = time(0L);
X                sprintf(buffer,"%ld",temp-base_env.start_at);
X                io_writestring(0,buffer);
X            }
X        }
X        else io_writestring(0,vp->value);
X    }
X    io_writestring(0,"\n");
X}   /* end of dump_var */
X
Xstatic void var_reserved(vp)
Xregister struct variable *vp;
X{
X    register int i;
X    int temp1,temp2;
X    register struct hist_phrase *nh;
X
X    for (i = 0; reserved_names[i].name != (char *)NULL; i++)
X    {   /* a variable with special handling when set? */
X        temp1 = strcmp(vp->name,reserved_names[i].name);
X        if (temp1 > 0)
X            continue;
X        if (temp1 < 0)
X            return;
X        switch (reserved_names[i].flag)
X        {   /* found a variable that needs special handling; go do it */
X            case VAR_CDPATH:
X                base_env.cd_path = vp->value;
X                break;
X            case VAR_COLUMNS:
X                base_env.columns = atoi(vp->value)-1;   /* last usable column */
X                break;
X            case VAR_ENV:
X                base_env.envfile = vp->value;
X                break;
X            case VAR_HISTSIZE:
X                temp1 = atoi(vp->value);
X                if (temp1 <= 0)
X                {   /* completely kill old list */
X                    if (base_env.history_size > 0)
X                    {   /* need to free old stuff? */
X                        for (temp2 = 0; temp2 < base_env.history_size; temp2++)
X                            if (base_env.history_list[temp2].cmd != (struct phrase *)NULL)
X                                phrase_free(base_env.history_list[temp2].cmd);
X                        free(base_env.history_list);
X                        base_env.history_list = (struct hist_phrase *)NULL;
X                        base_env.history_size = 0;
X                    }
X#ifdef  LINED
X                    History.maxSize = 1;
X#endif  /* LINED */
X                    return;
X                }
X                nh = (struct hist_phrase *)malloc(sizeof(struct hist_phrase)*temp1);
X                if (nh == (struct hist_phrase *)NULL)
X                {   /* out of memory? */
X                    errmsg(SHERR_NOMEM,LOC("var_reserved"));
X                    return;
X                }
X                for (temp2 = 0; temp2 < temp1; temp2++)
X                {   /* make sure it starts out empty */
X                    nh[temp2].cmd = (struct phrase *)NULL;
X                    nh[temp2].number = -1;
X                }
X                for (temp2 = 0; temp2 < ((temp1<base_env.history_size)?temp1:base_env.history_size); temp2++)
X                {   /* copy in old stuff */
X                    nh[temp2].cmd = base_env.history_list[temp2].cmd;
X                    nh[temp2].number = base_env.history_list[temp2].number;
X                }
X                for (; temp2 < base_env.history_size; temp2++)
X                    if (base_env.history_list[temp2].cmd != (struct phrase *)NULL)
X                        phrase_free(base_env.history_list[temp2].cmd);
X                if (base_env.history_size > 0)
X                    free(base_env.history_list);
X                base_env.history_size = temp1;
X#ifdef  LINED
X                History.maxSize = temp1;
X#endif  /* LINED */
X                base_env.history_list = nh;
X                        break;
X            case VAR_HOME:
X                base_env.homedir = vp->value;
X                break;
X            case VAR_IFS:
X                base_env.separators = vp->value;
X                break;
X            case VAR_LINES:
X                base_env.lines = atoi(vp->value);
X                break;
X            case VAR_PS1:
X                base_env.prompts[0] = vp->value;
X                break;
X            case VAR_PS2:
X                base_env.prompts[1] = vp->value;
X                break;
X            case VAR_PS3:
X                base_env.prompts[2] = vp->value;
X                break;
X            case VAR_PS4:
X                base_env.prompts[3] = vp->value;
X                break;
X            case VAR_PATH:
X                base_env.exec_path = vp->value;
X                break;
X            case VAR_PWD:
X                if (base_env.dir->current != (char *)NULL)
X                    free(base_env.dir->current);
X                base_env.dir->current = strcopy(vp->value);
X                break;
X            case VAR_SHELL:
X                base_env.shellname = strcopy(vp->value);
X                break;
X#ifdef  GEMDOS
X            case VAR_SUFF:
X                base_env.exec_suff = vp->value;
X                break;
X            case VAR_TMPDIR:
X                base_env.tmpdir = vp->value;
X                break;
X#endif  /* GEMDOS */
X        }
X        break;
X    }
X}   /* end of var_reserved */
X
Xvoid var_setarg0(arg)
Xchar *arg;
X{
X    if (arg == (char *)NULL || strlen(arg) == 0)
X        var_arg0 = "shell";
X    else var_arg0 = arg;
X    var_define0("SHELL",var_arg0,0);
X}   /* end of var_setarg0 */
X
Xvoid var_setargs(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    register int i;
X
X    var_argc = argc;
X    var_argv = new_argv(var_argc+1);
X    if (var_argv == (char **)NULL)
X    {   /* enough memory */
X        errmsg(SHERR_NOMEM,LOC("var_setargs"));
X        var_argc = 0;
X        return;
X    }
X    var_argv[0] = var_arg0;
X    for (i = 1; i < var_argc; i++)
X    {   /* now set up the args */
X        var_argv[i] = strcopy(argv[i]);
X    }
X    var_argv[i] = (char *)NULL;
X}   /* end of var_setargs */
X
Xvoid var_resetargs(tp)
Xstruct token *tp;
X{
X    register int i;
X    register struct token *tpp;
X
X    if (var_argc > 0)
X    {   /* free old args */
X        for (i = 1; i < var_argc; i++)
X            if (var_argv[i] != (char *)NULL)
X                free(var_argv[i]);
X        free(var_argv);
X    }
X    var_argc = 0;
X    for (tpp = tp; tpp != (struct token *)NULL; tpp = tpp->next)
X        var_argc++;
X    var_argv = new_argv(var_argc+2);
X    if (var_argv == (char **)NULL)
X    {   /* enough memory */
X        errmsg(SHERR_NOMEM,LOC("var_resetargs"));
X        var_argc = 0;
X        return;
X    }
X    var_argv[0] = var_arg0;
X    tpp = tp;
X    for (i = 0; i < var_argc; i++)
X    {   /* now set up the args */
X        var_argv[i+1] = strcopy(tpp->name);
X        tpp = tpp->next;
X    }
X    var_argv[i+1] = (char *)NULL;
X    var_argc++;
X}   /* end of var_resetargs */
X
Xvoid var_shiftargs(count)
Xint count;
X{
X    register int i,j;
X
X    if (var_argv[1] != (char *)NULL)
X        free(var_argv[1]);
X    for (i = 0; i < count; i++)
X    {   /* shift the required number of arguments */
X        for (j = 1; j < var_argc; j++)
X            var_argv[j] = var_argv[j+1];
X        var_argc--;
X    }
X}   /* end of var_shiftargs */
X
Xstatic void unpad(s)
Xregister char *s;
X{
X    register char *p;
X
X    while (*s == ' ')
X        strcpy(s,&s[1]);
X    for (p = s; *p; p++)
X        /* do nothing */;
X    p--;
X    while (p > s && *p == ' ')
X        *p-- = '\0';
X}   /* end of unpad */
X
Xstatic void var_fixtype(vp,side_effects)
Xregister struct variable *vp;
Xint side_effects;
X{
X    register char *p;
X    register int temp;
X    char buffer[16];
X    char *value;
X
X    if (vp->value == (char *)NULL)
X        return;
X    if (vp->type & TYPE_INTEGER)
X    {   /* if need to eval value */
X        temp = 1;
X        for (p = vp->value; *p; p++)
X            if (!isdigit(*p))
X                temp = 0;
X        if (!temp)
X        {   /* if need to eval an expression */
X            temp = parse_c_expression(vp->value,side_effects);
X            sprintf(buffer,"%d",temp);
X            free(vp->value);
X            vp->value = strcopy(buffer);
X        }
X    }
X    if (vp->type & TYPE_UPPERCASE)
X    {   /* if should be upcased... */
X        for (p = vp->value; *p; p++)
X            if (islower(*p))
X                *p = _toupper(*p);
X    }
X    if (vp->type & TYPE_LOWERCASE)
X    {   /* if should be lowercased... */
X        for (p = vp->value; *p; p++)
X            if (isupper(*p))
X                *p = _tolower(*p);
X    }
X    if (vp->type & TYPE_LEFTJUST)
X    {   /* left justify the value */
X        unpad(vp->value);
X        if (vp->type & TYPE_ZEROS)
X        {   /* eliminate any initial zeros */
X            while (vp->value[0] == '0')
X                strcpy(vp->value,&vp->value[1]);
X        }
X        value = new_string(vp->misc+1);
X        if (value == (char *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("var_fixtype"));
X            return;
X        }
X        sprintf(buffer,"%%-%ds",vp->misc);
X        sprintf(value,buffer,vp->value);
X        free(vp->value);
X        vp->value = value;
X    }
X    if (vp->type & TYPE_RIGHTJUST)
X    {   /* right justify the value */
X        unpad(vp->value);
X        value = new_string(vp->misc+1);
X        if (value == (char *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("var_fixtype"));
X            return;
X        }
X        if (vp->type & TYPE_ZEROS)
X            sprintf(buffer,"%%0%ds",vp->misc);
X        else sprintf(buffer,"%%%ds",vp->misc);
X        sprintf(value,buffer,vp->value);
X        free(vp->value);
X        vp->value = value;
X    }
X    if (vp->type & TYPE_HOSTMAP)
X    {   /* make into good filename */
X        /* a start... */
X#ifdef  GEMDOS
X        for (p = vp->value; *p; p++)
X        {   /* check each char... */
X            if (*p == '/')
X                *p = '\\';
X            if (isupper(*p))
X                *p = _tolower(*p);
X        }
X#else
X        for (p = vp->value; *p; p++)
X            if (*p == '\\')
X                *p = '/';
X#endif  /* GEMDOS */
X    }
X}   /* end of var_fixtype */
X
Xstatic void var_setvalue(svp,value)
Xregister struct variable *svp;
Xregister char *value;
X{
X    if (svp->type & TYPE_READONLY)
X    {   /* can value be changed? */
X        errmsg(0,LOC("var_define0"),"value of '%s' is readonly",svp->name);
X        return;
X    }
X    if (svp->type == TYPE_DELETED)
X        svp->type = 0;
X    if (svp->value != (char *)NULL)
X        free(svp->value);
X    svp->value = strcopy(value);
X    var_fixtype(svp,1);
X    var_reserved(svp);
X    svp->cmd = cmd_count;
X    if (flag_allexport)
X        svp->type |= TYPE_EXPORTED;
X}   /* end of var_setvalue */
X
Xvoid var_define0(name,value,create)
Xchar *name;
Xchar *value;
Xint create;
X{
X    int rc;
X    char *xname,*ptr;
X    register struct variable *vp,*svp;
X    struct varstack *vs;
X
X    if (strlen(name) == 1 && (strchr("*@$!?-#",*name) != (char *)NULL || isdigit(*name)))
X    {   /* can't do this directly */
X        errmsg(0,LOC("var_define0"),"illegal assignment: '%s'",name);
X        return;
X    }
X
X    vp = new_variable();
X    if (vp == (struct variable *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("var_define0"));
X        return;
X    }
X
X    xname = var_subeval(name,1);
X    if (xname == (char *)NULL)
X        ptr = name;
X    else ptr = xname;
X    vs = base_env.var;
X
X    if (!create)
X    {   /* if to use existing created slot if possible */
X        for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X        {   /* for each variable table */
X            for (svp = vs->table; svp != (struct variable *)NULL; )
X            {   /* look for where to get the variable */
X                rc = var_namecmp(ptr,svp->name);
X                if (rc == 0)
X                {   /* found the variable */
X                    if (svp->type == TYPE_DELETED)
X                        svp = (struct variable *)NULL;
X                    break;
X                }
X                else if (rc < 0)
X                {   /* go down the left side? */
X                    svp = svp->left;
X                }
X                else
X                {   /* go down right side */
X                    svp = svp->right;
X                }
X            }
X            if (svp != (struct variable *)NULL)
X                break;
X        }
X        if (svp != (struct variable *)NULL)
X        {   /* if found "correct" place for variable */
X            free(vp);
X            var_setvalue(svp,value);
X            if (xname != (char *)NULL)
X                free(xname);
X            return;
X        }
X        for (vs = base_env.var; vs->next != (struct varstack *)NULL; vs = vs->next)
X            /* do nothing */;
X    }
X
X    for (svp = vs->table; svp != (struct variable *)NULL; )
X    {   /* look for where to put the variable */
X        rc = var_namecmp(ptr,svp->name);
X        if (rc == 0)
X        {   /* replace existing value */
X            free(vp);
X            var_setvalue(svp,value);
X            if (xname != (char *)NULL)
X                free(xname);
X            return;
X        }
X        else if (rc < 0)
X        {   /* go down the left side? */
X            if (svp->left == (struct variable *)NULL)
X                break;
X            svp = svp->left;
X        }
X        else
X        {   /* go down right side */
X            if (svp->right == (struct variable *)NULL)
X                break;
X            svp = svp->right;
X        }
X    }
X    vp->name = strcopy(ptr);
X    if (base_env.var->table == (struct variable *)NULL)
X        base_env.var->table = vp;
X    else if (rc < 0)
X        svp->left = vp;
X    else
X        svp->right = vp;
X    var_setvalue(vp,value);
X    if (xname != (char *)NULL)
X        free(xname);
X}   /* end of var_define0 */
X
Xvoid var_define(word,type,create)
Xchar *word;
Xint type;
Xint create;
X{
X    register char *p,*ptr;
X    register struct variable *svp;
X    int result,rc;
X    char buffer[16];
X    struct varstack *vs;
X    char *xname;
X
X    result = 0;
X    for (p = word; result != 0 || *p != '='; p++)
X    {   /* find end of name */
X        if (*p == '[')
X            result++;
X        else if (*p == ']')
X            result--;
X    }
X    /* ASSERT that *p == '=' */
X    *p++ = '\0';
X    xname = var_subeval(word,1);
X    if (xname == (char *)NULL)
X        ptr = word;
X    else ptr = xname;
X
X    svp = (struct variable *)NULL;
X    for (vs = base_env.var; !create && vs != (struct varstack *)NULL; vs = vs->next)
X    {   /* for each variable table */
X        for (svp = vs->table; svp != (struct variable *)NULL; )
X        {   /* look for where to get the variable */
X            rc = var_namecmp(ptr,svp->name);
X            if (rc == 0)
X            {   /* found the variable */
X                if (svp->type == TYPE_DELETED)
X                    svp = (struct variable *)NULL;
X                break;
X            }
X            else if (rc < 0)
X            {   /* go down the left side? */
X                svp = svp->left;
X            }
X            else
X            {   /* go down right side */
X                svp = svp->right;
X            }
X        }
X        if (svp != (struct variable *)NULL)
X            break;
X    }
X    if (svp != (struct variable *)NULL)
X    {   /* known spot for variable */
X        if (svp->type & TYPE_INTEGER)
X        {   /* an integer type? */
X            sprintf(buffer,"%d",parse_c_expression(p,1));
X            var_setvalue(svp,buffer);
X        }
X        else
X        {   /* normal strategy */
X            var_setvalue(svp,p);
X        }
X        if (svp->type == type)
X        {   /* no type change needed? */
X            if (xname != (char *)NULL)
X                free(xname);
X            return;
X        }
X        var_settype(ptr,type,~0);
X        if (xname != (char *)NULL)
X            free(xname);
X        return;
X    }
X
X    var_define0(ptr,p,create);
X    var_settype(ptr,type,~0);
X    *--p = '=';
X    if (xname != (char *)NULL)
X        free(xname);
X}   /* end of var_define */
X
Xvoid var_settype(name,type,mask)
Xchar *name;
Xint type;
Xint mask;
X{
X    register struct variable *svp;
X    int rc,otype;
X    char *ptr,*xname;
X    struct varstack *vs;
X
X    xname = var_subeval(name,0);
X    if (xname == (char *)NULL)
X        ptr = name;
X    else ptr = xname;
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X    {   /* for each variable table */
X        for (svp = vs->table; svp != (struct variable *)NULL; )
X        {   /* look for where to put the variable */
X            rc = var_namecmp(ptr,svp->name);
X            if (rc == 0)
X            {   /* found value, set type */
X                otype = svp->type;
X                if (type == TYPE_DELETED)
X                {   /* remove this variable */
X                    svp->type = type;
X                    free(svp->value);
X                    svp->value = (char *)NULL;
X                    if (xname != (char *)NULL)
X                        free(xname);
X                    return;
X                }
X                svp->type &= ~TYPE_DELETED;
X                svp->type &= mask;
X                svp->type |= type;
X                if (xname != (char *)NULL)
X                    free(xname);
X                if (svp->type != otype)
X                {   /* was there any change? */
X                    var_fixtype(svp,0);
X                    var_reserved(svp);
X                }
X                return;
X            }
X            else if (rc < 0)
X            {   /* go down the left side? */
X                if (svp->left == (struct variable *)NULL)
X                    break;
X                svp = svp->left;
X            }
X            else
X            {   /* go down right side */
X                if (svp->right == (struct variable *)NULL)
X                    break;
X                svp = svp->right;
X            }
X        }
X    }
X    /* variable not found; make dummy one, set its type */
X    if (type == TYPE_DELETED)
X    {   /* if we really don't need to */
X        if (xname != (char *)NULL)
X            free(xname);
X        return;
X    }
X    var_define0(ptr,"",0);
X    var_settype(ptr,type,mask);
X    if (xname != (char *)NULL)
X        free(xname);
X}   /* end of var_settype */
X
Xvoid var_setmisc(name,misc)
Xchar *name;
Xint misc;
X{
X    register struct variable *svp;
X    int rc;
X    char *ptr,*xname;
X    struct varstack *vs;
X
X    xname = var_subeval(name,0);
X    if (xname == (char *)NULL)
X        ptr = name;
X    else ptr = xname;
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X    {   /* for each variable table */
X        for (svp = vs->table; svp != (struct variable *)NULL; )
X        {   /* look for where to put the variable */
X            rc = var_namecmp(ptr,svp->name);
X            if (rc == 0)
X            {   /* found value, set type */
X                if (svp->type == TYPE_DELETED)
X                {   /* really there? */
X                    break;
X                }
X                svp->misc = misc;
X                if (xname != (char *)NULL)
X                    free(xname);
X                var_fixtype(svp,0);
X                var_reserved(svp);
X                return;
X            }
X            else if (rc < 0)
X            {   /* go down the left side? */
X                if (svp->left == (struct variable *)NULL)
X                    break;
X                svp = svp->left;
X            }
X            else
X            {   /* go down right side */
X                if (svp->right == (struct variable *)NULL)
X                    break;
X                svp = svp->right;
X            }
X        }
X    }
X    /* variable not found; make dummy one, set its type */
X    var_define0(ptr,"",0);
X    var_setmisc(ptr,misc);
X    if (xname != (char *)NULL)
X        free(xname);
X}   /* end of var_setmisc */
X
Xchar *var_special(name)
Xregister char *name;
X{
X    int rc,i;
X    char *p;
X    char buf[2];
X    char word[BUFSIZ];
X
X    if (strlen(name) == 2 &&
X        (isdigit(name[1]) || name[1] == '*' || name[1] == '@'))
X    {   /* reference to positional args? */
X        p = (char *)NULL;
X        rc = 0;
X        if (name[1] == '0')
X            p = var_arg0;
X        else if (isdigit(name[1]))
X        {   /* a single arg */
X            if ((name[1]-'0') < var_argc)
X                p = var_argv[name[1]-'0'];
X            else
X            {   /* supply a null string */
X                p = "''";
X            }
X        }
X        else if (name[1] == '*')
X        {   /* all args, separate entities */
X            rc = 0;
X            for (i = 1; i < var_argc; i++)
X                rc += strlen(var_argv[i])+3;
X            rc++;
X            p = new_string(rc);
X            if (p == (char *)NULL)
X            {   /* enough memory? */
X                errmsg(SHERR_NOMEM,LOC("var_special"));
X                return (char *)NULL;
X            }
X            *p = '\0';
X            for (i = 1; i < var_argc; i++)
X            {   /* now tack on args */
X                strcat(p,"'");
X                strcat(p,var_argv[i]);
X                strcat(p,"'");
X                if ((i+1) < var_argc)
X                    strcat(p," ");
X            }
X        }
X        else if (name[1] == '@')
X        {   /* all args, one hunk */
X            buf[0] = base_env.separators[0];
X            buf[1] = '\0';
X            rc = 0;
X            for (i = 1; i < var_argc; i++)
X                rc += strlen(var_argv[i])+1;
X            rc += 3;
X            p = new_string(rc);
X            if (p == (char *)NULL)
X            {   /* enough memory? */
X                errmsg(SHERR_NOMEM,LOC("var_special"));
X                return (char *)NULL;
X            }
X            *p = '\0';
X            strcat(p,"'");
X            for (i = 1; i < var_argc; i++)
X            {   /* now tack on args */
X                strcat(p,var_argv[i]);
X                if ((i+1) < var_argc)
X                    strcat(p,buf);
X            }
X            strcat(p,"'");
X        }
X        if (p == (char *)NULL)
X            p = "";
X        if (rc == 0)
X            p = strcopy(p);
X        return p;
X    }
X    if  (strlen(name) == 2 && name[1] == '?')
X    {   /* status of last cmd */
X        sprintf(word,"%d",cmd_lastrc);
X        return strcopy(word);
X    }
X    if (strlen(name) == 2 && name[1] == '#')
X    {   /* number of args */
X        sprintf(word,"%d",var_argc);
X        return strcopy(word);
X    }
X    if (strlen(name) == 2 && name[1] == '$')
X    {   /* current pid */
X#ifdef  GEMDOS
X        sprintf(word,"%lx",BP);
X#else
X        sprintf(word,"%d",getpid());
X#endif  /* GEMDOS */
X        return strcopy(word);
X    }
X    if (strlen(name) == 2 && name[1] == '!')
X    {   /* last background pid */
X#ifdef  GEMDOS
X        strcpy(word,"0");
X#else
X        sprintf(word,"%d",base_env.background_pid);
X#endif  /* GEMDOS */
X        return strcopy(word);
X    }
X    if (strlen(name) == 2 && name[1] == '-')
X    {   /* status of options */
X        p = word;
X        *p = '\0';
X        if (flag_allexport)
X            *p++ = 'a';
X        if (flag_noglob)
X            *p++ = 'f';
X        if (flag_cmdhash)
X            *p++ = 'h';
X        if (flag_interactive)
X            *p++ = 'i';
X        if (flag_keywords)
X            *p++ = 'k';
X        if (flag_monitor)
X            *p++ = 'm';
X        if (flag_noexec)
X            *p++ = 'n';
X        if (flag_varerr)
X            *p++ = 'u';
X        if (flag_echoinput)
X            *p++ = 'v';
X        if (flag_echoexec)
X            *p++ = 'x';
X        *p = '\0';
X        return strcopy(word);
X    }
X    return (char *)NULL;
X}   /* end of var_special */
X
Xchar *var_normal(name)
Xregister char *name;
X{
X    int rc;
X    register struct variable *svp;
X    struct varstack *vs;
X    long temp;
X    char buffer[32];
X#ifndef GEMDOS
X#ifndef USG
X    extern long random();
X#else
X#endif  /* USG */
X#endif  /* GEMDOS */
X
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X    {   /* for each variable table */
X        for (svp = vs->table; svp != (struct variable *)NULL; )
X        {   /* look for where to get the variable */
X            rc = var_namecmp(&name[1],svp->name);
X            if (rc == 0)
X            {   /* found the variable */
X                if (svp->type == TYPE_DELETED)
X                    break;
X                if (svp->type & TYPE_FUNCTION)
X                {   /* "special" variables, like "RANDOM" and "SECONDS" */
X                    if (strcmp(&name[1],"RANDOM") == 0)
X                    {   /* return a random number */
X#ifndef GEMDOS
X#ifndef USG
X                        temp = random();
X#else
X                        temp = rand();
X#endif  /* USG */
X#else
X                        temp = Random();
X#endif  /* GEMDOS */
X                        sprintf(buffer,"%ld",temp);
X                        return strcopy(buffer);
X                    }
X                    else if (strcmp(&name[1],"SECONDS") == 0)
X                    {   /* how long have we been running? */
X                        temp = time(0L);
X                        sprintf(buffer,"%ld",temp-base_env.start_at);
X                        return strcopy(buffer);
X                    }
X                }
X                return strcopy(svp->value);
X            }
X            else if (rc < 0)
X            {   /* go down the left side? */
X                svp = svp->left;
X            }
X            else
X            {   /* go down right side */
X                svp = svp->right;
X            }
X        }
X    }
X    if (flag_varerr)
X        errmsg(0,LOC("var_normal"),"%s: variable not found",name);
X    return (char *)NULL;
X}   /* end of var_normal */
X
Xstatic int var_0submatches(name,svp)
Xchar *name;
Xregister struct variable *svp;
X{
X    register int matches;
X
X    matches = 0;
X    if (svp->left != (struct variable *)NULL)
X        matches += var_submatches(name,svp->left);
X    if (wild_match(svp->name,&name[1]))
X        matches++;
X    if (svp->right != (struct variable *)NULL)
X        matches += var_submatches(name,svp->right);
X    return matches;
X}   /* end of var_0submatches */
X
Xstatic int var_submatches(name)
Xchar *name;
X{
X    struct varstack *vs;
X    register int accum;
X
X    accum = 0;
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X        accum += var_0submatches(name,vs->table);
X    return accum;
X}   /* end of var_submatches */
X
Xstatic int var_0subgetlen(name,svp)
Xchar *name;
Xregister struct variable *svp;
X{
X    register int length;
X
X    length = 0;
X    if (svp->left != (struct variable *)NULL)
X        length += var_0subgetlen(name,svp->left);
X    if (wild_match(svp->name,&name[1]))
X        length += strlen(svp->value)+3;
X    if (svp->right != (struct variable *)NULL)
X        length += var_0subgetlen(name,svp->right);
X    return length;
X}   /* end of var_0subgetlen */
X
Xstatic int var_subgetlen(name)
Xchar *name;
X{
X    struct varstack *vs;
X    register int accum;                               
X
X    accum = 0;
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X        accum += var_0subgetlen(name,vs->table);
X    return accum;
X}   /* end of var_subgetlen */
X
Xstatic void var_0subfilbuf(name,svp,buf,flag)
Xregister char *name;
Xregister struct variable *svp;
Xregister char *buf;
Xint flag;
X{
X    if (svp->left != (struct variable *)NULL)
X        var_0subfilbuf(name,svp->left,buf,flag);
X    if (wild_match(svp->name,&name[1]))
X    {   /* tack on the value of this name */
X        if (strlen(svp->value) > 0 || flag)
X        {    /* tack this one on? */
X            strcat(buf,svp->value);
X            strcat(buf," ");
X        }
X    }
X    if (svp->right != (struct variable *)NULL)
X        var_0subfilbuf(name,svp->right,buf,flag);
X}   /* end of var_0subfilbuf */
X
Xstatic void var_subfilbuf(name,buf,flag)
Xchar *name;
Xchar *buf;
Xint flag;
X{
X    struct varstack *vs;
X
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X        var_0subfilbuf(name,vs->table,buf,flag);
X}   /* end of var_subfilbuf */
X
Xchar *var_getval();
X
Xchar *var_expression(name)
Xregister char *name;
X{
X    register char *p,*q;
X    char buffer[BUFSIZ];
X    int temp;
X
X    sprintf(buffer,"#*%c[%c*%c]",ESCAPE_CHAR,ESCAPE_CHAR,ESCAPE_CHAR);
X    if (wild_match(&name[1],buffer))
X    {   /* number of matching subscripted vars defined */
X        strcpy(buffer,name);
X        sprintf(&buffer[strlen(buffer)-3],"%c[*%c]",ESCAPE_CHAR,ESCAPE_CHAR);
X        temp = var_submatches(&buffer[1]);
X        sprintf(buffer,"%d",temp);
X        return strcopy(buffer);
X    }
X    if (wild_match(&name[1],"#*"))
X    {   /* get length of var instead */
X        p = var_getval(&name[1],1);
X        strcpy(buffer,"0");
X        if (p != (char *)NULL)
X        {   /* if a value to look at */
X            sprintf(buffer,"%d",strlen(p));
X            free(p);
X        }
X        return strcopy(buffer);
X    }
X    sprintf(buffer,"*%c[%c@%c]",ESCAPE_CHAR,ESCAPE_CHAR,ESCAPE_CHAR);
X    if (wild_match(&name[1],buffer))
X    {   /* all values */
X        strcpy(buffer,name);
X        sprintf(&buffer[strlen(buffer)-3],"%c[*%c]",ESCAPE_CHAR,ESCAPE_CHAR);
X        temp = var_subgetlen(buffer);
X        p = new_string(temp+2);
X        if (p == (char *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("var_expression"));
X            return (char *)NULL;
X        }
X        var_subfilbuf(buffer,p,0);
X        return p;
X    }
X    sprintf(buffer,"*%c[%c*%c]",ESCAPE_CHAR,ESCAPE_CHAR,ESCAPE_CHAR);
X    if (wild_match(&name[1],buffer))
X    {   /* all values */
X        strcpy(buffer,name);
X        sprintf(&buffer[strlen(buffer)-3],"%c[*%c]",ESCAPE_CHAR,ESCAPE_CHAR);
X        temp = var_subgetlen(buffer);
X        p = new_string(temp+2);
X        if (p == (char *)NULL)
X        {   /* enough memory? */
X            errmsg(SHERR_NOMEM,LOC("var_expression"));
X            return (char *)NULL;
X        }
X        var_subfilbuf(buffer,p,1);
X        return p;
X    }
X    sprintf(buffer,"*%c[*%c]",ESCAPE_CHAR,ESCAPE_CHAR);
X    if (wild_match(&name[1],buffer))
X    {   /* a subscripted variable */
X        p = var_subeval(name,1);
X        if (p == (char *)NULL)
X            q = name;
X        else q = p;
X        q = var_getval(q,0);
X        if (p != (char *)NULL)
X            free(p);
X        return q;
X    }
X    if (wild_match(&name[1],"*:-*"))
X    {   /* alternatives, but non-null */
X        p = strchr(name,':');
X        /* ASSERT that p != NULL */
X        while (p[1] != '-')
X            p = strchr(&p[1],':');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL && strlen(q) > 0)
X            return q;
X        if (q != (char *)NULL)
X            free(q);
X        return strcopy(&p[2]);
X    }
X    if (wild_match(&name[1],"*-*"))
X    {   /* alternatives */
X        p = strchr(name,'-');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL)
X            return q;
X        return strcopy(&p[1]);
X    }
X    if (wild_match(&name[1],"*:=*"))
X    {   /* alternatives, assignment, non-null */
X        p = strchr(name,':');
X        /* ASSERT that p != NULL */
X        while (p[1] != '=')
X            p = strchr(&p[1],':');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL && strlen(q) > 0)
X            return q;
X        if (q != (char *)NULL)
X            free(q);
X        var_define0(&buffer[1],&p[2],0);
X        return strcopy(&p[2]);
X    }
X    if (wild_match(&name[1],"*=*"))
X    {   /* alternatives, assignment */
X        p = strchr(name,'=');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL)
X            return q;
X        var_define0(&buffer[1],&p[1],0);
X        return strcopy(&p[1]);
X    }
X    sprintf(buffer,"*:%c?*",ESCAPE_CHAR);
X    if (wild_match(&name[1],buffer))
X    {   /* alternatives with printing, non-null */
X        p = strchr(name,':');
X        /* ASSERT that p != NULL */
X        while (p[1] != '?')
X            p = strchr(&p[1],':');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL && strlen(q) != 0)
X            return q;
X        if (q != (char *)NULL)
X            free(q);
X        strcpy(buffer,&buffer[1]);
X        if (p[2] != '\0')
X            strcpy(buffer,&p[2]);
X        else    strcat(buffer,": parameter null or not set");
X        io_writestring(0,buffer);
X        io_writestring(0,"\n");
X        return strcopy("");
X    }
X    sprintf(buffer,"*%c??*",ESCAPE_CHAR);
X    if (wild_match(&name[1],buffer))
X    {   /* alternatives with printing */
X        p = strchr(name,'?');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL)
X            return q;
X        strcpy(buffer,&buffer[1]);
X        if (p[1] != '\0')
X            strcpy(buffer,&p[1]);
X        else    strcat(buffer,": parameter not set");
X        io_writestring(0,buffer);
X        io_writestring(0,"\n");
X        return strcopy("");
X    }
X    if (wild_match(&name[1],"*:+*"))
X    {   /* substitution, non-null */
X        p = strchr(name,':');
X        /* ASSERT that p != NULL */
X        while (p[1] != '+')
X            p = strchr(&p[1],':');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL && strlen(q) != 0)
X        {   /* do substitution */
X            free(q);
X            return strcopy(&p[2]);
X        }
X        if (q != (char *)NULL)
X            free(q);
X        return strcopy("");
X    }
X    if (wild_match(&name[1],"*+*"))
X    {   /* substitution */
X        p = strchr(name,'-');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q != (char *)NULL)
X        {   /* do substitution */
X            free(q);
X            return strcopy(&p[1]);
X        }
X        return strcopy("");
X    }
X    if (wild_match(&name[1],"*##*"))
X    {   /* cut from beginning */
X        p = strchr(name,'#');
X        while (p[1] != '#')
X            p = strchr(&p[1],'#');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q == (char *)NULL)
X            return q;
X        for (temp = strlen(q)-1; temp >= 0; temp--)
X        {   /* looks for first largest portion that matches */
X            strncpy(buffer,q,temp+1);
X            buffer[temp+1] = '\0';
X            if (wild_match(buffer,&p[2]))
X            {   /* found a match? */
X                strcpy(buffer,&q[temp+1]);
X                free(q);
X                return strcopy(buffer);
X            }
X        }
X        return q;
X    }
X    if (wild_match(&name[1],"*#*"))
X    {   /* cut from beginning */
X        p = strchr(name,'#');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q == (char *)NULL)
X            return q;
X        for (temp = 0; temp < strlen(q); temp++)
X        {   /* looks for first portion that matches */
X            strncpy(buffer,q,temp+1);
X            buffer[temp+1] = '\0';
X            if (wild_match(buffer,&p[1]))
X            {   /* found a match? */
X                strcpy(buffer,&q[temp+1]);
X                free(q);
X                return strcopy(buffer);
X            }
X        }
X        return q;
X    }
X    if (wild_match(&name[1],"*%%*"))
X    {   /* cut from beginning */
X        p = strchr(name,'%');
X        while (p[1] != '%')
X            p = strchr(&p[1],'%');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q == (char *)NULL)
X            return q;
X        for (temp = 0; temp < strlen(q); temp++)
X        {   /* looks for first largest portion that matches */
X            strcpy(buffer,&q[temp]);
X            if (wild_match(buffer,&p[2]))
X            {   /* found a match? */
X                strncpy(buffer,q,strlen(q)-strlen(buffer));
X                buffer[strlen(q)-strlen(buffer)] = '\0';
X                free(q);
X                return strcopy(buffer);
X            }
X        }
X        return q;
X    }
X    if (wild_match(&name[1],"*%*"))
X    {   /* cut from beginning */
X        p = strchr(name,'%');
X        /* ASSERT that p != NULL */
X        strncpy(buffer,name,(int)(p-name));
X        buffer[(int)(p-name)] = '\0';
X        q = var_getval(buffer,1);
X        if (q == (char *)NULL)
X            return q;
X        for (temp = strlen(q)-1; temp >= 0; temp--)
X        {   /* looks for first portion that matches */
X            strcpy(buffer,&q[temp]);
X            if (wild_match(buffer,&p[1]))
X            {   /* found a match? */
X                strncpy(buffer,q,strlen(q)-strlen(buffer));
X                buffer[strlen(q)-strlen(buffer)] = '\0';
X                free(q);
X                return strcopy(buffer);
X            }
X        }
X        return q;
X    }
X    
X    return (char *)NULL;
X}   /* end of var_expression */
X
Xchar *var_getval(name,flag)
Xregister char *name;
Xint flag;
X{
X    register char *value;
X
X    if (flag)
X        value = var_expression(name);
X    else value = (char *)NULL;
X    if (value == (char *)NULL)
X        value = var_special(name);
X    if (value == (char *)NULL)
X        value = var_normal(name);
X    return value;
X}   /* end of var_getval */
X
Xchar *var_reference(dont_expand)
Xint dont_expand;
X{
X    int rc,count,bracketed;
X    register char *p;
X    char tomatch;
X    char word[BUFSIZ],buf[2];
X
X    bracketed = 0;
X    buf[1] = '\0';
X    p = word;
X    *p++ = '$';
X    rc = io_getchar(0);
X    if (rc == SYM_EOF)
X    {   /* end of file? */
X        return (char *)NULL;
X    }
X    else if (rc == '{' || rc == '(')
X    {   /* a "quoted" pair */
X        bracketed++;
X        if (rc == '{')
X            tomatch = '}';
X        else    tomatch = ')';
X        rc = io_getchar(0);
X        while (rc != SYM_EOF && rc != tomatch && rc != '\n')
X        {   /* build up the variable name */
X#ifdef  GEMDOS
X            if (rc == '\r')
X                break;
X#endif  /* GEMDOS */
X            *p++ = rc;
X            if (p >= &word[sizeof word])
X            {   /* enough space? */
X                errmsg(0,LOC("var_reference"),"name too long");
X                p--;
X                buf[0] = rc;
X                io_savestring(buf);
X                break;
X            }
X            rc = io_getchar(0);
X        }
X#ifdef  GEMDOS
X        if (rc == '\r' || rc == '\n')
X#else
X        if (rc == '\n')
X#endif  /* GEMDOS */
X        {   /* put eol back */
X            buf[0] = '\n';
X            io_savestring(buf);
X        }
X        if (rc == SYM_EOF)
X            return (char *)NULL;
X    }
X    else if (isdigit(rc))
X    {   /* numerical variable? */
X        *p++ = rc;
X    }
X    else if (isalpha(rc) || rc == '_')
X    {   /* named variable */
X        *p++ = rc;
X        while ((rc = io_getchar(0)) != SYM_EOF)
X        {   /* get rest of word */
X            if (rc == '[')
X            {   /* a bracketed subscript */
X                count = 1;
X                *p++ = rc;
X                if (p >= &word[sizeof word])
X                {   /* enough space? */
X                    errmsg(0,LOC("var_reference"),"name too long");
X                    p--;
X                    buf[0] = rc;
X                    io_savestring(buf);
X                    break;
X                }
X                while ((rc = io_getchar(0)) != SYM_EOF)
X                {   /* rest of subscript... */
X                    if (rc == '[')
X                        count++;
X                    *p++ = rc;
X                    if (p >= &word[sizeof word])
X                    {   /* enough space? */
X                        errmsg(0,LOC("var_reference"),"name too long");
X                        p--;
X                        buf[0] = rc;
X                        io_savestring(buf);
X                        break;
X                    }
X                    if (rc == ']')
X                        count--;
X                    if (count == 0)
X                        break;
X                }
X                if (rc == ']')
X                    rc = io_getchar(0);
X                break;
X            }
X            if (!isalpha(rc) && !isdigit(rc) && rc != '_')
X                break;
X            *p++ = rc;
X            if (p >= &word[sizeof word])
X            {   /* enough space? */
X                errmsg(0,LOC("var_reference"),"name too long");
X                p--;
X                buf[0] = rc;
X                io_savestring(buf);
X                break;
X            }
X        }
X        if (rc == SYM_EOF)
X            return (char *)NULL;
X        buf[0] = rc;
X        io_savestring(buf);
X    }
X    else
X    {   /* special variable */
X        *p++ = rc;
X    }
X    *p = '\0';
X
X    if (!dont_expand)
X    {   /* if to expand variable */
X        p = var_getval(word,1);
X        if (p != (char *)NULL)
X        {   /* if found */
X            io_savestring(p);
X            free(p);
X            return (char *)NULL;
X        }
X    }
X    rc = strlen(word);
X    if (bracketed)
X        rc += 2;
X    p = new_string(rc+1);
X    if (p == (char *)NULL)
X    {   /* enough memory? */
X        errmsg(SHERR_NOMEM,LOC("var_reference"));
X        return (char *)NULL;
X    }
X    if (!bracketed)
X        strcpy(p,word);
X    else sprintf(p,"${%s}",&word[1]);
X    return p;
X}   /* end of var_reference */
X
Xstatic void var_0dump(vp,type,flag)
Xregister struct variable *vp;
Xint type;
Xint flag;
X{
X    if (vp == (struct variable *)NULL)
X        return;
X    if (vp->left != (struct variable *)NULL)
X        var_0dump(vp->left,type,flag);
X    if (vp->type != TYPE_DELETED)
X    {   /* if variable really there */
X        if (type == 0 || ((type & vp->type) != 0))
X            dump_var(vp,flag);
X    }
X    if (vp->right != (struct variable *)NULL)
X        var_0dump(vp->right,type,flag);
X}   /* end of var_0dump */
X
Xvoid var_dump(type,flag)
Xint type;
Xint flag;
X{
X    struct varstack *vs;
X
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X        var_0dump(vs->table,type,flag);
X}   /* end of var_dump */
X
Xvoid var_readenv()
X{
X    extern char **environ;
X    register int i;
X#ifdef  GEMDOS
X    char buffer[16];
X#endif  /* GEMDOS */
X
X#ifdef  GEMDOS
X    sprintf(buffer,"%lx",BP->p_parent);
X    var_define0("PPID",buffer,0);
X#endif  /* GEMDOS */
X    if (environ != (char **)NULL)
X    {   /* if an environment is present */
X        for (i = 0; environ[i] != (char *)NULL; i++)
X        {   /* look through environment variables */
X#ifdef  MWC_ARGV
X            if (strncmp(environ[i],"ARGV=",5) == 0)
X                break;
X#endif  /* MWC_ARGV */
X            var_define(environ[i],TYPE_EXPORTED);
X        }
X    }
X}   /* end of var_readenv */
X
Xstatic  int     e_length;
Xstatic  char    *e_area,*e_last;
X
Xstatic void e_getlength(vp)
Xregister struct variable *vp;
X{
X    if (vp == (struct variable *)NULL)
X        return;
X    if (vp->left != (struct variable *)NULL)
X        e_getlength(vp->left);
X    if (vp->type != TYPE_DELETED)
X    {   /* if variable really there */
X        if ((vp->type & TYPE_EXPORTED) || (vp->cmd == cmd_count))
X            e_length += strlen(vp->name)+strlen(vp->value)+2;
X    }
X    if (vp->right != (struct variable *)NULL)
X        e_getlength(vp->right);
X}   /* end of e_getlength */
X
Xstatic void e_fillarea(vp)
Xregister struct variable *vp;
X{
X    if (vp == (struct variable *)NULL)
X        return;
X    if (vp->left != (struct variable *)NULL)
X        e_fillarea(vp->left);
X    if (vp->type != TYPE_DELETED)
X    {   /* if variable really there */
X        if ((vp->type & TYPE_EXPORTED) || (vp->cmd == cmd_count))
X        {   /* put into table */
X            sprintf(e_last,"%s=%s",vp->name,vp->value);
X            while (*e_last)
X                e_last++;
X            e_last++;
X        }
X    }
X    if (vp->right != (struct variable *)NULL)
X        e_fillarea(vp->right);
X}   /* end of e_fillarea */
X
Xchar *var_makeenv()
X{
X    struct varstack *vs;
X
X    e_length = 2;
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X        e_getlength(vs->table);
X    e_area = new_string(e_length);
X    if (e_area == (char *)NULL)
X    {   /* enough memory */
X        errmsg(SHERR_NOMEM,LOC("var_makeenv"));
X        return (char *)NULL;
X    }
X    e_last = e_area;
X    for (vs = base_env.var; vs != (struct varstack *)NULL; vs = vs->next)
X        e_fillarea(vs->table);
X    *e_last = '\0';
X    return e_area;
X}   /* end of var_makeenv */
X
Xvoid var_tablefree(vp)
Xregister struct variable *vp;
X{
X    if (vp == (struct variable *)NULL)
X        return;
X    if (vp->left != (struct variable *)NULL)
X        var_tablefree(vp->left);
X    if (vp->right != (struct variable *)NULL)
X        var_tablefree(vp->right);
X    if (vp->value != (char *)NULL)
X        free(vp->value);
X    if (vp->name != (char *)NULL)
X        free(vp->name);
X    free(vp);
X}   /* end of var_tablefree */
END_OF_FILE
if test 50361 -ne `wc -c <'var.c'`; then
    echo shar: \"'var.c'\" unpacked with wrong size!
fi
# end of 'var.c'
fi
echo shar: End of archive 11 \(of 11\).
cp /dev/null ark11isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 11 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0



More information about the Alt.sources mailing list