/***********************************************************************\

   Filename: spath.c

\***********************************************************************/

#include <language.h>
#include "corelex.h"
#include "cache.h"
#include "clam.h"
#include "lex.h"
#include "spath.h"
#include "environ.h"

/* These routines are used to manipulate the Searchpath. */

SPENTRY *Srchend = Srchpath;    /* end of the SP array */
SPENTRY Srchpath[SRCHMAXSIZE];  /* The wordlists to search */

/* Add a new entry to the Searchpath.  Return TRUE if added.

   The order in which routines like clamopen() and lexopen() are called 
   forces the order in which the wordlists are searched, since pathadd() 
   simply puts their structures sequentially into the Searchpath.  

   Multiple environments are allowed in the Searchpath, but calling programs 
   are restricted to one environment at a time.  */ 

static int
pathadd(flags, idcode, type, errcode, access)
int    flags;                  /* Searchpath control flags */
int    idcode;                 /* Searchpath entry identifier */
int    type;                   /* associated wordlist type (IW_LEX, etc.) */
int    errcode;                /* Error code for placing in Scerror. */
char   *access;                /* Wordlist ptr */
{
SPENTRY *addptr;               /* pointer into the searchpath */

        /* Special case: if opened with no flags then do not add the 
           wordlist to the searchpath.  */ 

   if (flags == 0)
       return (TRUE);

        /* make sure there is room in the Searchpath array and that a proper 
           environment has been set.  */ 

   if (Srchend == &Srchpath[SRCHMAXSIZE])
   {
       Scerror = errcode | ERR_PATH;
       return (FALSE);
   }

   /* put the new entry in the next available slot */

   addptr = Srchend;
   addptr->sp_type = type;
   addptr->sp_flags = flags & SP_MASK;
   addptr->sp_idcode = idcode;
   addptr->sp_access = access;
   ++Srchend;

   return (TRUE);
}

/* Remove the wordlist entry at 'access' from the Searchpath.  Move all the 
   other entries up.  

   The entries in the searchpath are located by using their 'sp_access' 
   fields.  This field typically points to a structure that is used while 
   accessing the wordlist, and must be unique to each word list.  */ 

static void pathdel(access)
char    *access;                /* the entry to delete */
{
SPENTRY *delptr;       /* pointer into the searchpath */

   /* Locate the structure pointer in the Searchpath, then move the
           entries which are past it up one entry.  */ 

   delptr = Srchend;
   while (--delptr >= Srchpath) {
       if (delptr->sp_access == access) {
           --Srchend;
           scmove(delptr, delptr + 1,
               sizeof(SPENTRY) * (Srchend - delptr));
           return;
       }
   }
   /* The structure was not found, so do nothing. */
}

/* Pairs of routines for each type of word list, one open routine and one 
   close routine.  The open routines verify that the word list can be added 
   to the Searchpath, allocate the word list, and return a pointer to the 
   allocaed word list.  The close routines free the word list and remove it 
   from the Searchpath.  */ 

CLAM *clamopen(idcode, flags, fname, ftype, atype)
int     idcode;                 /* Identifier for this word list */
int     flags;                  /* Searchpath flags */
char    *fname;                 /* File name */
int     ftype;                  /* If CL_INIT, new file type */
long    atype;                  /* If CL_INIT, new file auxtype */
{
extern CLAM *clamalloc();
CLAM *cp;

    if (!(cp = clamalloc(fname, flags, ftype, atype)))
        return(NULL);
    if (!pathadd(flags, idcode, IW_CLAM >> 8, ERR_CLAM, cp))
        return (NULL);
    return(cp);
}

void clamclose(cp)
CLAM *cp;
{
extern void clamfree();

    clamfree(cp);
    pathdel((char *) cp);
}

clxopen(idcode, flags)
int    idcode;                 /* Identifier for this word list */
int    flags;                  /* Searchpath flags */
{
extern clxalloc();

   return(pathadd(flags, idcode, IW_CORELEX >> 8, ERR_LEX, (char *)
     &Clxversion) && getacorelex());
}

void clxclose()
{
extern void clxfree();

   clxfree();
   pathdel((char *) &Clxversion);
}

lexopen(idcode, flags, fname)
int     idcode;                 /* Identifier for this word list */
int     flags;                  /* Searchpath flags */
char    *fname;                 /* Name of file containing lexicon */
{
extern lexalloc();

   return(pathadd(flags, idcode, IW_LEX >> 8, ERR_LEX, (char *) &Lexenvcode)
     && lexalloc(fname));
}

void lexclose()
{
extern void lexfree();

   lexfree();
   pathdel((char *) &Lexenvcode);
}
