rokicki@navajo.STANFORD.EDU (Tomas Rokicki) (07/31/86)
[ Snugglebunnies snugglebunnies snuggl%!
Here is an environment variable program which can be used in place of
the Manx set command for distribution purposes. This one doesn't place
a limit on the size of the environment string space, has a smaller
executable, and takes less system memory for smaller environments.
Enjoy!
------cut here------
/*
* Written by Tomas Rokicki.
*
* This routine replaces Manx's SET command. It should have exactly
* equivalent functionality. Do not use the Manx SET command with it,
* though; my library structure has an extra field which Manx ignores.
* Thus, if the Manx set command modifies a library created by my set
* command, or vice versa, a system crash could result.
*
* Another caveat: the Manx getenv() routine does not do a Forbid()
* Permit() around it's library examining code, so it could
* conceivably return bad data if someone's executing a set while it
* is called. You might want to rewrite getenv(); it's simple enough.
*
* The following code could easily be hacked to provide setenv() and
* getenv() library routines; I leave that as an exersize for the reader.
*/
#include "stdio.h"
#include "exec/memory.h"
/*
* The increment size for the string space.
*/
#define ENVINC (128)
/*
* The pointer to the environment data.
*/
char **envloc = NULL ;
long *envsize ;
char *envname = "environment" ;
/*
* A library structure declaration, pieced together from various
* include files and extended a bit.
*/
struct lib {
struct lib *next, *prev ;
char type, priority ;
char *name ;
short flags ;
short negsize ;
short possize ;
short version ;
short revision ;
char *ID ;
long checksum ;
short opencount ;
char *env ;
long size ;
} ;
/*
* The actual library structure. Note I have relative branches in the
* vectors field, and actual assembled code in the code field. Be
* careful if you change any of this!
*/
struct envlib {
short vectors[12] ;
struct lib lp ;
short code[4] ;
char name[12] ; } envinit =
{ { 0x6044, 0x0000, 0x0000,
0x603e, 0x0000, 0x0000,
0x6038, 0x0000, 0x0000,
0x602e, 0x0000, 0x0000 },
{ NULL, NULL,
0, 0,
NULL,
0,
24,
42 + 8 + 12 + 2,
1,
1,
NULL,
0,
1,
NULL,
ENVINC },
{ 0x200e, 0x4e75, 0x7000, 0x4e75 },
{ 'e', 'n', 'v', 'i', 'r', 'o', 'n', 'm', 'e', 'n', 't', 0}
} ;
/*
* The main routine is straightforward. If no arguments are given, we
* print out the contents of the environment. If one ? is given as an
* argument, we print out a blurb. Otherwise, we scan through the
* argument list, adding new definitions.
*/
char *index() ;
main(argc, argv)
int argc ;
char *argv[] ;
{
register char *p, *q ;
argc-- ; argv++ ;
openenv() ;
if (argc <= 0) {
if (envloc != NULL)
for (q=*envloc; *q!=0; ) {
puts(q) ;
while (*q++) ;
}
} else if (argc==1 && argv[0][0]=='?' && argv[0][1]==0) {
puts("Environment variable utility---Radical Eye Software") ;
} else while (argc > 0) {
if ((p = index(*argv, '=')) && p[1] != 0) {
deleteenv(*argv) ;
if (envloc==NULL)
makeenv() ;
for (;;) {
q = *envloc ;
while (*q!=0)
while (*q++) ;
if (q+strlen(*argv)+1 > *envloc + *envsize)
biggerenv() ;
else
break ;
}
Forbid() ;
strcpy(q, *argv) ;
q[strlen(*argv)+1] = 0 ;
Permit() ;
} else {
deleteenv(*argv) ;
}
argv++ ;
argc-- ;
}
}
/*
* This routines opens the environment library if it exists and sets
* the global pointer to the correct location.
*/
openenv()
{
register struct lib *lp, *_OpenLibrary() ;
if (lp=_OpenLibrary(envname, 0L)) {
_CloseLibrary(lp) ;
envloc = &lp->env ;
envsize = &lp->size ;
} else
envloc = NULL ;
}
/*
* We need a simple memcopy routine. Only works for even numbers of bytes.
*/
memcop(dst, src, bytes)
register short *dst, *src ;
register long bytes ;
{
while (bytes > 0) {
*dst = *src ;
dst++ ; src++ ;
bytes -= 2 ;
}
}
/*
* This is the tricky routine which adds a library.
*/
makeenv()
{
char *AllocMem() ;
register struct lib *lp ;
register struct envlib *elp ;
register char *p ;
elp = (struct envlib *)AllocMem((long)sizeof(struct envlib),
(long)MEMF_PUBLIC) ;
p = AllocMem((long)ENVINC, (long)MEMF_PUBLIC | MEMF_CLEAR) ;
if (elp==NULL || p==NULL) {
puts("Couldn't make environment library!") ;
if (elp!=NULL)
FreeMem(elp, (long)sizeof(struct envlib)) ;
if (p!=NULL)
FreeMem(p, (long)ENVINC) ;
exit(1) ;
}
memcop(elp, &envinit, (long)sizeof(struct envlib)) ;
lp = &(elp->lp) ;
lp->name = elp->name ;
lp->env = p ;
AddLibrary(lp) ;
envloc = &(lp->env) ;
envsize = &(lp->size) ;
return ;
}
/*
* This routine makes the environment string space bigger if needed.
*/
biggerenv() {
register char *p ;
register long size ;
register char *t ;
size = *envsize + ENVINC ;
p = AllocMem(size, (long)MEMF_PUBLIC | MEMF_CLEAR) ;
if (p==NULL) {
puts("Couldn't increase environment size.\n") ;
exit(1) ;
}
Forbid() ;
t = *envloc ;
memcop(p, t, *envsize) ;
*envloc = p ;
*envsize = size ;
Permit() ;
size -= ENVINC ;
FreeMem(t, size) ;
}
/*
* This routine deletes a symbol definition and moves all other strings
* down. We can afford to use a simple algorithm here.
*/
deleteenv(s)
register char *s ;
{
register char *q ;
register int i, j ;
if (envloc==NULL) return ;
if (q=index(s, '='))
i = q - s ;
else
i = strlen(s) ;
Forbid() ;
q = *envloc ;
while (*q!=0)
if ((j=index(q, '=')-q) && i==j && strncmp(q, s, i)==0) {
s = q + strlen(q) + 1 ;
while (*s != 0) {
*q++ = *s++ ;
if (*s == 0)
*q++ = *s++ ;
}
*q++ = 0 ;
*q++ = 0 ;
Permit() ;
return ;
} else
q += strlen(q) + 1 ;
Permit() ;
}
------cut here------