[net.micro.amiga] environment variables

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------