diff options
author | Gerald Carter <jerry@samba.org> | 2000-07-18 05:12:49 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2000-07-18 05:12:49 +0000 |
commit | 695e596446950f315d973cb4920461fba6d6f53f (patch) | |
tree | 4db9ae5422d5002c8dba82ab1fc32279d9c54e06 /source3/lib | |
parent | 05fdec749d34812c437c8f4dd318af11ebb9561e (diff) | |
download | samba-695e596446950f315d973cb4920461fba6d6f53f.tar.gz samba-695e596446950f315d973cb4920461fba6d6f53f.tar.bz2 samba-695e596446950f315d973cb4920461fba6d6f53f.zip |
I really didn't like the way generic arrays (lists) were
implemented in util_array.c so I wrote a smaller (and simplier
package).
I would like to replace the use of util_array.c functions
in the rest of the source tree if no one objects.
This will be an interface change, but not really a difference
in the functionality provided.
--jerry
(This used to be commit 0863ce3a31e4c76c8356850ac128f6d96ea54917)
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/util_list.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/source3/lib/util_list.c b/source3/lib/util_list.c new file mode 100644 index 0000000000..5593ccb518 --- /dev/null +++ b/source3/lib/util_list.c @@ -0,0 +1,321 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-1999 + Copyright (C) Gerald Carter <jerry@samba.org> 2000 + + 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. +*/ + +/**************************************************************** + In order to make use of the GENERIC_LIST data structure, you + should create wrapper functions around: + + BOOL generic_list_insert() + void* generic_list_remove() + void* generic_list_locate() + + The reason this is necessary is that the GENERIC_LIST uses a + void pointer to store your data structure. This means that + you get no type checking and can create a hetergenous list. + However, you will need to have some way to determine the type + of your data. If you are using a homogenous list, then + wrapper functions are the easiest way. If you are creating + a hetergenous list, then you will need to use the type field + for your arbitrary identifiers. + + TODO: + If neccessary, you can add a few generic_list_*() to do things + like grab from the front (to implement a FIFO queue) or from + the tail (to implement a FILO stack) + ****************************************************************/ + +#include "includes.h" + + +/* + * list variables + */ +static GENERIC_LIST hnds; + + +/**************************************************************** + Initialize the list. This doesn't do much currently. Just make + sure that you call it so we can determine wether the list is + empty or not. + ****************************************************************/ +static void generic_list_init(GENERIC_LIST *l) +{ + + l->head = NULL; + l->tail = NULL; + l->length = 0; + l->initialized = True; + + return; +} + + +/***************************************************************** + Insert some data into the list (appended to the end of the list) + *****************************************************************/ +static BOOL generic_list_insert(GENERIC_LIST *l, + void *item, uint8 type) +{ + /* check for an emtpy list first */ + if (l->length == 0) + { + if ((l->head = malloc(sizeof(struct _list_node))) == NULL) + { + DEBUG(0, ("ERROR: out of memory! Cannot allocate a list node!\n")); + return False; + } + l->head->data = item; + l->head->type = type; + l->head->next = NULL; + l->length++; + l->tail = l->head; + } + + /* we already have an existing list */ + else + { + if ((l->tail->next = malloc(sizeof(struct _list_node))) == NULL) + { + DEBUG(0, ("ERROR: out of memory! Cannot allocate a list node!\n")); + return False; + } + l->tail = l->tail->next; + l->tail->next = NULL; + l->tail->data = item; + l->tail->type = type; + l->length++; + } + + /* return the list pointer in case this was the first node */ + return True; +} + +/**************************************************************** + In order to locate an item in the list we need a pointer to + a compare function for the data items. + + We will return the actual pointer to the item in the list. Not + a copy of the item. + ****************************************************************/ +static void* generic_list_locate (GENERIC_LIST *l, void *search, + BOOL(*cmp)(const void*,const void*)) +{ + struct _list_node *item; + + /* loop through the list in linear order */ + item = l->head; + while (item != NULL) + { + if (cmp(search, item->data)) + return item->data; + else + { + item = item->next; + } + } + + return NULL; +} + + +/*************************************************************** + In order to remove a node from the list, we will need a pointer + to a compare function. The function will return a pointer to + data in the removed node. + + **WARNING** It is the responsibility of the caller to save + the pointer and destroy the data. + ***************************************************************/ + static void* generic_list_remove(GENERIC_LIST *l, void *search, + BOOL(*cmp)(const void*,const void*)) +{ + struct _list_node *item, *tag; + void *data_ptr; + + /* loop through the list in linear order */ + tag = NULL; + item = l->head; + while (item != NULL) + { + /* did we find it? If so remove the node */ + if (cmp(search, item->data)) + { + /* found, so remove the node */ + + /* remove the first item in the list */ + if (item == l->head) + l->head = item->next; + /* remove from the middle or the end */ + else + tag->next = item->next; + + /* check to see if we need to update the tail */ + if (l->tail == item) + l->tail = tag; + + l->length--; + data_ptr = item->data; + free(item); + return data_ptr; + } + /* increment to the nbext node in the list */ + else + { + tag = item; + item = item->next; + } + } + + return NULL; +} + +/************************************************************** + copy a POLICY_HND + *************************************************************/ +BOOL copy_policy_hnd (POLICY_HND *dest, const POLICY_HND *src) +{ + int i; + + /* if we have no destination, return an error */ + if (dest == NULL) + return False; + + /* if the src handle is NULL, then copy 0x00 to + the dest handle */ + if (src == NULL) + { + /* if POLICY_HND internals ever changes, + this will need to be fixed */ + memset (dest->data, 0, POLICY_HND_SIZE); + return True; + } + + /* copy the src handle to the dest */ + for (i=0; i<POLICY_HND_SIZE; i++) + dest->data[i] = src->data[i]; + + return True; +} + +/*************************************************************** + Return True if the to RPC_HND_NODEs are eqivalent in value. + Return False if they are not. Since a POLICY_HND is really + a UUID, two RPC_HND_NODES are considered to be the same if the + POLICY_HND value matches. + + No ordering betweeen the two is attempted. + **************************************************************/ +BOOL compare_rpc_hnd_node(const RPC_HND_NODE *x, + const RPC_HND_NODE *y) +{ + /* only compare valid nodes */ + if (x==NULL || y==NULL) + return FALSE; + + /* if the POLICY_HND field(s) are ever changed, this + will need to be updated. Probably should be a set of + support function for dealing with POLICY_HND */ + return (memcmp(x->hnd.data, y->hnd.data, POLICY_HND_SIZE) == 0); +} + +/*************************************************************** + associate a POLICY_HND with a cli_connection + **************************************************************/ +BOOL RpcHndList_set_connection(const POLICY_HND *hnd, + struct cli_connection *con) +{ + + RPC_HND_NODE *node = NULL; + + /* initialize the list if necessary */ + if (!hnds.initialized) + generic_list_init(&hnds); + + /* allocate a node to insert */ + if ((node=(RPC_HND_NODE*)malloc(sizeof(RPC_HND_NODE))) == NULL) + { + DEBUG(0, ("ERROR: Unable to allocate memory for an RPC_HND_NODE!\n")); + return False; + } + + /* fill in the RPC_HND_NODE */ + copy_policy_hnd (&node->hnd, hnd); + node->cli = con; + + /* insert the node into the list: + The 3rd parameter is set to 0 since we don't care + anything about the type field */ + return (generic_list_insert(&hnds, (void*)node, 0)); +} + +/************************************************************************ + delete a POLICY_HND (and associated cli_connection) from the list + ***********************************************************************/ +BOOL RpcHndList_del_connection(const POLICY_HND *hnd) +{ + RPC_HND_NODE node, *located; + + /* return NULL if the list has not been initialized */ + if (!hnds.initialized) + return False; + + /* fill in the RPC_HND_NODE */ + copy_policy_hnd (&node.hnd, hnd); + node.cli = NULL; + + /* search for the POLICY_HND */ + located = (RPC_HND_NODE*)generic_list_remove(&hnds, &node, + (BOOL(*)(const void*, const void*))compare_rpc_hnd_node); + if (located == NULL) + return False; + + /* delete the information */ + cli_connection_free(located->cli); + free(located); + return True; +} + +/************************************************************************ + search for a POLICY_HND and return a pointer to the associated + cli_connection struct in the list + **********************************************************************/ +struct cli_connection* RpcHndList_get_connection(const POLICY_HND *hnd) +{ + RPC_HND_NODE node, *located; + + /* return NULL if the list has not been initialized */ + if (!hnds.initialized) + return NULL; + + /* fill in the RPC_HND_NODE */ + copy_policy_hnd (&node.hnd, hnd); + node.cli = NULL; + + /* search for the POLICY_HND */ + located = (RPC_HND_NODE*)generic_list_locate(&hnds, &node, + (BOOL(*)(const void*, const void*))compare_rpc_hnd_node); + if (located == NULL) + return NULL; + else + return located->cli; +} + |