diff -r 1fdbf4170ef4 -r b8bf95b39952 src/server/util/plist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/util/plist.c Sat Jan 14 13:53:44 2012 +0100 @@ -0,0 +1,1273 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * MODULE: plist.c + * + * DESCRIPTION: + * + * This module implements property lists. A property list is an + * ordered array of property values. Each property value has an + * handle for some data item, and may have a reference to + * another property list which describes the type of the data + * item. Each property value has a property index which specifies + * its position in the property list. A property value may also + * have a name. Since the data item associated with a property + * value may reference another property list, it is possible to + * construct arbitrary linked structures of property lists. + * + * IMPLEMENTATION NOTES: + */ + +#include "../daemon/netsite.h" +#include "plist.h" +#include "plist_pvt.h" + +int plistHashSizes[] = PLSTSIZES; + +/* + * FUNCTION: PListAssignValue + * + * DESCRIPTION: + * + * This function sets the value and/or type of a defined property + * in given property list. If the property type is specified as + * NULL, it is unchanged. However, the property value is always + * set to the specified value. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pname - the property name + * pvalue - the new property value + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index of the referenced property is + * returned as the function value. Errors are indicated by a + * negative return code as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListAssignValue(PList_t plist, const char *pname, + const void *pvalue, PList_t ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t *pv; + int pindex; + int i; + + if (!plist) return ERRPLUNDEF; + + /* Got a symbol table for this property list? */ + if (pl->pl_symtab) { + + /* Yes, compute hash of specified name */ + i = PListHashName(pl->pl_symtab, pname); + + /* Search hash collision list for matching name */ + for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) { + + if (!strcmp(pname, pv->pv_name)) { + + /* Name match, get property index */ + pindex = pv->pv_pi; + + /* Set the new value */ + pv->pv_value = (char *)pvalue; + + /* Set type if type is given */ + if (ptype) pv->pv_type = (PListStruct_t *)ptype; + + /* Return the property index */ + return pindex; + } + } + } + + /* Error - specified property name is undefined */ + return ERRPLUNDEF; +} + +/* + * FUNCTION: PListCreate + * + * DESCRIPTION: + * + * This function creates a new property list and returns a handle for + * it. It allows the caller to reserve a specified number of + * property indices at the beginning of the list, and also to limit + * the total number of property values that may be added to the list. + * + * ARGUMENTS: + * + * mempool - handle for a memory pool to be associated + * with the new property list + * resvprop - number of reserved property indices + * maxprop - maximum number of properties in list + * (zero or negative imposes no limit) + * flags - unused, reserved, must be zero + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +NSAPI_PUBLIC PList_t +PListCreate(pool_handle_t *mempool, int resvprop, int maxprop, int flags) +{ + PListStruct_t *plist; /* pointer to property list structure */ + int i; + + plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t)); + if (plist) { + + /* Negative maxprop is the same as zero, i.e. no limit */ + if (maxprop < 0) maxprop = 0; + + /* If resvprop and maxprop are both specified, limit resvprop */ + if (resvprop > 0) { + if (maxprop && (resvprop > maxprop)) resvprop = maxprop; + } + else resvprop = 0; + + /* Initialize property list structure */ + plist->pl_mempool = mempool; + plist->pl_symtab = NULL; + plist->pl_maxprop = maxprop; + plist->pl_resvpi = resvprop; + plist->pl_initpi = resvprop; + plist->pl_lastpi = resvprop; + + /* Set initialize size for array of property value pointers */ + plist->pl_cursize = (resvprop) ? resvprop : PLIST_DEFSIZE; + + /* Allocate the initial array of property value pointers */ + plist->pl_ppval = (pb_entry **)pool_malloc(mempool, + (plist->pl_cursize * + sizeof(PLValueStruct_t *))); + if (!plist->pl_ppval) { + + /* Failed - insufficient memory */ + pool_free(mempool, (void *)plist); + plist = NULL; + } + else { + /* NULL out pointers in the reserved index range, if any */ + for (i = 0; i < plist->pl_lastpi; ++i) { + plist->pl_ppval[i] = 0; + } + } + } + + return (PList_t)plist; +} + +/* + * FUNCTION: PListDefProp + * + * DESCRIPTION: + * + * This function creates a new property in a specified property list. + * The 'pindex' argument may be used to request a particular property + * index for the new property. If 'pindex' is greater than zero, + * the specified value is used as the new property's index, provided + * there is no property at that index already. If 'pindex' is zero, + * then the next available property index is assigned to the new + * property. A name may optionally be specified for the new property. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - new property index (or zero) + * pname - new property name (or NULL) + * + * RETURNS: + * + * If successful, the index of the new property is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListDefProp(PList_t plist, int pindex, const char *pname, const int flags) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t *pv; + + if (!plist) return ERRPLUNDEF; + + /* Is pindex specified? */ + if (pindex > 0) { + + /* Yes, is it in the reserved range? */ + if (flags != PLFLG_IGN_RES && pindex > pl->pl_resvpi) { + /* No, error */ + return ERRPLINVPI; + } + + PLValueStruct_t **ppval = (PLValueStruct_t **)(pl->pl_ppval); + if (ppval[pindex - 1]) { + /* Error - property already exists at specified index */ + return ERRPLEXIST; + } + } + else { + + /* Look for a free property index */ + pindex = PListGetFreeIndex(pl); + if (pindex < 1) { + /* Error - no free property index */ + return pindex; + } + } + + /* We have a property index. Create a new property value */ + pv = (PLValueStruct_t *)pool_calloc(pl->pl_mempool, + 1, sizeof(PLValueStruct_t)); + if (!pv) { + + /* Error - insufficient memory */ + return ERRPLNOMEM; + } + + PLValueStruct_t **ppval = (PLValueStruct_t **)(pl->pl_ppval); + pv->pv_pbentry.param = &pv->pv_pbparam; + pv->pv_pi = pindex; + pv->pv_mempool = pl->pl_mempool; + ppval[pindex - 1] = pv; + + /* Name the property if the name was specified */ + if (pname) { + + /* XXX Maybe should delete property if naming fails */ + return PListNameProp(plist, pindex, pname); + } + + /* Return the property index of the new property */ + return pindex; +} + +/* + * FUNCTION: PListDeleteProp + * + * DESCRIPTION: + * + * This function deletes a property from a specified property list. + * The property can be specified by its property index, using a + * pindex value greater than zero, or by its name, by specifying + * pindex as zero and pname as the property name. This does not + * have any effect on the data referenced by the property value, + * if any, nor does it have any effect on the property list that + * describes the property value's type, if any. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index, or zero + * pname - the property name, or NULL + */ + +NSAPI_PUBLIC const void * +PListDeleteProp(PList_t plist, int pindex, const char *pname_in) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t **pvp; + PLValueStruct_t *pv = NULL; + int i; + const void *pvalue = NULL; + char *pname = (char *)pname_in; + + if (!plist) return NULL; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Get the pointer to the property structure */ + pv = ppval[pindex - 1]; + pname = 0; + if (pv) { + pname = pv->pv_name; + } + } + + if (pname && pl->pl_symtab) { + + /* Compute hash of specified property name */ + i = PListHashName(pl->pl_symtab, pname); + + /* Search hash collision list for matching name */ + for (pvp = &pl->pl_symtab->pt_hash[i]; *pvp; pvp = &(*pvp)->pv_next) { + + pv = *pvp; + if (!strcmp(pname, pv->pv_name)) { + + /* Found it. Get its index and remove it. */ + pindex = pv->pv_pi; + *pvp = pv->pv_next; + pl->pl_symtab->pt_nsyms--; + break; + } + pv = NULL; + } + } + + /* Found the indicated property by index or name? */ + if (pv) { + + /* Yes, remove it from the property list */ + ppval[pindex - 1] = NULL; + + /* Free the property name, if any */ + if (pv->pv_name) { + pool_free(pv->pv_mempool, (void *)(pv->pv_name)); + } + pvalue = pv->pv_value; + + /* Free the property */ + pool_free(pv->pv_mempool, (void *)pv); + } + return(pvalue); +} + +/* + * FUNCTION: PListFindValue + * + * DESCRIPTION: + * + * This function retrieves the value and type of a property with a + * specified property name. If the pvalue argument is non-NULL, + * it specifies a location in which to return the property value. + * Similarly, if ptype is non-NULL, it specifies where the property + * list describing the property type is to be returned. If a + * property has no value, the value returned for pvalue is NULL. + * If a property has no type, the value returned for ptype is NULL. + * A property can have a value, a type, both, or neither. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pname - pointer to property name string + * pvalue - property value return pointer + * ptype - property type return pointer + * + * RETURNS: + * + * If successful, the index of the referenced property is returned + * as the function value. Errors are indicated by a negative + * return code as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListFindValue(PList_t plist, const char *pname, void **pvalue, PList_t *ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t *pv; + int pindex; + int i; + + if (!plist) return ERRPLUNDEF; + + /* Got a symbol table for this property list? */ + if (pl->pl_symtab) { + + /* Yes, compute hash of specified name */ + i = PListHashName(pl->pl_symtab, pname); + + /* Search hash collision list for matching name */ + for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) { + + if (!strcmp(pname, pv->pv_name)) { + + /* Name match, get property index */ + pindex = pv->pv_pi; + + /* Return the value if requested */ + if (pvalue) *pvalue = (void *)(pv->pv_value); + + /* Return the type if requested */ + if (ptype) *ptype = (PList_t)(pv->pv_type); + + /* Return the property index */ + return pindex; + } + } + } + + /* Error - specified property name is undefined */ + return ERRPLUNDEF; +} + +/* + * FUNCTION: PListInitProp + * + * DESCRIPTION: + * + * This function combines the functions of PListDefProp() and + * PListSetValue(), defining a new property and assigning it an + * initial value and optionally a type and/or a name. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - a reserved property index, or zero + * pname - the new property name, or NULL + * pvalue - the new property value + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListInitProp(PList_t plist, int pindex, const char *pname, + const void *pvalue, PList_t ptype) +{ + int rv; + + if (!plist) return ERRPLUNDEF; + + /* Create the property */ + rv = PListDefProp(plist, pindex, pname, PLFLG_USE_RES); + if (rv > 0) { + + /* If that worked, set the value and type */ + rv = PListSetValue(plist, rv, pvalue, ptype); + } + + return rv; +} + +/* + * FUNCTION: PListNew + * + * DESCRIPTION: + * + * This function creates a new property list, using the specified + * memory pool for allocating the internal data structures used to + * represent it. If the mempool argument is NULL, the default + * memory pool is used. + * + * ARGUMENTS: + * + * mempool - handle for a memory pool to be associated + * with the new property list + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +NSAPI_PUBLIC PList_t +PListNew(pool_handle_t *mempool) +{ + /* Just call PListCreate with default parameters */ + return PListCreate(mempool, 0, 0, 0); +} + +/* + * FUNCTION: PListDestroy + * + * DESCRIPTION: + * + * This function destroys a specified property list. This means + * that any dynamic memory which was allocated as a result of calls + * to the property list API is freed to the memory pool from which + * it was allocated. Property value data is not freed, nor are + * any property lists associated with property types. + * + * ARGUMENTS: + * + * plist - handle for the property list + */ + +void +PListDestroy(PList_t plist) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + int i; + + if (!plist) return; + + /* Free the property name symbol table if any */ + if (pl->pl_symtab) { + pool_free(pl->pl_mempool, (void *)(pl->pl_symtab)); + } + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Loop over the initialized property indices */ + for (i = 0; i < pl->pl_initpi; ++i) { + + /* Got a property here? */ + pv = ppval[i]; + if (pv) { + + /* Free the property name string if any */ + if (pv->pv_name) { + pool_free(pv->pv_mempool, (void *)(pv->pv_name)); + } + + /* Free the property value structure */ + pool_free(pv->pv_mempool, (void *)pv); + } + } + + /* Free the array of pointers to property values */ + pool_free(pl->pl_mempool, (void *)ppval); + + /* Free the property list head */ + pool_free(pl->pl_mempool, (void *)pl); +} + +/* + * FUNCTION: PListGetValue + * + * DESCRIPTION: + * + * This function retrieves the value and type of the property with + * the property index given by pindex in the specified property + * list. The pindex argument must specify the index of a defined + * property. If the pvalue argument is non-NULL, it specifies a + * location in which to return the property value. Similarly, if + * ptype is non-NULL, it specifies where the property list + * describing the property type is to be returned. If a property + * has no value, the value returned for pvalue is NULL. If a + * property has no type, the value returned for ptype is NULL. A + * property can have a value, a type, both, or neither. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * pvalue - property value return pointer + * ptype - property type return pointer + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListGetValue(PList_t plist, int pindex, void **pvalue, PList_t *ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + + if (!plist) return ERRPLUNDEF; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ppval[pindex - 1]; + if (pv) { + + /* Yes, return the value if requested */ + if (pvalue) *pvalue = (void *)(pv->pv_value); + + /* Return the type if requested */ + if (ptype) *ptype = (PList_t)(pv->pv_type); + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListHash + * + * DESCRIPTION: + * + * This function hashes a given string. + * + * ARGUMENTS: + * + * string - pointer to the string to hash + * + * RETURNS: + * + * The hash value is returned as the function value. + */ + +unsigned int +PListHash(const char *string) +{ + unsigned int hashval = 0; /* hash value */ + + while (*string) { + hashval = (hashval<<5) ^ (*string++ & 0x7f); + } + + return hashval; +} + +/* + * FUNCTION: PListHashName + * + * DESCRIPTION: + * + * This function hashes a given property name for a specified + * symbol table. It produces a value that can be used as an + * index in the pt_hash array associated with the symbol table. + * + * ARGUMENTS: + * + * symtab - pointer to the symbol table + * pname - pointer to the property name string + * + * RETURNS: + * + * The hash index is returned as the function value. + */ + +int +PListHashName(PLSymbolTable_t *symtab, const char *pname) +{ + return PListHash(pname) % PLSIZENDX(symtab->pt_sizendx); +} + +/* + * FUNCTION: PListNameProp + * + * DESCRIPTION: + * + * This function assigns a name to a defined property with the + * property index, pindex. If the property has an existing name, + * it will be replaced with the name specified by pname. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * pname - the new property name + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListNameProp(PList_t plist, int pindex, const char *pname) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t *pv; + PLSymbolTable_t *pt; + int i; + + if (!plist) return ERRPLUNDEF; + + pt = pl->pl_symtab; + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ((PLValueStruct_t **)(pl->pl_ppval))[pindex - 1]; + if (pv) { + + /* If it has a name already, unname it */ + if (pv->pv_name) { + PLValueStruct_t **pvp; + + /* Get hash bucket index */ + i = PListHashName(pt, pv->pv_name); + + /* Seach hash collision list for this property */ + for (pvp = &pt->pt_hash[i]; + *pvp; pvp = &(*pvp)->pv_next) { + + if (*pvp == pv) { + + /* Remove it from the list */ + *pvp = pv->pv_next; + pt->pt_nsyms--; + break; + } + } + + /* Free the current name string */ + pool_free(pv->pv_mempool, (void *)(pv->pv_name)); + } + + /* Got a new name? */ + if (pname) { + + /* Allocate/grow the symbol table as needed */ + pt = PListSymbolTable(pl); + if (!pt) { + return ERRPLNOMEM; + } + + /* Duplicate the name string */ + pv->pv_name = pool_strdup(pv->pv_mempool, (char *)pname); + + /* Add name to symbol table */ + i = PListHashName(pt, pname); + pv->pv_next = pt->pt_hash[i]; + pt->pt_hash[i] = pv; + pt->pt_nsyms++; + } + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListSetType + * + * DESCRIPTION: + * + * This function sets the property type of the defined property + * with the property index, pindex. The property list describing + * the property type is specified by ptype. If ptype is NULL, + * the property type will be set to be undefined (NULL). + * + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListSetType(PList_t plist, int pindex, PList_t ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + + if (!plist) return ERRPLUNDEF; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ppval[pindex - 1]; + if (pv) { + + /* Yes, set the new type */ + pv->pv_type = ptype; + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListSetValue + * + * DESCRIPTION: + * + * This function sets the value and optionally the type of a + * defined property in a given property list. The pindex argument + * specifies the property index, which must be greater than zero. + * The ptype argument specifies a property list that describes the + * property type. If ptype is NULL, the property type, if any, is + * unchanged by this function. However, the property value is + * always set to the value given by pvalue. + * + * ARGUMENTS: + * + * plist - handle for the property list + * pindex - the property index + * pvalue - the new property value + * ptype - the new property type, or NULL + * + * RETURNS: + * + * If successful, the property index (pindex) is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +NSAPI_PUBLIC int +PListSetValue(PList_t plist, int pindex, const void *pvalue, PList_t ptype) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + + if (!plist) return ERRPLUNDEF; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Check for valid property index */ + if ((pindex > 0) && (pindex <= pl->pl_initpi)) { + + /* Does the property exist? */ + pv = ppval[pindex - 1]; + if (pv) { + + /* Yes, set the new value */ + pv->pv_value = (char *)pvalue; + + /* Set type if type is given */ + if (ptype) pv->pv_type = (PListStruct_t *)ptype; + + /* Successful return */ + return pindex; + } + } + + /* Error - invalid property index or non-existent property */ + return ERRPLINVPI; +} + +/* + * FUNCTION: PListEnumerate + * + * DESCRIPTION: + * + * This function walks through a specified property list + * calling a user supplied function with the property + * name and value as parameters. + * + * ARGUMENTS: + * + * plist - handle for the property list + * user_func - handle for the user function + */ + +NSAPI_PUBLIC void +PListEnumerate(PList_t plist, PListFunc_t *user_func, void *user_data) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + int i; + + if (!plist) return; + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Loop over the initialized property indices */ + for (i = 0; i < pl->pl_initpi; ++i) { + + /* Got a property here? */ + pv = ppval[i]; + if (pv) { + (*user_func)(pv->pv_name, pv->pv_value, user_data); + } + + } + +} + +/* + * FUNCTION: PListCreateDuplicate + * + * DESCRIPTION: + * + * This function creates a new property list and returns a handle for + * it. The source plist provides the new plists parameters. + * + * ARGUMENTS: + * + * src_plist - source plist to duplicate + * mempool - handle for a memory pool to be associated + * with the new property list, only + * used if flags is set to PLFLG_NEW_MPOOL + * flags - if PLFLG_NEW_MPOOL uses new_mempool + * parameter + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +static PList_t +PListCreateDuplicate(PList_t src_plist, pool_handle_t *new_mempool, int flags) +{ + PListStruct_t *plist; /* pointer to property list structure */ + int i; + pool_handle_t *mempool; + + mempool = (flags == PLFLG_NEW_MPOOL) ? new_mempool : src_plist->pl_mempool; + + plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t)); + if (plist) { + + /* Initialize property list structure */ + plist->pl_mempool = mempool; + plist->pl_symtab = NULL; + plist->pl_maxprop = src_plist->pl_maxprop; + plist->pl_resvpi = src_plist->pl_resvpi; + plist->pl_initpi = src_plist->pl_initpi; + plist->pl_lastpi = src_plist->pl_lastpi; + + /* Set initialize size for array of property value pointers */ + plist->pl_cursize = src_plist->pl_cursize; + + /* Allocate the initial array of property value pointers */ + plist->pl_ppval = (pb_entry **)pool_malloc(mempool, + (plist->pl_cursize * + sizeof(PLValueStruct_t *))); + if (!plist->pl_ppval) { + + /* Failed - insufficient memory */ + pool_free(mempool, (void *)plist); + plist = NULL; + } + else { + /* NULL out pointers in the reserved index range, if any */ + for (i = 0; i < plist->pl_lastpi; ++i) { + plist->pl_ppval[i] = 0; + } + } + } + + return (PList_t)plist; +} + + +/* + * FUNCTION: PListDuplicate + * + * DESCRIPTION: + * + * This function duplicates a specified PList_t. + * + * ARGUMENTS: + * + * plist - handle for the property list + * mempool - handle for a memory pool to be associated + * with the new property list + * resvprop - number of reserved property indices + * maxprop - maximum number of properties in list + * (zero or negative imposes no limit) + * flags - unused, reserved, must be zero + * + * RETURNS: + * + * If successful, the function return value is a handle for the new + * property list. Otherwise NULL is returned. + */ + +NSAPI_PUBLIC PList_t +PListDuplicate(PList_t plist, pool_handle_t *new_mempool, int flags) +{ + PListStruct_t *pl = (PListStruct_t *)plist; + PLValueStruct_t **ppval; + PLValueStruct_t *pv; + int i; + int rv = 0; + PList_t new_plist; + + if (!plist) return NULL; + + new_plist = PListCreateDuplicate(plist, new_mempool, flags); + if (new_plist == NULL) { + return(NULL); + } + + ppval = (PLValueStruct_t **)(pl->pl_ppval); + + /* Loop over the initialized property indices */ + for (i = 0; i < pl->pl_initpi; ++i) { + + /* Got a property here? */ + pv = ppval[i]; + if (pv) { + /* Create the property */ + rv = PListDefProp(new_plist, i + 1, pv->pv_name, PLFLG_IGN_RES); + if (rv > 0) { + + /* If that worked, set the value and type */ + rv = PListSetValue(new_plist, rv, pv->pv_value, pv->pv_type); + } + + if ( rv <= 0 ) { + PListDestroy(new_plist); + return(NULL); + } + } + + } + + return(new_plist); +} + +/* + * FUNCTION: PListGetPool + * + * DESCRIPTION: + * + * This function returns the memory pool the PList is allocated from. + * + * ARGUMENTS: + * + * plist - handle for the property list + * + * RETURNS: + * + * The memory pool address, which can be NULL. + */ + +NSAPI_PUBLIC pool_handle_t * +PListGetPool(PList_t plist) +{ + if (!plist) return NULL; + + return(plist->pl_mempool); +} + +/* + * FUNCTION: PListGetFreeIndex + * + * DESCRIPTION: + * + * This function returns an available property index. + * + * ARGUMENTS: + * + * plist - handle for the property list + * + * RETURNS: + * + * If successful, an available property index is returned as the + * function value. Errors are indicated by a negative return code + * as defined in plist.h. + */ + +int +PListGetFreeIndex(PListStruct_t *pl) +{ + PLValueStruct_t **ppval = (PLValueStruct_t **)(pl->pl_ppval); + int wrapped; + int i; + + /* + * Look for a free property index, starting at pl_lastpi + 1. + * (Note that i is the property index - 1) + */ + for (wrapped = 0, i = pl->pl_lastpi; ;) { + + /* Are we in an initialized part of the array? */ + if (i < pl->pl_initpi) { + + /* Yes, use this index if it's free */ + if (ppval[i] == 0) break; + + /* Otherwise step to the next one */ + ++i; + } + else { + + /* Have we reached the end yet? */ + if (i < pl->pl_cursize) { + + /* + * We are above the highest initialized index, but + * still within the allocated size. An index in + * this range can be used with no further checks. + */ + ppval[i] = 0; + } + else { + + /* + * It's looking like time to grow the array, but + * first go back and look for an unused, unreserved + * index that might have been freed. + */ + if (!wrapped) { + + i = pl->pl_resvpi; + wrapped = 1; + continue; + } + + /* + * Grow the array unless there is a specified maximum + * size and we've reached it. + */ + i = pl->pl_cursize; + if (pl->pl_maxprop && (i > pl->pl_maxprop)) { + + /* Error - property list is full */ + return ERRPLFULL; + } + + /* Increase planned size of list */ + int cursize = i + PLIST_DEFGROW; + + /* Reallocate the array of property value pointers */ + ppval = (PLValueStruct_t **)pool_realloc(pl->pl_mempool, + (void *)ppval, + (cursize * sizeof(PLValueStruct_t *))); + if (!ppval) { + + /* Error - insufficient memory */ + return ERRPLNOMEM; + } + + /* Initialize the first new entry and select it */ + ppval[i] = NULL; + pl->pl_ppval = (pb_entry **)ppval; + pl->pl_cursize = cursize; + } + + /* Update the highest initialized index value */ + pl->pl_initpi = i + 1; + break; + } + } + + /* Set the starting point for the next allocation */ + pl->pl_lastpi = i + 1; + + return i + 1; +} + +/* + * FUNCTION: PListSymbolTable + * + * DESCRIPTION: + * + * This function allocates or grows a property list's symbol table as + * needed. + * + * ARGUMENTS: + * + * plist - handle for the property list + * + * RETURNS: + * + * If successful, a pointer to the symbol table is returned as the + * function value. Errors are indicated by a NULL return code. + */ + +PLSymbolTable_t * +PListSymbolTable(PListStruct_t *pl) +{ + PLSymbolTable_t *pt; + int i; + + pt = pl->pl_symtab; + + /* Is there a hash table? */ + if (!pl->pl_symtab) { + + /* No, create one */ + pt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1, PLHASHSIZE(0)); + + pl->pl_symtab = pt; + } + else { + + /* Is it time to grow the hash table? */ + i = PLSIZENDX(pt->pt_sizendx); + if ((pt->pt_sizendx < PLMAXSIZENDX) && pt->pt_nsyms >= (i + i)) { + + PLSymbolTable_t *npt; + + /* Yes, allocate the new table */ + npt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1, + PLHASHSIZE(pt->pt_sizendx+1)); + if (npt) { + npt->pt_sizendx = pt->pt_sizendx + 1; + npt->pt_nsyms = pt->pt_nsyms; + + /* Rehash all the names into the new table, preserving order */ + for (i = 0; i < PLSIZENDX(pt->pt_sizendx); ++i) { + /* While there are names at this hash index... */ + while (pt->pt_hash[i]) { + PLValueStruct_t **pvp; + int j; + + /* Find the last name at this hash index */ + for (pvp = &pt->pt_hash[i]; (*pvp)->pv_next; pvp = &(*pvp)->pv_next); + + /* Move the name to the new table */ + j = PListHashName(npt, (*pvp)->pv_name); + (*pvp)->pv_next = npt->pt_hash[j]; + npt->pt_hash[j] = (*pvp); + + /* Remove the name from the old table */ + *pvp = NULL; + } + } + + pl->pl_symtab = npt; + + /* Free the old symbol table */ + pool_free(pl->pl_mempool, (void *)pt); + pt = npt; + } + } + } + + return pl->pl_symtab; +}