diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2007-10-11 21:09:42 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2007-10-11 21:09:42 (GMT) |
commit | e5413fa795c68dda46c11aee4a3615f52377b0df (patch) | |
tree | 23ddfdc3e1aa280fe7093b079942b49c906660c6 /src/H5Pint.c | |
parent | 8e4bcb5fee17d87d07ab0672439ed391731c96b8 (diff) | |
download | hdf5-e5413fa795c68dda46c11aee4a3615f52377b0df.zip hdf5-e5413fa795c68dda46c11aee4a3615f52377b0df.tar.gz hdf5-e5413fa795c68dda46c11aee4a3615f52377b0df.tar.bz2 |
[svn-r14202] Description:
Move H5Pregister our of old "compat v1.6" section and add it to the
versioned symbols.
Add simple regression test for H5Pregister1()
Split H5P.c source file into H5P/H5Pint/H5Pdeprec files.
Tested on:
FreeBSD/32 6.2 (duty) in debug mode
FreeBSD/64 6.2 (liberty) w/C++ & FORTRAN, in debug mode
Linux/32 2.6 (kagiso) w/PGI compilers, w/C++ & FORTRAN, w/threadsafe,
in debug mode
Linux/64-amd64 2.6 (smirom) w/default API=1.6.x, w/C++ & FORTRAN,
in production mode
Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN,
in production mode
Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN,
w/szip filter, in production mode
Mac OS X/32 10.4.10 (amazon) in debug mode
Diffstat (limited to 'src/H5Pint.c')
-rw-r--r-- | src/H5Pint.c | 4448 |
1 files changed, 4448 insertions, 0 deletions
diff --git a/src/H5Pint.c b/src/H5Pint.c new file mode 100644 index 0000000..3147020 --- /dev/null +++ b/src/H5Pint.c @@ -0,0 +1,4448 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu> + * + * Purpose: Generic Property Functions + */ + +/****************/ +/* Module Setup */ +/****************/ + +#define H5P_PACKAGE /*suppress error about including H5Ppkg */ + +/* Interface initialization */ +#define H5_INTERFACE_INIT_FUNC H5P_init_interface + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Ppkg.h" /* Property lists */ + +/****************/ +/* Local Macros */ +/****************/ + +#define H5P_DEFAULT_SKIPLIST_HEIGHT 8 + + +/******************/ +/* Local Typedefs */ +/******************/ + +/* Typedef for checking for duplicate class names in parent class */ +typedef struct { + const H5P_genclass_t *parent; /* Pointer to parent class */ + const char *name; /* Pointer to name to check */ +} H5P_check_class_t; + + +/********************/ +/* Local Prototypes */ +/********************/ + +/* General helper routines */ +static H5P_genprop_t *H5P_dup_prop(H5P_genprop_t *oprop, H5P_prop_within_t type); +static herr_t H5P_free_prop(H5P_genprop_t *prop); +static int H5P_cmp_prop(const H5P_genprop_t *prop1, const H5P_genprop_t *prop2); + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* + * Predefined property list classes. These are initialized at runtime by + * H5P_init_interface() in this source file. + */ +hid_t H5P_CLS_ROOT_g = FAIL; +hid_t H5P_CLS_OBJECT_CREATE_g = FAIL; +hid_t H5P_CLS_FILE_CREATE_g = FAIL; +hid_t H5P_CLS_FILE_ACCESS_g = FAIL; +hid_t H5P_CLS_DATASET_CREATE_g = FAIL; +hid_t H5P_CLS_DATASET_ACCESS_g = FAIL; +hid_t H5P_CLS_DATASET_XFER_g = FAIL; +hid_t H5P_CLS_FILE_MOUNT_g = FAIL; +hid_t H5P_CLS_GROUP_CREATE_g = FAIL; +hid_t H5P_CLS_GROUP_ACCESS_g = FAIL; +hid_t H5P_CLS_DATATYPE_CREATE_g = FAIL; +hid_t H5P_CLS_DATATYPE_ACCESS_g = FAIL; +hid_t H5P_CLS_ATTRIBUTE_CREATE_g = FAIL; +hid_t H5P_CLS_OBJECT_COPY_g = FAIL; +hid_t H5P_CLS_LINK_CREATE_g = FAIL; +hid_t H5P_CLS_LINK_ACCESS_g = FAIL; +hid_t H5P_CLS_STRING_CREATE_g = FAIL; + +/* + * Predefined property lists for each predefined class. These are initialized + * at runtime by H5P_init_interface() in this source file. + */ +hid_t H5P_LST_FILE_CREATE_g = FAIL; +hid_t H5P_LST_FILE_ACCESS_g = FAIL; +hid_t H5P_LST_DATASET_CREATE_g = FAIL; +hid_t H5P_LST_DATASET_ACCESS_g = FAIL; +hid_t H5P_LST_DATASET_XFER_g = FAIL; +hid_t H5P_LST_FILE_MOUNT_g = FAIL; +hid_t H5P_LST_GROUP_CREATE_g = FAIL; +hid_t H5P_LST_GROUP_ACCESS_g = FAIL; +hid_t H5P_LST_DATATYPE_CREATE_g = FAIL; +hid_t H5P_LST_DATATYPE_ACCESS_g = FAIL; +hid_t H5P_LST_ATTRIBUTE_CREATE_g = FAIL; +hid_t H5P_LST_OBJECT_COPY_g = FAIL; +hid_t H5P_LST_LINK_CREATE_g = FAIL; +hid_t H5P_LST_LINK_ACCESS_g = FAIL; + +/* Root property list class library initialization object */ +const H5P_libclass_t H5P_CLS_ROOT[1] = {{ + "root", /* Class name for debugging */ + NULL, /* Parent class ID */ + &H5P_CLS_ROOT_g, /* Pointer to class ID */ + NULL, /* Pointer to default property list ID */ + NULL, /* Default property registration routine */ + NULL, /* Class creation callback */ + NULL, /* Class creation callback info */ + NULL, /* Class copy callback */ + NULL, /* Class copy callback info */ + NULL, /* Class close callback */ + NULL /* Class close callback info */ +}}; + +/* Group access property list class library initialization object */ +/* (move to proper source code file when used for real) */ +const H5P_libclass_t H5P_CLS_GACC[1] = {{ + "group access", /* Class name for debugging */ + &H5P_CLS_LINK_ACCESS_g, /* Parent class ID */ + &H5P_CLS_GROUP_ACCESS_g, /* Pointer to class ID */ + &H5P_LST_GROUP_ACCESS_g, /* Pointer to default property list ID */ + NULL, /* Default property registration routine */ + NULL, /* Class creation callback */ + NULL, /* Class creation callback info */ + NULL, /* Class copy callback */ + NULL, /* Class copy callback info */ + NULL, /* Class close callback */ + NULL /* Class close callback info */ +}}; + +/* Dataset access property list class library initialization object */ +/* (move to proper source code file when used for real) */ +const H5P_libclass_t H5P_CLS_DACC[1] = {{ + "dataset access", /* Class name for debugging */ + &H5P_CLS_LINK_ACCESS_g, /* Parent class ID */ + &H5P_CLS_DATASET_ACCESS_g, /* Pointer to class ID */ + &H5P_LST_DATASET_ACCESS_g, /* Pointer to default property list ID */ + NULL, /* Default property registration routine */ + NULL, /* Class creation callback */ + NULL, /* Class creation callback info */ + NULL, /* Class copy callback */ + NULL, /* Class copy callback info */ + NULL, /* Class close callback */ + NULL /* Class close callback info */ +}}; + +/* Datatype creation property list class library initialization object */ +/* (move to proper source code file when used for real) */ +const H5P_libclass_t H5P_CLS_TCRT[1] = {{ + "datatype create", /* Class name for debugging */ + &H5P_CLS_OBJECT_CREATE_g, /* Parent class ID */ + &H5P_CLS_DATATYPE_CREATE_g, /* Pointer to class ID */ + &H5P_LST_DATATYPE_CREATE_g, /* Pointer to default property list ID */ + NULL, /* Default property registration routine */ + NULL, /* Class creation callback */ + NULL, /* Class creation callback info */ + NULL, /* Class copy callback */ + NULL, /* Class copy callback info */ + NULL, /* Class close callback */ + NULL /* Class close callback info */ +}}; + +/* Datatype access property list class library initialization object */ +/* (move to proper source code file when used for real) */ +const H5P_libclass_t H5P_CLS_TACC[1] = {{ + "datatype access", /* Class name for debugging */ + &H5P_CLS_LINK_ACCESS_g, /* Parent class ID */ + &H5P_CLS_DATATYPE_ACCESS_g, /* Pointer to class ID */ + &H5P_LST_DATATYPE_ACCESS_g, /* Pointer to default property list ID */ + NULL, /* Default property registration routine */ + NULL, /* Class creation callback */ + NULL, /* Class creation callback info */ + NULL, /* Class copy callback */ + NULL, /* Class copy callback info */ + NULL, /* Class close callback */ + NULL /* Class close callback info */ +}}; + + +/* Library property list classes defined in other code modules */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_OCRT[1]; /* Object creation */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_STRCRT[1]; /* String create */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_LACC[1]; /* Link access */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_GCRT[1]; /* Group create */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_OCPY[1]; /* Object copy */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_FCRT[1]; /* File creation */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_FACC[1]; /* File access */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_DCRT[1]; /* Dataset creation */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_DXFR[1]; /* Data transfer */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_FMNT[1]; /* File mount */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_ACRT[1]; /* Attribute creation */ +H5_DLLVAR const H5P_libclass_t H5P_CLS_LCRT[1]; /* Link creation */ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Track the revision count of a class, to make comparisons faster */ +static unsigned H5P_next_rev = 0; +#define H5P_GET_NEXT_REV (H5P_next_rev++) + +/* List of all property list classes in the library */ +/* (order here is not important, they will be initialized in the proper + * order according to their parent class dependencies) + */ +static H5P_libclass_t const * const init_class[] = { + H5P_CLS_ROOT, /* Root */ + H5P_CLS_OCRT, /* Object create */ + H5P_CLS_STRCRT, /* String create */ + H5P_CLS_LACC, /* Link access */ + H5P_CLS_GCRT, /* Group create */ + H5P_CLS_OCPY, /* Object copy */ + H5P_CLS_GACC, /* Group access */ + H5P_CLS_FCRT, /* File creation */ + H5P_CLS_FACC, /* File access */ + H5P_CLS_DCRT, /* Dataset creation */ + H5P_CLS_DACC, /* Dataset access */ + H5P_CLS_DXFR, /* Data transfer */ + H5P_CLS_FMNT, /* File mount */ + H5P_CLS_TCRT, /* Datatype creation */ + H5P_CLS_TACC, /* Datatype access */ + H5P_CLS_ACRT, /* Attribute creation */ + H5P_CLS_LCRT /* Link creation */ +}; + +/* Declare a free list to manage the H5P_genclass_t struct */ +H5FL_DEFINE_STATIC(H5P_genclass_t); + +/* Declare a free list to manage the H5P_genprop_t struct */ +H5FL_DEFINE_STATIC(H5P_genprop_t); + +/* Declare a free list to manage the H5P_genplist_t struct */ +H5FL_DEFINE_STATIC(H5P_genplist_t); + + +/*-------------------------------------------------------------------------- + NAME + H5P_do_prop_cb1 + PURPOSE + Internal routine to call a property list callback routine and update + the property list accordingly. + USAGE + herr_t H5P_do_prop_cb1(slist,prop,cb) + H5SL_t *slist; IN/OUT: Skip list to hold changed properties + H5P_genprop_t *prop; IN: Property to call callback for + H5P_prp_cb1_t *cb; IN: Callback routine to call + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Calls the callback routine passed in. If the callback routine changes + the property value, then the property is duplicated and added to skip list. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5P_do_prop_cb1(H5SL_t *slist, H5P_genprop_t *prop, H5P_prp_cb1_t cb) +{ + void *tmp_value=NULL; /* Temporary value buffer */ + H5P_genprop_t *pcopy=NULL; /* Copy of property to insert into skip list */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_do_prop_cb1); + + /* Allocate space for a temporary copy of the property value */ + if(NULL == (tmp_value = H5MM_malloc(prop->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for temporary property value"); + HDmemcpy(tmp_value,prop->value,prop->size); + + /* Call "type 1" callback ('create', 'copy' or 'close') */ + if(cb(prop->name,prop->size,tmp_value) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, FAIL,"Property callback failed"); + + /* Check if the property value changed */ + if(HDmemcmp(tmp_value,prop->value,prop->size)) { + /* Make a copy of the class's property */ + if((pcopy=H5P_dup_prop(prop,H5P_PROP_WITHIN_LIST)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property"); + + /* Copy the changed value into the new property */ + HDmemcpy(pcopy->value,tmp_value,prop->size); + + /* Insert the changed property into the property list */ + if(H5P_add_prop(slist,pcopy) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into skip list"); + } /* end if */ + +done: + /* Release the temporary value buffer */ + if(tmp_value!=NULL) + H5MM_xfree(tmp_value); + + /* Cleanup on failure */ + if(ret_value<0) { + if(pcopy!=NULL) + H5P_free_prop(pcopy); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5P_do_prop_cb1() */ + + +/*------------------------------------------------------------------------- + * Function: H5P_init + * + * Purpose: Initialize the interface from some other layer. + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Saturday, March 4, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5P_init(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5P_init, FAIL) + /* FUNC_ENTER() does all the work */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P_init() */ + + +/*-------------------------------------------------------------------------- +NAME + H5P_init_interface -- Initialize interface-specific information +USAGE + herr_t H5P_init_interface() +RETURNS + Non-negative on success/Negative on failure +DESCRIPTION + Initializes any interface-specific data or routines. +--------------------------------------------------------------------------*/ +static herr_t +H5P_init_interface(void) +{ + size_t tot_init; /* Total # of classes initialized */ + size_t pass_init; /* # of classes initialized in each pass */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_init_interface) + + /* + * Initialize the Generic Property class & object groups. + */ + if(H5I_register_type(H5I_GENPROP_CLS, (size_t)H5I_GENPROPCLS_HASHSIZE, 0, (H5I_free_t)H5P_close_class) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, FAIL, "unable to initialize ID group") + if(H5I_register_type(H5I_GENPROP_LST, (size_t)H5I_GENPROPOBJ_HASHSIZE, 0, (H5I_free_t)H5P_close) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTINIT, FAIL, "unable to initialize ID group") + + /* Repeatedly pass over the list of property list classes for the library, + * initializing each class if it's parent class is initialized, until no + * more progress is made. + */ + tot_init = 0; + do { + size_t u; /* Local index variable */ + + /* Reset pass initialization counter */ + pass_init = 0; + + /* Make a pass over all the library's property list classes */ + for(u = 0; u < NELMTS(init_class); u++) { + H5P_libclass_t const *lib_class = init_class[u]; /* Current class to operate on */ + + /* Check if the current class hasn't been initialized and can be now */ + HDassert(lib_class->class_id); + if(*lib_class->class_id == (-1) && (lib_class->par_class_id == NULL + || *lib_class->par_class_id > 0)) { + H5P_genclass_t *par_pclass = NULL; /* Parent class of new class */ + H5P_genclass_t *new_pclass; /* New property list class created */ + + /* Sanity check - only the root class is not allowed to have a parent class */ + HDassert(lib_class->par_class_id || lib_class == H5P_CLS_ROOT); + + /* Check for parent class */ + if(lib_class->par_class_id) { + /* Get the pointer to the parent class */ + if(NULL == (par_pclass = H5I_object(*lib_class->par_class_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class") + } /* end if */ + + /* Allocate the new class */ + if(NULL == (new_pclass = H5P_create_class(par_pclass, lib_class->name, 1, lib_class->create_func, lib_class->create_data, lib_class->copy_func, lib_class->copy_data, lib_class->close_func, lib_class->close_data))) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "class initialization failed") + + /* Call routine to register properties for class */ + if(lib_class->reg_prop_func && (*lib_class->reg_prop_func)(new_pclass) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register properties") + + /* Register the new class */ + if((*lib_class->class_id = H5I_register(H5I_GENPROP_CLS, new_pclass)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register property list class") + + /* Only register the default property list if it hasn't been created yet */ + if(lib_class->def_plist_id && *lib_class->def_plist_id == (-1)) { + /* Register the default property list for the new class*/ + if((*lib_class->def_plist_id = H5P_create_id(new_pclass)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register default property list for class") + } /* end if */ + + /* Increment class initialization counters */ + pass_init++; + tot_init++; + } /* end if */ + } /* end for */ + } while(pass_init > 0); + + /* Verify that all classes were initialized */ + HDassert(tot_init == NELMTS(init_class)); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5P_init_interface() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_term_interface + PURPOSE + Terminate various H5P objects + USAGE + void H5P_term_interface() + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Release the atom group and any other resources allocated. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Can't report errors... + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +int +H5P_term_interface(void) +{ + int nlist=0; + int nclass=0; + int n=0; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_term_interface); + + if(H5_interface_initialize_g) { + /* Destroy HDF5 library property classes & lists */ + + /* Check if there are any open property list classes or lists */ + nclass = H5I_nmembers(H5I_GENPROP_CLS); + nlist = H5I_nmembers(H5I_GENPROP_LST); + n=nclass+nlist; + + /* If there are any open classes or groups, attempt to get rid of them. */ + if(n) { + /* Clear the lists */ + if(nlist>0) { + H5I_clear_type(H5I_GENPROP_LST, FALSE); + + /* Reset the default property lists, if they've been closed */ + if(H5I_nmembers(H5I_GENPROP_LST)==0) { + H5P_LST_FILE_CREATE_g = + H5P_LST_FILE_ACCESS_g = + H5P_LST_DATASET_CREATE_g = + H5P_LST_DATASET_ACCESS_g = + H5P_LST_DATASET_XFER_g = + H5P_LST_GROUP_CREATE_g = + H5P_LST_GROUP_ACCESS_g = + H5P_LST_DATATYPE_CREATE_g = + H5P_LST_DATATYPE_ACCESS_g = + H5P_LST_ATTRIBUTE_CREATE_g = + H5P_LST_OBJECT_COPY_g = + H5P_LST_LINK_CREATE_g = + H5P_LST_LINK_ACCESS_g = + H5P_LST_FILE_MOUNT_g = (-1); + } /* end if */ + } /* end if */ + + /* Only attempt to close the classes after all the lists are closed */ + if(nlist==0 && nclass>0) { + H5I_clear_type(H5I_GENPROP_CLS, FALSE); + + /* Reset the default property lists, if they've been closed */ + if(H5I_nmembers(H5I_GENPROP_CLS)==0) { + H5P_CLS_ROOT_g = + H5P_CLS_OBJECT_CREATE_g = + H5P_CLS_FILE_CREATE_g = + H5P_CLS_FILE_ACCESS_g = + H5P_CLS_DATASET_CREATE_g = + H5P_CLS_DATASET_ACCESS_g = + H5P_CLS_DATASET_XFER_g = + H5P_CLS_GROUP_CREATE_g = + H5P_CLS_GROUP_ACCESS_g = + H5P_CLS_DATATYPE_CREATE_g = + H5P_CLS_DATATYPE_ACCESS_g = + H5P_CLS_STRING_CREATE_g = + H5P_CLS_ATTRIBUTE_CREATE_g = + H5P_CLS_OBJECT_COPY_g = + H5P_CLS_LINK_CREATE_g = + H5P_CLS_LINK_ACCESS_g = + H5P_CLS_FILE_MOUNT_g = (-1); + } /* end if */ + } /* end if */ + } else { + H5I_dec_type_ref(H5I_GENPROP_LST); + n++; /*H5I*/ + H5I_dec_type_ref(H5I_GENPROP_CLS); + n++; /*H5I*/ + + H5_interface_initialize_g = 0; + } + } + FUNC_LEAVE_NOAPI(n); +} + + +/*-------------------------------------------------------------------------- + NAME + H5P_copy_pclass + PURPOSE + Internal routine to copy a generic property class + USAGE + hid_t H5P_copy_pclass(pclass) + H5P_genclass_t *pclass; IN: Property class to copy + RETURNS + Success: valid property class ID on success (non-negative) + Failure: negative + DESCRIPTION + Copy a property class and return the ID. This routine does not make + any callbacks. (They are only make when operating on property lists). + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +H5P_genclass_t * +H5P_copy_pclass(H5P_genclass_t *pclass) +{ + H5P_genclass_t *new_pclass = NULL; /* Property list class copied */ + H5P_genprop_t *pcopy; /* Copy of property to insert into class */ + H5P_genclass_t *ret_value=NULL; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_copy_pclass); + + assert(pclass); + + /* + * Create new property class object + */ + + /* Create the new property list class */ + if(NULL==(new_pclass=H5P_create_class(pclass->parent, pclass->name, 0, pclass->create_func, pclass->create_data, pclass->copy_func, pclass->copy_data, pclass->close_func, pclass->close_data))) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, NULL, "unable to create property list class"); + + /* Copy the properties registered for this class */ + if(pclass->nprops>0) { + H5SL_node_t *curr_node; /* Current node in skip list */ + + /* Walk through the properties in the old class */ + curr_node=H5SL_first(pclass->props); + while(curr_node!=NULL) { + /* Make a copy of the class's property */ + if((pcopy=H5P_dup_prop(H5SL_item(curr_node),H5P_PROP_WITHIN_CLASS)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, NULL,"Can't copy property"); + + /* Insert the initialized property into the property list */ + if(H5P_add_prop(new_pclass->props,pcopy) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, NULL,"Can't insert property into class"); + + /* Increment property count for class */ + new_pclass->nprops++; + + /* Get the next property node in the list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Set the return value */ + ret_value=new_pclass; + +done: + if(ret_value==NULL && new_pclass) + H5P_close_class(new_pclass); + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_copy_pclass() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_copy_plist + PURPOSE + Internal routine to copy a generic property list + USAGE + hid_t H5P_copy_plist(old_plist_id) + hid_t old_plist_id; IN: Property list ID to copy + RETURNS + Success: valid property list ID on success (non-negative) + Failure: negative + DESCRIPTION + Copy a property list and return the ID. This routine calls the + class 'copy' callback after any property 'copy' callbacks are called + (assuming all property 'copy' callbacks return successfully). + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hid_t +H5P_copy_plist(H5P_genplist_t *old_plist) +{ + H5P_genclass_t *tclass; /* Temporary class pointer */ + H5P_genplist_t *new_plist=NULL; /* New property list generated from copy */ + H5P_genprop_t *tmp; /* Temporary pointer to properties */ + H5P_genprop_t *new_prop; /* New property created for copy */ + hid_t new_plist_id; /* Property list ID of new list created */ + H5SL_node_t *curr_node; /* Current node in skip list */ + H5SL_t *seen=NULL; /* Skip list containing properties already seen */ + size_t nseen; /* Number of items 'seen' */ + hbool_t has_parent_class; /* Flag to indicate that this property list's class has a parent */ + hid_t ret_value=FAIL; /* return value */ + + FUNC_ENTER_NOAPI(H5P_copy_plist, FAIL); + + assert(old_plist); + + /* + * Create new property list object + */ + + /* Allocate room for the property list */ + if(NULL==(new_plist = H5FL_CALLOC(H5P_genplist_t))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL,"memory allocation failed"); + + /* Set class state */ + new_plist->pclass = old_plist->pclass; + new_plist->nprops = 0; /* Initially the plist has the same number of properties as the class */ + new_plist->class_init = 0; /* Initially, wait until the class callback finishes to set */ + + /* Initialize the skip list to hold the changed properties */ + if((new_plist->props = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for changed properties"); + + /* Create the skip list for deleted properties */ + if((new_plist->del = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for deleted properties"); + + /* Create the skip list to hold names of properties already seen + * (This prevents a property in the class hierarchy from having it's + * 'create' callback called, if a property in the class hierarchy has + * already been seen) + */ + if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT))== NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties"); + nseen = 0; + + /* Cycle through the deleted properties & copy them into the new list's deleted section */ + if(H5SL_count(old_plist->del)>0) { + curr_node=H5SL_first(old_plist->del); + while(curr_node) { + char *new_name; /* Pointer to new name */ + + /* Duplicate string for insertion into new deleted property skip list */ + if((new_name=H5MM_xstrdup((char *)H5SL_item(curr_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE,H5E_NOSPACE,FAIL,"memory allocation failed"); + + /* Insert property name into deleted list */ + if(H5SL_insert(new_plist->del,new_name,new_name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into deleted skip list"); + + /* Add property name to "seen" list */ + if(H5SL_insert(seen,new_name,new_name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list"); + nseen++; + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Cycle through the properties and copy them also */ + if(H5SL_count(old_plist->props)>0) { + curr_node=H5SL_first(old_plist->props); + while(curr_node) { + /* Get a pointer to the node's property */ + tmp=H5SL_item(curr_node); + + /* Make a copy of the list's property */ + if((new_prop=H5P_dup_prop(tmp,H5P_PROP_WITHIN_LIST)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property"); + + /* Call property copy callback, if it exists */ + if(new_prop->copy) { + if((new_prop->copy)(new_prop->name,new_prop->size,new_prop->value) < 0) { + H5P_free_prop(new_prop); + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property"); + } /* end if */ + } /* end if */ + + /* Insert the initialized property into the property list */ + if(H5P_add_prop(new_plist->props,new_prop) < 0) { + H5P_free_prop(new_prop); + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into list"); + } /* end if */ + + /* Add property name to "seen" list */ + if(H5SL_insert(seen,new_prop->name,new_prop->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list"); + nseen++; + + /* Increment the number of properties in list */ + new_plist->nprops++; + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* + * Check for copying class properties (up through list of parent classes also), + * initialize each with default value & make property 'copy' callback. + */ + tclass=old_plist->pclass; + has_parent_class=(tclass!=NULL && tclass->parent!=NULL && tclass->parent->nprops>0); + while(tclass!=NULL) { + if(tclass->nprops>0) { + /* Walk through the properties in the old class */ + curr_node=H5SL_first(tclass->props); + while(curr_node!=NULL) { + /* Get pointer to property from node */ + tmp=H5SL_item(curr_node); + + /* Only "copy" properties we haven't seen before */ + if(nseen==0 || H5SL_search(seen,tmp->name) == NULL) { + /* Call property creation callback, if it exists */ + if(tmp->copy) { + /* Call the callback & insert changed value into skip list (if necessary) */ + if(H5P_do_prop_cb1(new_plist->props,tmp,tmp->copy) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't create property"); + } /* end if */ + + /* Add property name to "seen" list, if we have other classes to work on */ + if(has_parent_class) { + if(H5SL_insert(seen,tmp->name,tmp->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list"); + nseen++; + } /* end if */ + + /* Increment the number of properties in list */ + new_plist->nprops++; + } /* end if */ + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* Increment the number of property lists derived from class */ + if(H5P_access_class(new_plist->pclass,H5P_MOD_INC_LST) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, FAIL,"Can't increment class ref count"); + + /* Get an atom for the property list */ + if((new_plist_id = H5I_register(H5I_GENPROP_LST, new_plist)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list"); + + /* Save the property list ID in the property list struct, for use in the property class's 'close' callback */ + new_plist->plist_id=new_plist_id; + + /* Call the class callback (if it exists) now that we have the property list ID */ + if(new_plist->pclass->copy_func!=NULL) { + if((new_plist->pclass->copy_func)(new_plist_id,old_plist->plist_id,old_plist->pclass->copy_data) < 0) { + /* Delete ID, ignore return value */ + H5I_remove(new_plist_id); + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, FAIL,"Can't initialize property"); + } /* end if */ + } /* end if */ + + /* Set the class initialization flag */ + new_plist->class_init=1; + + /* Set the return value */ + ret_value=new_plist_id; + +done: + /* Release the list of 'seen' properties */ + if(seen!=NULL) + H5SL_close(seen); + + if(ret_value<0 && new_plist) + H5P_close(new_plist); + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_copy_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_dup_prop + PURPOSE + Internal routine to duplicate a property + USAGE + H5P_genprop_t *H5P_dup_prop(oprop) + H5P_genprop_t *oprop; IN: Pointer to property to copy + H5P_prop_within_t type; IN: Type of object the property will be inserted into + RETURNS + Returns a pointer to the newly created duplicate of a property on success, + NULL on failure. + DESCRIPTION + Allocates memory and copies property information into a new property object. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5P_genprop_t * +H5P_dup_prop(H5P_genprop_t *oprop, H5P_prop_within_t type) +{ + H5P_genprop_t *prop=NULL; /* Pointer to new property copied */ + H5P_genprop_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_dup_prop); + + assert(oprop); + assert(type!=H5P_PROP_WITHIN_UNKNOWN); + + /* Allocate the new property */ + if(NULL==(prop = H5FL_MALLOC (H5P_genprop_t))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* Copy basic property information */ + HDmemcpy(prop,oprop,sizeof(H5P_genprop_t)); + + /* Check if we should duplicate the name or share it */ + + /* Duplicating property for a class */ + if(type==H5P_PROP_WITHIN_CLASS) { + assert(oprop->type==H5P_PROP_WITHIN_CLASS); + assert(oprop->shared_name==0); + + /* Duplicate name */ + prop->name = H5MM_xstrdup(oprop->name); + } /* end if */ + /* Duplicating property for a list */ + else { + /* Check if we are duplicating a property from a list or a class */ + + /* Duplicating a property from a list */ + if(oprop->type==H5P_PROP_WITHIN_LIST) { + /* If the old property's name wasn't shared, we have to copy it here also */ + if(!oprop->shared_name) + prop->name = H5MM_xstrdup(oprop->name); + } /* end if */ + /* Duplicating a property from a class */ + else { + assert(oprop->type==H5P_PROP_WITHIN_CLASS); + assert(oprop->shared_name==0); + + /* Share the name */ + prop->shared_name=1; + + /* Set the type */ + prop->type=type; + } /* end else */ + } /* end else */ + + /* Duplicate current value, if it exists */ + if(oprop->value!=NULL) { + assert(prop->size>0); + if(NULL==(prop->value = H5MM_malloc (prop->size))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + HDmemcpy(prop->value,oprop->value,prop->size); + } /* end if */ + + /* Set return value */ + ret_value=prop; + +done: + /* Free any resources allocated */ + if(ret_value==NULL) { + if(prop!=NULL) { + if(prop->name!=NULL) + H5MM_xfree(prop->name); + if(prop->value!=NULL) + H5MM_xfree(prop->value); + H5FL_FREE(H5P_genprop_t,prop); + } /* end if */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_dup_prop() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_create_prop + PURPOSE + Internal routine to create a new property + USAGE + H5P_genprop_t *H5P_create_prop(name,size,type,value,prp_create,prp_set, + prp_get,prp_delete,prp_close) + const char *name; IN: Name of property to register + size_t size; IN: Size of property in bytes + H5P_prop_within_t type; IN: Type of object the property will be inserted into + void *value; IN: Pointer to buffer containing value for property + H5P_prp_create_func_t prp_create; IN: Function pointer to property + creation callback + H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback + H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback + H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback + H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback + H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback + H5P_prp_close_func_t prp_close; IN: Function pointer to property close + callback + RETURNS + Returns a pointer to the newly created property on success, + NULL on failure. + DESCRIPTION + Allocates memory and copies property information into a new property object. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5P_genprop_t * +H5P_create_prop(const char *name, size_t size, H5P_prop_within_t type, + const void *value, + H5P_prp_create_func_t prp_create, H5P_prp_set_func_t prp_set, + H5P_prp_get_func_t prp_get, H5P_prp_delete_func_t prp_delete, + H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp, + H5P_prp_close_func_t prp_close) +{ + H5P_genprop_t *prop=NULL; /* Pointer to new property copied */ + H5P_genprop_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_create_prop); + + assert(name); + assert((size>0 && value!=NULL) || (size==0)); + assert(type!=H5P_PROP_WITHIN_UNKNOWN); + + /* Allocate the new property */ + if(NULL==(prop = H5FL_MALLOC (H5P_genprop_t))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* Set the property initial values */ + prop->name = H5MM_xstrdup(name); /* Duplicate name */ + prop->shared_name=0; + prop->size=size; + prop->type=type; + + /* Duplicate value, if it exists */ + if(value!=NULL) { + if(NULL==(prop->value = H5MM_malloc (prop->size))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + HDmemcpy(prop->value,value,prop->size); + } /* end if */ + else + prop->value=NULL; + + /* Set the function pointers */ + prop->create=prp_create; + prop->set=prp_set; + prop->get=prp_get; + prop->del=prp_delete; + prop->copy=prp_copy; + /* Use custom comparison routine if available, otherwise default to memcmp() */ + if(prp_cmp!=NULL) + prop->cmp=prp_cmp; + else + prop->cmp=&memcmp; + prop->close=prp_close; + + /* Set return value */ + ret_value=prop; + +done: + /* Free any resources allocated */ + if(ret_value==NULL) { + if(prop!=NULL) { + if(prop->name!=NULL) + H5MM_xfree(prop->name); + if(prop->value!=NULL) + H5MM_xfree(prop->value); + H5FL_FREE(H5P_genprop_t,prop); + } /* end if */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_create_prop() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_add_prop + PURPOSE + Internal routine to insert a property into a property skip list + USAGE + herr_t H5P_add_prop(slist, prop) + H5SL_t *slist; IN/OUT: Pointer to skip list of properties + H5P_genprop_t *prop; IN: Pointer to property to insert + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Inserts a property into a skip list of properties. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_add_prop(H5SL_t *slist, H5P_genprop_t *prop) +{ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5P_add_prop,FAIL); + + assert(slist); + assert(prop); + assert(prop->type!=H5P_PROP_WITHIN_UNKNOWN); + + /* Insert property into skip list */ + if(H5SL_insert(slist,prop,prop->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into skip list"); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_add_prop() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_find_prop_plist + PURPOSE + Internal routine to check for a property in a property list's skip list + USAGE + H5P_genprop_t *H5P_find_prop(plist, name) + H5P_genplist_t *plist; IN: Pointer to property list to check + const char *name; IN: Name of property to check for + RETURNS + Returns pointer to property on success, NULL on failure. + DESCRIPTION + Checks for a property in a property list's skip list of properties. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5P_genprop_t * +H5P_find_prop_plist(H5P_genplist_t *plist, const char *name) +{ + H5P_genprop_t *ret_value; /* Property pointer return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_find_prop_plist); + + assert(plist); + assert(name); + + /* Check if the property has been deleted from list */ + if(H5SL_search(plist->del,name)!=NULL) { + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,NULL,"can't find property in skip list"); + } /* end if */ + else { + /* Get the property data from the skip list */ + if((ret_value=H5SL_search(plist->props,name)) == NULL) { + H5P_genclass_t *tclass; /* Temporary class pointer */ + + /* Couldn't find property in list itself, start searching through class info */ + tclass=plist->pclass; + while(tclass!=NULL) { + /* Find the property in the class */ + if((ret_value=H5SL_search(tclass->props,name))!=NULL) + /* Got pointer to property - leave now */ + break; + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* Check if we haven't found the property */ + if(ret_value==NULL) + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,NULL,"can't find property in skip list"); + } /* end else */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_find_prop_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_find_prop_pclass + PURPOSE + Internal routine to check for a property in a class skip list + USAGE + H5P_genprop_t *H5P_find_prop_class(pclass, name) + H5P_genclass *pclass; IN: Pointer generic property class to check + const char *name; IN: Name of property to check for + RETURNS + Returns pointer to property on success, NULL on failure. + DESCRIPTION + Checks for a property in a class's skip list of properties. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5P_genprop_t * +H5P_find_prop_pclass(H5P_genclass_t *pclass, const char *name) +{ + H5P_genprop_t *ret_value; /* Property pointer return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_find_prop_pclass); + + assert(pclass); + assert(name); + + /* Get the property from the skip list */ + if((ret_value=H5SL_search(pclass->props,name)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,NULL,"can't find property in skip list"); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_find_prop_pclass() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_free_prop + PURPOSE + Internal routine to destroy a property node + USAGE + herr_t H5P_free_prop(prop) + H5P_genprop_t *prop; IN: Pointer to property to destroy + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Releases all the memory for a property list. Does _not_ call the + properties 'close' callback, that should already have been done. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5P_free_prop(H5P_genprop_t *prop) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_free_prop); + + assert(prop); + + /* Release the property value if it exists */ + if(prop->value) + H5MM_xfree(prop->value); + + /* Only free the name if we own it */ + if(prop->shared_name==0) + H5MM_xfree(prop->name); + + H5FL_FREE(H5P_genprop_t,prop); + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* H5P_free_prop() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_free_prop_cb + PURPOSE + Internal routine to properties from a property skip list + USAGE + herr_t H5P_free_prop_cb(item, key, op_data) + void *item; IN/OUT: Pointer to property + void *key; IN/OUT: Pointer to property key + void *_make_cb; IN: Whether to make property callbacks or not + RETURNS + Returns zero on success, negative on failure. + DESCRIPTION + Calls the property 'close' callback for a property & frees property + info. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5P_free_prop_cb(void *item, void UNUSED *key, void *op_data) +{ + H5P_genprop_t *tprop=(H5P_genprop_t *)item; /* Temporary pointer to property */ + unsigned make_cb=*(unsigned *)op_data; /* Whether to make property 'close' callback */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_free_prop_cb); + + assert(tprop); + + /* Call the close callback and ignore the return value, there's nothing we can do about it */ + if(make_cb && tprop->close!=NULL) + (tprop->close)(tprop->name,tprop->size,tprop->value); + + /* Free the property, ignoring return value, nothing we can do */ + H5P_free_prop(tprop); + + FUNC_LEAVE_NOAPI(0); +} /* H5P_free_prop_cb() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_free_del_name_cb + PURPOSE + Internal routine to free 'deleted' property name + USAGE + herr_t H5P_free_del_name_cb(item, key, op_data) + void *item; IN/OUT: Pointer to deleted name + void *key; IN/OUT: Pointer to key + void *op_data; IN: Operator callback data (unused) + RETURNS + Returns zero on success, negative on failure. + DESCRIPTION + Frees the deleted property name + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5P_free_del_name_cb(void *item, void UNUSED *key, void UNUSED *op_data) +{ + char *del_name=(char *)item; /* Temporary pointer to deleted name */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_free_del_name_cb); + + assert(del_name); + + /* Free the name */ + H5MM_xfree(del_name); + + FUNC_LEAVE_NOAPI(0); +} /* H5P_free_del_name_cb() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_access_class + PURPOSE + Internal routine to increment or decrement list & class dependancies on a + property list class + USAGE + herr_t H5P_access_class(pclass,mod) + H5P_genclass_t *pclass; IN: Pointer to class to modify + H5P_class_mod_t mod; IN: Type of modification to class + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Increment/Decrement the class or list dependancies for a given class. + This routine is the final arbiter on decisions about actually releasing a + class in memory, such action is only taken when the reference counts for + both dependent classes & lists reach zero. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_access_class(H5P_genclass_t *pclass, H5P_class_mod_t mod) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_access_class); + + assert(pclass); + assert(mod>H5P_MOD_ERR && mod<H5P_MOD_MAX); + + switch(mod) { + case H5P_MOD_INC_CLS: /* Increment the dependant class count*/ + pclass->classes++; + break; + + case H5P_MOD_DEC_CLS: /* Decrement the dependant class count*/ + pclass->classes--; + break; + + case H5P_MOD_INC_LST: /* Increment the dependant list count*/ + pclass->plists++; + break; + + case H5P_MOD_DEC_LST: /* Decrement the dependant list count*/ + pclass->plists--; + break; + + case H5P_MOD_INC_REF: /* Increment the ID reference count*/ + /* Reset the deleted flag if incrementing the reference count */ + if(pclass->deleted) + pclass->deleted=0; + pclass->ref_count++; + break; + + case H5P_MOD_DEC_REF: /* Decrement the ID reference count*/ + pclass->ref_count--; + + /* Mark the class object as deleted if reference count drops to zero */ + if(pclass->ref_count==0) + pclass->deleted=1; + break; + + case H5P_MOD_ERR: + case H5P_MOD_MAX: + assert(0 && "Invalid H5P class modification"); + } /* end switch */ + + /* Check if we can release the class information now */ + if(pclass->deleted && pclass->plists==0 && pclass->classes==0 ) { + H5P_genclass_t *par_class=pclass->parent; /* Pointer to class's parent */ + + assert(pclass->name); + H5MM_xfree(pclass->name); + + /* Free the class properties without making callbacks */ + if(pclass->props) { + unsigned make_cb=0; + + H5SL_destroy(pclass->props,H5P_free_prop_cb,&make_cb); + } /* end if */ + + H5FL_FREE(H5P_genclass_t,pclass); + + /* Reduce the number of dependent classes on parent class also */ + if(par_class!=NULL) + H5P_access_class(par_class, H5P_MOD_DEC_CLS); + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* H5P_access_class() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_check_class + PURPOSE + Internal callback routine to check for duplicated names in parent class. + USAGE + int H5P_check_class(obj, id, key) + H5P_genclass_t *obj; IN: Pointer to class + hid_t id; IN: ID of object being looked at + const void *key; IN: Pointer to information used to compare + classes. + RETURNS + Returns >0 on match, 0 on no match and <0 on failure. + DESCRIPTION + Checks whether a property list class has the same parent and name as a + new class being created. This is a callback routine for H5I_search() + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static int +H5P_check_class(void *_obj, hid_t UNUSED id, void *_key) +{ + H5P_genclass_t *obj=(H5P_genclass_t *)_obj; /* Pointer to the class for this ID */ + const H5P_check_class_t *key=(const H5P_check_class_t *)_key; /* Pointer to key information for comparison */ + int ret_value=0; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_check_class); + + assert(obj); + assert(H5I_GENPROP_CLS==H5I_get_type(id)); + assert(key); + + /* Check if the class object has the same parent as the new class */ + if(obj->parent==key->parent) { + /* Check if they have the same name */ + if(HDstrcmp(obj->name,key->name)==0) + ret_value=1; /* Indicate a match */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5P_check_class() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_create_class + PURPOSE + Internal routine to create a new property list class. + USAGE + H5P_genclass_t H5P_create_class(par_class, name, internal, + cls_create, create_data, cls_close, close_data) + H5P_genclass_t *par_class; IN: Pointer to parent class + const char *name; IN: Name of class we are creating + unsigned internal; IN: Whether this is an internal class or not + H5P_cls_create_func_t; IN: The callback function to call when each + property list in this class is created. + void *create_data; IN: Pointer to user data to pass along to class + creation callback. + H5P_cls_copy_func_t; IN: The callback function to call when each + property list in this class is copied. + void *copy_data; IN: Pointer to user data to pass along to class + copy callback. + H5P_cls_close_func_t; IN: The callback function to call when each + property list in this class is closed. + void *close_data; IN: Pointer to user data to pass along to class + close callback. + RETURNS + Returns a pointer to the newly created property list class on success, + NULL on failure. + DESCRIPTION + Allocates memory and attaches a class to the property list class hierarchy. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +H5P_genclass_t * +H5P_create_class(H5P_genclass_t *par_class, const char *name, unsigned internal, + H5P_cls_create_func_t cls_create, void *create_data, + H5P_cls_copy_func_t cls_copy, void *copy_data, + H5P_cls_close_func_t cls_close, void *close_data) +{ + H5P_genclass_t *pclass=NULL; /* Property list class created */ + H5P_genclass_t *ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_create_class, NULL) + + assert(name); + /* Allow internal classes to break some rules */ + /* (This allows the root of the tree to be created with this routine -QAK) */ + if(!internal) { + assert(par_class); + } + + /* Allocate room for the class */ + if(NULL==(pclass = H5FL_CALLOC(H5P_genclass_t))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL,"memory allocation failed"); + + /* Set class state */ + pclass->parent = par_class; + pclass->name = H5MM_xstrdup(name); + pclass->nprops = 0; /* Classes are created without properties initially */ + pclass->plists = 0; /* No properties lists of this class yet */ + pclass->classes = 0; /* No classes derived from this class yet */ + pclass->ref_count = 1; /* This is the first reference to the new class */ + pclass->internal = internal; + pclass->deleted = 0; /* Not deleted yet... :-) */ + pclass->revision = H5P_GET_NEXT_REV; /* Get a revision number for the class */ + + /* Create the skip list for properties */ + if((pclass->props = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for properties"); + + /* Set callback functions and pass-along data */ + pclass->create_func = cls_create; + pclass->create_data = create_data; + pclass->copy_func = cls_copy; + pclass->copy_data = copy_data; + pclass->close_func = cls_close; + pclass->close_data = close_data; + + /* Increment parent class's derived class value */ + if(par_class!=NULL) { + if(H5P_access_class(par_class,H5P_MOD_INC_CLS) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, NULL,"Can't increment parent class ref count"); + } /* end if */ + + /* Set return value */ + ret_value=pclass; + +done: + /* Free any resources allocated */ + if(ret_value==NULL) + if(pclass!=NULL) + H5FL_FREE(H5P_genclass_t,pclass); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5P_create_class() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_create + PURPOSE + Internal routine to create a new property list of a property list class. + USAGE + H5P_genplist_t *H5P_create(class) + H5P_genclass_t *class; IN: Property list class create list from + RETURNS + Returns a pointer to the newly created property list on success, + NULL on failure. + DESCRIPTION + Creates a property list of a given class. If a 'create' callback + exists for the property list class, it is called before the + property list is passed back to the user. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + If this routine is called from a library routine other than + H5P_c, the calling routine is responsible for getting an ID for + the property list and calling the class 'create' callback (if one exists) + and also setting the "class_init" flag. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5P_genplist_t * +H5P_create(H5P_genclass_t *pclass) +{ + H5P_genclass_t *tclass; /* Temporary class pointer */ + H5P_genplist_t *plist=NULL; /* New property list created */ + H5P_genprop_t *tmp; /* Temporary pointer to parent class properties */ + H5SL_t *seen=NULL; /* Skip list to hold names of properties already seen */ + H5P_genplist_t *ret_value; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_create); + + assert(pclass); + + /* + * Create new property list object + */ + + /* Allocate room for the property list */ + if(NULL==(plist = H5FL_CALLOC(H5P_genplist_t))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL,"memory allocation failed"); + + /* Set class state */ + plist->pclass = pclass; + plist->nprops = 0; /* Initially the plist has the same number of properties as the class */ + plist->class_init = 0; /* Initially, wait until the class callback finishes to set */ + + /* Create the skip list for changed properties */ + if((plist->props = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for changed properties"); + + /* Create the skip list for deleted properties */ + if((plist->del = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for deleted properties"); + + /* Create the skip list to hold names of properties already seen + * (This prevents a property in the class hierarchy from having it's + * 'create' callback called, if a property in the class hierarchy has + * already been seen) + */ + if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,NULL,"can't create skip list for seen properties"); + + /* + * Check if we should copy class properties (up through list of parent classes also), + * initialize each with default value & make property 'create' callback. + */ + tclass=pclass; + while(tclass!=NULL) { + if(tclass->nprops>0) { + H5SL_node_t *curr_node; /* Current node in skip list */ + + /* Walk through the properties in the old class */ + curr_node=H5SL_first(tclass->props); + while(curr_node!=NULL) { + /* Get pointer to property from node */ + tmp=H5SL_item(curr_node); + + /* Only "create" properties we haven't seen before */ + if(H5SL_search(seen,tmp->name) == NULL) { + /* Call property creation callback, if it exists */ + if(tmp->create) { + /* Call the callback & insert changed value into skip list (if necessary) */ + if(H5P_do_prop_cb1(plist->props,tmp,tmp->create) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, NULL,"Can't create property"); + } /* end if */ + + /* Add property name to "seen" list */ + if(H5SL_insert(seen,tmp->name,tmp->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,NULL,"can't insert property into seen skip list"); + + /* Increment the number of properties in list */ + plist->nprops++; + } /* end if */ + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* Increment the number of property lists derived from class */ + if(H5P_access_class(plist->pclass,H5P_MOD_INC_LST) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, NULL,"Can't increment class ref count"); + + /* Set return value */ + ret_value=plist; + +done: + /* Release the skip list of 'seen' properties */ + if(seen!=NULL) + H5SL_close(seen); + + /* Release resources allocated on failure */ + if(ret_value==NULL) { + if(plist!=NULL) { + /* Close & free any changed properties */ + if(plist->props) { + unsigned make_cb=1; + + H5SL_destroy(plist->props,H5P_free_prop_cb,&make_cb); + } /* end if */ + + /* Close the deleted property skip list */ + if(plist->del) + H5SL_close(plist->del); + + /* Release the property list itself */ + H5FL_FREE(H5P_genplist_t,plist); + } /* end if */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_create() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_create_id + PURPOSE + Internal routine to create a new property list of a property list class. + USAGE + hid_t H5P_create_id(pclass) + H5P_genclass_t *pclass; IN: Property list class create list from + RETURNS + Returns a valid property list ID on success, FAIL on failure. + DESCRIPTION + Creates a property list of a given class. If a 'create' callback + exists for the property list class, it is called before the + property list is passed back to the user. If 'create' callbacks exist for + any individual properties in the property list, they are called before the + class 'create' callback. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hid_t +H5P_create_id(H5P_genclass_t *pclass) +{ + H5P_genplist_t *plist=NULL; /* Property list created */ + hid_t plist_id=FAIL; /* Property list ID */ + hid_t ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_create_id, FAIL); + + assert(pclass); + + /* Create the new property list */ + if((plist=H5P_create(pclass)) == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCREATE, FAIL, "unable to create property list"); + + /* Get an atom for the property list */ + if((plist_id = H5I_register(H5I_GENPROP_LST, plist)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to atomize property list"); + + /* Save the property list ID in the property list struct, for use in the property class's 'close' callback */ + plist->plist_id=plist_id; + + /* Call the class callback (if it exists) now that we have the property list ID */ + if(plist->pclass->create_func!=NULL) { + if((plist->pclass->create_func)(plist_id,plist->pclass->create_data) < 0) { + /* Delete ID, ignore return value */ + H5I_remove(plist_id); + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, FAIL,"Can't initialize property"); + } /* end if */ + } /* end if */ + + /* Set the class initialization flag */ + plist->class_init=1; + + /* Set the return value */ + ret_value=plist_id; + +done: + if(ret_value<0 && plist) + H5P_close(plist); + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_create_id() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_register + PURPOSE + Internal routine to register a new property in a property list class. + USAGE + herr_t H5P_register(class, name, size, default, prp_create, prp_set, prp_get, prp_close) + H5P_genclass_t *class; IN: Property list class to close + const char *name; IN: Name of property to register + size_t size; IN: Size of property in bytes + void *def_value; IN: Pointer to buffer containing default value + for property in newly created property lists + H5P_prp_create_func_t prp_create; IN: Function pointer to property + creation callback + H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback + H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback + H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback + H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback + H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback + H5P_prp_close_func_t prp_close; IN: Function pointer to property close + callback + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Registers a new property with a property list class. The property will + exist in all property list objects of that class after this routine is + finished. The name of the property must not already exist. The default + property value must be provided and all new property lists created with this + property will have the property value set to the default provided. Any of + the callback routines may be set to NULL if they are not needed. + + Zero-sized properties are allowed and do not store any data in the + property list. These may be used as flags to indicate the presence or + absence of a particular piece of information. The 'default' pointer for a + zero-sized property may be set to NULL. The property 'create' & 'close' + callbacks are called for zero-sized properties, but the 'set' and 'get' + callbacks are never called. + + The 'create' callback is called when a new property list with this + property is being created. H5P_prp_create_func_t is defined as: + typedef herr_t (*H5P_prp_create_func_t)(hid_t prop_id, const char *name, + size_t size, void *initial_value); + where the parameters to the callback function are: + hid_t prop_id; IN: The ID of the property list being created. + const char *name; IN: The name of the property being modified. + size_t size; IN: The size of the property value + void *initial_value; IN/OUT: The initial value for the property being created. + (The 'default' value passed to H5Pregister2) + The 'create' routine may modify the value to be set and those changes will + be stored as the initial value of the property. If the 'create' routine + returns a negative value, the new property value is not copied into the + property and the property list creation routine returns an error value. + + The 'set' callback is called before a new value is copied into the + property. H5P_prp_set_func_t is defined as: + typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name, + size_t size, void *value); + where the parameters to the callback function are: + hid_t prop_id; IN: The ID of the property list being modified. + const char *name; IN: The name of the property being modified. + size_t size; IN: The size of the property value + void *new_value; IN/OUT: The value being set for the property. + The 'set' routine may modify the value to be set and those changes will be + stored as the value of the property. If the 'set' routine returns a + negative value, the new property value is not copied into the property and + the property list set routine returns an error value. + + The 'get' callback is called before a value is retrieved from the + property. H5P_prp_get_func_t is defined as: + typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name, + size_t size, void *value); + where the parameters to the callback function are: + hid_t prop_id; IN: The ID of the property list being queried. + const char *name; IN: The name of the property being queried. + size_t size; IN: The size of the property value + void *value; IN/OUT: The value being retrieved for the property. + The 'get' routine may modify the value to be retrieved and those changes + will be returned to the calling function. If the 'get' routine returns a + negative value, the property value is returned and the property list get + routine returns an error value. + + The 'delete' callback is called when a property is deleted from a + property list. H5P_prp_del_func_t is defined as: + typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name, + size_t size, void *value); + where the parameters to the callback function are: + hid_t prop_id; IN: The ID of the property list the property is deleted from. + const char *name; IN: The name of the property being deleted. + size_t size; IN: The size of the property value + void *value; IN/OUT: The value of the property being deleted. + The 'delete' routine may modify the value passed in, but the value is not + used by the library when the 'delete' routine returns. If the + 'delete' routine returns a negative value, the property list deletion + routine returns an error value but the property is still deleted. + + The 'copy' callback is called when a property list with this + property is copied. H5P_prp_copy_func_t is defined as: + typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size, + void *value); + where the parameters to the callback function are: + const char *name; IN: The name of the property being copied. + size_t size; IN: The size of the property value + void *value; IN: The value of the property being copied. + The 'copy' routine may modify the value to be copied and those changes will be + stored as the value of the property. If the 'copy' routine returns a + negative value, the new property value is not copied into the property and + the property list copy routine returns an error value. + + The 'compare' callback is called when a property list with this + property is compared to another property list. H5P_prp_compare_func_t is + defined as: + typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2, + size_t size); + where the parameters to the callback function are: + const void *value1; IN: The value of the first property being compared. + const void *value2; IN: The value of the second property being compared. + size_t size; IN: The size of the property value + The 'compare' routine may not modify the values to be compared. The + 'compare' routine should return a positive value if VALUE1 is greater than + VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1 + and VALUE2 are equal. + + The 'close' callback is called when a property list with this + property is being destroyed. H5P_prp_close_func_t is defined as: + typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size, + void *value); + where the parameters to the callback function are: + const char *name; IN: The name of the property being closed. + size_t size; IN: The size of the property value + void *value; IN: The value of the property being closed. + The 'close' routine may modify the value passed in, but the value is not + used by the library when the 'close' routine returns. If the + 'close' routine returns a negative value, the property list close + routine returns an error value but the property list is still closed. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + The 'set' callback function may be useful to range check the value being + set for the property or may perform some tranformation/translation of the + value set. The 'get' callback would then [probably] reverse the + transformation, etc. A single 'get' or 'set' callback could handle + multiple properties by performing different actions based on the property + name or other properties in the property list. + + I would like to say "the property list is not closed" when a 'close' + routine fails, but I don't think that's possible due to other properties in + the list being successfully closed & removed from the property list. I + suppose that it would be possible to just remove the properties which have + successful 'close' callbacks, but I'm not happy with the ramifications + of a mangled, un-closable property list hanging around... Any comments? -QAK + + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_register(H5P_genclass_t *pclass, const char *name, size_t size, + const void *def_value, H5P_prp_create_func_t prp_create, H5P_prp_set_func_t prp_set, + H5P_prp_get_func_t prp_get, H5P_prp_delete_func_t prp_delete, + H5P_prp_copy_func_t prp_copy, H5P_prp_compare_func_t prp_cmp, + H5P_prp_close_func_t prp_close) +{ + H5P_genclass_t *new_class; /* New class pointer */ + H5P_genprop_t *new_prop=NULL; /* Temporary property pointer */ + H5P_genprop_t *pcopy; /* Property copy */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5P_register, FAIL); + + assert(pclass); + assert(name); + assert((size>0 && def_value!=NULL) || (size==0)); + + /* Check for duplicate named properties */ + if(H5SL_search(pclass->props,name)!=NULL) + HGOTO_ERROR(H5E_PLIST, H5E_EXISTS, FAIL, "property already exists"); + + /* Check if class needs to be split because property lists or classes have + * been created since the last modification was made to the class. + */ + if(pclass->plists>0 || pclass->classes>0) { + if((new_class=H5P_create_class(pclass->parent,pclass->name, + pclass->internal,pclass->create_func,pclass->create_data, + pclass->copy_func,pclass->copy_data, + pclass->close_func,pclass->close_data)) == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "can't copy class"); + + /* Walk through the skip list of the old class and copy properties */ + if(pclass->nprops>0) { + H5SL_node_t *curr_node; /* Current node in skip list */ + + /* Walk through the properties in the old class */ + curr_node=H5SL_first(pclass->props); + while(curr_node!=NULL) { + /* Make a copy of the class's property */ + if((pcopy=H5P_dup_prop(H5SL_item(curr_node),H5P_PROP_WITHIN_CLASS)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property"); + + /* Insert the initialized property into the property list */ + if(H5P_add_prop(new_class->props,pcopy) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into class"); + + /* Increment property count for class */ + new_class->nprops++; + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Use the new class instead of the old one */ + pclass=new_class; + } /* end if */ + + /* Create property object from parameters */ + if((new_prop=H5P_create_prop(name,size,H5P_PROP_WITHIN_CLASS,def_value,prp_create,prp_set,prp_get,prp_delete,prp_copy,prp_cmp,prp_close)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCREATE, FAIL,"Can't create property"); + + /* Insert property into property list class */ + if(H5P_add_prop(pclass->props,new_prop) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into class"); + + /* Increment property count for class */ + pclass->nprops++; + + /* Update the revision for the class */ + pclass->revision = H5P_GET_NEXT_REV; + +done: + if(ret_value==FAIL) { + if(new_prop!=NULL) { + if(new_prop->name!=NULL) + H5MM_xfree(new_prop->name); + if(new_prop->value!=NULL) + H5MM_xfree(new_prop->value); + H5FL_FREE(H5P_genprop_t,new_prop); + } /* end if */ + } /* end if */ + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_register() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_insert + PURPOSE + Internal routine to insert a new property in a property list. + USAGE + herr_t H5P_insert(plist, name, size, value, prp_set, prp_get, prp_close) + H5P_genplist_t *plist; IN: Property list to add property to + const char *name; IN: Name of property to add + size_t size; IN: Size of property in bytes + void *value; IN: Pointer to the value for the property + H5P_prp_set_func_t prp_set; IN: Function pointer to property set callback + H5P_prp_get_func_t prp_get; IN: Function pointer to property get callback + H5P_prp_delete_func_t prp_delete; IN: Function pointer to property delete callback + H5P_prp_copy_func_t prp_copy; IN: Function pointer to property copy callback + H5P_prp_compare_func_t prp_cmp; IN: Function pointer to property compare callback + H5P_prp_close_func_t prp_close; IN: Function pointer to property close + callback + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Inserts a temporary property into a property list. The property will + exist only in this property list object. The name of the property must not + already exist. The value must be provided unless the property is zero- + sized. Any of the callback routines may be set to NULL if they are not + needed. + + Zero-sized properties are allowed and do not store any data in the + property list. These may be used as flags to indicate the presence or + absence of a particular piece of information. The 'value' pointer for a + zero-sized property may be set to NULL. The property 'close' callback is + called for zero-sized properties, but the 'set' and 'get' callbacks are + never called. + + The 'set' callback is called before a new value is copied into the + property. H5P_prp_set_func_t is defined as: + typedef herr_t (*H5P_prp_set_func_t)(hid_t prop_id, const char *name, + size_t size, void *value); + where the parameters to the callback function are: + hid_t prop_id; IN: The ID of the property list being modified. + const char *name; IN: The name of the property being modified. + size_t size; IN: The size of the property value + void *new_value; IN/OUT: The value being set for the property. + The 'set' routine may modify the value to be set and those changes will be + stored as the value of the property. If the 'set' routine returns a + negative value, the new property value is not copied into the property and + the property list set routine returns an error value. + + The 'get' callback is called before a value is retrieved from the + property. H5P_prp_get_func_t is defined as: + typedef herr_t (*H5P_prp_get_func_t)(hid_t prop_id, const char *name, + size_t size, void *value); + where the parameters to the callback function are: + hid_t prop_id; IN: The ID of the property list being queried. + const char *name; IN: The name of the property being queried. + size_t size; IN: The size of the property value + void *value; IN/OUT: The value being retrieved for the property. + The 'get' routine may modify the value to be retrieved and those changes + will be returned to the calling function. If the 'get' routine returns a + negative value, the property value is returned and the property list get + routine returns an error value. + + The 'delete' callback is called when a property is deleted from a + property list. H5P_prp_del_func_t is defined as: + typedef herr_t (*H5P_prp_del_func_t)(hid_t prop_id, const char *name, + size_t size, void *value); + where the parameters to the callback function are: + hid_t prop_id; IN: The ID of the property list the property is deleted from. + const char *name; IN: The name of the property being deleted. + size_t size; IN: The size of the property value + void *value; IN/OUT: The value of the property being deleted. + The 'delete' routine may modify the value passed in, but the value is not + used by the library when the 'delete' routine returns. If the + 'delete' routine returns a negative value, the property list deletion + routine returns an error value but the property is still deleted. + + The 'copy' callback is called when a property list with this + property is copied. H5P_prp_copy_func_t is defined as: + typedef herr_t (*H5P_prp_copy_func_t)(const char *name, size_t size, + void *value); + where the parameters to the callback function are: + const char *name; IN: The name of the property being copied. + size_t size; IN: The size of the property value + void *value; IN: The value of the property being copied. + The 'copy' routine may modify the value to be copied and those changes will be + stored as the value of the property. If the 'copy' routine returns a + negative value, the new property value is not copied into the property and + the property list copy routine returns an error value. + + The 'compare' callback is called when a property list with this + property is compared to another property list. H5P_prp_compare_func_t is + defined as: + typedef int (*H5P_prp_compare_func_t)( void *value1, void *value2, + size_t size); + where the parameters to the callback function are: + const void *value1; IN: The value of the first property being compared. + const void *value2; IN: The value of the second property being compared. + size_t size; IN: The size of the property value + The 'compare' routine may not modify the values to be compared. The + 'compare' routine should return a positive value if VALUE1 is greater than + VALUE2, a negative value if VALUE2 is greater than VALUE1 and zero if VALUE1 + and VALUE2 are equal. + + The 'close' callback is called when a property list with this + property is being destroyed. H5P_prp_close_func_t is defined as: + typedef herr_t (*H5P_prp_close_func_t)(const char *name, size_t size, + void *value); + where the parameters to the callback function are: + const char *name; IN: The name of the property being closed. + size_t size; IN: The size of the property value + void *value; IN: The value of the property being closed. + The 'close' routine may modify the value passed in, but the value is not + used by the library when the 'close' routine returns. If the + 'close' routine returns a negative value, the property list close + routine returns an error value but the property list is still closed. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + The 'set' callback function may be useful to range check the value being + set for the property or may perform some tranformation/translation of the + value set. The 'get' callback would then [probably] reverse the + transformation, etc. A single 'get' or 'set' callback could handle + multiple properties by performing different actions based on the property + name or other properties in the property list. + + There is no 'create' callback routine for temporary property list + objects, the initial value is assumed to have any necessary setup already + performed on it. + + I would like to say "the property list is not closed" when a 'close' + routine fails, but I don't think that's possible due to other properties in + the list being successfully closed & removed from the property list. I + suppose that it would be possible to just remove the properties which have + successful 'close' callbacks, but I'm not happy with the ramifications + of a mangled, un-closable property list hanging around... Any comments? -QAK + + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_insert(H5P_genplist_t *plist, const char *name, size_t size, + void *value, H5P_prp_set_func_t prp_set, H5P_prp_get_func_t prp_get, + H5P_prp_delete_func_t prp_delete, H5P_prp_copy_func_t prp_copy, + H5P_prp_compare_func_t prp_cmp, H5P_prp_close_func_t prp_close) +{ + H5P_genprop_t *new_prop=NULL; /* Temporary property pointer */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_insert); + + assert(plist); + assert(name); + assert((size>0 && value!=NULL) || (size==0)); + + /* Check for duplicate named properties */ + if(H5SL_search(plist->props,name)!=NULL) + HGOTO_ERROR(H5E_PLIST, H5E_EXISTS, FAIL, "property already exists"); + + /* Check if the property has been deleted */ + if(H5SL_search(plist->del,name)!=NULL) { + /* Remove the property name from the deleted property skip list */ + if(H5SL_remove(plist->del,name) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTDELETE,FAIL,"can't remove property from deleted skip list"); + + /* Fall through to add property to list */ + } /* end if */ + else { + H5P_genclass_t *tclass; /* Temporary class pointer */ + + /* Check if the property is already in the class hierarchy */ + tclass=plist->pclass; + while(tclass!=NULL) { + if(tclass->nprops>0) { + /* Find the property in the class */ + if(H5SL_search(tclass->props,name)!=NULL) + HGOTO_ERROR(H5E_PLIST, H5E_EXISTS, FAIL, "property already exists"); + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* Fall through to add property to list */ + } /* end else */ + + /* Ok to add to property list */ + + /* Create property object from parameters */ + if((new_prop=H5P_create_prop(name,size,H5P_PROP_WITHIN_LIST,value,NULL,prp_set,prp_get,prp_delete,prp_copy,prp_cmp,prp_close)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCREATE, FAIL,"Can't create property"); + + /* Insert property into property list class */ + if(H5P_add_prop(plist->props,new_prop) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into class"); + + /* Increment property count for class */ + plist->nprops++; + +done: + if(ret_value==FAIL) { + if(new_prop!=NULL) { + if(new_prop->name!=NULL) + H5MM_xfree(new_prop->name); + if(new_prop->value!=NULL) + H5MM_xfree(new_prop->value); + H5FL_FREE(H5P_genprop_t,new_prop); + } /* end if */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_insert() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_set + PURPOSE + Internal routine to set a property's value in a property list. + USAGE + herr_t H5P_set(plist, name, value) + H5P_genplist_t *plist; IN: Property list to find property in + const char *name; IN: Name of property to set + void *value; IN: Pointer to the value for the property + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Sets a new value for a property in a property list. The property name + must exist or this routine will fail. If there is a 'set' callback routine + registered for this property, the 'value' will be passed to that routine and + any changes to the 'value' will be used when setting the property value. + The information pointed at by the 'value' pointer (possibly modified by the + 'set' callback) is copied into the property list value and may be changed + by the application making the H5Pset call without affecting the property + value. + + If the 'set' callback routine returns an error, the property value will + not be modified. This routine may not be called for zero-sized properties + and will return an error in that case. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_set(H5P_genplist_t *plist, const char *name, const void *value) +{ + H5P_genclass_t *tclass; /* Temporary class pointer */ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5P_set, FAIL); + + assert(plist); + assert(name); + assert(value); + + /* Check if the property has been deleted */ + if(H5SL_search(plist->del,name)!=NULL) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist"); + + /* Find property in changed list */ + if((prop=H5SL_search(plist->props,name))!=NULL) { + /* Check for property size >0 */ + if(prop->size==0) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size"); + + /* Make a copy of the value and pass to 'set' callback */ + if(prop->set!=NULL) { + void *tmp_value; /* Temporary value for property */ + + /* Make a copy of the current value, in case the callback fails */ + if(NULL==(tmp_value=H5MM_malloc(prop->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed temporary property value"); + HDmemcpy(tmp_value,value,prop->size); + + /* Call user's callback */ + if((*(prop->set))(plist->plist_id,name,prop->size,tmp_value) < 0) { + H5MM_xfree(tmp_value); + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value"); + } /* end if */ + + /* Copy new [possibly unchanged] value into property value */ + HDmemcpy(prop->value,tmp_value,prop->size); + + /* Free the temporary value buffer */ + H5MM_xfree(tmp_value); + } /* end if */ + /* No 'set' callback, just copy value */ + else + HDmemcpy(prop->value,value,prop->size); + } /* end if */ + else { + /* + * Check if we should set class properties (up through list of parent classes also), + * & make property 'set' callback. + */ + tclass=plist->pclass; + while(tclass!=NULL) { + if(tclass->nprops>0) { + /* Find the property in the class */ + if((prop=H5SL_search(tclass->props,name))!=NULL) { + H5P_genprop_t *pcopy; /* Copy of property to insert into skip list */ + + /* Check for property size >0 */ + if(prop->size==0) + HGOTO_ERROR(H5E_PLIST,H5E_BADVALUE,FAIL,"property has zero size"); + + /* Make a copy of the value and pass to 'set' callback */ + if(prop->set!=NULL) { + void *tmp_value; /* Temporary value for property */ + + /* Make a copy of the current value, in case the callback fails */ + if(NULL==(tmp_value=H5MM_malloc(prop->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed temporary property value"); + HDmemcpy(tmp_value,value,prop->size); + + /* Call user's callback */ + if((*(prop->set))(plist->plist_id,name,prop->size,tmp_value) < 0) { + H5MM_xfree(tmp_value); + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value"); + } /* end if */ + + if(HDmemcmp(tmp_value,prop->value,prop->size)) { + /* Make a copy of the class's property */ + if((pcopy=H5P_dup_prop(prop,H5P_PROP_WITHIN_LIST)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCOPY,FAIL,"Can't copy property"); + + /* Copy new value into property value */ + HDmemcpy(pcopy->value,tmp_value,pcopy->size); + + /* Insert the changed property into the property list */ + if(H5P_add_prop(plist->props,pcopy) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert changed property into skip list"); + } /* end if */ + + /* Free the temporary value buffer */ + H5MM_xfree(tmp_value); + } /* end if */ + /* No 'set' callback, just copy value */ + else { + if(HDmemcmp(value,prop->value,prop->size)) { + /* Make a copy of the class's property */ + if((pcopy=H5P_dup_prop(prop,H5P_PROP_WITHIN_LIST)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCOPY,FAIL,"Can't copy property"); + + HDmemcpy(pcopy->value,value,pcopy->size); + + /* Insert the changed property into the property list */ + if(H5P_add_prop(plist->props,pcopy) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert changed property into skip list"); + } /* end if */ + } /* end else */ + + /* Leave */ + HGOTO_DONE(SUCCEED); + } /* end while */ + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* If we get this far, then it wasn't in the list of changed properties, + * nor in the properties in the class hierarchy, indicate an error + */ + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,FAIL,"can't find property in skip list"); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_set() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_exist_plist + PURPOSE + Internal routine to query the existance of a property in a property list. + USAGE + herr_t H5P_exist_plist(plist, name) + H5P_genplist_t *plist; IN: Property list to check + const char *name; IN: Name of property to check for + RETURNS + Success: Positive if the property exists in the property list, zero + if the property does not exist. + Failure: negative value + DESCRIPTION + This routine checks if a property exists within a property list. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5P_exist_plist(H5P_genplist_t *plist, const char *name) +{ + htri_t ret_value=FAIL; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_exist_plist); + + assert(plist); + assert(name); + + /* Check for property in deleted property list */ + if(H5SL_search(plist->del,name)!=NULL) + ret_value=0; + else { + /* Check for property in changed property list */ + if(H5SL_search(plist->props,name)!=NULL) + ret_value=1; + else { + H5P_genclass_t *tclass; /* Temporary class pointer */ + + tclass=plist->pclass; + while(tclass!=NULL) { + if(H5SL_search(tclass->props,name)!=NULL) + HGOTO_DONE(1); + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* If we've reached here, we couldn't find the property */ + ret_value=0; + } /* end else */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_exist_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_exist_pclass + PURPOSE + Internal routine to query the existance of a property in a property class. + USAGE + herr_t H5P_exist_pclass(pclass, name) + H5P_genclass_t *pclass; IN: Property class to check + const char *name; IN: Name of property to check for + RETURNS + Success: Positive if the property exists in the property list, zero + if the property does not exist. + Failure: negative value + DESCRIPTION + This routine checks if a property exists within a property list. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5P_exist_pclass(H5P_genclass_t *pclass, const char *name) +{ + htri_t ret_value=FAIL; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_exist_pclass); + + assert(pclass); + assert(name); + + /* Check for property in property list */ + if(H5SL_search(pclass->props,name) == NULL) + ret_value=0; + else + ret_value=1; + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_exist_pclass() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_size_plist + PURPOSE + Internal routine to query the size of a property in a property list. + USAGE + herr_t H5P_get_size_plist(plist, name) + H5P_genplist_t *plist; IN: Property list to check + const char *name; IN: Name of property to query + size_t *size; OUT: Size of property + RETURNS + Success: non-negative value + Failure: negative value + DESCRIPTION + This routine retrieves the size of a property's value in bytes. Zero- + sized properties are allowed and return a value of 0. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_get_size_plist(H5P_genplist_t *plist, const char *name, size_t *size) +{ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value=SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_get_size_plist); + + assert(plist); + assert(name); + assert(size); + + /* Find property */ + if((prop=H5P_find_prop_plist(plist,name)) == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist"); + + /* Get property size */ + *size=prop->size; + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_get_size_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_size_pclass + PURPOSE + Internal routine to query the size of a property in a property class. + USAGE + herr_t H5P_get_size_pclass(pclass, name) + H5P_genclass_t *pclass; IN: Property class to check + const char *name; IN: Name of property to query + size_t *size; OUT: Size of property + RETURNS + Success: non-negative value + Failure: negative value + DESCRIPTION + This routine retrieves the size of a property's value in bytes. Zero- + sized properties are allowed and return a value of 0. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_get_size_pclass(H5P_genclass_t *pclass, const char *name, size_t *size) +{ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value=SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_get_size_pclass); + + assert(pclass); + assert(name); + assert(size); + + /* Find property */ + if((prop=H5P_find_prop_pclass(pclass,name)) == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist"); + + /* Get property size */ + *size=prop->size; + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_get_size_pclass() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_class + PURPOSE + Internal routine to query the class of a generic property list + USAGE + H5P_genclass_t *H5P_get_class(plist) + H5P_genplist_t *plist; IN: Property list to check + RETURNS + Success: Pointer to the class for a property list + Failure: NULL + DESCRIPTION + This routine retrieves a pointer to the class for a property list. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +H5P_genclass_t * +H5P_get_class(const H5P_genplist_t *plist) +{ + H5P_genclass_t *ret_value; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_get_class); + + HDassert(plist); + + /* Get property size */ + ret_value = plist->pclass; + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_get_class() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_nprops_plist + PURPOSE + Internal routine to query the number of properties in a property list + USAGE + herr_t H5P_get_nprops_plist(plist, nprops) + H5P_genplist_t *plist; IN: Property list to check + size_t *nprops; OUT: Number of properties in the property list + RETURNS + Success: non-negative value + Failure: negative value + DESCRIPTION + This routine retrieves the number of a properties in a property list. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_get_nprops_plist(const H5P_genplist_t *plist, size_t *nprops) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_get_nprops_plist); + + HDassert(plist); + HDassert(nprops); + + /* Get property size */ + *nprops = plist->nprops; + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* H5P_get_nprops_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_nprops_pclass + PURPOSE + Internal routine to query the number of properties in a property class + USAGE + herr_t H5P_get_nprops_pclass(pclass, nprops) + H5P_genclass_t *pclass; IN: Property class to check + size_t *nprops; OUT: Number of properties in the property list + hbool_t recurse; IN: Include properties in parent class(es) also + RETURNS + Success: non-negative value (can't fail) + Failure: negative value + DESCRIPTION + This routine retrieves the number of a properties in a property class. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_get_nprops_pclass(const H5P_genclass_t *pclass, size_t *nprops, hbool_t recurse) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5P_get_nprops_pclass, FAIL) + + HDassert(pclass); + HDassert(nprops); + + /* Get number of properties */ + *nprops = pclass->nprops; + + /* Check if the class is derived, and walk up the chain, if so */ + if(recurse) + while(pclass->parent != NULL) { + pclass = pclass->parent; + *nprops += pclass->nprops; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5P_get_nprops_pclass() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_cmp_prop + PURPOSE + Internal routine to compare two generic properties + USAGE + int H5P_cmp_prop(prop1, prop2) + H5P_genprop_t *prop1; IN: 1st property to compare + H5P_genprop_t *prop1; IN: 2nd property to compare + RETURNS + Success: negative if prop1 "less" than prop2, positive if prop1 "greater" + than prop2, zero if prop1 is "equal" to prop2 + Failure: can't fail + DESCRIPTION + This function compares two generic properties together to see if + they are the same property. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static int +H5P_cmp_prop(const H5P_genprop_t *prop1, const H5P_genprop_t *prop2) +{ + int cmp_value; /* Value from comparison */ + int ret_value = 0; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_cmp_prop); + + HDassert(prop1); + HDassert(prop2); + + /* Check the name */ + if((cmp_value = HDstrcmp(prop1->name, prop2->name)) != 0) + HGOTO_DONE(cmp_value); + + /* Check the size of properties */ + if(prop1->size < prop2->size) HGOTO_DONE(-1); + if(prop1->size > prop2->size) HGOTO_DONE(1); + + /* Check if they both have the same 'create' callback */ + if(prop1->create == NULL && prop2->create != NULL) HGOTO_DONE(-1); + if(prop1->create != NULL && prop2->create == NULL) HGOTO_DONE(1); + if(prop1->create != prop2->create) HGOTO_DONE(-1); + + /* Check if they both have the same 'set' callback */ + if(prop1->set == NULL && prop2->set != NULL) HGOTO_DONE(-1); + if(prop1->set != NULL && prop2->set == NULL) HGOTO_DONE(1); + if(prop1->set != prop2->set) HGOTO_DONE(-1); + + /* Check if they both have the same 'get' callback */ + if(prop1->get == NULL && prop2->get != NULL) HGOTO_DONE(-1); + if(prop1->get != NULL && prop2->get == NULL) HGOTO_DONE(1); + if(prop1->get != prop2->get) HGOTO_DONE(-1); + + /* Check if they both have the same 'delete' callback */ + if(prop1->del == NULL && prop2->del != NULL) HGOTO_DONE(-1); + if(prop1->del != NULL && prop2->del == NULL) HGOTO_DONE(1); + if(prop1->del != prop2->del) HGOTO_DONE(-1); + + /* Check if they both have the same 'copy' callback */ + if(prop1->copy == NULL && prop2->copy != NULL) HGOTO_DONE(-1); + if(prop1->copy != NULL && prop2->copy == NULL) HGOTO_DONE(1); + if(prop1->copy != prop2->copy) HGOTO_DONE(-1); + + /* Check if they both have the same 'compare' callback */ + if(prop1->cmp == NULL && prop2->cmp != NULL) HGOTO_DONE(-1); + if(prop1->cmp != NULL && prop2->cmp == NULL) HGOTO_DONE(1); + if(prop1->cmp != prop2->cmp) HGOTO_DONE(-1); + + /* Check if they both have the same 'close' callback */ + if(prop1->close == NULL && prop2->close != NULL) HGOTO_DONE(-1); + if(prop1->close != NULL && prop2->close == NULL) HGOTO_DONE(1); + if(prop1->close != prop2->close) HGOTO_DONE(-1); + + /* Check if they both have values allocated (or not allocated) */ + if(prop1->value == NULL && prop2->value != NULL) HGOTO_DONE(-1); + if(prop1->value != NULL && prop2->value == NULL) HGOTO_DONE(1); + if(prop1->value != NULL) { + /* Call comparison routine */ + if((cmp_value = prop1->cmp(prop1->value, prop2->value, prop1->size)) != 0) + HGOTO_DONE(cmp_value); + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_cmp_prop() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_cmp_class + PURPOSE + Internal routine to compare two generic property classes + USAGE + int H5P_cmp_class(pclass1, pclass2) + H5P_genclass_t *pclass1; IN: 1st property class to compare + H5P_genclass_t *pclass2; IN: 2nd property class to compare + RETURNS + Success: negative if class1 "less" than class2, positive if class1 "greater" + than class2, zero if class1 is "equal" to class2 + Failure: can't fail + DESCRIPTION + This function compares two generic property classes together to see if + they are the same class. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +int +H5P_cmp_class(const H5P_genclass_t *pclass1, const H5P_genclass_t *pclass2) +{ + H5SL_node_t *tnode1, *tnode2; /* Temporary pointer to property nodes */ + int cmp_value; /* Value from comparison */ + int ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_cmp_class); + + HDassert(pclass1); + HDassert(pclass2); + + /* Use the revision number to quickly check for identical classes */ + if(pclass1->revision == pclass2->revision) + HGOTO_DONE(0); + + /* Check the name */ + if((cmp_value = HDstrcmp(pclass1->name, pclass2->name)) != 0) + HGOTO_DONE(cmp_value); + + /* Check the number of properties */ + if(pclass1->nprops < pclass2->nprops) HGOTO_DONE(-1); + if(pclass1->nprops > pclass2->nprops) HGOTO_DONE(1); + + /* Check the number of property lists created from the class */ + if(pclass1->plists < pclass2->plists) HGOTO_DONE(-1); + if(pclass1->plists > pclass2->plists) HGOTO_DONE(1); + + /* Check the number of classes derived from the class */ + if(pclass1->classes < pclass2->classes) HGOTO_DONE(-1); + if(pclass1->classes > pclass2->classes) HGOTO_DONE(1); + + /* Check the number of ID references open on the class */ + if(pclass1->ref_count < pclass2->ref_count) HGOTO_DONE(-1); + if(pclass1->ref_count > pclass2->ref_count) HGOTO_DONE(1); + + /* Check whether they are internal or not */ + if(pclass1->internal < pclass2->internal) HGOTO_DONE(-1); + if(pclass1->internal > pclass2->internal) HGOTO_DONE(1); + + /* Check whether they are deleted or not */ + if(pclass1->deleted < pclass2->deleted) HGOTO_DONE(-1); + if(pclass1->deleted > pclass2->deleted) HGOTO_DONE(1); + + /* Check whether they have creation callback functions & data */ + if(pclass1->create_func == NULL && pclass2->create_func != NULL) HGOTO_DONE(-1); + if(pclass1->create_func != NULL && pclass2->create_func == NULL) HGOTO_DONE(1); + if(pclass1->create_func != pclass2->create_func) HGOTO_DONE(-1); + if(pclass1->create_data < pclass2->create_data) HGOTO_DONE(-1); + if(pclass1->create_data > pclass2->create_data) HGOTO_DONE(1); + + /* Check whether they have close callback functions & data */ + if(pclass1->close_func == NULL && pclass2->close_func != NULL) HGOTO_DONE(-1); + if(pclass1->close_func != NULL && pclass2->close_func == NULL) HGOTO_DONE(1); + if(pclass1->close_func != pclass2->close_func) HGOTO_DONE(-1); + if(pclass1->close_data < pclass2->close_data) HGOTO_DONE(-1); + if(pclass1->close_data > pclass2->close_data) HGOTO_DONE(1); + + /* Cycle through the properties and compare them also */ + tnode1 = H5SL_first(pclass1->props); + tnode2 = H5SL_first(pclass2->props); + while(tnode1 || tnode2) { + H5P_genprop_t *prop1, *prop2; /* Property for node */ + + /* Check if they both have properties in this skip list node */ + if(tnode1 == NULL && tnode2 != NULL) HGOTO_DONE(-1); + if(tnode1 != NULL && tnode2 == NULL) HGOTO_DONE(1); + + /* Compare the two properties */ + prop1 = H5SL_item(tnode1); + prop2 = H5SL_item(tnode2); + if((cmp_value = H5P_cmp_prop(prop1, prop2)) != 0) + HGOTO_DONE(cmp_value); + + /* Advance the pointers */ + tnode1 = H5SL_next(tnode1); + tnode2 = H5SL_next(tnode2); + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_cmp_class() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_cmp_plist + PURPOSE + Internal routine to compare two generic property lists + USAGE + int H5P_cmp_plist(plist1, plist2) + H5P_genplist_t *plist1; IN: 1st property list to compare + H5P_genplist_t *plist2; IN: 2nd property list to compare + RETURNS + Success: negative if list1 "less" than list2, positive if list1 "greater" + than list2, zero if list1 is "equal" to list2 + Failure: can't fail + DESCRIPTION + This function compares two generic property lists together to see if + they are the same list. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +int +H5P_cmp_plist(const H5P_genplist_t *plist1, const H5P_genplist_t *plist2) +{ + H5SL_node_t *tnode1, *tnode2; /* Temporary pointer to property nodes */ + int cmp_value; /* Value from comparison */ + int ret_value = 0; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_cmp_plist); + + HDassert(plist1); + HDassert(plist2); + + /* Check the number of properties */ + if(plist1->nprops < plist2->nprops) HGOTO_DONE(-1); + if(plist1->nprops > plist2->nprops) HGOTO_DONE(1); + + /* Check whether they've been initialized */ + if(plist1->class_init < plist2->class_init) HGOTO_DONE(-1); + if(plist1->class_init > plist2->class_init) HGOTO_DONE(1); + + /* Check for identical deleted properties */ + if(H5SL_count(plist1->del) > 0) { + /* Check for no deleted properties in plist2 */ + if(H5SL_count(plist2->del) == 0) HGOTO_DONE(1); + + tnode1 = H5SL_first(plist1->del); + tnode2 = H5SL_first(plist2->del); + while(tnode1 || tnode2) { + const char *name1, *name2; /* Name for node */ + + /* Check if they both have properties in this node */ + if(tnode1 == NULL && tnode2 != NULL) HGOTO_DONE(-1); + if(tnode1 != NULL && tnode2 == NULL) HGOTO_DONE(1); + + /* Compare the two deleted properties */ + name1 = H5SL_item(tnode1); + name2 = H5SL_item(tnode2); + if((cmp_value = HDstrcmp(name1, name2)) != 0) + HGOTO_DONE(cmp_value); + + /* Advance the pointers */ + tnode1 = H5SL_next(tnode1); + tnode2 = H5SL_next(tnode2); + } /* end while */ + } /* end if */ + else + if(H5SL_count(plist2->del) > 0) HGOTO_DONE (-1); + + /* Cycle through the changed properties and compare them also */ + if(H5SL_count(plist1->props) > 0) { + /* Check for no changed properties in plist2 */ + if(H5SL_count(plist2->props) == 0) HGOTO_DONE(1); + + tnode1 = H5SL_first(plist1->props); + tnode2 = H5SL_first(plist2->props); + while(tnode1 || tnode2) { + H5P_genprop_t *prop1, *prop2; /* Property for node */ + + /* Check if they both have properties in this node */ + if(tnode1 == NULL && tnode2 != NULL) HGOTO_DONE(-1); + if(tnode1 != NULL && tnode2 == NULL) HGOTO_DONE(1); + + /* Compare the two properties */ + prop1 = H5SL_item(tnode1); + prop2 = H5SL_item(tnode2); + if((cmp_value = H5P_cmp_prop(prop1, prop2)) != 0) + HGOTO_DONE(cmp_value); + + /* Advance the pointers */ + tnode1 = H5SL_next(tnode1); + tnode2 = H5SL_next(tnode2); + } /* end while */ + } /* end if */ + else + if(H5SL_count(plist2->props)>0) HGOTO_DONE (-1); + + /* Check the parent classes */ + if((cmp_value = H5P_cmp_class(plist1->pclass, plist2->pclass)) != 0) + HGOTO_DONE(cmp_value); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_cmp_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_isa_class_real + PURPOSE + Internal routine to query whether a property class is the same as another + class. + USAGE + htri_t H5P_isa_class_real(pclass1, pclass2) + H5P_genclass_t *pclass1; IN: Property class to check + H5P_genclass_t *pclass2; IN: Property class to compare with + RETURNS + Success: TRUE (1) or FALSE (0) + Failure: negative value + DESCRIPTION + This routine queries whether a property class is the same as another class, + and walks up the hierarchy of derived classes, checking if the first class + is derived from the second class also. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5P_isa_class_real(H5P_genclass_t *pclass1, H5P_genclass_t *pclass2) +{ + htri_t ret_value; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_isa_class_real); + + assert(pclass1); + assert(pclass2); + + /* Compare property classes */ + if(H5P_cmp_class(pclass1, pclass2) == 0) { + HGOTO_DONE(TRUE); + } else { + /* Check if the class is derived, and walk up the chain, if so */ + if(pclass1->parent != NULL) + ret_value = H5P_isa_class_real(pclass1->parent, pclass2); + else + HGOTO_DONE(FALSE); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_isa_class_real() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_isa_class + PURPOSE + Internal routine to query whether a property list is a certain class + USAGE + hid_t H5P_isa_class(plist_id, pclass_id) + hid_t plist_id; IN: Property list to query + hid_t pclass_id; IN: Property class to query + RETURNS + Success: TRUE (1) or FALSE (0) + Failure: negative + DESCRIPTION + This routine queries whether a property list is a member of the property + list class. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + This function is special in that it is an internal library function, but + accepts hid_t's as parameters. Since it is used in basically the same way + as the H5I functions, this should be OK. Don't make more library functions + which accept hid_t's without thorough discussion. -QAK + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5P_isa_class(hid_t plist_id, hid_t pclass_id) +{ + H5P_genplist_t *plist; /* Property list to query */ + H5P_genclass_t *pclass; /* Property list class */ + htri_t ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_isa_class, FAIL); + + /* Check arguments. */ + if(NULL == (plist = H5I_object_verify(plist_id, H5I_GENPROP_LST))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list"); + if(NULL == (pclass = H5I_object_verify(pclass_id, H5I_GENPROP_CLS))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property class"); + + /* Compare the property list's class against the other class */ + if((ret_value = H5P_isa_class_real(plist->pclass, pclass)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "unable to compare property list classes"); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_isa_class() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_object_verify + PURPOSE + Internal routine to query whether a property list is a certain class and + retrieve the property list object associated with it. + USAGE + void *H5P_object_verify(plist_id, pclass_id) + hid_t plist_id; IN: Property list to query + hid_t pclass_id; IN: Property class to query + RETURNS + Success: valid pointer to a property list object + Failure: NULL + DESCRIPTION + This routine queries whether a property list is member of a certain class + and retrieves the property list object associated with it. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + This function is special in that it is an internal library function, but + accepts hid_t's as parameters. Since it is used in basically the same way + as the H5I functions, this should be OK. Don't make more library functions + which accept hid_t's without thorough discussion. -QAK + + This function is similar (in spirit) to H5I_object_verify() + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +void * +H5P_object_verify(hid_t plist_id, hid_t pclass_id) +{ + void *ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_object_verify, NULL); + + /* Compare the property list's class against the other class */ + if(H5P_isa_class(plist_id, pclass_id) != TRUE) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, NULL, "property list is not a member of the class"); + + /* Get the plist structure */ + if(NULL == (ret_value = H5I_object(plist_id))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, NULL, "can't find object for ID"); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_object_verify() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_iterate_plist + PURPOSE + Internal routine to iterate over the properties in a property list + USAGE + herr_t H5P_iterate_plist(plist_id, idx, iter_func, iter_data) + hid_t plist_id; IN: ID of property list to iterate over + int *idx; IN/OUT: Index of the property to begin with + H5P_iterate_t iter_func; IN: Function pointer to function to be + called with each property iterated over. + void *iter_data; IN/OUT: Pointer to iteration data from user + RETURNS + Success: Returns the return value of the last call to ITER_FUNC if it was + non-zero, or zero if all properties have been processed. + Failure: negative value + DESCRIPTION + This routine iterates over the properties in the property object specified +with PLIST_ID. For each property in the object, the ITER_DATA and some +additional information, specified below, are passed to the ITER_FUNC function. +The iteration begins with the IDX property in the object and the next element +to be processed by the operator is returned in IDX. If IDX is NULL, then the +iterator starts at the first property; since no stopping point is returned in +this case, the iterator cannot be restarted if one of the calls to its operator +returns non-zero. + +The prototype for H5P_iterate_t is: + typedef herr_t (*H5P_iterate_t)(hid_t id, const char *name, void *iter_data); +The operation receives the property list or class identifier for the object +being iterated over, ID, the name of the current property within the object, +NAME, and the pointer to the operator data passed in to H5Piterate, ITER_DATA. + +The return values from an operator are: + Zero causes the iterator to continue, returning zero when all properties + have been processed. + Positive causes the iterator to immediately return that positive value, + indicating short-circuit success. The iterator can be restarted at the + index of the next property. + Negative causes the iterator to immediately return that value, indicating + failure. The iterator can be restarted at the index of the next + property. + +H5Piterate assumes that the properties in the object identified by ID remains +unchanged through the iteration. If the membership changes during the +iteration, the function's behavior is undefined. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +int +H5P_iterate_plist(hid_t plist_id, int *idx, H5P_iterate_t iter_func, void *iter_data) +{ + H5P_genclass_t *tclass; /* Temporary class pointer */ + H5P_genplist_t *plist; /* Property list pointer */ + H5P_genprop_t *tmp; /* Temporary pointer to properties */ + H5SL_t *seen = NULL; /* Skip list to hold names of properties already seen */ + H5SL_node_t *curr_node; /* Current node in skip list */ + int curr_idx = 0; /* Current iteration index */ + int ret_value = FAIL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_iterate_plist); + + HDassert(idx); + HDassert(iter_func); + + /* Get the property list object */ + if(NULL == (plist = H5I_object_verify(plist_id, H5I_GENPROP_LST))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list"); + + /* Create the skip list to hold names of properties already seen */ + if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties"); + + /* Walk through the changed properties in the list */ + if(H5SL_count(plist->props) > 0) { + curr_node = H5SL_first(plist->props); + while(curr_node != NULL) { + /* Get pointer to property from node */ + tmp = H5SL_item(curr_node); + + /* Check if we've found the correctly indexed property */ + if(curr_idx>=*idx) { + /* Call the callback function */ + ret_value=(*iter_func)(plist_id,tmp->name,iter_data); + + if(ret_value!=0) + HGOTO_DONE(ret_value); + } /* end if */ + + /* Increment the current index */ + curr_idx++; + + /* Add property name to "seen" list */ + if(H5SL_insert(seen,tmp->name,tmp->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list"); + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Walk up the class hiearchy */ + tclass=plist->pclass; + while(tclass!=NULL) { + if(tclass->nprops>0) { + /* Walk through the properties in the class */ + curr_node=H5SL_first(tclass->props); + while(curr_node!=NULL) { + /* Get pointer to property from node */ + tmp=H5SL_item(curr_node); + + /* Only call iterator callback for properties we haven't seen + * before and that haven't been deleted + */ + if(H5SL_search(seen,tmp->name) == NULL && + H5SL_search(plist->del,tmp->name) == NULL) { + + + /* Check if we've found the correctly indexed property */ + if(curr_idx>=*idx) { + /* Call the callback function */ + ret_value=(*iter_func)(plist_id,tmp->name,iter_data); + + if(ret_value!=0) + HGOTO_DONE(ret_value); + } /* end if */ + + /* Increment the current index */ + curr_idx++; + + /* Add property name to "seen" list */ + if(H5SL_insert(seen,tmp->name,tmp->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list"); + } /* end if */ + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + +done: + /* Set the index we stopped at */ + *idx=curr_idx; + + /* Release the skip list of 'seen' properties */ + if(seen!=NULL) + H5SL_close(seen); + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_iterate_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_iterate_pclass + PURPOSE + Internal routine to iterate over the properties in a property class + USAGE + herr_t H5P_iterate_pclass(pclass_id, idx, iter_func, iter_data) + hid_t pclass_id; IN: ID of property class to iterate over + int *idx; IN/OUT: Index of the property to begin with + H5P_iterate_t iter_func; IN: Function pointer to function to be + called with each property iterated over. + void *iter_data; IN/OUT: Pointer to iteration data from user + RETURNS + Success: Returns the return value of the last call to ITER_FUNC if it was + non-zero, or zero if all properties have been processed. + Failure: negative value + DESCRIPTION + This routine iterates over the properties in the property object specified +with PCLASS_ID. For each property in the object, the ITER_DATA and some +additional information, specified below, are passed to the ITER_FUNC function. +The iteration begins with the IDX property in the object and the next element +to be processed by the operator is returned in IDX. If IDX is NULL, then the +iterator starts at the first property; since no stopping point is returned in +this case, the iterator cannot be restarted if one of the calls to its operator +returns non-zero. + +The prototype for H5P_iterate_t is: + typedef herr_t (*H5P_iterate_t)(hid_t id, const char *name, void *iter_data); +The operation receives the property list or class identifier for the object +being iterated over, ID, the name of the current property within the object, +NAME, and the pointer to the operator data passed in to H5Piterate, ITER_DATA. + +The return values from an operator are: + Zero causes the iterator to continue, returning zero when all properties + have been processed. + Positive causes the iterator to immediately return that positive value, + indicating short-circuit success. The iterator can be restarted at the + index of the next property. + Negative causes the iterator to immediately return that value, indicating + failure. The iterator can be restarted at the index of the next + property. + +H5Piterate assumes that the properties in the object identified by ID remains +unchanged through the iteration. If the membership changes during the +iteration, the function's behavior is undefined. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +int +H5P_iterate_pclass(hid_t pclass_id, int *idx, H5P_iterate_t iter_func, void *iter_data) +{ + H5P_genclass_t *pclass; /* Property list pointer */ + H5SL_node_t *curr_node; /* Current node in skip list */ + H5P_genprop_t *prop; /* Temporary property pointer */ + int curr_idx=0; /* Current iteration index */ + int ret_value=FAIL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_iterate_pclass); + + assert(idx); + assert(iter_func); + + /* Get the property list object */ + if(NULL == (pclass = H5I_object_verify(pclass_id, H5I_GENPROP_CLS))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property class"); + + /* Cycle through the properties and call the callback */ + curr_idx=0; + curr_node=H5SL_first(pclass->props); + while(curr_node!=NULL) { + if(curr_idx>=*idx) { + /* Get the property for the node */ + prop=H5SL_item(curr_node); + + /* Call the callback function */ + ret_value=(*iter_func)(pclass_id,prop->name,iter_data); + + /* Check if iteration function succeeded */ + if(ret_value!=0) + HGOTO_DONE(ret_value); + } /* end if */ + + /* Increment the iteration index */ + curr_idx++; + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + +done: + /* Set the index we stopped at */ + *idx=curr_idx; + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_iterate_pclass() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_peek_unsigned + PURPOSE + Internal routine to quickly retrieve the value of a property in a property list. + USAGE + int H5P_peek_unsigned(plist, name) + H5P_genplist_t *plist; IN: Property list to check + const char *name; IN: Name of property to query + RETURNS + Directly returns the value of the property in the list + DESCRIPTION + This function directly returns the value of a property in a property + list. Because this function is only able to just copy a particular property + value to the return value, there is no way to check for errors. We attempt + to make certain that bad things don't happen by validating that the size of + the property is the same as the size of the return type, but that can't + catch all errors. + This function does call the user's 'get' callback routine still. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + No error checking! + Use with caution! + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +unsigned +H5P_peek_unsigned(H5P_genplist_t *plist, const char *name) +{ + unsigned ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_peek_unsigned, UFAIL); + + assert(plist); + assert(name); + + /* Get the value to return, don't worry about the return value, we can't return it */ + H5P_get(plist,name,&ret_value); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_peek_unsigned() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_peek_hid_t + PURPOSE + Internal routine to quickly retrieve the value of a property in a property list. + USAGE + hid_t H5P_peek_hid_t(plist, name) + H5P_genplist_t *plist; IN: Property list to check + const char *name; IN: Name of property to query + RETURNS + Directly returns the value of the property in the list + DESCRIPTION + This function directly returns the value of a property in a property + list. Because this function is only able to just copy a particular property + value to the return value, there is no way to check for errors. We attempt + to make certain that bad things don't happen by validating that the size of + the property is the same as the size of the return type, but that can't + catch all errors. + This function does call the user's 'get' callback routine still. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + No error checking! + Use with caution! + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hid_t +H5P_peek_hid_t(H5P_genplist_t *plist, const char *name) +{ + hid_t ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_peek_hid_t, FAIL); + + assert(plist); + assert(name); + + /* Get the value to return, don't worry about the return value, we can't return it */ + H5P_get(plist,name,&ret_value); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_peek_hid_t() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_peek_voidp + PURPOSE + Internal routine to quickly retrieve the value of a property in a property list. + USAGE + void *H5P_peek_voidp(plist, name) + H5P_genplist_t *plist; IN: Property list to check + const char *name; IN: Name of property to query + RETURNS + Directly returns the value of the property in the list + DESCRIPTION + This function directly returns the value of a property in a property + list. Because this function is only able to just copy a particular property + value to the return value, there is no way to check for errors. We attempt + to make certain that bad things don't happen by validating that the size of + the property is the same as the size of the return type, but that can't + catch all errors. + This function does call the user's 'get' callback routine still. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + No error checking! + Use with caution! + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +void * +H5P_peek_voidp(H5P_genplist_t *plist, const char *name) +{ + void * ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_peek_voidp, NULL); + + assert(plist); + assert(name); + + /* Get the value to return, don't worry about the return value, we can't return it */ + H5P_get(plist,name,&ret_value); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_peek_voidp() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_peek_size_t + PURPOSE + Internal routine to quickly retrieve the value of a property in a property list. + USAGE + hsize_t H5P_peek_size_t(plist, name) + H5P_genplist_t *plist; IN: Property list to check + const char *name; IN: Name of property to query + RETURNS + Directly returns the value of the property in the list + DESCRIPTION + This function directly returns the value of a property in a property + list. Because this function is only able to just copy a particular property + value to the return value, there is no way to check for errors. We attempt + to make certain that bad things don't happen by validating that the size of + the property is the same as the size of the return type, but that can't + catch all errors. + This function does call the user's 'get' callback routine still. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + No error checking! + Use with caution! + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +size_t +H5P_peek_size_t(H5P_genplist_t *plist, const char *name) +{ + size_t ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_peek_size_t, UFAIL); + + assert(plist); + assert(name); + + /* Get the value to return, don't worry about the return value, we can't return it */ + H5P_get(plist,name,&ret_value); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_peek_size_t() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get + PURPOSE + Internal routine to query the value of a property in a property list. + USAGE + herr_t H5P_get(plist, name, value) + H5P_genplist_t *plist; IN: Property list to check + const char *name; IN: Name of property to query + void *value; OUT: Pointer to the buffer for the property value + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Retrieves a copy of the value for a property in a property list. The + property name must exist or this routine will fail. If there is a + 'get' callback routine registered for this property, the copy of the + value of the property will first be passed to that routine and any changes + to the copy of the value will be used when returning the property value + from this routine. + If the 'get' callback routine returns an error, 'value' will not be + modified and this routine will return an error. This routine may not be + called for zero-sized properties. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_get(H5P_genplist_t *plist, const char *name, void *value) +{ + H5P_genclass_t *tclass; /* Temporary class pointer */ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5P_get, FAIL); + + assert(plist); + assert(name); + assert(value); + + /* Check if the property has been deleted */ + if(H5SL_search(plist->del,name)!=NULL) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property doesn't exist"); + + /* Find property */ + if((prop=H5SL_search(plist->props,name))!=NULL) { + /* Check for property size >0 */ + if(prop->size==0) + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "property has zero size"); + + /* Make a copy of the value and pass to 'get' callback */ + if(prop->get!=NULL) { + void *tmp_value; /* Temporary value for property */ + + /* Make a copy of the current value, in case the callback fails */ + if(NULL==(tmp_value=H5MM_malloc(prop->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed temporary property value"); + HDmemcpy(tmp_value,prop->value,prop->size); + + /* Call user's callback */ + if((*(prop->get))(plist->plist_id,name,prop->size,tmp_value) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't get property value"); + + /* Copy new [possibly unchanged] value into return value */ + HDmemcpy(value,tmp_value,prop->size); + + /* Free the temporary value buffer */ + H5MM_xfree(tmp_value); + } /* end if */ + /* No 'get' callback, just copy value */ + else + HDmemcpy(value,prop->value,prop->size); + } /* end if */ + else { + /* + * Check if we should get class properties (up through list of parent classes also), + * & make property 'get' callback. + */ + tclass=plist->pclass; + while(tclass!=NULL) { + if(tclass->nprops>0) { + /* Find the property in the class */ + if((prop=H5SL_search(tclass->props,name))!=NULL) { + /* Check for property size >0 */ + if(prop->size==0) + HGOTO_ERROR(H5E_PLIST,H5E_BADVALUE,FAIL,"property has zero size"); + + /* Call the 'get' callback, if there is one */ + if(prop->get!=NULL) { + void *tmp_value; /* Temporary value for property */ + + /* Make a copy of the current value, in case the callback fails */ + if(NULL==(tmp_value=H5MM_malloc(prop->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed temporary property value"); + HDmemcpy(tmp_value,prop->value,prop->size); + + /* Call user's callback */ + if((*(prop->get))(plist->plist_id,name,prop->size,tmp_value) < 0) { + H5MM_xfree(tmp_value); + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value"); + } /* end if */ + + if(HDmemcmp(tmp_value,prop->value,prop->size)) { + H5P_genprop_t *pcopy; /* Copy of property to insert into skip list */ + + /* Make a copy of the class's property */ + if((pcopy=H5P_dup_prop(prop,H5P_PROP_WITHIN_LIST)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCOPY,FAIL,"Can't copy property"); + + /* Copy new value into property value */ + HDmemcpy(pcopy->value,tmp_value,prop->size); + + /* Insert the changed property into the property list */ + if(H5P_add_prop(plist->props,pcopy) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert changed property into skip list"); + } /* end if */ + + /* Copy new [possibly unchanged] value into return value */ + HDmemcpy(value,tmp_value,prop->size); + + /* Free the temporary value buffer */ + H5MM_xfree(tmp_value); + } /* end if */ + /* No 'get' callback, just copy value */ + else + HDmemcpy(value,prop->value,prop->size); + + /* Leave */ + HGOTO_DONE(SUCCEED); + } /* end while */ + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* If we get this far, then it wasn't in the list of changed properties, + * nor in the properties in the class hierarchy, indicate an error + */ + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,FAIL,"can't find property in skip list"); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_get() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_remove + PURPOSE + Internal routine to remove a property from a property list. + USAGE + herr_t H5P_remove(plist, name) + H5P_genplist_t *plist; IN: Property list to modify + const char *name; IN: Name of property to remove + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Removes a property from a property list. Both properties which were + in existance when the property list was created (i.e. properties registered + with H5Pregister2) and properties added to the list after it was created + (i.e. added with H5Pinsert) may be removed from a property list. + Properties do not need to be removed a property list before the list itself + is closed, they will be released automatically when H5Pclose is called. + The 'close' callback for this property is called before the property is + release, if the callback exists. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_remove(hid_t plist_id, H5P_genplist_t *plist, const char *name) +{ + H5P_genclass_t *tclass; /* Temporary class pointer */ + H5P_genprop_t *prop; /* Temporary property pointer */ + char *del_name; /* Pointer to deleted name */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5P_remove,FAIL); + + assert(plist); + assert(name); + + /* Indicate that the property isn't in the list if it has been deleted already */ + if(H5SL_search(plist->del,name)!=NULL) + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,FAIL,"can't find property in skip list"); + + /* Get the property node from the changed property skip list */ + if((prop=H5SL_search(plist->props,name))!=NULL) { + /* Pass value to 'close' callback, if it exists */ + if(prop->del!=NULL) { + /* Call user's callback */ + if((*(prop->del))(plist_id,name,prop->size,prop->value) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't close property value"); + } /* end if */ + + /* Duplicate string for insertion into new deleted property skip list */ + if((del_name=H5MM_xstrdup(name)) == NULL) + HGOTO_ERROR(H5E_RESOURCE,H5E_NOSPACE,FAIL,"memory allocation failed"); + + /* Insert property name into deleted list */ + if(H5SL_insert(plist->del,del_name,del_name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into deleted skip list"); + + /* Remove the property from the skip list */ + if(H5SL_remove(plist->props,prop->name) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTDELETE,FAIL,"can't remove property from skip list"); + + /* Free the property, ignoring return value, nothing we can do */ + H5P_free_prop(prop); + + /* Decrement the number of properties in list */ + plist->nprops--; + } /* end if */ + /* Walk through all the properties in the class hierarchy, looking for the property */ + else { + /* + * Check if we should delete class properties (up through list of parent classes also), + * & make property 'delete' callback. + */ + tclass=plist->pclass; + while(tclass!=NULL) { + if(tclass->nprops>0) { + /* Find the property in the class */ + if((prop=H5P_find_prop_pclass(tclass,name))!=NULL) { + /* Pass value to 'del' callback, if it exists */ + if(prop->del!=NULL) { + void *tmp_value; /* Temporary value buffer */ + + /* Allocate space for a temporary copy of the property value */ + if(NULL==(tmp_value=H5MM_malloc(prop->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for temporary property value"); + HDmemcpy(tmp_value,prop->value,prop->size); + + /* Call user's callback */ + if((*(prop->del))(plist_id,name,prop->size,tmp_value) < 0) { + H5MM_xfree(tmp_value); + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't close property value"); + } /* end if */ + + /* Release the temporary value buffer */ + H5MM_xfree(tmp_value); + } /* end if */ + + /* Duplicate string for insertion into new deleted property skip list */ + if((del_name=H5MM_xstrdup(name)) == NULL) + HGOTO_ERROR(H5E_RESOURCE,H5E_NOSPACE,FAIL,"memory allocation failed"); + + /* Insert property name into deleted list */ + if(H5SL_insert(plist->del,del_name,del_name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into deleted skip list"); + + /* Decrement the number of properties in list */ + plist->nprops--; + + /* Leave */ + HGOTO_DONE(SUCCEED); + } /* end while */ + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* If we get this far, then it wasn't in the list of changed properties, + * nor in the properties in the class hierarchy, indicate an error + */ + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,FAIL,"can't find property in skip list"); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_remove() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_copy_prop_plist + PURPOSE + Internal routine to copy a property from one list to another + USAGE + herr_t H5P_copy_prop_plist(dst_plist, src_plist, name) + hid_t dst_id; IN: ID of destination property list or class + hid_t src_id; IN: ID of source property list or class + const char *name; IN: Name of property to copy + RETURNS + Success: non-negative value. + Failure: negative value. + DESCRIPTION + Copies a property from one property list to another. + + If a property is copied from one list to another, the property will be + first deleted from the destination list (generating a call to the 'close' + callback for the property, if one exists) and then the property is copied + from the source list to the destination list (generating a call to the + 'copy' callback for the property, if one exists). + + If the property does not exist in the destination list, this call is + equivalent to calling H5Pinsert and the 'create' callback will be called + (if such a callback exists for the property). + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_copy_prop_plist(hid_t dst_id, hid_t src_id, const char *name) +{ + H5P_genplist_t *dst_plist; /* Pointer to destination property list */ + H5P_genplist_t *src_plist; /* Pointer to source property list */ + H5P_genprop_t *prop; /* Temporary property pointer */ + H5P_genprop_t *new_prop=NULL; /* Pointer to new property */ + herr_t ret_value=SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_copy_prop_plist); + + assert(name); + + /* Get the objects to operate on */ + if(NULL == (src_plist = H5I_object(src_id)) || NULL == (dst_plist = H5I_object(dst_id))) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "property object doesn't exist"); + + /* If the property exists in the destination alread */ + if(H5P_find_prop_plist(dst_plist,name)!=NULL) { + /* Delete the property from the destination list, calling the 'close' callback if necessary */ + if(H5P_remove(dst_id,dst_plist,name) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "unable to remove property"); + + /* Get the pointer to the source property */ + prop=H5P_find_prop_plist(src_plist,name); + + /* Make a copy of the source property */ + if((new_prop=H5P_dup_prop(prop,H5P_PROP_WITHIN_LIST)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property"); + + /* Call property copy callback, if it exists */ + if(new_prop->copy) { + if((new_prop->copy)(new_prop->name,new_prop->size,new_prop->value) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCOPY, FAIL,"Can't copy property"); + } /* end if */ + + /* Insert the initialized property into the property list */ + if(H5P_add_prop(dst_plist->props,new_prop) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into list"); + + /* Increment the number of properties in list */ + dst_plist->nprops++; + } /* end if */ + /* If not, get the information required to do an H5Pinsert with the property into the destination list */ + else { + /* Get the pointer to the source property */ + prop=H5P_find_prop_plist(src_plist,name); + + /* Create property object from parameters */ + if((new_prop=H5P_create_prop(prop->name,prop->size,H5P_PROP_WITHIN_LIST,prop->value,prop->create,prop->set,prop->get,prop->del,prop->copy,prop->cmp,prop->close)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_CANTCREATE, FAIL,"Can't create property"); + + /* Call property creation callback, if it exists */ + if(new_prop->create) { + if((new_prop->create)(new_prop->name,new_prop->size,new_prop->value) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, FAIL,"Can't initialize property"); + } /* end if */ + + /* Insert property into property list class */ + if(H5P_add_prop(dst_plist->props,new_prop) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINSERT, FAIL,"Can't insert property into class"); + + /* Increment property count for class */ + dst_plist->nprops++; + + } /* end else */ + +done: + /* Cleanup, if necessary */ + if(ret_value<0) { + if(new_prop!=NULL) + H5P_free_prop(new_prop); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_copy_prop_plist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_copy_prop_pclass + PURPOSE + Internal routine to copy a property from one class to another + USAGE + herr_t H5P_copy_prop_pclass(dst_pclass, src_pclass, name) + H5P_genclass_t *dst_pclass; IN: Pointer to destination class + H5P_genclass_t *src_pclass; IN: Pointer to source class + const char *name; IN: Name of property to copy + RETURNS + Success: non-negative value. + Failure: negative value. + DESCRIPTION + Copies a property from one property class to another. + + If a property is copied from one class to another, all the property + information will be first deleted from the destination class and then the + property information will be copied from the source class into the + destination class. + + If the property does not exist in the destination class or list, this call + is equivalent to calling H5Pregister2. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_copy_prop_pclass(H5P_genclass_t *dst_pclass, H5P_genclass_t *src_pclass, const char *name) +{ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value=SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_copy_prop_pclass); + + assert(dst_pclass); + assert(src_pclass); + assert(name); + + /* If the property exists in the destination already */ + if(H5P_exist_pclass(dst_pclass,name)) { + /* Delete the old property from the destination class */ + if(H5P_unregister(dst_pclass,name) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "unable to remove property"); + } /* end if */ + + /* Get the property from the source */ + if((prop=H5P_find_prop_pclass(src_pclass,name)) == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, FAIL, "unable to locate property"); + + /* Register the property into the destination */ + if(H5P_register(dst_pclass,name,prop->size,prop->value,prop->create,prop->set,prop->get,prop->del,prop->copy,prop->cmp,prop->close) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTDELETE, FAIL, "unable to remove property"); + +done: + /* Cleanup, if necessary */ + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_copy_prop_pclass() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_unregister + PURPOSE + Internal routine to remove a property from a property list class. + USAGE + herr_t H5P_unregister(pclass, name) + H5P_genclass_t *pclass; IN: Property list class to modify + const char *name; IN: Name of property to remove + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Removes a property from a property list class. Future property lists + created of that class will not contain this property. Existing property + lists containing this property are not affected. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_unregister(H5P_genclass_t *pclass, const char *name) +{ + H5P_genprop_t *prop; /* Temporary property pointer */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_unregister); + + assert(pclass); + assert(name); + + /* Get the property node from the skip list */ + if((prop=H5SL_search(pclass->props,name)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_NOTFOUND,FAIL,"can't find property in skip list"); + + /* Remove the property from the skip list */ + if(H5SL_remove(pclass->props,prop->name) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTDELETE,FAIL,"can't remove property from skip list"); + + /* Free the property, ignoring return value, nothing we can do */ + H5P_free_prop(prop); + + /* Decrement the number of registered properties in class */ + pclass->nprops--; + + /* Update the revision for the class */ + pclass->revision = H5P_GET_NEXT_REV; + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_unregister() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_close + PURPOSE + Internal routine to close a property list. + USAGE + herr_t H5P_close(plist) + H5P_genplist_t *plist; IN: Property list to close + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Closes a property list. If a 'close' callback exists for the property + list class, it is called before the property list is destroyed. If 'close' + callbacks exist for any individual properties in the property list, they are + called after the class 'close' callback. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + The property list class 'close' callback routine is not called from + here, it must have been check for and called properly prior to this routine + being called + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_close(void *_plist) +{ + H5P_genclass_t *tclass; /* Temporary class pointer */ + H5P_genplist_t *plist=(H5P_genplist_t *)_plist; + H5SL_t *seen=NULL; /* Skip list to hold names of properties already seen */ + size_t nseen; /* Number of items 'seen' */ + hbool_t has_parent_class; /* Flag to indicate that this property list's class has a parent */ + size_t ndel; /* Number of items deleted */ + H5SL_node_t *curr_node; /* Current node in skip list */ + H5P_genprop_t *tmp; /* Temporary pointer to properties */ + unsigned make_cb=0; /* Operator data for property free callback */ + herr_t ret_value=SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_close); + + assert(plist); + + /* Make call to property list class close callback, if needed */ + if(plist->class_init!=0 && plist->pclass->close_func!=NULL) { + /* Call user's "close" callback function, ignoring return value */ + (plist->pclass->close_func)(plist->plist_id,plist->pclass->close_data); + } /* end if */ + + /* Create the skip list to hold names of properties already seen + * (This prevents a property in the class hierarchy from having it's + * 'close' callback called, if a property in the class hierarchy has + * already been seen) + */ + if((seen = H5SL_create(H5SL_TYPE_STR, 0.5, (size_t)H5P_DEFAULT_SKIPLIST_HEIGHT)) == NULL) + HGOTO_ERROR(H5E_PLIST,H5E_CANTCREATE,FAIL,"can't create skip list for seen properties"); + nseen = 0; + + /* Walk through the changed properties in the list */ + if(H5SL_count(plist->props)>0) { + curr_node=H5SL_first(plist->props); + while(curr_node!=NULL) { + /* Get pointer to property from node */ + tmp=H5SL_item(curr_node); + + /* Call property close callback, if it exists */ + if(tmp->close) { + /* Call the 'close' callback */ + (tmp->close)(tmp->name,tmp->size,tmp->value); + } /* end if */ + + /* Add property name to "seen" list */ + if(H5SL_insert(seen,tmp->name,tmp->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list"); + nseen++; + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Determine number of deleted items from property list */ + ndel=H5SL_count(plist->del); + + /* + * Check if we should remove class properties (up through list of parent classes also), + * initialize each with default value & make property 'remove' callback. + */ + tclass=plist->pclass; + has_parent_class=(tclass!=NULL && tclass->parent!=NULL && tclass->parent->nprops>0); + while(tclass!=NULL) { + if(tclass->nprops>0) { + /* Walk through the properties in the class */ + curr_node=H5SL_first(tclass->props); + while(curr_node!=NULL) { + /* Get pointer to property from node */ + tmp=H5SL_item(curr_node); + + /* Only "delete" properties we haven't seen before + * and that haven't already been deleted + */ + if((nseen==0 || H5SL_search(seen,tmp->name) == NULL) && + (ndel==0 || H5SL_search(plist->del,tmp->name) == NULL)) { + + /* Call property close callback, if it exists */ + if(tmp->close) { + void *tmp_value; /* Temporary value buffer */ + + /* Allocate space for a temporary copy of the property value */ + if(NULL==(tmp_value=H5MM_malloc(tmp->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for temporary property value"); + HDmemcpy(tmp_value,tmp->value,tmp->size); + + /* Call the 'close' callback */ + (tmp->close)(tmp->name,tmp->size,tmp_value); + + /* Release the temporary value buffer */ + H5MM_xfree(tmp_value); + } /* end if */ + + /* Add property name to "seen" list, if we have other classes to work on */ + if(has_parent_class) { + if(H5SL_insert(seen,tmp->name,tmp->name) < 0) + HGOTO_ERROR(H5E_PLIST,H5E_CANTINSERT,FAIL,"can't insert property into seen skip list"); + nseen++; + } /* end if */ + } /* end if */ + + /* Get the next property node in the skip list */ + curr_node=H5SL_next(curr_node); + } /* end while */ + } /* end if */ + + /* Go up to parent class */ + tclass=tclass->parent; + } /* end while */ + + /* Decrement class's dependant property list value! */ + if(H5P_access_class(plist->pclass,H5P_MOD_DEC_LST) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTINIT, FAIL, "Can't decrement class ref count"); + + /* Free the list of 'seen' properties */ + H5SL_close(seen); + seen=NULL; + + /* Free the list of deleted property names */ + H5SL_destroy(plist->del,H5P_free_del_name_cb,NULL); + + /* Free the properties */ + H5SL_destroy(plist->props,H5P_free_prop_cb,&make_cb); + + /* Destroy property list object */ + H5FL_FREE(H5P_genplist_t,plist); + +done: + /* Release the skip list of 'seen' properties */ + if(seen!=NULL) + H5SL_close(seen); + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_close() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_class_name + PURPOSE + Internal routine to query the name of a generic property list class + USAGE + char *H5P_get_class_name(pclass) + H5P_genclass_t *pclass; IN: Property list class to check + RETURNS + Success: Pointer to a malloc'ed string containing the class name + Failure: NULL + DESCRIPTION + This routine retrieves the name of a generic property list class. + The pointer to the name must be free'd by the user for successful calls. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +char * +H5P_get_class_name(H5P_genclass_t *pclass) +{ + char *ret_value; /* return value */ + + FUNC_ENTER_NOAPI(H5P_get_class_name, NULL); + + assert(pclass); + + /* Get class name */ + ret_value=H5MM_xstrdup(pclass->name); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_get_class_name() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_class_path + PURPOSE + Internal routine to query the full path of a generic property list class + USAGE + char *H5P_get_class_name(pclass) + H5P_genclass_t *pclass; IN: Property list class to check + RETURNS + Success: Pointer to a malloc'ed string containing the full path of class + Failure: NULL + DESCRIPTION + This routine retrieves the full path name of a generic property list + class, starting with the root of the class hierarchy. + The pointer to the name must be free'd by the user for successful calls. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +char * +H5P_get_class_path(H5P_genclass_t *pclass) +{ + char *par_path; /* Parent class's full path */ + size_t par_path_len;/* Parent class's full path's length */ + size_t my_path_len; /* This class's name's length */ + char *ret_value; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_get_class_path); + + assert(pclass); + + /* Recursively build the full path */ + if(pclass->parent!=NULL) { + /* Get the parent class's path */ + par_path=H5P_get_class_path(pclass->parent); + if(par_path!=NULL) { + /* Get the string lengths we need to allocate space */ + par_path_len=HDstrlen(par_path); + my_path_len=HDstrlen(pclass->name); + + /* Allocate enough space for the parent class's path, plus the '/' + * separator, this class's name and the string terminator + */ + if(NULL==(ret_value=H5MM_malloc(par_path_len+1+my_path_len+1))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for class name"); + + /* Build the full path for this class */ + HDstrcpy(ret_value,par_path); + HDstrcat(ret_value,"/"); + HDstrcat(ret_value,pclass->name); + + /* Free the parent class's path */ + H5MM_xfree(par_path); + } /* end if */ + else + ret_value=H5MM_xstrdup(pclass->name); + } /* end if */ + else + ret_value=H5MM_xstrdup(pclass->name); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_get_class_path() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_open_class_path + PURPOSE + Internal routine to open [a copy of] a class with its full path name + USAGE + H5P_genclass_t *H5P_open_class_path(path) + const char *path; IN: Full path name of class to open [copy of] + RETURNS + Success: Pointer to a generic property class object + Failure: NULL + DESCRIPTION + This routine opens [a copy] of the class indicated by the full path. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +H5P_genclass_t * +H5P_open_class_path(const char *path) +{ + char *tmp_path=NULL; /* Temporary copy of the path */ + char *curr_name; /* Pointer to current component of path name */ + char *delimit; /* Pointer to path delimiter during traversal */ + H5P_genclass_t *curr_class; /* Pointer to class during path traversal */ + H5P_genclass_t *ret_value; /* Return value */ + H5P_check_class_t check_info; /* Structure to hold the information for checking duplicate names */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_open_class_path); + + assert(path); + + /* Duplicate the path to use */ + tmp_path=H5MM_xstrdup(path); + assert(tmp_path); + + /* Find the generic property class with this full path */ + curr_name=tmp_path; + curr_class=NULL; + while((delimit=HDstrchr(curr_name,'/'))!=NULL) { + /* Change the delimiter to terminate the string */ + *delimit='\0'; + + /* Set up the search structure */ + check_info.parent=curr_class; + check_info.name=curr_name; + + /* Find the class with this name & parent by iterating over the open classes */ + if((curr_class=H5I_search(H5I_GENPROP_CLS,H5P_check_class,&check_info)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class"); + + /* Advance the pointer in the path to the start of the next component */ + curr_name=delimit+1; + } /* end while */ + + /* Should be pointing to the last component in the path name now... */ + + /* Set up the search structure */ + check_info.parent=curr_class; + check_info.name=curr_name; + + /* Find the class with this name & parent by iterating over the open classes */ + if((curr_class=H5I_search(H5I_GENPROP_CLS,H5P_check_class,&check_info)) == NULL) + HGOTO_ERROR (H5E_PLIST, H5E_NOTFOUND, NULL, "can't locate class"); + + /* Copy it */ + if((ret_value=H5P_copy_pclass(curr_class)) == NULL) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, NULL, "can't copy property class"); + +done: + /* Free the duplicated path */ + H5MM_xfree(tmp_path); + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_open_class_path() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_get_class_parent + PURPOSE + Internal routine to query the parent class of a generic property class + USAGE + H5P_genclass_t *H5P_get_class_parent(pclass) + H5P_genclass_t *pclass; IN: Property class to check + RETURNS + Success: Pointer to the parent class of a property class + Failure: NULL + DESCRIPTION + This routine retrieves a pointer to the parent class for a property class. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +H5P_genclass_t * +H5P_get_class_parent(const H5P_genclass_t *pclass) +{ + H5P_genclass_t *ret_value; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_get_class_parent); + + assert(pclass); + + /* Get property size */ + ret_value = pclass->parent; + + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_get_class_parent() */ + + +/*-------------------------------------------------------------------------- + NAME + H5P_close_class + PURPOSE + Internal routine to close a property list class. + USAGE + herr_t H5P_close_class(class) + H5P_genclass_t *class; IN: Property list class to close + RETURNS + Returns non-negative on success, negative on failure. + DESCRIPTION + Releases memory and de-attach a class from the property list class hierarchy. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5P_close_class(void *_pclass) +{ + H5P_genclass_t *pclass=(H5P_genclass_t *)_pclass; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5P_close_class); + + assert(pclass); + + /* Decrement the reference count & check if the object should go away */ + if(H5P_access_class(pclass,H5P_MOD_DEC_REF) < 0) + HGOTO_ERROR (H5E_PLIST, H5E_NOTFOUND, FAIL, "Can't decrement ID ref count"); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* H5P_close_class() */ + |