mirror of
https://github.com/obarthel/amiga-smbfs.git
synced 2025-12-08 14:58:35 +00:00
360 lines
7.5 KiB
C
360 lines
7.5 KiB
C
/*
|
|
* :ts=4
|
|
*
|
|
* SMB file system wrapper for AmigaOS, using the AmiTCP V3 API
|
|
*
|
|
* Copyright (C) 2000-2019 by Olaf 'Olsen' Barthel <obarthel -at- gmx -dot- net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "smbfs.h"
|
|
|
|
/****************************************************************************/
|
|
|
|
#ifdef USE_SPLAY_TREE
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* This implementation was adapted from Daniel Sleator's March 1992
|
|
* top-down splaying example code.
|
|
*/
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Simple top down splay, not requiring the key to be in the tree. */
|
|
static INLINE struct splay_node *
|
|
splay(splay_key_compare_t compare, struct splay_node * t, const splay_key_t key)
|
|
{
|
|
struct splay_node N, *l, *r, *y;
|
|
int d;
|
|
|
|
memset(&N, 0, sizeof(N));
|
|
|
|
l = r = &N;
|
|
|
|
while((d = (*compare)(key, t->sn_key)) != 0)
|
|
{
|
|
if(d < 0)
|
|
{
|
|
if(t->sn_left == NULL)
|
|
break;
|
|
|
|
if((*compare)(key, t->sn_left->sn_key) < 0)
|
|
{
|
|
/* rotate right */
|
|
y = t->sn_left;
|
|
t->sn_left = y->sn_right;
|
|
y->sn_right = t;
|
|
t = y;
|
|
|
|
if(t->sn_left == NULL)
|
|
break;
|
|
}
|
|
|
|
/* link right */
|
|
r->sn_left = t;
|
|
r = t;
|
|
t = t->sn_left;
|
|
}
|
|
else
|
|
{
|
|
if(t->sn_right == NULL)
|
|
break;
|
|
|
|
if((*compare)(key, t->sn_right->sn_key) > 0)
|
|
{
|
|
/* rotate left */
|
|
y = t->sn_right;
|
|
t->sn_right = y->sn_left;
|
|
y->sn_left = t;
|
|
t = y;
|
|
|
|
if(t->sn_right == NULL)
|
|
break;
|
|
}
|
|
|
|
/* link left */
|
|
l->sn_right = t;
|
|
l = t;
|
|
t = t->sn_right;
|
|
}
|
|
}
|
|
|
|
/* assemble */
|
|
l->sn_right = t->sn_left;
|
|
r->sn_left = t->sn_right;
|
|
t->sn_left = N.sn_right;
|
|
t->sn_right = N.sn_left;
|
|
|
|
return(t);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Try to insert a node into the splay tree. Returns TRUE for success and
|
|
* FALSE otherwise. FALSE indicates that a duplicate key was to be added
|
|
* and could not be stored.
|
|
*/
|
|
BOOL
|
|
splay_tree_add(struct splay_tree * tree, struct splay_node * new_node)
|
|
{
|
|
splay_key_compare_t compare;
|
|
BOOL success = TRUE;
|
|
|
|
ASSERT(tree != NULL && new_node != NULL);
|
|
|
|
compare = tree->st_compare;
|
|
|
|
if(tree->st_root != NULL)
|
|
{
|
|
struct splay_node * t;
|
|
int d;
|
|
|
|
t = splay(compare, tree->st_root, new_node->sn_key);
|
|
|
|
d = (*compare)(new_node->sn_key, t->sn_key);
|
|
|
|
if (d < 0)
|
|
{
|
|
new_node->sn_left = t->sn_left;
|
|
new_node->sn_right = t;
|
|
|
|
t->sn_left = NULL;
|
|
}
|
|
else if (d > 0)
|
|
{
|
|
new_node->sn_right = t->sn_right;
|
|
new_node->sn_left = t;
|
|
|
|
t->sn_right = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Can we add the duplicate to the list? */
|
|
if(tree->st_allow_duplicates)
|
|
{
|
|
new_node->sn_next = t->sn_next;
|
|
t->sn_next = new_node;
|
|
}
|
|
else
|
|
{
|
|
/* We do not allow duplicates in the tree. */
|
|
success = FALSE;
|
|
}
|
|
|
|
/* Splaying the tree changed the root, which we
|
|
* will have to update.
|
|
*/
|
|
new_node = t;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
new_node->sn_left = new_node->sn_right = NULL;
|
|
}
|
|
|
|
tree->st_root = new_node;
|
|
|
|
return(success);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Removes a node from the tree if it's there. Return a pointer to the
|
|
* node or NULL if it could not be removed.
|
|
*/
|
|
struct splay_node *
|
|
splay_tree_remove(
|
|
struct splay_tree * tree,
|
|
struct splay_node * this_node,
|
|
const splay_key_t key)
|
|
{
|
|
struct splay_node * result = NULL;
|
|
|
|
ASSERT(tree != NULL);
|
|
|
|
if(tree->st_root != NULL)
|
|
{
|
|
splay_key_compare_t compare = tree->st_compare;
|
|
struct splay_node * t;
|
|
|
|
t = splay(compare, tree->st_root, key);
|
|
|
|
if((*compare)(t->sn_key, key) == 0)
|
|
{
|
|
struct splay_node * x;
|
|
|
|
/* Are there duplicate keys attached to this node? */
|
|
if(t->sn_next != NULL)
|
|
{
|
|
/* Find and remove a specific node? */
|
|
if(this_node != NULL)
|
|
{
|
|
/* Remove the root? */
|
|
if(this_node == t)
|
|
{
|
|
/* We return the root and install a node
|
|
* from the duplicate list in its place.
|
|
*/
|
|
result = t;
|
|
|
|
/* The next node will do. */
|
|
t = t->sn_next;
|
|
|
|
/* Install a new root, but keep the linkage
|
|
* of the old root.
|
|
*/
|
|
t->sn_left = this_node->sn_left;
|
|
t->sn_right = this_node->sn_right;
|
|
}
|
|
/* Remove one of the duplicates, keeping the current root. */
|
|
else
|
|
{
|
|
struct splay_node * p;
|
|
struct splay_node * n;
|
|
|
|
/* We still have to find the duplicate which we
|
|
* intend to remove.
|
|
*/
|
|
result = NULL;
|
|
|
|
/* Try to find the node to be removed among the duplicates,
|
|
* remove it from the list and return it.
|
|
*/
|
|
for(p = t, n = t->sn_next ; n != NULL ; p = n, n = n->sn_next)
|
|
{
|
|
if(this_node == n)
|
|
{
|
|
/* Remove this node from the list of duplicates. */
|
|
p->sn_next = this_node->sn_next;
|
|
|
|
/* Return this specific duplicate. */
|
|
result = this_node;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* No, any node will do. */
|
|
else
|
|
{
|
|
/* Return a duplicate, and remove it from the list. */
|
|
result = t->sn_next;
|
|
|
|
t->sn_next = result->sn_next;
|
|
}
|
|
}
|
|
/* No duplicates expected; we found what we came for. */
|
|
else
|
|
{
|
|
result = t;
|
|
|
|
if(t->sn_left == NULL)
|
|
{
|
|
x = t->sn_right;
|
|
}
|
|
else
|
|
{
|
|
x = splay(compare, t->sn_left, key);
|
|
|
|
x->sn_right = t->sn_right;
|
|
}
|
|
|
|
t = x;
|
|
}
|
|
}
|
|
|
|
tree->st_root = t;
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Find a key in the tree, then splay the tree when the matching node is found.
|
|
* Returns a pointer to the node found or NULL if none matches.
|
|
*
|
|
* If duplicates are permitted, the splay node returned can contain more
|
|
* than one matching entry in the splay_node->sn_next list.
|
|
*/
|
|
struct splay_node *
|
|
splay_tree_find(struct splay_tree * tree, const splay_key_t key)
|
|
{
|
|
splay_key_compare_t compare;
|
|
struct splay_node * found = NULL;
|
|
struct splay_node * t;
|
|
int d;
|
|
|
|
ASSERT(tree != NULL);
|
|
|
|
compare = tree->st_compare;
|
|
|
|
t = tree->st_root;
|
|
|
|
while(t != NULL)
|
|
{
|
|
d = (*compare)(key, t->sn_key);
|
|
if(d < 0)
|
|
{
|
|
/* Key is smaller than the current node; move left
|
|
* to a smaller node value.
|
|
*/
|
|
t = t->sn_left;
|
|
}
|
|
else if (d > 0)
|
|
{
|
|
/* Key is greater than the current node; move right
|
|
* to a greater node value.
|
|
*/
|
|
t = t->sn_right;
|
|
}
|
|
else
|
|
{
|
|
found = t;
|
|
|
|
/* Found the key. Now splay the tree. */
|
|
if(t != tree->st_root)
|
|
tree->st_root = splay(compare, tree->st_root, key);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(found);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Initialize a splay tree to be empty. By default, duplicate keys
|
|
* are not allowed.
|
|
*/
|
|
void
|
|
splay_tree_init(struct splay_tree *tree, splay_key_compare_t compare)
|
|
{
|
|
ASSERT( tree != NULL );
|
|
|
|
tree->st_root = NULL;
|
|
tree->st_compare = compare;
|
|
tree->st_allow_duplicates = FALSE;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
#endif /* USE_SPLAY_TREE */
|