/* Program Name            : DIRECTQUE.C                                */
/*   Original Author       : C. K. Hung					*/
/*   Date                  : 24-SEP-1991				*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
 
/* ****  INCLUDE FILES *** */
#include "global.h"
#include "direct.h"
#include "filerenc.h"
#include "directque.h"
#include "dx.h"
#include <libdef.h>
 
 
 
/* ****  INTERNAL FUNCTION PROTOTYPING *** */
static struct node_tag *	search_queue_node(struct node_tag *, char *);
static int			free_root_equ(struct root_equ_names_tag **);
static int			insert_root_equ_name(
				    struct root_equ_names_tag **, char *);
static int			cmp_root_equ(
				    struct root_equ_names_tag *, struct root_equ_names_tag *);
 
 
 
/*
**  FUNCTIONAL DESCRIPTION:
**
*/
int	    initialize_direct_cache()
{
    int i;
 
    for (i = 0;  i < MAX_DIRECT_BUFFER;  i++)
    {
	convert_date_string (
	    "17-NOV-1858 00:00:00.00", &direct_cache[i].time_stamp);
	direct_cache[i].root_equ_names = (struct root_equ_names_tag *)NULL;
	direct_cache[i].direction = advance;
	strcpy(direct_cache[i].pattern, "[]");
	direct_cache[i].root = (struct node_tag *)NULL;
    }
    return DX__NORMAL;
}
 
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      find_LRU_in_direct_cache() find the Least-Recently-Used slot
**	in the directory cache.
**
**--
**/
int	find_LRU_in_direct_cache()
{
    DATE_TIME earliest_time,
	      cmp;
    int m,
        n;
 
    m = 0;
    memcpy (&earliest_time, &direct_cache[0].time_stamp, 8);
    for (n = 1;  n < MAX_DIRECT_BUFFER;  n++)
    {
        if (lib$sub_times(
                &direct_cache[n].time_stamp,
                &earliest_time,
                &cmp) == LIB$_NEGTIM)
	{
	    memcpy(
		&earliest_time, &direct_cache[n].time_stamp, 8);
	    m = n;
	}
    }
 
    /*
    **  Reset the default values and free up memory used by this node
    **/
 
    direct_cache[m].direction = advance;
    strcpy(direct_cache[m].pattern, "[]");
    free_root_equ (&(direct_cache[m].root_equ_names));
    direct_cache[m].root_equ_names = (struct root_equ_names_tag *)NULL;
    free_dirtree (&(direct_cache[m].root), (struct node_tag *)NULL);
    direct_cache[m].root = (struct node_tag *)NULL;
 
    return m;
}
 
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	search_direct_cache(n)
char *n;
{
    static _align (QUADWORD) int logicalQ[2];
 
    struct logical_queue_entry_tag *E;
    unsigned long int status;
    int number_of_bytes;
    char *cp;
    int i;
    struct root_equ_names_tag *l;
 
    /*
    **	Translate the root logical name.
    **/
 
    l = (struct root_equ_names_tag *)NULL;
    logicalQ[0] = logicalQ[1] = 0;
    trnlnm(n, logicalQ);
    while (_REMQHI (logicalQ, &E) != 3)
    {
	number_of_bytes = strlen(E->equivalent_name)+1;
	if ((cp = strstr (E->equivalent_name, ".000000]")) != NULL)
	{
	    *cp++ = ']';
	    *cp = EOS;
	}
	insert_root_equ_name(&l, E->equivalent_name);
	check_OK(lib$free_vm (
		     &number_of_bytes,
		     &E->equivalent_name,
		     0))
    }
 
    for (i = 0;  i < MAX_DIRECT_BUFFER;  i++)
    {
	if (cmp_root_equ(l, direct_cache[i].root_equ_names))
	{
	    free_root_equ(&l);
	    return i;
	}
    }
 
    free_root_equ(&l);
    return -1;	    /**  Not found  **/
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    save_to_direct_cache(i, r, d, p, n)
int i;
char *r;
enum directions d;
char *p;
struct node_tag *n;
{
    static _align (QUADWORD) int logicalQ[2];
 
    struct logical_queue_entry_tag *E;
    unsigned long int status;
    int number_of_bytes;
    char *cp;
 
    check_OK(sys$gettim (       /**  Time stamp  **/
		&direct_cache[i].time_stamp))
 
    /*
    **	Translate the root logical name.
    **	Should only expand to a single name.
    **/
 
    direct_cache[i].root_equ_names = (struct root_equ_names_tag *)NULL;
    logicalQ[0] = logicalQ[1] = 0;
    trnlnm(r, logicalQ);
    while (_REMQHI (logicalQ, &E) != 3)
    {
	number_of_bytes = strlen(E->equivalent_name)+1;
	if ((cp = strstr (E->equivalent_name, ".000000]")) != NULL)
	{
	    *cp++ = ']';
	    *cp = EOS;
	}
	insert_root_equ_name(&(direct_cache[i].root_equ_names), E->equivalent_name);
	check_OK(lib$free_vm (
		     &number_of_bytes,
		     &E->equivalent_name,
		     0))
    }
 
    direct_cache[i].direction = d;
    strcpy(direct_cache[i].pattern, p);
    direct_cache[i].root = n;
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    restore_from_direct_cache(i, d, p, n)
int i;
enum directions *d;
char *p;
struct node_tag **n;
{
    *d = direct_cache[i].direction;
    strcpy(p, direct_cache[i].pattern);
    *n = direct_cache[i].root;
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    add_to_direct_cache(e, errmsg)
char *e;
char *errmsg;
{
    static _align (QUADWORD) int logicalQ[2];
 
    struct logical_queue_entry_tag *E;
    unsigned long int status;
    int number_of_bytes;
    char *cp;
    int i;
    char f[MAXFILESPEC+1];
    int len;
    char s1[MAXFILESPEC+1],
	 s2[MAXFILESPEC+1];
    int allocate_size = sizeof (struct node_tag);
    struct root_equ_names_tag *p;
 
    /*
    **	Translate the logical name.
    **	Should only expand to a single name.
    **/
 
    logicalQ[0] = logicalQ[1] = 0;
    trnlnm(e, logicalQ);
    while (_REMQHI (logicalQ, &E) != 3)
    {
	number_of_bytes = strlen(E->equivalent_name)+1;
	if ((cp = strstr (E->equivalent_name, ".000000]")) != NULL)
	{
	    *cp++ = ']';
	    *cp = EOS;
	}
	strcpy(f, E->equivalent_name);
	check_OK(lib$free_vm (
		     &number_of_bytes,
		     &E->equivalent_name,
		     0))
    }
 
    /*
    **	Search queue for insertion.
    **/
 
    for (i = 0;  i < MAX_DIRECT_BUFFER;  i++)
    {	    /**  Compare device and root name  **/
        for (p = direct_cache[i].root_equ_names;
	     p != (struct root_equ_names_tag *)NULL;  p = p->next)
        {
	    strcpy(s1, p->equ_name);
	    s1[ strlen(s1)-1 ] = EOS;	    /**   Delete ']'  **/
 
            if (strstr (f, s1))
            {
                break;			    /**   Root is an ancestor  **/
            }
        }
	
	if (p != (struct root_equ_names_tag *)NULL)
	{
	    /*
	    **  Insert the newly created directory into the tree
	    **/
	    if (add_node(
		&direct_cache[i].root,
		f,
		(struct node_tag *)NULL) == DX__ERROR)
	    {
		return DX__ERROR;
	    }
 
 
	    /*
	    **	    Rebuild the directory tree
	    **/
 
	    traverse_tree(
		direct_cache[i].root, (struct node_tag *)NULL, 1, 1, dummy);
	}
    }
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    delete_from_direct_cache(e, errmsg)
char *e;
char *errmsg;
{
    static _align (QUADWORD) int logicalQ[2];
 
    struct logical_queue_entry_tag *E;
    unsigned long int status;
    int number_of_bytes;
    char *cp;
    int i;
    char f[MAXFILESPEC+1];
    struct node_tag *current,
		    *downnode,
		    *upnode,
		    *leftnode,
		    *rightnode;
    int len;
    char s1[MAXFILESPEC+1],
	 s2[MAXFILESPEC+1];
    int allocate_size = sizeof (struct node_tag);
    struct root_equ_names_tag *p;
 
    /*
    **	Translate the logical name.
    **	Should only expand to a single name.
    **/
 
    logicalQ[0] = logicalQ[1] = 0;
    trnlnm(e, logicalQ);
    while (_REMQHI (logicalQ, &E) != 3)
    {
	number_of_bytes = strlen(E->equivalent_name)+1;
	if ((cp = strstr (E->equivalent_name, ".000000]")) != NULL)
	{
	    *cp++ = ']';
	    *cp = EOS;
	}
	strcpy(f, E->equivalent_name);
	check_OK(lib$free_vm (
		     &number_of_bytes,
		     &E->equivalent_name,
		     0))
    }
 
    /*
    **	Search queue for deletion.
    **/
 
    for (i = 0;  i < MAX_DIRECT_BUFFER;  i++)
    {
        for (p = direct_cache[i].root_equ_names;
	     p != (struct root_equ_names_tag *)NULL;  p = p->next)
        {
	    strcpy(s1, p->equ_name);
	    s1[ strlen(s1)-1 ] = EOS;	    /**   Delete ']'  **/
 
            if (strstr (f, s1))
            {
                break;			    /**   Root is an ancestor  **/
            }
        }
	
	if (p != (struct root_equ_names_tag *)NULL)
	{
	    if ((current = search_queue_node(direct_cache[i].root, f)) != NULL)
	    {
		/**  Re-link UP node  **/
		if ((upnode = current->up) != (struct node *)NULL)
		    upnode->down = current->down;
 
		/**  Re-link DOWN node  **/
		if ((downnode = current->down) != (struct node *)NULL)
		    downnode->up = upnode;
 
		/*
		**  Re-link RIGHT node if the node deleted was the
		**  first child
		**/
		leftnode = current->left;
		if (leftnode->right == current)	
		{	/**  This is the oldest child  **/
		    if (current->down == NULL)		 /**  No more child  **/
			leftnode->right = (struct node *)NULL;
		    else if (leftnode == downnode->left) /**  Same parent    **/
			leftnode->right = downnode;
		    else
			leftnode->right = (struct node *)NULL;
		}
 
		/**  Free up memory allocated to this node  **/
		lib$free_vm (
			&allocate_size,
			&current,
			0);
	    }
	}
    }
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
static struct node_tag *	search_queue_node(n, f)
struct node_tag *n;
char *f;
{
    struct fil_dx_tag st;
    struct node_tag *m;
    char errmsg[MAXFILESPEC+1];
 
    if (n == (struct node_tag *)NULL)
    {
        return (struct node_tag *)NULL;
    }
    else if (!strcmp(n->full_path_name, f))
    {
        return n;
    }
    else if ((m = search_queue_node(n->right, f)) != (struct node_tag *)NULL)
    {
	return m;
    }
    else if (n->down->left == n->left)
    {
	return search_queue_node(n->down, f);
    }
    else
    {
	return (struct node_tag *)NULL;
    }
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
static int	    free_root_equ(r)
struct root_equ_names_tag **r;
{
    int node_entry_size = sizeof (struct root_equ_names_tag);
 
    if (*r != (struct root_equ_names_tag *)NULL)
    {
        free_root_equ(&((*r)->next));
	check_OK(lib$free_vm (
		    &node_entry_size,
		    r,
		    0))
	*r = (struct root_equ_names_tag *)NULL;
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
static int		    insert_root_equ_name(r, name)
struct root_equ_names_tag **r;
char *name;
{
    int allocate_size = sizeof (struct root_equ_names_tag);
    struct root_equ_names_tag *new;
 
    if (*r != (struct root_equ_names_tag *)NULL)
    {
        insert_root_equ_name(&((*r)->next), name);
    }
    else
    {
        check_OK(lib$get_vm (
			 &allocate_size,
                         &new,
                         0))
	strcpy(new->equ_name, name);
	new->next = (struct root_equ_names_tag *)NULL;
	*r = new;
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
static int	    cmp_root_equ(s, t)
struct root_equ_names_tag *s,
			  *t;
{
    struct root_equ_names_tag *p,
			      *q;
 
    for (p = s; p != (struct root_equ_names_tag *)NULL;  p = p->next)
    {
        for (q = t;  q != (struct root_equ_names_tag *)NULL;  q = q->next)
        {
            if (!strcmp(p->equ_name, q->equ_name))
            {
                break;
            }
        }
        if (q == (struct root_equ_names_tag *)NULL)
        {
            return 0;	    /**  Not found  **/
        }
    }
 
    for (p = t; p != (struct root_equ_names_tag *)NULL;  p = p->next)
    {
        for (q = s;  q != (struct root_equ_names_tag *)NULL;  q = q->next)
        {
            if (!strcmp(p->equ_name, q->equ_name))
            {
                break;
            }
        }
        if (q == (struct root_equ_names_tag *)NULL)
        {
            return 0;	    /**  Not found  **/
        }
    }
 
    return 1;		/**  Same list  **/
}
