summaryrefslogtreecommitdiffstats
path: root/CTestCustom.cmake.in
blob: 2a6ce06047bef5a7a4ecfcd71ded6a92ddf53efc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
SET(CTEST_CUSTOM_WARNING_EXCEPTION
  ${CTEST_CUSTOM_WARNING_EXCEPTION}
  "xtree.[0-9]+. : warning C4702: unreachable code"
  "warning LNK4221"
  "warning LNK4204" # Occurs by race condition with objects in small libs
  "variable .var_args[2]*. is used before its value is set"
  "jobserver unavailable"
  "warning: \\(Long double usage is reported only once for each file"
  "warning: To disable this warning use"
  "could not be inlined"
  "libcmcurl.*has no symbols"
  "not sorted slower link editing will result"
  "stl_deque.h:479"
  "Utilities.cmzlib."
  "Source.CTest.Curl"
  "Source.CursesDialog.form"
  "Utilities.cmcurl"
  "Utilities.cmexpat."
  "Utilities.cmtar"
  "/usr/include.*warning.*shadowed declaration is here"
  "/usr/bin/ld.*warning.*-..*directory.name.*bin.*does not exist"
  "Redeclaration of .send..... with a different storage class specifier"
  "is not used for resolving any symbol"
  "Clock skew detected"
  "remark\\(1209"
  "stl_deque.h:1051"
  "(Lexer|Parser).*warning.*conversion.*may (alter its value|change the sign)"
  "[Qq]t([Cc]ore|[Gg]ui).*warning.*conversion.*may alter its value"
  "Parser.cxx.*warning.*2111-D.*statement is unreachable"
  "CMakeSetupManifest.xml.*manifest authoring warning.*Unrecognized Element"
  )

IF(NOT "@CMAKE_GENERATOR@" MATCHES "Xcode")
  SET(CTEST_CUSTOM_COVERAGE_EXCLUDE
    ${CTEST_CUSTOM_COVERAGE_EXCLUDE}
    "XCode"
    )
ENDIF (NOT "@CMAKE_GENERATOR@" MATCHES "Xcode")

IF(NOT "@CMAKE_GENERATOR@" MATCHES "KDevelop")
  SET(CTEST_CUSTOM_COVERAGE_EXCLUDE
    ${CTEST_CUSTOM_COVERAGE_EXCLUDE}
    "Kdevelop"
    )
ENDIF (NOT "@CMAKE_GENERATOR@" MATCHES "KDevelop")

SET(CTEST_CUSTOM_COVERAGE_EXCLUDE
  ${CTEST_CUSTOM_COVERAGE_EXCLUDE}

  # Exclude kwsys files from coverage results. They are reported
  # (with better coverage results) on kwsys dashboards...
  "/Source/(cm|kw)sys/"

  # Exclude try_compile sources from coverage results:
  "/CMakeFiles/CMakeTmp/"
  )
msg
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>1997-07-30 21:17:56 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>1997-07-30 21:17:56 (GMT)
commit03997b1f368f935ab4b3a9a878fd3587cbc74862 (patch)
tree193909bb46d7310f8ea8d31308cddc8850530220
parentad9255a57faca8454d0a5f2f955001eed32833ea (diff)
downloadhdf5-03997b1f368f935ab4b3a9a878fd3587cbc74862.zip
hdf5-03997b1f368f935ab4b3a9a878fd3587cbc74862.tar.gz
hdf5-03997b1f368f935ab4b3a9a878fd3587cbc74862.tar.bz2
[svn-r2] Oops...
Diffstat
-rw-r--r--Makefile117
-rw-r--r--src/H5.c275
-rw-r--r--src/H5A.c789
-rw-r--r--src/H5AC.c315
-rw-r--r--src/H5ACprivate.h71
-rw-r--r--src/H5ACproto.h29
-rw-r--r--src/H5Aprivate.h90
-rw-r--r--src/H5Aproto.h204
-rw-r--r--src/H5B.c1177
-rw-r--r--src/H5Bprivate.h85
-rw-r--r--src/H5Bproto.h29
-rw-r--r--src/H5C.c506
-rw-r--r--src/H5Cprivate.h25
-rw-r--r--src/H5Cproto.h41
-rw-r--r--src/H5E.c394
-rw-r--r--src/H5Eprivate.h131
-rw-r--r--src/H5Eproto.h126
-rw-r--r--src/H5F.c852
-rw-r--r--src/H5Fprivate.h101
-rw-r--r--src/H5Fproto.h43
-rw-r--r--src/H5G.c196
-rw-r--r--src/H5Gnode.c661
-rw-r--r--src/H5Gprivate.h125
-rw-r--r--src/H5Gproto.h29
-rw-r--r--src/H5H.c653
-rw-r--r--src/H5Hprivate.h36
-rw-r--r--src/H5Hproto.h29
-rw-r--r--src/H5M.c257
-rw-r--r--src/H5MF.c88
-rw-r--r--src/H5MFprivate.h28
-rw-r--r--src/H5MFproto.h29
-rw-r--r--src/H5MM.c175
-rw-r--r--src/H5MMprivate.h32
-rw-r--r--src/H5MMproto.h29
-rw-r--r--src/H5Mprivate.h86
-rw-r--r--src/H5Mproto.h37
-rw-r--r--src/H5P.c216
-rw-r--r--src/H5Pprivate.h30
-rw-r--r--src/H5Pproto.h39
-rw-r--r--src/H5T.c662
-rw-r--r--src/H5Tprivate.h50
-rw-r--r--src/H5Tproto.h57
-rw-r--r--src/H5private.h30
-rw-r--r--src/H5proto.h35
-rw-r--r--src/Makefile92
-rw-r--r--src/h5oplat.h555
-rw-r--r--src/hdf5.h60
-rw-r--r--src/hdf5fort.h75
-rw-r--r--src/hdf5gen.h49
-rw-r--r--src/hdf5glob.h58
-rw-r--r--src/hdf5lims.h60
-rw-r--r--src/hdf5meta.h145
-rw-r--r--src/hdf5pabl.h32
-rw-r--r--src/hdf5plat.h750
-rw-r--r--src/hdf5port.h202
-rw-r--r--src/hdf5type.h70
-rw-r--r--test/Makefile50
-rw-r--r--test/testhdf5.c302
-rw-r--r--test/testhdf5.h115
-rw-r--r--test/tfile.c288
-rw-r--r--test/theap.c87
-rw-r--r--test/tmeta.c120
62 files changed, 12119 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c081fc9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,117 @@
+# ##################################################################
+#
+#
+# This is the top level Makefile to build HDF5 on Unix based
+# platforms
+#
+
+# Define your sh shell
+#SHELL=/bin/sh
+
+# Define your machine type
+#MACHINE=UNIX386
+
+# Define your C compiler and flags
+CC= gcc
+#CFLAGS= -ansi -Wall -pedantic -O -c
+CFLAGS= -ansi -Wall -pedantic -g -c
+
+# Define your FORTRAN compiler
+FC= f77
+FFLAGS=
+
+# Location where the HDF include files are to be installed
+HDFINC= `pwd`/src
+
+# Location where the HDF library is to be installed
+HDFLIB= `pwd`/src
+
+# Location to put HDF utility executables
+HDFBIN= `pwd`/bin
+
+# Name of library archiver and flags to send
+AR= ar
+ARFLAGS= ru
+
+# Name of achive randomizer (use 'touch' if non-existant)
+RANLIB= ranlib
+
+# Name of remove utility
+RM= /bin/rm
+RMFLAGS= -f
+
+# ##################################################################
+#
+# This is the top level Makefile to build HDF5 on Unix based
+# platforms
+#
+
+#
+#
+# Flags to recursively send
+#
+
+HDF_FLAGS = \
+ CC="$(CC)" \
+ CFLAGS="$(CFLAGS)" \
+ FC="$(FC)" \
+ FFLAGS="$(FFLAGS)" \
+ RANLIB="$(RANLIB)" \
+ AR="$(AR)" \
+ ARFLAGS="$(ARFLAGS)" \
+ RM="$(RM)" \
+ RMFLAGS="$(RMFLAGS)" \
+ MACHINE="$(MACHINE)" \
+ HDFLIB="$(HDFLIB)" \
+ HDFINC="$(HDFINC)" \
+ HDFBIN="$(HDFBIN)"
+
+#
+#
+# General rules
+#
+all:
+ @$(MAKE) $(MFLAGS) $(HDF_FLAGS) TARG=$@ \
+ SUBDIRS="src test" subd message
+
+rebuild:
+ @$(MAKE) $(MFLAGS) $(HDF_FLAGS) TARG=$@ \
+ SUBDIRS="src test" subd message
+
+libhdf5:
+ @$(MAKE) $(MFLAGS) $(HDF_FLAGS) TARG=all \
+ SUBDIRS="src" subd
+
+tests:
+ @$(MAKE) $(MFLAGS) $(HDF_FLAGS) TARG=test \
+ SUBDIRS="src test" subd
+
+debug:
+ @$(MAKE) $(MFLAGS) $(HDF_FLAGS) TARG=debug \
+ SUBDIRS="src test" subd message
+
+clean:
+ @$(MAKE) $(MFLAGS) $(HDF_FLAGS) TARG=$@ \
+ SUBDIRS="src test" subd
+ $(RM) $(RMFLAGS) core *.log
+
+distclean:
+ @$(MAKE) $(MFLAGS) $(HDF_FLAGS) TARG=$@ \
+ SUBDIRS="src test" subd
+ $(RM) $(RMFLAGS) core *.log
+ $(RM) -rf bin lib include
+
+subd:
+ @for dir in $(SUBDIRS); do \
+ (cd $$dir; echo Making \`$(TARG)\' in `pwd`; \
+ $(MAKE) $(MFLAGS) $(HDF_FLAGS) $(TARG)); \
+ done
+
+message:
+ @echo ""
+ @echo "***********************************************************"
+ @echo " HDF5 library successfully created."
+ @echo ""
+ @echo "***********************************************************"
+ @echo ""
+
diff --git a/src/H5.c b/src/H5.c
new file mode 100644
index 0000000..cf77b61
--- /dev/null
+++ b/src/H5.c
@@ -0,0 +1,275 @@
+/****************************************************************************
+* NCSA HDF *
+* Software Development Group *
+* National Center for Supercomputing Applications *
+* University of Illinois at Urbana-Champaign *
+* 605 E. Springfield, Champaign IL 61820 *
+* *
+* For conditions of distribution and use, see the accompanying *
+* hdf/COPYING file. *
+* *
+****************************************************************************/
+
+#ifdef RCSID
+static char RcsId[] = "@(#)$Revision$";
+#endif
+
+/* $Id$ */
+
+/*LINTLIBRARY */
+/*+
+ FILE
+ hdf5.c
+ HDF library support routines
+
+ EXPORTED ROUTINES
+ H5dont_atexit -- Indicate that an 'atexit' routine is _not_ to be installed
+ H5version -- Check the version of the library
+
+ LIBRARY-SCOPED ROUTINES
+ H5_init_library -- initialize the HDF5 library
+ H5_term_library -- shut-down the HDF5 library
+ H5_init_thread -- initialize thread-specific information
+
+ LOCAL ROUTINES
+ H5_init_interface -- initialize the H5 interface
+ + */
+
+#define HDF5_MASTER
+#include "hdf5.h"
+#undef HDF5_MASTER
+
+/* private headers */
+#include "H5ACprivate.h" /*cache */
+#include "H5Bprivate.h" /*B-link trees */
+#include "H5private.h" /* Generic info */
+
+/*--------------------- Locally scoped variables -----------------------------*/
+
+/* Whether we've installed the library termination function yet for this interface */
+static intn interface_initialize = FALSE;
+
+/*------------------_-- Local function prototypes ----------------------------*/
+static herr_t H5_init_interface(void);
+
+/*--------------------------------------------------------------------------
+NAME
+ H5_init_library -- Initialize library-global information
+USAGE
+ herr_t H5_init_library()
+
+RETURNS
+ SUCCEED/FAIL
+DESCRIPTION
+ Initializes any library-global data or routines.
+
+--------------------------------------------------------------------------*/
+herr_t H5_init_library(void)
+{
+ CONSTR(FUNC, "H5_init_library"); /* For HERROR */
+ herr_t ret_value = SUCCEED;
+
+ /* Don't use "FUNC_ENTER" macro, to avoid potential infinite recursion */
+ PABLO_TRACE_ON(H5_mask, ID_H5_init_library);
+
+ /* Don't call this routine again... */
+ library_initialize = TRUE;
+
+ /* Install atexit() library cleanup routine */
+ if(install_atexit==TRUE)
+ if (HDatexit(&H5_term_library) != 0)
+ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL);
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ FUNC_LEAVE(H5_mask, ID_H5_init_library,ret_value);
+} /* H5_init_library */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5_term_library
+ PURPOSE
+ Terminate various static buffers and shutdown the library.
+ USAGE
+ void HPend()
+ RETURNS
+ none
+ DESCRIPTION
+ Walk through the shutdown routines for the various interfaces and
+ terminate them all.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Should only ever be called by the "atexit" function, or real power-users.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+void H5_term_library(void)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5_term_library"); /* for HERROR */
+#endif /* LATER */
+
+} /* end H5_term_library() */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5_init_thread -- Initialize thread-specific information
+USAGE
+ void H5_init_thread()
+
+RETURNS
+ SUCCEED/FAIL
+DESCRIPTION
+ Initializes any thread-specific data or routines.
+
+--------------------------------------------------------------------------*/
+herr_t H5_init_thread(void)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5_init_thread"); /* For HERROR */
+#endif /* LATER */
+ herr_t ret_value = SUCCEED;
+
+ /* Don't use "FUNC_ENTER" macro, to avoid potential infinite recursion */
+ PABLO_TRACE_ON(H5_mask, ID_H5_init_thread);
+
+ /* Don't call this routine again... */
+ thread_initialize = TRUE;
+
+
+ /* Create/initialize this thread's error stack */
+ if((thrderrid=H5Enew_err_stack(16))==FAIL)
+ ret_value=FAIL;
+
+ FUNC_LEAVE(H5_mask, ID_H5_init_thread, ret_value);
+} /* H5_init_thread */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5_init_interface -- Initialize interface-specific information
+USAGE
+ herr_t H5_init_interface()
+
+RETURNS
+ SUCCEED/FAIL
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+static herr_t H5_init_interface(void)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5_init_interface"); /* For HERROR */
+#endif /* LATER */
+ herr_t ret_value = SUCCEED;
+
+ /* Don't use "FUNC_ENTER" macro, to avoid potential infinite recursion */
+ PABLO_TRACE_ON(H5_mask, ID_H5_init_interface);
+
+ /* Don't call this routine again... */
+ interface_initialize = TRUE;
+
+ FUNC_LEAVE(H5_mask, ID_H5_init_interface, ret_value);
+} /* H5_init_interface */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5dont_atexit
+ PURPOSE
+ Indicates to the library that an 'atexit()' routine is _not_ to be installed
+ USAGE
+ herr_t H5dont_atexit(void)
+ RETURNS
+ Returns SUCCEED/FAIL
+ DESCRIPTION
+ This routine indicates to the library that an 'atexit()' cleanip routine
+ should not be installed. The major (only?) purpose for this is in
+ situations where the library is dynamically linked into an application and
+ is un-linked from the application before 'exit()' gets callled. In those
+ situations, a routine installed with 'atexit()' would jump to a routine
+ which was no longer in memory, causing errors.
+ In order to be effective, this routine _must_ be called before any other
+ HDF function calls, and must be called each time the library is loaded/
+ linked into the application. (the first time and after it's been un-loaded)
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ If this routine is used, certain memory buffers will not be de-allocated,
+ although in theory a user could call HPend on their own...
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t H5dont_atexit(void)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5dont_atexit"); /* for HERROR */
+#endif /* LATER */
+ intn ret_value = SUCCEED;
+
+ /* Don't use "FUNC_ENTER" macro, we are trying to avoid certain initialization code */
+ PABLO_TRACE_ON(H5_mask, ID_H5dont_atexit);
+
+ if(install_atexit == TRUE)
+ install_atexit=FALSE;
+
+#ifdef LATER
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+#endif /* LATER */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5_mask, ID_H5dont_atexit,ret_value);
+} /* end H5dont_atexit() */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5version -- Checks the version of the library
+USAGE
+ herr_t H5version(majnum, minnum, relnum, patnum)
+ uintn *majnum; OUT: The major revision number of the HDF5 library
+ uintn *minnum; OUT: The minor revision number of the HDF5 library
+ uintn *relnum; OUT: The release revision number of the HDF5 library
+ uintn *patnum; OUT: The patch revision number of the HDF5 library
+
+RETURNS
+ SUCCEED/FAIL
+DESCRIPTION
+ Checks the version numbers of the library.
+
+--------------------------------------------------------------------------*/
+herr_t H5version(uintn *majnum, uintn *minnum, uintn *relnum, uintn *patnum)
+{
+ CONSTR(FUNC, "H5version"); /* For HERROR */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5_mask, ID_H5version, H5_init_interface,FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+ if (majnum==NULL || minnum==NULL || relnum==NULL || patnum==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+
+ /* Set the version information */
+ *majnum=HDF5_MAJOR_VERSION;
+ *minnum=HDF5_MINOR_VERSION;
+ *relnum=HDF5_RELEASE_VERSION;
+ *patnum=HDF5_PATCH_VERSION;
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5_mask, ID_H5version, ret_value);
+} /* H5version */
+
diff --git a/src/H5A.c b/src/H5A.c
new file mode 100644
index 0000000..3733bf8
--- /dev/null
+++ b/src/H5A.c
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * NCSA HDF *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * hdf/COPYING file. *
+ * *
+ ****************************************************************************/
+
+#ifdef RCSID
+static char RcsId[] = "@(#)$Revision$";
+#endif
+
+/* $Id$ */
+
+/*
+FILE
+ atom.c - Internal storage routines for handling "atoms"
+
+REMARKS
+ Atoms are just ID's which allow objects (void *'s currently) to be
+ bundled into "groups" for more general storage.
+
+DESIGN
+ The groups are stored in an array of pointers to store each group in an
+ element. Each "atomic group" node contains a link to a hash table to
+ manage the atoms in each group. The allowed "atomic groups" are stored
+ in an enum (called group_t) in atom.h.
+
+BUGS/LIMITATIONS
+ Can't interate over the atoms in a group.
+
+LOCAL ROUTINES
+ H5A_find_atom - Returns a pointer to an atom_info_t from a atom ID
+ H5A_get_atom_node - Gets an atom node (uses the atom free list)
+ H5A_release_atom_node - Releases an atom node (uses the atom free list)
+EXPORTED ROUTINES
+ Atom Functions:
+ H5Aregister_atom - Register an object in a group and get an atom for it
+ H5Aatom_object - Get the object for an atom
+ H5Aatom_group - Get the group for an atom
+ H5Aremove_atom - Remove an atom from a group
+ H5Asearch_atom - Search a group for a particular object
+ H5Ais_reserved - Check whether an atom is a reserved atom in a group
+ Atom Group Functions:
+ H5Ainit_group - Initialize a group to store atoms in
+ H5Adestroy_group - Destroy an atomic group
+ Atom Group Cleanup:
+ H5Ashutdown - Terminate various static buffers.
+
+AUTHOR
+ Quincey Koziol
+
+MODIFICATION HISTORY
+ 1/3/96 - Starting writing specs & coding prototype
+ 1/7/96 - Finished coding prototype
+ 6/10/97 - Moved into HDF5 library
+*/
+
+#define HDF5_ATOM_MASTER
+#include "hdf5.h"
+#include "H5Aprivate.h"
+
+
+/* Private function prototypes */
+static atom_info_t *H5A_find_atom(hatom_t atm);
+
+static atom_info_t *H5A_get_atom_node(void);
+
+static void H5A_release_atom_node(atom_info_t *atm);
+
+/******************************************************************************
+ NAME
+ H5Ainit_group - Initialize an atomic group
+
+ DESCRIPTION
+ Creates a global atomic group to store atoms in. If the group has already
+ been initialized, this routine just increments the count of # of
+ initializations and returns without trying to change the size of the hash
+ table. A specific number of group entries may be reserved to enable
+ "constant" values to be handed out which are valid atoms in the group, but
+ which do not map to any data structures and are not allocated dynamicly
+ later.
+
+ RETURNS
+ Returns SUCCEED if successful and FAIL otherwise
+
+*******************************************************************************/
+intn H5Ainit_group(group_t grp, /* IN: Group to initialize */
+ intn hash_size, /* IN: Minimum hash table size to use for group */
+ uintn reserved /* IN: Number of hash table entries to reserve */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Ainit_group"); /* for HERROR */
+#endif /* LATER */
+ atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
+ intn ret_value=SUCCEED;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Ainit_group);
+
+ if((grp<=BADGROUP || grp>=MAXGROUP) && hash_size>0)
+ HGOTO_DONE(FAIL);
+
+#ifdef HASH_SIZE_POWER_2
+ /* If anyone knows a faster test for a power of two, please change this silly code -QAK */
+ if(!(hash_size==2 || hash_size==4 || hash_size==8 || hash_size==16
+ || hash_size==32 || hash_size==64 || hash_size==128 || hash_size==256
+ || hash_size==512 || hash_size==1024 || hash_size==2048
+ || hash_size==4096 || hash_size==8192 || hash_size==16374
+ || hash_size==32768 || hash_size==65536 || hash_size==131072
+ || hash_size==262144 || hash_size==524288 || hash_size==1048576
+ || hash_size==2097152 || hash_size==4194304 || hash_size==8388608
+ || hash_size==16777216 || hash_size==33554432 || hash_size==67108864
+ || hash_size==134217728 || hash_size==268435456))
+ HGOTO_DONE(FAIL);
+#endif /* HASH_SIZE_POWER_2 */
+
+ if(atom_group_list[grp]==NULL)
+ { /* Allocate the group information */
+ grp_ptr=(atom_group_t *)HDcalloc(1,sizeof(atom_group_t));
+ if(grp_ptr==NULL)
+ HGOTO_DONE(FAIL);
+ atom_group_list[grp]=grp_ptr;
+ } /* end if */
+ else /* Get the pointer to the existing group */
+ grp_ptr=atom_group_list[grp];
+
+ if(grp_ptr->count==0)
+ { /* Initialize the atom group structure */
+ grp_ptr->hash_size=hash_size;
+ grp_ptr->reserved=reserved;
+ grp_ptr->wrapped=0;
+ grp_ptr->atoms=0;
+ grp_ptr->nextid=0;
+ if((grp_ptr->atom_list=(atom_info_t **)HDcalloc(hash_size,sizeof(atom_info_t *)))==NULL)
+ HGOTO_DONE(FAIL);
+ } /* end if */
+
+ /* Increment the count of the times this group has been initialized */
+ grp_ptr->count++;
+
+#ifdef QAK
+printf("%s: group ID=%d, count=%d, current # of active atoms=%d\n",FUNC,grp,grp_ptr->count,grp_ptr->atoms);
+#endif /* QAK */
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+ if(grp_ptr!=NULL)
+ {
+ if(grp_ptr->atom_list!=NULL)
+ HDfree(grp_ptr->atom_list);
+ HDfree(grp_ptr);
+ } /* end if */
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Ainit_group, ret_value);
+} /* end H5Ainit_group() */
+
+/******************************************************************************
+ NAME
+ H5Adestroy_group - Destroy an atomic group
+
+ DESCRIPTION
+ Destroys an atomic group which atoms are stored in. If the group still
+ has atoms which are registered, this routine fails. If there have been
+ multiple initializations of the group, this routine just decrements the
+ count of initializations and does not check the atoms out-standing.
+
+ RETURNS
+ Returns SUCCEED if successful and FAIL otherwise
+
+*******************************************************************************/
+intn H5Adestroy_group(group_t grp /* IN: Group to destroy */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Adestroy_group"); /* for HERROR */
+#endif /* LATER */
+ atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
+ intn ret_value=SUCCEED;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Adestroy_group);
+
+ if(grp<=BADGROUP || grp>=MAXGROUP)
+ HGOTO_DONE(FAIL);
+
+ grp_ptr=atom_group_list[grp];
+ if(grp_ptr==NULL || grp_ptr->count<=0)
+ HGOTO_DONE(FAIL);
+
+#ifdef QAK
+printf("%s: group ID=%d, count=%d, current # of active atoms=%d\n",FUNC,grp,grp_ptr->count,grp_ptr->atoms);
+#endif /* QAK */
+ /* Decrement the number of users of the atomic group */
+ if((--(grp_ptr->count))==0)
+ {
+#ifdef ATOMS_ARE_CACHED
+ {
+ uintn i;
+
+ for(i=0; i<ATOM_CACHE_SIZE; i++)
+ if(ATOM_TO_GROUP(atom_id_cache[i])==grp)
+ {
+ atom_id_cache[i]=(-1);
+ atom_obj_cache[i]=NULL;
+ } /* end if */
+ } /* end block */
+#endif /* ATOMS_ARE_CACHED */
+ HDfree(grp_ptr->atom_list);
+ } /* end if */
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Adestroy_group, ret_value);
+} /* end H5Adestroy_group() */
+
+/******************************************************************************
+ NAME
+ H5Aregister_atom - Register an object in a group and get an atom for it.
+
+ DESCRIPTION
+ Registers an object in a group and returns an atom for it. This routine
+ does _not_ check for unique-ness of the objects, if you register an object
+ twice, you will get two different atoms for it. This routine does make
+ certain that each atom in a group is unique. Atoms are created by getting
+ a unique number for the group the atom is in and incorporating the group
+ into the atom which is returned to the user.
+
+ RETURNS
+ Returns atom if successful and FAIL otherwise
+
+*******************************************************************************/
+hatom_t H5Aregister_atom(group_t grp, /* IN: Group to register the object in */
+ const VOIDP object /* IN: Object to attach to atom */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Aregister_atom"); /* for HERROR */
+#endif /* LATER */
+ atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
+ atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
+ hatom_t atm_id; /* new atom ID */
+ uintn hash_loc; /* new item's hash table location */
+ hatom_t ret_value=SUCCEED;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Aregister_atom);
+
+ if(grp<=BADGROUP || grp>=MAXGROUP)
+ HGOTO_DONE(FAIL);
+
+ grp_ptr=atom_group_list[grp];
+ if(grp_ptr==NULL || grp_ptr->count<=0)
+ HGOTO_DONE(FAIL);
+
+ if((atm_ptr=H5A_get_atom_node())==NULL)
+ HGOTO_DONE(FAIL);
+
+ /* Create the atom & it's ID */
+ atm_id=MAKE_ATOM(grp,grp_ptr->nextid);
+ atm_ptr->id=atm_id;
+ atm_ptr->obj_ptr=object;
+ atm_ptr->next=NULL;
+
+ /* hash bucket already full, prepend to front of chain */
+ hash_loc=grp_ptr->nextid%(uintn)grp_ptr->hash_size;
+ if(grp_ptr->atom_list[hash_loc]!=NULL)
+ atm_ptr->next=grp_ptr->atom_list[hash_loc];
+
+ /* Insert into the group */
+ grp_ptr->atom_list[hash_loc]=atm_ptr;
+ grp_ptr->atoms++;
+ grp_ptr->nextid++;
+
+ /*
+ * This next section of code checks for the 'nextid' getting too large and
+ * wrapping around, thus necessitating checking for duplicate atoms being
+ * handed out.
+ */
+ if(grp_ptr->nextid>(uintn)ATOM_MASK || grp_ptr->wrapped!=0)
+ {
+ if(grp_ptr->wrapped==0)
+ {
+ grp_ptr->wrapped=1; /* set the "wrapped around" flag if it isn't already */
+ grp_ptr->nextid=grp_ptr->reserved; /* re-start the ID counter */
+ } /* end if */
+ do {
+ hatom_t next_atom=MAKE_ATOM(grp,grp_ptr->nextid); /* new atom to check for */
+ atom_info_t *curr_atm; /* ptr to the current atom */
+
+ curr_atm=grp_ptr->atom_list[(uintn)ATOM_TO_LOC(grp_ptr->nextid,grp_ptr->hash_size)];
+ if(curr_atm==NULL) /* Ha! this is not likely... */
+ break;
+
+ while(curr_atm!=NULL)
+ {
+ if(curr_atm->id==next_atom)
+ break;
+ curr_atm=curr_atm->next;
+ } /* end while */
+ if(curr_atm==NULL) /* must not have found a match */
+ break;
+ grp_ptr->nextid++;
+ } while(grp_ptr->nextid<=(uintn)ATOM_MASK);
+ if(grp_ptr->nextid>(uintn)ATOM_MASK) /* All the atoms are gone! */
+ HGOTO_DONE(FAIL);
+ } /* end if */
+
+ ret_value=atm_id;
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Aregister_atom, ret_value);
+} /* end H5Aregister_atom() */
+
+/******************************************************************************
+ NAME
+ H5Aatom_object - Returns to the object ptr for the atom
+
+ DESCRIPTION
+ Retrieves the object ptr which is associated with the atom.
+
+ RETURNS
+ Returns object ptr if successful and NULL otherwise
+
+*******************************************************************************/
+VOIDP H5Aatom_object(hatom_t atm /* IN: Atom to retrieve object for */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Aatom_object"); /* for HERROR */
+#endif /* LATER */
+#ifdef ATOMS_ARE_CACHED
+ uintn i; /* local counter */
+#endif /* ATOMS_ARE_CACHED */
+ atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
+ VOIDP ret_value=NULL;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Aatom_object);
+
+#ifdef ATOMS_ARE_CACHED
+ /* Look for the atom in the cache first */
+ for(i=0; i<ATOM_CACHE_SIZE; i++)
+ if(atom_id_cache[i]==atm)
+ {
+ ret_value=atom_obj_cache[i];
+ if(i>0)
+ { /* Implement a simple "move forward" caching scheme */
+ hatom_t t_atom=atom_id_cache[i-1];
+ VOIDP t_obj=atom_obj_cache[i-1];
+
+ atom_id_cache[i-1]=atom_id_cache[i];
+ atom_obj_cache[i-1]=atom_obj_cache[i];
+ atom_id_cache[i]=t_atom;
+ atom_obj_cache[i]=t_obj;
+ } /* end if */
+ HGOTO_DONE(ret_value);
+ } /* end if */
+#endif /* ATOMS_ARE_CACHED */
+
+ /* General lookup of the atom */
+ if((atm_ptr=H5A_find_atom(atm))==NULL)
+ HGOTO_DONE(NULL);
+
+ /* Check if we've found the correct atom */
+ if(atm_ptr!=NULL)
+ ret_value=atm_ptr->obj_ptr;
+
+done:
+ if(ret_value == NULL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Aatom_object, ret_value);
+} /* end H5Aatom_object() */
+
+/******************************************************************************
+ NAME
+ H5Aatom_group - Returns to the group for the atom
+
+ DESCRIPTION
+ Retrieves the group which is associated with the atom.
+
+ RETURNS
+ Returns group if successful and BADGROUP otherwise
+
+*******************************************************************************/
+group_t H5Aatom_group(hatom_t atm /* IN: Atom to retrieve group for */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Aatom_group"); /* for HERROR */
+#endif /* LATER */
+ group_t ret_value=BADGROUP;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Aatom_group);
+
+ ret_value=ATOM_TO_GROUP(atm);
+ if(ret_value<=BADGROUP || ret_value>=MAXGROUP)
+ HGOTO_DONE(BADGROUP);
+
+done:
+ if(ret_value == BADGROUP)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Aatom_group, ret_value);
+} /* end H5Aatom_group() */
+
+/******************************************************************************
+ NAME
+ H5Aremove_atom - Removes an atom from a group
+
+ DESCRIPTION
+ Removes an atom from a group.
+
+ RETURNS
+ Returns atom's object if successful and NULL otherwise
+
+*******************************************************************************/
+VOIDP H5Aremove_atom(hatom_t atm /* IN: Atom to remove */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Aremove_atom"); /* for HERROR */
+#endif /* LATER */
+ atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
+ atom_info_t *curr_atm, /* ptr to the current atom */
+ *last_atm; /* ptr to the last atom */
+ group_t grp; /* atom's atomic group */
+ uintn hash_loc; /* atom's hash table location */
+#ifdef ATOMS_ARE_CACHED
+ uintn i; /* local counting variable */
+#endif /* ATOMS_ARE_CACHED */
+ VOIDP ret_value=NULL;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Aremove_atom);
+
+ grp=ATOM_TO_GROUP(atm);
+ if(grp<=BADGROUP || grp>=MAXGROUP)
+ HGOTO_DONE(NULL);
+
+ grp_ptr=atom_group_list[grp];
+ if(grp_ptr==NULL || grp_ptr->count<=0)
+ HGOTO_DONE(NULL);
+
+ /* Get the location in which the atom is located */
+ hash_loc=(uintn)ATOM_TO_LOC(atm,grp_ptr->hash_size);
+ curr_atm=grp_ptr->atom_list[hash_loc];
+ if(curr_atm==NULL)
+ HGOTO_DONE(NULL);
+
+ last_atm=NULL;
+ while(curr_atm!=NULL)
+ {
+ if(curr_atm->id==atm)
+ break;
+ last_atm=curr_atm;
+ curr_atm=curr_atm->next;
+ } /* end while */
+
+ if(curr_atm!=NULL)
+ {
+ if(last_atm==NULL) /* atom is the first the chain */
+ grp_ptr->atom_list[hash_loc]=curr_atm->next;
+ else
+ last_atm->next=curr_atm->next;
+ ret_value=curr_atm->obj_ptr;
+ H5A_release_atom_node(curr_atm);
+ } /* end if */
+ else /* couldn't find the atom in the proper place */
+ HGOTO_DONE(NULL);
+
+#ifdef ATOMS_ARE_CACHED
+ /* Delete object from cache */
+ for(i=0; i<ATOM_CACHE_SIZE; i++)
+ if(atom_id_cache[i]==atm)
+ {
+ atom_id_cache[i]=(-1);
+ atom_obj_cache[i]=NULL;
+ break; /* we assume there is only one instance in the cache */
+ } /* end if */
+#endif /* ATOMS_ARE_CACHED */
+
+ /* Decrement the number of atoms in the group */
+ (grp_ptr->atoms)--;
+
+done:
+ if(ret_value == NULL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Aremove_atom, ret_value);
+} /* end H5Aremove_atom() */
+
+/******************************************************************************
+ NAME
+ H5Asearch_atom - Search for an object in a group and get it's pointer.
+
+ DESCRIPTION
+ Searchs for an object in a group and returns the pointer to it.
+ This routine calls the function pointer passed in for each object in the
+ group until it finds a match. Currently there is no way to resume a
+ search.
+
+ RETURNS
+ Returns pointer an atom's object if successful and NULL otherwise
+
+*******************************************************************************/
+VOIDP H5Asearch_atom(group_t grp, /* IN: Group to search for the object in */
+ H5Asearch_func_t func, /* IN: Ptr to the comparison function */
+ const VOIDP key /* IN: pointer to key to compare against */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Asearch_atom"); /* for HERROR */
+#endif /* LATER */
+ atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
+ atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
+ intn i; /* local counting variable */
+ VOIDP ret_value=NULL;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Asearch_atom);
+
+ if(grp<=BADGROUP || grp>=MAXGROUP)
+ HGOTO_DONE(NULL);
+
+ grp_ptr=atom_group_list[grp];
+ if(grp_ptr==NULL || grp_ptr->count<=0)
+ HGOTO_DONE(NULL);
+
+ /* Start at the beginning of the array */
+ for(i=0; i<grp_ptr->hash_size; i++)
+ {
+ atm_ptr=grp_ptr->atom_list[i];
+ while(atm_ptr!=NULL)
+ {
+ if((*func)(atm_ptr->obj_ptr,key))
+ HGOTO_DONE(atm_ptr->obj_ptr); /* found the item we are looking for */
+ atm_ptr=atm_ptr->next;
+ } /* end while */
+ } /* end for */
+
+done:
+ if(ret_value == NULL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Asearch_atom, ret_value);
+} /* end H5Asearch_atom() */
+
+/******************************************************************************
+ NAME
+ H5Ais_reserved - Check whether an atom is a reserved atom in a group
+
+ DESCRIPTION
+ Determines the group an atom belongs to and checks if the atom is a
+ reserved atom in the group.
+
+ RETURNS
+ Returns BTRUE/BFALSE/BFAIL
+
+*******************************************************************************/
+intn H5Ais_reserved(hatom_t atm /* IN: Group to search for the object in */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5Ais_reserved"); /* for HERROR */
+#endif /* LATER */
+ atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
+ group_t grp; /* atom's atomic group */
+ hbool_t ret_value=BFAIL;
+
+ PABLO_TRACE_ON(H5A_mask, ID_H5Ais_reserved);
+
+ grp=ATOM_TO_GROUP(atm);
+ if(grp<=BADGROUP || grp>=MAXGROUP)
+ HGOTO_DONE(BFAIL);
+
+ grp_ptr=atom_group_list[grp];
+ if(grp_ptr==NULL)
+ HGOTO_DONE(BFAIL);
+
+ /* Get the location in which the atom is located */
+ if((atm&ATOM_MASK)<grp_ptr->reserved)
+ ret_value=BTRUE;
+ else
+ ret_value=BFALSE;
+
+done:
+ if(ret_value == BFAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+ FUNC_LEAVE(H5A_mask, ID_H5Ais_reserved, ret_value);
+} /* end H5Ais_reserved() */
+
+/******************************************************************************
+ NAME
+ H5A_find_atom - Finds a atom in a group
+
+ DESCRIPTION
+ Retrieves the atom ptr which is associated with the atom.
+
+ RETURNS
+ Returns atom ptr if successful and NULL otherwise
+
+*******************************************************************************/
+static atom_info_t *H5A_find_atom(hatom_t atm /* IN: Atom to retrieve atom for */
+)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5A_find_atom"); /* for HERROR */
+#endif /* LATER */
+ atom_group_t *grp_ptr=NULL; /* ptr to the atomic group */
+ atom_info_t *atm_ptr=NULL; /* ptr to the new atom */
+ group_t grp; /* atom's atomic group */
+ uintn hash_loc; /* atom's hash table location */
+ atom_info_t *ret_value=NULL;
+
+
+ grp=ATOM_TO_GROUP(atm);
+ if(grp<=BADGROUP || grp>=MAXGROUP)
+ HGOTO_DONE(NULL);
+
+ grp_ptr=atom_group_list[grp];
+ if(grp_ptr==NULL || grp_ptr->count<=0)
+ HGOTO_DONE(NULL);
+
+ /* Get the location in which the atom is located */
+ hash_loc=(uintn)ATOM_TO_LOC(atm,grp_ptr->hash_size);
+ atm_ptr=grp_ptr->atom_list[hash_loc];
+ if(atm_ptr==NULL)
+ HGOTO_DONE(NULL);
+
+ while(atm_ptr!=NULL)
+ {
+ if(atm_ptr->id==atm)
+ break;
+ atm_ptr=atm_ptr->next;
+ } /* end while */
+ ret_value=atm_ptr;
+
+#ifdef ATOMS_ARE_CACHED
+ atom_id_cache[ATOM_CACHE_SIZE-1]=atm;
+ atom_obj_cache[ATOM_CACHE_SIZE-1]=atm_ptr->obj_ptr;
+#endif /* ATOMS_ARE_CACHED */
+
+done:
+ if(ret_value == NULL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ return ret_value;
+} /* end H5A_find_atom() */
+
+/******************************************************************************
+ NAME
+ H5A_get_atom_node - Gets an atom node
+
+ DESCRIPTION
+ Either gets an atom node from the free list (if there is one available)
+ or allocate a node.
+
+ RETURNS
+ Returns atom ptr if successful and NULL otherwise
+
+*******************************************************************************/
+static atom_info_t *H5A_get_atom_node(void)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5A_get_atom_node"); /* for HERROR */
+#endif /* LATER */
+ atom_info_t *ret_value=NULL;
+
+ if(atom_free_list!=NULL)
+ {
+ ret_value=atom_free_list;
+ atom_free_list=atom_free_list->next;
+ } /* end if */
+ else
+ {
+ if((ret_value=(atom_info_t *)HDmalloc(sizeof(atom_info_t)))==NULL)
+ HGOTO_DONE(NULL);
+ } /* end else */
+
+done:
+ if(ret_value == NULL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ return ret_value;
+} /* end H5A_get_atom_node() */
+
+/******************************************************************************
+ NAME
+ H5A_release_atom_node - Releases an atom node
+
+ DESCRIPTION
+ Puts an atom node into the free list
+
+ RETURNS
+ No return value
+
+*******************************************************************************/
+static void H5A_release_atom_node(atom_info_t *atm)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5A_release_atom_node"); /* for HERROR */
+#endif /* LATER */
+
+ /* Insert the atom at the beginning of the free list */
+ atm->next=atom_free_list;
+ atom_free_list=atm;
+} /* end H5A_release_atom_node() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Ashutdown
+ PURPOSE
+ Terminate various static buffers.
+ USAGE
+ intn H5Ashutdown()
+ RETURNS
+ Returns SUCCEED/FAIL
+ DESCRIPTION
+ Free various buffers allocated in the H5A routines.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Should only ever be called by the "atexit" function HDFend
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+intn
+H5Ashutdown(void)
+{
+ atom_info_t *curr;
+ intn i;
+
+ /* Release the free-list if it exists */
+ if(atom_free_list!=NULL)
+ {
+ while(atom_free_list!=NULL)
+ {
+ curr=atom_free_list;
+ atom_free_list=atom_free_list->next;
+ HDfree(curr);
+ } /* end while */
+ } /* end if */
+
+ for(i=0; i<(intn)MAXGROUP; i++)
+ if(atom_group_list[i]!=NULL)
+ {
+ HDfree(atom_group_list[i]);
+ atom_group_list[i]=NULL;
+ } /* end if */
+ return (SUCCEED);
+} /* end H5Ashutdown() */
+
diff --git a/src/H5AC.c b/src/H5AC.c
new file mode 100644
index 0000000..a0123b1
--- /dev/null
+++ b/src/H5AC.c
@@ -0,0 +1,315 @@
+/*-------------------------------------------------------------------------
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * Created: hdf5cache.c
+ * Jul 9 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Functions in this file implement a cache for
+ * things which exist on disk. All "things" associated
+ * with a particular HDF file share the same cache; each
+ * HDF file has it's own cache.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <assert.h>
+#include "hdf5.h"
+
+#include "H5ACprivate.h"
+
+#define HASH(addr) ((unsigned)(addr) % H5AC_NSLOTS)
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_new
+ *
+ * Purpose: Initialize the cache just after a file is opened.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 9 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_new (hdf5_file_t *f)
+{
+ f->cache = HDcalloc (H5AC_NSLOTS, sizeof (H5AC_cache_t));
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_dest
+ *
+ * Purpose: Flushes all data to disk and destroys the cache.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 9 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_dest (hdf5_file_t *f)
+{
+ if (H5AC_flush (f, NULL, 0, TRUE)<0) return -1;
+ HDfree (f->cache);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_find
+ *
+ * Purpose: Given an object type and the address at which that object
+ * is located in the file, return a pointer to the object.
+ * The optional UDATA structure is passed down to the function
+ * that is responsible for loading the object into memory.
+ *
+ * Return: Success: Pointer to the object. The pointer is
+ * valid until some other cache function
+ * is called.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 9 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5AC_find (hdf5_file_t *f, const H5AC_class_t *type, off_t addr,
+ const void *udata)
+{
+ unsigned idx = HASH(addr);
+ herr_t status;
+ void *thing = NULL;
+ herr_t (*flush)(hdf5_file_t*,hbool_t,off_t,void*)=NULL;
+
+ assert (type);
+ assert (type->load);
+ assert (type->flush);
+
+ /*
+ * Return right away if the item is in the cache.
+ */
+ if (f->cache[idx].type==type && f->cache[idx].addr==addr) {
+ return f->cache[idx].thing;
+ }
+
+ /*
+ * Load a new thing. If it can't be loaded, then return an error
+ * without preempting anything.
+ */
+ if (NULL==(thing=(type->load)(f, addr, udata))) {
+ return NULL;
+ }
+
+ /*
+ * Free the previous cache entry if there is one.
+ */
+ if (f->cache[idx].type) {
+ flush = f->cache[idx].type->flush;
+ status = (flush)(f, TRUE, f->cache[idx].addr, f->cache[idx].thing);
+ if (status<0) {
+ /*
+ * The old thing could not be removed from the stack.
+ * Release the new thing and fail.
+ */
+ status = (type->flush)(f, TRUE, addr, thing);
+ assert (status>=0);
+ return NULL;
+ }
+ }
+
+ /*
+ * Make the cache point to the new thing.
+ */
+ f->cache[idx].type = type;
+ f->cache[idx].addr = addr;
+ f->cache[idx].thing = thing;
+
+ return thing;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_flush
+ *
+ * Purpose: Flushes (and destroys if DESTROY is non-zero) the specified
+ * entry from the cache. If the entry type is CACHE_FREE then
+ * all types of entries are flushed. If the ADDR is zero then
+ * all entries of the specified type are flushed.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 9 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, off_t addr,
+ hbool_t destroy)
+{
+ uintn i = HASH(addr);
+ herr_t status;
+ herr_t (*flush)(hdf5_file_t*,hbool_t,off_t,void*)=NULL;
+
+ if (!type || 0==addr) {
+ /*
+ * Look at all cache entries.
+ */
+ for (i=0; i<H5AC_NSLOTS; i++) {
+ if (NULL==f->cache[i].type) continue;
+ if ((!type || type==f->cache[i].type) &&
+ (0==addr || addr==f->cache[i].addr)) {
+ flush = f->cache[i].type->flush;
+ status = (flush)(f, destroy, f->cache[i].addr,
+ f->cache[i].thing);
+ if (status<0) return -1;
+ if (destroy) f->cache[i].type = NULL;
+ }
+ }
+
+ } else if (f->cache[i].type==type && f->cache[i].addr==addr) {
+ /*
+ * Flush just this entry.
+ */
+ flush = f->cache[i].type->flush;
+ status = (flush) (f, destroy, f->cache[i].addr, f->cache[i].thing);
+ if (status<0) return -1;
+ if (destroy) f->cache[i].type = NULL;
+
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_set
+ *
+ * Purpose: Adds the specified thing to the cache. The thing need not
+ * exist on disk yet, but it must have an address and disk
+ * space reserved.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 9 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_set (hdf5_file_t *f, const H5AC_class_t *type, off_t addr, void *thing)
+{
+ herr_t status;
+ uintn idx = HASH (addr);
+ herr_t (*flush)(hdf5_file_t*,hbool_t,off_t,void*)=NULL;
+
+ assert (type);
+ assert (type->flush);
+
+ if (f->cache[idx].type) {
+ flush = f->cache[idx].type->flush;
+ status = (flush)(f, TRUE, f->cache[idx].addr, f->cache[idx].thing);
+ if (status<0) return -1;
+ }
+
+ f->cache[idx].type = type;
+ f->cache[idx].addr = addr;
+ f->cache[idx].thing = thing;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_rename
+ *
+ * Purpose: Use this function to notify the cache that an object's
+ * file address changed.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 9 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_rename (hdf5_file_t *f, const H5AC_class_t *type,
+ off_t old_addr, off_t new_addr)
+{
+ uintn old_idx = HASH (old_addr);
+ uintn new_idx = HASH (new_addr);
+ herr_t (*flush)(hdf5_file_t*, hbool_t, off_t, void*);
+ herr_t status;
+
+ assert (type);
+
+ if (f->cache[old_idx].type!=type || f->cache[old_idx].addr!=old_addr) {
+ return 0; /*item not in cache*/
+ }
+
+ if (old_idx==new_idx) {
+ f->cache[old_idx].addr = new_addr;
+ return 0;
+ }
+
+ /*
+ * Free the item from the destination cache line.
+ */
+ if (f->cache[new_idx].type) {
+ flush = f->cache[new_idx].type->flush;
+ status = (flush)(f, TRUE, f->cache[new_idx].addr,
+ f->cache[new_idx].thing);
+ if (status<0) return -1;
+ }
+
+ /*
+ * Move the source to the destination (it might not be cached)
+ */
+ f->cache[new_idx].type = f->cache[old_idx].type;
+ f->cache[new_idx].addr = new_addr;
+ f->cache[new_idx].thing = f->cache[old_idx].thing;
+ f->cache[old_idx].type = NULL;
+
+ return 0;
+}
+
diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h
new file mode 100644
index 0000000..5dce2cd
--- /dev/null
+++ b/src/H5ACprivate.h
@@ -0,0 +1,71 @@
+/*-------------------------------------------------------------------------
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * Created: H5ACprivate.h
+ * Jul 9 1997
+ * Robb Matzke <robb@maya.nuance.com>
+ *
+ * Purpose: Constants and typedefs available to the rest of the
+ * library.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5ACprivate_H
+#define _H5ACprivate_H
+
+#include "H5ACproto.h" /*public prototypes */
+#include "H5Fprivate.h" /*for private hdf5_file_t definition */
+
+/*
+ * Class methods pertaining to caching. Each type of cached object will
+ * have a constant variable with permanent life-span that describes how
+ * to cache the object. That variable will be of type H5AC_class_t and
+ * have the following required fields...
+ *
+ * LOAD: Loads an object from disk to memory. The function
+ * should allocate some data structure and return it.
+ *
+ * FLUSH: Writes some data structure back to disk. It would be
+ * wise for the data structure to include dirty flags to
+ * indicate whether it really needs to be written. This
+ * function is also responsible for freeing memory allocated
+ * by the LOAD method if the DEST argument is non-zero.
+ */
+typedef struct H5AC_class_t {
+ void *(*load)(hdf5_file_t*, off_t addr, const void *udata);
+ herr_t (*flush)(hdf5_file_t*, hbool_t dest, off_t addr, void *thing);
+} H5AC_class_t;
+
+/*
+ * A cache has a certain number of entries. Objects are mapped into a
+ * cache entry by hashing the object's file address. Each file has its
+ * own cache, an array of slots.
+ */
+#define H5AC_NSLOTS 1033 /*prime number tend to work best */
+
+typedef struct H5AC_cache_t {
+ const H5AC_class_t *type; /*type of object stored here */
+ off_t addr; /*file address for object */
+ void *thing; /*the thing which is cached */
+} H5AC_cache_t;
+
+/*
+ * Library prototypes.
+ */
+herr_t H5AC_dest (hdf5_file_t *f);
+void *H5AC_find (hdf5_file_t *f, const H5AC_class_t *type, off_t addr,
+ const void *udata);
+herr_t H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, off_t addr,
+ hbool_t destroy);
+herr_t H5AC_new (hdf5_file_t *f);
+herr_t H5AC_rename (hdf5_file_t *f, const H5AC_class_t *type,
+ off_t old, off_t new);
+herr_t H5AC_set (hdf5_file_t *f, const H5AC_class_t *type, off_t addr,
+ void *thing);
+
+#endif /* !_H5ACprivate_H */
diff --git a/src/H5ACproto.h b/src/H5ACproto.h
new file mode 100644
index 0000000..25218a9
--- /dev/null
+++ b/src/H5ACproto.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * Created: H5ACproto.h
+ * Jul 10 1997
+ * Robb Matzke <robb@maya.nuance.com>
+ *
+ * Purpose: Function prototypes for the H5AC package.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5ACproto_H
+#define _H5ACproto_H
+
+#if defined c_plusplus || defined __cplusplus
+extern "C"
+{
+#endif
+
+#if defined c_plusplus || defined __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/H5Aprivate.h b/src/H5Aprivate.h
new file mode 100644
index 0000000..1a2db6f
--- /dev/null
+++ b/src/H5Aprivate.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+ * NCSA HDF *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * hdf/COPYING file. *
+ * *
+ ****************************************************************************/
+
+/* $Id$ */
+
+/*-----------------------------------------------------------------------------
+ * File: atom.h
+ * Purpose: header file for atom API
+ *---------------------------------------------------------------------------*/
+
+/* avoid re-inclusion */
+#ifndef __ATOM_H
+#define __ATOM_H
+
+#include "H5Aproto.h" /* Include Public Definitions */
+
+/* Atom Features control */
+/* Define the following macro for fast hash calculations (but limited hash sizes) */
+#define HASH_SIZE_POWER_2
+
+/* Define the following macro for atom caching over all the atoms */
+#define ATOMS_ARE_CACHED
+
+#if defined HDF5_ATOM_MASTER | defined HDF5_ATOM_TESTER
+#ifdef ATOMS_ARE_CACHED
+/* # of previous atoms cached */
+#define ATOM_CACHE_SIZE 4
+#endif /* ATOMS_ARE_CACHED */
+
+/* Map an atom to a Group number */
+#define ATOM_TO_GROUP(a) ((group_t)((((hatom_t)(a))>>((sizeof(hatom_t)*8)-GROUP_BITS))&GROUP_MASK))
+
+#ifdef HASH_SIZE_POWER_2
+/* Map an atom to a hash location (assumes s is a power of 2 and smaller than the ATOM_MASK constant) */
+#define ATOM_TO_LOC(a,s) ((hatom_t)(a)&((s)-1))
+#else /* HASH_SIZE_POWER_2 */
+/* Map an atom to a hash location */
+#define ATOM_TO_LOC(a,s) (((hatom_t)(a)&ATOM_MASK)%(s))
+#endif /* HASH_SIZE_POWER_2 */
+
+/* Atom information structure used */
+typedef struct atom_info_struct_tag {
+ hatom_t id; /* atom ID for this info */
+ VOIDP *obj_ptr; /* pointer associated with the atom */
+ struct atom_info_struct_tag *next; /* link to next atom (in case of hash-clash) */
+ }atom_info_t;
+
+/* Atom group structure used */
+typedef struct atom_group_struct_tag {
+ uintn count; /* # of times this group has been initialized */
+ uintn reserved; /* # of atoms to reserve for constant atoms */
+ uintn wrapped; /* whether the id count has wrapped around */
+ intn hash_size; /* size of the hash table to store the atoms in */
+ uintn atoms; /* current number of atoms held */
+ uintn nextid; /* atom ID to use for the next atom */
+ atom_info_t **atom_list;/* pointer to an array of ptrs to atoms */
+ }atom_group_t;
+
+/* Define this in only one place */
+#ifdef HDF5_ATOM_MASTER
+
+/* Array of pointers to atomic groups */
+static atom_group_t *atom_group_list[MAXGROUP]={NULL};
+
+/* Pointer to the atom node free list */
+static atom_info_t *atom_free_list=NULL;
+
+#ifdef ATOMS_ARE_CACHED
+/* Array of pointers to atomic groups */
+static hatom_t atom_id_cache[ATOM_CACHE_SIZE]={-1,-1,-1,-1};
+static VOIDP atom_obj_cache[ATOM_CACHE_SIZE]={NULL};
+#endif /* ATOMS_ARE_CACHED */
+
+#endif /* HDF5_ATOM_MASTER */
+
+/* Useful routines for generally private use */
+
+#endif /* HDF5_ATOM_MASTER | HDF5_ATOM_TESTER */
+
+#endif /* __ATOM_H */
+
diff --git a/src/H5Aproto.h b/src/H5Aproto.h
new file mode 100644
index 0000000..2bf2ba5
--- /dev/null
+++ b/src/H5Aproto.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+ * NCSA HDF *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * hdf/COPYING file. *
+ * *
+ ****************************************************************************/
+
+/* $Id$ */
+
+/*
+ * This file contains function prototypes for each exported function in the H5A module
+ */
+
+#ifndef H5APROTO_H
+#define H5APROTO_H
+
+/* Group values allowed */
+typedef enum {BADGROUP=(-1), /* Invalid Group */
+H5_ERR=0, /* Group ID for Error stack objects */
+H5_FILE, /* Group ID for File objects */
+H5_TEMPLATE, /* Group ID for Template objects */
+H5_DATATYPE, /* Group ID for Datatype objects */
+H5_DATASPACE, /* Group ID for Dataspace objects */
+MAXGROUP /* Highest group in group_t (Invalid as true group) */
+} group_t;
+
+/* Type of atoms to return to users */
+typedef int32 hatom_t;
+
+/* Type of the function to compare objects & keys */
+typedef intn (*H5Asearch_func_t)(const VOIDP obj, const VOIDP key);
+
+/* # of bits to use for Group ID in each atom (change if MAXGROUP>16) */
+#define GROUP_BITS 4
+#define GROUP_MASK 0x0F
+
+/* # of bits to use for the Atom index in each atom (assumes 8-bit bytes) */
+#define ATOM_BITS ((sizeof(hatom_t)*8)-GROUP_BITS)
+#define ATOM_MASK 0x0FFFFFFF
+
+/* Combine a Group number and an atom index into an atom */
+#define MAKE_ATOM(g,i) ((((hatom_t)(g)&GROUP_MASK)<<((sizeof(hatom_t)*8)-GROUP_BITS))|((hatom_t)(i)&ATOM_MASK))
+
+#if defined c_plusplus || defined __cplusplus
+extern "C"
+{
+#endif /* c_plusplus || __cplusplus */
+
+/* Functions in H5A.c */
+/******************************************************************************
+ NAME
+ H5Ainit_group - Initialize an atomic group
+
+ DESCRIPTION
+ Creates an atomic group to store atoms in. If the group has already been
+ initialized, this routine just increments the count of # of initializations
+ and returns without trying to change the size of the hash table.
+
+ RETURNS
+ Returns SUCCEED if successful and FAIL otherwise
+
+*******************************************************************************/
+intn H5Ainit_group(group_t grp, /* IN: Group to initialize */
+ intn hash_size, /* IN: Minimum hash table size to use for group */
+ uintn reserved /* IN: Number of hash table entries to reserve */
+);
+
+/******************************************************************************
+ NAME
+ H5Adestroy_group - Destroy an atomic group
+
+ DESCRIPTION
+ Destroys an atomic group which atoms are stored in. If the group still
+ has atoms which are registered, this routine fails. If there have been
+ multiple initializations of the group, this routine just decrements the
+ count of initializations and does not check the atoms out-standing.
+
+ RETURNS
+ Returns SUCCEED if successful and FAIL otherwise
+
+*******************************************************************************/
+intn H5Adestroy_group(group_t grp /* IN: Group to destroy */
+);
+
+/******************************************************************************
+ NAME
+ H5Aregister_atom - Register an object in a group and get an atom for it.
+
+ DESCRIPTION
+ Registers an object in a group and returns an atom for it. This routine
+ does _not_ check for unique-ness of the objects, if you register an object
+ twice, you will get two different atoms for it. This routine does make
+ certain that each atom in a group is unique. Atoms are created by getting
+ a unique number for the group the atom is in and incorporating the group
+ into the atom which is returned to the user.
+
+ RETURNS
+ Returns atom if successful and FAIL otherwise
+
+*******************************************************************************/
+hatom_t H5Aregister_atom(group_t grp, /* IN: Group to register the object in */
+ const VOIDP object /* IN: Object to attach to atom */
+);
+
+/******************************************************************************
+ NAME
+ H5Aatom_object - Returns to the object ptr for the atom
+
+ DESCRIPTION
+ Retrieves the object ptr which is associated with the atom.
+
+ RETURNS
+ Returns object ptr if successful and NULL otherwise
+
+*******************************************************************************/
+VOIDP H5Aatom_object(hatom_t atm /* IN: Atom to retrieve object for */
+);
+
+/******************************************************************************
+ NAME
+ H5Aatom_group - Returns to the group for the atom
+
+ DESCRIPTION
+ Retrieves the group which is associated with the atom.
+
+ RETURNS
+ Returns group if successful and FAIL otherwise
+
+*******************************************************************************/
+group_t H5Aatom_group(hatom_t atm /* IN: Atom to retrieve group for */
+);
+
+/******************************************************************************
+ NAME
+ H5Aremove_atom - Removes an atom from a group
+
+ DESCRIPTION
+ Removes an atom from a group.
+
+ RETURNS
+ Returns atom's object if successful and FAIL otherwise
+
+*******************************************************************************/
+VOIDP H5Aremove_atom(hatom_t atm /* IN: Atom to remove */
+);
+
+/******************************************************************************
+ NAME
+ H5Asearch_atom - Search for an object in a group and get it's pointer.
+
+ DESCRIPTION
+ Searchs for an object in a group and returns the pointer to it.
+ This routine calls the function pointer passed in for each object in the
+ group until it finds a match. Currently there is no way to resume a
+ search.
+
+ RETURNS
+ Returns pointer an atom's object if successful and NULL otherwise
+
+*******************************************************************************/
+VOIDP H5Asearch_atom(group_t grp, /* IN: Group to search for the object in */
+ H5Asearch_func_t func, /* IN: Ptr to the comparison function */
+ const VOIDP key /* IN: pointer to key to compare against */
+);
+
+/******************************************************************************
+ NAME
+ H5Ais_reserved - Check whether an atom is a reserved atom in a group
+
+ DESCRIPTION
+ Determines the group an atom belongs to and checks if the atom is a
+ reserved atom in the group.
+
+ RETURNS
+ Returns BTRUE/BFALSE/BFAIL
+
+*******************************************************************************/
+intn H5Ais_reserved(hatom_t atm /* IN: Group to search for the object in */
+);
+
+/******************************************************************************
+ NAME
+ H5Ashutdown - Terminate various static buffers.
+
+ DESCRIPTION
+ Free various buffers allocated in the H5A routines.
+
+ RETURNS
+ Returns SUCCEED/FAIL
+
+*******************************************************************************/
+intn H5Ashutdown(void);
+
+#if defined c_plusplus || defined __cplusplus
+}
+#endif /* c_plusplus || __cplusplus */
+
+#endif /* H5APROTO_H */
+
diff --git a/src/H5B.c b/src/H5B.c
new file mode 100644
index 0000000..f3a7052
--- /dev/null
+++ b/src/H5B.c
@@ -0,0 +1,1177 @@
+/*-------------------------------------------------------------------------
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * Created: hdf5btree.c
+ * Jul 10 1997
+ * Robb Matzke <robb@maya.nuance.com>
+ *
+ * Purpose: Implements balanced, sibling-linked, N-ary trees
+ * capable of storing any type of data with unique key
+ * values.
+ *
+ * A B-link-tree is a balanced tree where each node has
+ * a pointer to its left and right siblings. A
+ * B-link-tree is a rooted tree having the following
+ * properties:
+ *
+ * 1. Every node, x, has the following fields:
+ *
+ * a. level[x], the level in the tree at which node
+ * x appears. Leaf nodes are at level zero.
+ *
+ * b. n[x], the number of children pointed to by the
+ * node. Internal nodes point to subtrees while
+ * leaf nodes point to arbitrary data.
+ *
+ * c. The child pointers themselves, child[x,i] such
+ * that 0 <= i < n[x].
+ *
+ * d. n[x]+1 key values stored in increasing
+ * order:
+ *
+ * key[x,0] < key[x,1] < ... < key[x,n[x]].
+ *
+ * e. left[x] is a pointer to the node's left sibling
+ * or the null pointer if this is the left-most
+ * node at this level in the tree.
+ *
+ * f. right[x] is a pointer to the node's right
+ * sibling or the null pointer if this is the
+ * right-most node at this level in the tree.
+ *
+ * 3. The keys key[x,i] partition the key spaces of the
+ * children of x:
+ *
+ * key[x,i] <= key[child[x,i],j] <= key[x,i+1]
+ *
+ * for any valid combination of i and j.
+ *
+ * 4. There are lower and upper bounds on the number of
+ * child pointers a node can contain. These bounds
+ * can be expressed in terms of a fixed integer k>=2
+ * called the `minimum degree' of the B-tree.
+ *
+ * a. Every node other than the root must have at least
+ * k child pointers and k+1 keys. If the tree is
+ * nonempty, the root must have at least one child
+ * pointer and two keys.
+ *
+ * b. Every node can contain at most 2k child pointers
+ * and 2k+1 keys. A node is `full' if it contains
+ * exactly 2k child pointers and 2k+1 keys.
+ *
+ * 5. When searching for a particular value, V, and
+ * key[V] = key[x,i] for some node x and entry i,
+ * then:
+ *
+ * a. If i=0 the child[0] is followed.
+ *
+ * b. If i=n[x] the child[n[x]-1] is followed.
+ *
+ * c. Otherwise, the child that is followed
+ * (either child[x,i-1] or child[x,i]) is
+ * determined by the type of object to which the
+ * leaf nodes of the tree point and is controlled
+ * by the key comparison function registered for
+ * that type of B-tree.
+ *
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * Define this if the root address of a B-link tree should never change.
+ *
+ * If this isn't defined and the root node of a tree splits, then the
+ * new root (which points to the old root plus the new node from the
+ * split) will be at a new file address.
+ *
+ * But if this is defined, then the old root will be copied to a new
+ * location and the new root will occupy the file memory vacated by the
+ * old root.
+ */
+#define H5B_ANCHOR_ROOT
+
+/* system headers */
+#include <assert.h>
+#include "hdf5.h"
+
+/* private headers */
+#include "H5ACprivate.h" /*cache */
+#include "H5Bprivate.h" /*B-link trees */
+#include "H5MFprivate.h" /*File memory management */
+#include "H5MMprivate.h" /*Core memory management */
+
+#define BOUND(MIN,X,MAX) ((MIN)<(X)?(MIN):((MAX)>(X)?(MAX):(X)))
+#define false 0
+#define true 1
+
+/* PRIVATE PROTOTYPES */
+static off_t H5B_insert_helper (hdf5_file_t *f, off_t addr,
+ const H5B_class_t *type,
+ uint8 *lt_key, intn *lt_key_changed,
+ uint8 *md_key, void *udata,
+ uint8 *rt_key, intn *rt_key_changed);
+static herr_t H5B_flush (hdf5_file_t *f, hbool_t destroy, off_t addr,
+ H5B_t *b);
+static H5B_t *H5B_load (hdf5_file_t *f, off_t addr, const void *_data);
+static herr_t H5B_decode_key (hdf5_file_t *f, H5B_t *bt, intn idx);
+static size_t H5B_nodesize (hdf5_file_t *f, const H5B_class_t *type,
+ size_t *total_nkey_size, size_t sizeof_rkey);
+
+/* H5B inherits cache-like properties from H5AC */
+static const H5AC_class_t H5AC_BT[1] = {{
+ (void*(*)(hdf5_file_t*,off_t,const void*))H5B_load,
+ (herr_t(*)(hdf5_file_t*,hbool_t,off_t,void*))H5B_flush,
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_new
+ *
+ * Purpose: Creates a new empty B-tree leaf node.
+ *
+ * Return: Success: address of new node.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+off_t
+H5B_new (hdf5_file_t *f, const H5B_class_t *type, size_t sizeof_rkey)
+{
+ H5B_t *bt=NULL;
+ off_t addr;
+ size_t size;
+ size_t total_native_keysize;
+ intn offset, i;
+
+ /*
+ * Allocate file and memory data structures.
+ */
+ size = H5B_nodesize (f, type, &total_native_keysize, sizeof_rkey);
+ if ((addr = H5MF_alloc (f, size))<=0) return 0;
+ bt = H5MM_xmalloc (sizeof(H5B_t));
+ bt->type = type;
+ bt->sizeof_rkey = sizeof_rkey;
+ bt->dirty = 1;
+ bt->ndirty = 0;
+ bt->type = type;
+ bt->level = 0;
+ bt->left = bt->right = 0;
+ bt->nchildren = 0;
+ bt->page = H5MM_xmalloc (size);
+ bt->native = H5MM_xmalloc (total_native_keysize);
+ bt->child = H5MM_xmalloc (2*type->k * sizeof(off_t));
+ bt->key = H5MM_xmalloc ((2*type->k+1) * sizeof(H5B_key_t));
+
+ /*
+ * Initialize each entry's raw child and key pointers to point into the
+ * `page' buffer. Each native key pointer should be null until the key is
+ * translated to native format.
+ */
+ for (i=0,offset=H5B_HDR_SIZE(f);
+ i<2*type->k;
+ i++,offset+=bt->sizeof_rkey+SIZEOF_OFFSET(f)) {
+
+ bt->key[i].dirty = 0;
+ bt->key[i].rkey = bt->page + offset;
+ bt->key[i].nkey = NULL;
+ bt->child[i] = 0;
+ }
+
+ /*
+ * The last possible key...
+ */
+ bt->key[2*type->k].dirty = 0;
+ bt->key[2*type->k].rkey = bt->page + offset;
+ bt->key[2*type->k].nkey = NULL;
+
+ /*
+ * Cache the new B-tree node.
+ */
+ H5AC_set (f, H5AC_BT, addr, bt);
+ return addr;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_load
+ *
+ * Purpose: Loads a B-tree node from the disk.
+ *
+ * Return: Success: Pointer to a new B-tree node.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5B_t *
+H5B_load (hdf5_file_t *f, off_t addr, const void *_data)
+{
+ const H5B_class_t *type = (const H5B_class_t *)_data;
+ size_t size, total_nkey_size;
+ H5B_t *bt = H5MM_xmalloc (sizeof(H5B_t));
+ intn i;
+ uint8 *p;
+
+ assert (type);
+ assert (type->get_sizeof_rkey);
+
+
+ bt->sizeof_rkey = (type->get_sizeof_rkey)(f);
+ size = H5B_nodesize (f, type, &total_nkey_size, bt->sizeof_rkey);
+ bt->type = type;
+ bt->dirty = 0;
+ bt->ndirty = 0;
+ bt->page = H5MM_xmalloc (size);
+ bt->native = H5MM_xmalloc (total_nkey_size);
+ bt->key = H5MM_xmalloc ((2*type->k+1) * sizeof(H5B_key_t));
+ bt->child = H5MM_xmalloc (2 * type->k * sizeof(off_t));
+ H5F_block_read (f, addr, size, bt->page);
+ p = bt->page;
+
+ /* magic number */
+ if (memcmp (p, H5B_MAGIC, 4)) goto error;
+ p += 4;
+
+ /* node type and level */
+ if (*p++ != type->id) goto error;
+ bt->level = *p++;
+
+ /* entries used */
+ UINT16DECODE (p, bt->nchildren);
+
+ /* sibling pointers */
+ H5F_decode_offset (f, p, bt->left);
+ H5F_decode_offset (f, p, bt->right);
+
+ /* the child/key pairs */
+ for (i=0; i<2*type->k; i++) {
+
+ bt->key[i].dirty = 0;
+ bt->key[i].rkey = p;
+ p += bt->sizeof_rkey;
+ bt->key[i].nkey = NULL;
+
+ if (i<bt->nchildren) {
+ H5F_decode_offset (f, p, bt->child[i]);
+ } else {
+ bt->child[i] = 0;
+ p += SIZEOF_OFFSET(f);
+ }
+ }
+
+ bt->key[2*type->k].dirty = 0;
+ bt->key[2*type->k].rkey = p;
+ bt->key[2*type->k].nkey = NULL;
+ return bt;
+
+error:
+ if (bt) {
+ H5MM_xfree (bt->child);
+ H5MM_xfree (bt->key);
+ H5MM_xfree (bt->page);
+ H5MM_xfree (bt->native);
+ H5MM_xfree (bt);
+ }
+ return NULL;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_flush
+ *
+ * Purpose: Flushes a dirty B-tree node to disk.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B_flush (hdf5_file_t *f, hbool_t destroy, off_t addr, H5B_t *bt)
+{
+ intn i;
+ size_t size = H5B_nodesize (f, bt->type, NULL, bt->sizeof_rkey);
+ uint8 *p = bt->page;
+
+ assert (bt->type);
+ assert (bt->type->encode);
+
+ if (bt->dirty) {
+
+ /* magic number */
+ memcpy (p, H5B_MAGIC, 4);
+ p += 4;
+
+ /* node type and level */
+ *p++ = bt->type->id;
+ *p++ = bt->level;
+
+ /* entries used */
+ UINT16ENCODE (p, bt->nchildren);
+
+ /* sibling pointers */
+ H5F_encode_offset (f, p, bt->left);
+ H5F_encode_offset (f, p, bt->right);
+
+ /* child keys and pointers */
+ for (i=0; i<=bt->nchildren; i++) {
+
+ /* encode the key */
+ assert (bt->key[i].rkey == p);
+ if (bt->key[i].dirty) {
+ if (bt->key[i].nkey) {
+ (bt->type->encode)(f, bt->key[i].rkey, bt->key[i].nkey);
+ }
+ bt->key[i].dirty = 0;
+ }
+ p += bt->sizeof_rkey;
+
+ /* encode the child address */
+ if (i<bt->ndirty) {
+ H5F_encode_offset (f, p, bt->child[i]);
+ } else {
+ p += SIZEOF_OFFSET(f);
+ }
+ }
+
+ /*
+ * Write the disk page. We always write the header, but we don't
+ * bother writing data for the child entries that don't exist or
+ * for the final unchanged children.
+ */
+ H5F_block_write (f, addr, size, bt->page);
+ bt->dirty = 0;
+ bt->ndirty = 0;
+ }
+
+ if (destroy) {
+ H5MM_xfree (bt->child);
+ H5MM_xfree (bt->key);
+ H5MM_xfree (bt->page);
+ H5MM_xfree (bt->native);
+ H5MM_xfree (bt);
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_find
+ *
+ * Purpose: Locate the specified information in a B-tree and return
+ * that information by filling in fields of the caller-supplied
+ * UDATA pointer depending on the type of leaf node
+ * requested. The UDATA can point to additional data passed
+ * to the key comparison function.
+ *
+ * Note: This function does not follow the left/right sibling
+ * pointers since it assumes that all nodes can be reached
+ * from the parent node.
+ *
+ * Return: Success: 0 if found, values returned through the
+ * RETVAL argument.
+ *
+ * Failure: -1 if not found.
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_find (hdf5_file_t *f, const H5B_class_t *type, off_t addr, void *udata)
+{
+ H5B_t *bt=NULL;
+ uint8 lt_key[256], rt_key[256];
+ intn idx=-1, lt=0, rt, cmp=1;
+
+ assert (type);
+ assert (type->sizeof_nkey < sizeof lt_key);
+ assert (type->decode);
+ assert (type->cmp);
+ assert (type->found);
+
+ /*
+ * Perform a binary search to locate the child which contains
+ * the thing for which we're searching. The comparison function
+ * may preempt the B-tree node from the cache.
+ */
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ rt = bt->nchildren;
+
+ while (lt<rt && cmp) {
+ idx = (lt + rt) / 2;
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ if (!bt) return -1;
+
+ /* the left key */
+ if (!bt->key[idx].nkey) H5B_decode_key (f, bt, idx);
+ HDmemcpy (lt_key, bt->key[idx].nkey, type->sizeof_nkey);
+
+ /* the right key */
+ if (!bt->key[idx+1].nkey) H5B_decode_key (f, bt, idx+1);
+ HDmemcpy (rt_key, bt->key[idx+1].nkey, type->sizeof_nkey);
+
+ /* compare */
+ if ((cmp=(type->cmp)(f, lt_key, udata, rt_key))<0) {
+ rt = idx;
+ } else {
+ lt = idx+1;
+ }
+ }
+ if (cmp) return -1;
+
+ /*
+ * Follow the link to the subtree or to the data node.
+ */
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ assert (idx>=0 && idx<bt->nchildren);
+ if (bt->level > 0) {
+ return H5B_find (f, type, bt->child[idx], udata);
+ }
+
+ return (type->found)(f, bt->child[idx], lt_key, udata, rt_key);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_split
+ *
+ * Purpose: Split a single node into two nodes. If anchor is
+ * H5B_ANCHOR_LT then the new node gets the right half of
+ * the old node. If anchor is H5B_ANCHOR_RT then the
+ * new node gets the left half of the old node.
+ *
+ * Return: Success: Address of the new node.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 3 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static off_t
+H5B_split (hdf5_file_t *f, const H5B_class_t *type, off_t addr, intn anchor)
+{
+ H5B_t *old = H5AC_find (f, H5AC_BT, addr, type);
+ H5B_t *bt = H5MM_xmalloc (sizeof(H5B_t));
+ size_t total_nkey_size, size;
+ intn i, offset;
+ intn delta = H5B_ANCHOR_LT==anchor ? type->k : 0;
+ size_t recsize = old->sizeof_rkey + SIZEOF_OFFSET(f);
+ off_t tmp_addr, new_addr;
+ H5B_t *tmp=NULL;
+
+ /*
+ * Create the new B-tree node.
+ */
+ size = H5B_nodesize (f, type, &total_nkey_size, old->sizeof_rkey);
+ bt->dirty = 1;
+ bt->ndirty = BOUND (0, old->ndirty-delta, type->k);
+ bt->type = type;
+ bt->level = old->level;
+ bt->nchildren = type->k;
+ bt->page = H5MM_xmalloc (size);
+ bt->native = H5MM_xmalloc (total_nkey_size);
+ bt->child = H5MM_xmalloc (2*type->k * sizeof(off_t));
+ bt->key = H5MM_xmalloc ((2*type->k+1) * sizeof(H5B_key_t));
+
+ /*
+ * Copy data into the new node from the old node.
+ */
+ memcpy (bt->page + H5B_HDR_SIZE(f),
+ old->page + H5B_HDR_SIZE(f) + delta*recsize,
+ type->k * recsize);
+ memcpy (bt->native,
+ old->native + delta * type->sizeof_nkey,
+ (type->k+1) * type->sizeof_nkey);
+
+ for (i=0,offset=H5B_HDR_SIZE(f); i<=2*type->k; i++,offset+=recsize) {
+
+ /* key */
+ if (i<=type->k) {
+ bt->key[i].dirty = old->key[delta+i].dirty;
+ bt->key[i].rkey = bt->native + offset;
+ if (old->key[delta+i].nkey) {
+ bt->key[i].nkey = bt->native + i*type->sizeof_nkey;
+ } else {
+ bt->key[i].nkey = NULL;
+ }
+ } else {
+ bt->key[i].dirty = 0;
+ bt->key[i].rkey = bt->native + offset;
+ bt->key[i].nkey = NULL;
+ }
+
+ /* child */
+ if (i<type->k) {
+ bt->child[i] = old->child[delta+i];
+ } else if (i<2*type->k) {
+ bt->child[i] = 0;
+ }
+ }
+
+
+ /*
+ * Truncate the old node.
+ */
+ delta = H5B_ANCHOR_LT ? 0 : type->k;
+ old->dirty += 1;
+ old->ndirty = BOUND (0, old->ndirty-delta, type->k);
+ old->nchildren = type->k;
+
+ if (H5B_ANCHOR_RT==anchor) {
+ memcpy (old->page + H5B_HDR_SIZE(f),
+ old->page + H5B_HDR_SIZE(f) + delta*recsize,
+ type->k * recsize);
+ memmove (old->native,
+ old->native + delta * type->sizeof_nkey,
+ (type->k+1) * type->sizeof_nkey);
+
+ for (i=0; i<=2*type->k; i++) {
+
+ if (i<=type->k) {
+ old->key[i].dirty = old->key[delta+i].dirty;
+ if (old->key[delta+i].nkey) {
+ old->key[i].nkey = old->native + i * type->sizeof_nkey;
+ } else {
+ old->key[i].nkey = NULL;
+ }
+ } else {
+ old->key[i].nkey = NULL;
+ }
+ if (i<type->k) {
+ old->child[i] = old->child[delta+i];
+ } else if (i<2*type->k) {
+ old->child[i] = 0;
+ }
+ }
+ }
+
+ /*
+ * Update sibling pointers of new node.
+ */
+ if (H5B_ANCHOR_LT==anchor) {
+ bt->left = addr;
+ bt->right = old->right;
+ } else {
+ bt->left = old->left;
+ bt->right = addr;
+ }
+
+ /*
+ * Add the new node to the cache.
+ */
+ new_addr = H5MF_alloc (f, size);
+ H5AC_set (f, H5AC_BT, new_addr, bt);
+
+ /*
+ * Update sibling pointers of old nodes.
+ */
+ old = H5AC_find (f, H5AC_BT, addr, type);
+ if (H5B_ANCHOR_LT==anchor) {
+ old->dirty += 1;
+ tmp_addr = old->right;
+ old->right = new_addr;
+ if (tmp_addr) {
+ tmp = H5AC_find (f, H5AC_BT, tmp_addr, type);
+ tmp->dirty += 1;
+ tmp->left = new_addr;
+ }
+ } else {
+ old->dirty += 1;
+ tmp_addr = old->left;
+ old->left = new_addr;
+ if (tmp_addr) {
+ tmp = H5AC_find (f, H5AC_BT, tmp_addr, type);
+ tmp->dirty += 1;
+ tmp->right = new_addr;
+ }
+ }
+
+ return new_addr;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_decode_key
+ *
+ * Purpose: Decode the specified key into native format.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 8 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5B_decode_key (hdf5_file_t *f, H5B_t *bt, intn idx)
+{
+ bt->key[idx].nkey = bt->native + idx * bt->type->sizeof_nkey;
+ (bt->type->decode)(f, bt->key[idx].rkey, bt->key[idx].nkey);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_insert
+ *
+ * Purpose: Adds a new item to the B-tree. If the root node of
+ * the B-tree splits then the B-tree gets a new address.
+ *
+ * Return: Success: Address of the root of the B-tree. The
+ * B-tree root address may change if the old
+ * root is split.
+ *
+ * Failure: 0
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+off_t
+H5B_insert (hdf5_file_t *f, const H5B_class_t *type, off_t addr, void *udata)
+{
+ uint8 lt_key[256], md_key[256], rt_key[256];
+ intn lt_key_changed=false, rt_key_changed=false;
+ off_t child, new_root;
+ intn level;
+ H5B_t *bt;
+
+ assert (type);
+ assert (type->sizeof_nkey < sizeof lt_key);
+
+ child = H5B_insert_helper (f, addr, type, lt_key, &lt_key_changed,
+ md_key, udata, rt_key, &rt_key_changed);
+ if (child<0) return 0;
+ if (0==child) return addr;
+
+ /* the current root */
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ level = bt->level;
+ if (!lt_key_changed) {
+ if (!bt->key[0].nkey) H5B_decode_key (f, bt, 0);
+ memcpy (lt_key, bt->key[0].nkey, type->sizeof_nkey);
+ }
+
+ /* the new node */
+ bt = H5AC_find (f, H5AC_BT, child, type);
+ if (!rt_key_changed) {
+ if (!bt->key[bt->nchildren].nkey) H5B_decode_key (f, bt, bt->nchildren);
+ memcpy (rt_key, bt->key[bt->nchildren].nkey, type->sizeof_nkey);
+ }
+
+#ifdef H5B_ANCHOR_ROOT
+ {
+ /*
+ * Copy the old root node to some other file location and make the new
+ * root at the old root's previous address. This prevents the B-tree
+ * from "moving".
+ */
+ size_t size = H5B_nodesize (f, type, NULL, bt->sizeof_rkey);
+ uint8 *buf = H5MM_xmalloc (size);
+ off_t tmp_addr = H5MF_alloc (f, size);
+
+ H5AC_flush (f, H5AC_BT, addr, FALSE);
+ H5F_block_read (f, addr, size, buf);
+ H5F_block_write (f, tmp_addr, size, buf);
+ H5AC_rename (f, H5AC_BT, addr, tmp_addr);
+
+ buf = H5MM_xfree (buf);
+ new_root = addr;
+ addr = tmp_addr;
+
+ /* update the new child's left pointer */
+ bt = H5AC_find (f, H5AC_BT, child, type);
+ bt->dirty += 1;
+ bt->left = addr;
+
+ /* clear the old root at the old address */
+ bt = H5AC_find (f, H5AC_BT, new_root, type);
+ bt->dirty += 1;
+ bt->ndirty = 0;
+ bt->left = 0;
+ bt->right = 0;
+ bt->nchildren = 0;
+ }
+#else
+ /*
+ * The new root is created at a new file location.
+ */
+ new_root = H5B_new (f, type, bt->sizeof_rkey);
+#endif
+
+ /* the new root */
+ bt = H5AC_find (f, H5AC_BT, new_root, type);
+ bt->dirty += 1;
+ bt->ndirty = 2;
+ bt->level = level+1;
+ bt->nchildren = 2;
+
+ bt->child[0] = addr;
+ bt->key[0].dirty = 1;
+ bt->key[0].nkey = bt->native;
+ memcpy (bt->key[0].nkey, lt_key, type->sizeof_nkey);
+
+ bt->child[1] = child;
+ bt->key[1].dirty = 1;
+ bt->key[1].nkey = bt->native + type->sizeof_nkey;
+ memcpy (bt->key[1].nkey, md_key, type->sizeof_nkey);
+
+ bt->key[2].dirty = 1;
+ bt->key[2].nkey = bt->native + 2 * type->sizeof_nkey;
+ memcpy (bt->key[2].nkey, rt_key, type->sizeof_nkey);
+
+ return new_root;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_insert_child
+ *
+ * Purpose: Insert a child at the specified address with the
+ * specified left or right key.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 8 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+H5B_insert_child (hdf5_file_t *f, const H5B_class_t *type, off_t addr,
+ intn idx, off_t child, intn anchor, void *md_key)
+{
+ H5B_t *bt;
+ size_t recsize;
+ intn i;
+
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ assert (bt);
+ bt->dirty += 1;
+ recsize = bt->sizeof_rkey + SIZEOF_OFFSET(f);
+
+ if (H5B_ANCHOR_LT==anchor) {
+ /*
+ * The MD_KEY is the left key of the new node.
+ */
+ memmove (bt->page + H5B_HDR_SIZE(f) + (idx+1)*recsize,
+ bt->page + H5B_HDR_SIZE(f) + idx*recsize,
+ (bt->nchildren-idx)*recsize + bt->sizeof_rkey);
+
+ memmove (bt->native + (idx+1) * type->sizeof_nkey,
+ bt->native + idx * type->sizeof_nkey,
+ ((bt->nchildren-idx)+1) * type->sizeof_nkey);
+
+ for (i=bt->nchildren; i>=idx; --i) {
+ bt->key[i+1].dirty = bt->key[i].dirty;
+ }
+ bt->key[idx].dirty = 1;
+ bt->key[idx].nkey = bt->native + idx * type->sizeof_nkey;
+ memcpy (bt->key[idx].nkey, md_key, type->sizeof_nkey);
+
+ } else {
+ /*
+ * The MD_KEY is the right key of the new node.
+ */
+ memmove (bt->page + (H5B_HDR_SIZE(f) +
+ (idx+1)*recsize + bt->sizeof_rkey),
+ bt->page + (H5B_HDR_SIZE(f) +
+ idx*recsize + bt->sizeof_rkey),
+ (bt->nchildren-idx) * recsize);
+
+ memmove (bt->native + idx + 2,
+ bt->native + idx + 1,
+ (bt->nchildren-idx) * type->sizeof_nkey);
+
+ for (i=bt->nchildren; i>idx; --i) {
+ bt->key[i+1].dirty = bt->key[i].dirty;
+ }
+ bt->key[idx+1].dirty = 1;
+ bt->key[idx+1].nkey = bt->native +
+ (idx+1) * type->sizeof_nkey;
+ memcpy (bt->key[idx+1].nkey, md_key, type->sizeof_nkey);
+ }
+
+ memmove (bt->child + idx + 1,
+ bt->child + idx,
+ (bt->nchildren - idx) * sizeof(off_t));
+
+ bt->child[idx] = child;
+ bt->nchildren += 1;
+ bt->ndirty = bt->nchildren;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_insert_helper
+ *
+ * Purpose: Inserts the item UDATA into the tree rooted at ADDR and having
+ * the specified type.
+ *
+ * On return, if LT_KEY_CHANGED is non-zero, then LT_KEY is
+ * the new native left key. Similarily for RT_KEY_CHANGED
+ * and RT_KEY.
+ *
+ * If the node splits, then MD_KEY contains the key that
+ * was split between the two nodes (that is, the key that
+ * appears as the max key in the left node and the min key
+ * in the right node).
+ *
+ * Return: Success: Address of the new node if the node
+ * splits. The new node is always to the
+ * right of the previous node.
+ *
+ * 0 if the node didn't split. The MD_KEY
+ * buffer is undefined.
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 9 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static off_t
+H5B_insert_helper (hdf5_file_t *f, off_t addr, const H5B_class_t *type,
+ uint8 *lt_key, intn *lt_key_changed,
+ uint8 *md_key, void *udata,
+ uint8 *rt_key, intn *rt_key_changed)
+{
+ H5B_t *bt;
+ intn lt=0, idx=-1, rt, cmp=-1;
+ intn anchor;
+ off_t child, twin=0;
+
+ assert (type);
+ assert (type->decode);
+ assert (type->cmp);
+ assert (type->new);
+
+ /*
+ * Use a binary search to find the child that will receive the new
+ * data. The comparison function may preempt the B-tree node from
+ * the cache each time through the loop. When the search completes
+ * IDX points to the child that should get the new data.
+ */
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ if (!bt) goto error;
+ rt = bt->nchildren;
+
+ while (lt<rt && cmp) {
+ idx = (lt + rt) / 2;
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ if (!bt) goto error;
+
+ /* left key */
+ if (!bt->key[idx].nkey) H5B_decode_key (f, bt, idx);
+ memcpy (lt_key, bt->key[idx].nkey, type->sizeof_nkey);
+
+ /* right key */
+ if (!bt->key[idx+1].nkey) H5B_decode_key (f, bt, idx+1);
+ memcpy (rt_key, bt->key[idx+1].nkey, type->sizeof_nkey);
+
+ /* compare */
+ if ((cmp=(type->cmp)(f, lt_key, udata, rt_key))<0) {
+ rt = idx;
+ } else {
+ lt = idx+1;
+ }
+ }
+
+ /*
+ * Adjust for boundary conditions. If adjusting at the leaf level
+ * update the left and right key buffers since the data node insert
+ * function needs them as input. Don't worry about it at higher node
+ * levels because this function uses them for output only.
+ */
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ if (cmp<0 && idx<=0) {
+ idx = 0;
+ cmp = 0;
+ if (0==bt->level && bt->nchildren) {
+ if (!bt->key[idx].nkey) H5B_decode_key (f, bt, idx);
+ memcpy (lt_key, bt->key[idx].nkey, type->sizeof_nkey);
+ if (!bt->key[idx+1].nkey) H5B_decode_key (f, bt, idx+1);
+ memcpy (rt_key, bt->key[idx+1].nkey, type->sizeof_nkey);
+ }
+ } else if (cmp>0 && idx+1>=bt->nchildren) {
+ idx = bt->nchildren-1;
+ cmp = 0;
+ if (0==bt->level && bt->nchildren) {
+ if (!bt->key[idx].nkey) H5B_decode_key (f, bt, idx);
+ memcpy (lt_key, bt->key[idx].nkey, type->sizeof_nkey);
+ if (!bt->key[idx+1].nkey) H5B_decode_key (f, bt, idx+1);
+ memcpy (rt_key, bt->key[idx+1].nkey, type->sizeof_nkey);
+ }
+ }
+ assert (0==cmp);
+
+ /*
+ * If there are no children, then create a new child. This can only
+ * happen at the root of the B-tree. Creating a new child may
+ * preempt the B-tree node from the cache. The left and right key
+ * buffers are output values.
+ */
+ if (0==bt->nchildren) {
+ child = (type->new)(f, lt_key, udata, rt_key);
+ if (child<=0) goto error;
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ bt->nchildren = 1;
+ bt->dirty += 1;
+ bt->ndirty = 1;
+ bt->child[0] = child;
+
+ bt->key[0].dirty = 1;
+ bt->key[0].nkey = bt->native;
+ memcpy (bt->key[0].nkey, lt_key, type->sizeof_nkey);
+
+ bt->key[1].dirty = 1;
+ bt->key[1].nkey = bt->native + type->sizeof_nkey;
+ memcpy (bt->key[1].nkey, rt_key, type->sizeof_nkey);
+ idx = 0;
+ }
+
+ /*
+ * Insert the new data in the child B-tree node or in the data node.
+ */
+ if (bt->level > 0) {
+ child = H5B_insert_helper (f, bt->child[idx], type,
+ lt_key, lt_key_changed,
+ md_key, udata,
+ rt_key, rt_key_changed);
+ anchor = H5B_ANCHOR_LT;
+ } else {
+ child = (type->insert)(f, bt->child[idx], &anchor,
+ lt_key, lt_key_changed,
+ md_key, udata,
+ rt_key, rt_key_changed);
+ }
+ if (child<0) goto error;
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+
+ /*
+ * Update the left and right keys.
+ */
+ if (*lt_key_changed) {
+ bt->key[idx].nkey = bt->native + idx * type->sizeof_nkey;
+ memcpy (bt->key[idx].nkey, lt_key, type->sizeof_nkey);
+ bt->dirty += 1;
+ bt->key[idx].dirty = 1;
+ if (idx>0) *lt_key_changed = false;
+ }
+ if (*rt_key_changed) {
+ bt->key[idx+1].nkey = bt->native +
+ (idx+1) * type->sizeof_nkey;
+ memcpy (bt->key[idx+1].nkey, rt_key, type->sizeof_nkey);
+ bt->dirty += 1;
+ bt->key[idx+1].dirty = 1;
+ if (idx+1<bt->nchildren) *rt_key_changed = false;
+ }
+
+ /*
+ * If the child split and the left node is anchored, then the new
+ * child node gets inserted to the right of our current position.
+ */
+ if (child && H5B_ANCHOR_LT==anchor) idx++;
+
+ /*
+ * Split this node if the child node split and this node is full.
+ * Make sure `addr' points to the node that gets the new child
+ * and that `idx' is adjusted appropriately.
+ */
+ if (child && bt->nchildren==2*type->k) {
+ twin = H5B_split (f, type, addr, anchor);
+ if (idx<=type->k) {
+ addr = H5B_ANCHOR_LT==anchor ? addr : twin;
+ } else {
+ idx -= type->k;
+ addr = H5B_ANCHOR_LT==anchor ? twin : addr;
+ }
+ }
+
+ /*
+ * If the child split, then insert the new child.
+ */
+ if (child) {
+ H5B_insert_child (f, type, addr, idx, child, anchor, md_key);
+ }
+
+ /*
+ * If this node split, return the mid key (the one that is shared
+ * by the left and right node).
+ */
+ if (twin) {
+ bt = H5AC_find (f, H5AC_BT, twin, type);
+ if (H5B_ANCHOR_LT==anchor) {
+ if (!bt->key[0].nkey) {
+ H5B_decode_key (f, bt, 0);
+ }
+ memcpy (md_key, bt->key[0].nkey, type->sizeof_nkey);
+ } else {
+ if (!bt->key[bt->nchildren].nkey) {
+ H5B_decode_key (f, bt, bt->nchildren);
+ }
+ memcpy (md_key, bt->key[bt->nchildren].nkey, type->sizeof_nkey);
+ }
+ }
+
+ return twin;
+
+error:
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_list
+ *
+ * Purpose: Calls the list callback for each leaf node of the
+ * B-tree, passing it the UDATA structure.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jun 23 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5B_list (hdf5_file_t *f, const H5B_class_t *type, off_t addr, void *udata)
+{
+ H5B_t *bt;
+ off_t *child=NULL;
+ off_t twin;
+ intn i, nchildren, status;
+ herr_t (*list)(hdf5_file_t*,off_t,void*);
+
+ assert (type);
+ assert (type->list);
+
+ bt = H5AC_find (f, H5AC_BT, addr, type);
+ if (!bt) return -1;
+
+ if (bt->level>0) {
+ return H5B_list (f, type, bt->child[0], udata);
+ } else {
+ child = H5MM_xmalloc (2 * type->k * sizeof(off_t));
+ list = type->list;
+ twin = addr;
+
+ while (twin) { /*for each leaf node*/
+ bt = H5AC_find (f, H5AC_BT, twin, type);
+ if (!bt) {
+ H5MM_xfree (child);
+ return -1;
+ }
+ nchildren = bt->nchildren;
+ twin = bt->right;
+ HDmemcpy (child, bt->child, nchildren * sizeof(off_t));
+ bt = NULL; /*list callback may invalidate the cache*/
+
+ for (i=0; i<nchildren; i++) {
+ status = (list)(f, child[i], udata);
+ if (status<0) {
+ H5MM_xfree (child);
+ return -1;
+ }
+ }
+ }
+ H5MM_xfree (child);
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5B_nodesize
+ *
+ * Purpose: Returns the number of bytes needed for this type of
+ * B-tree node. The size is the size of the header plus
+ * enough space for 2t child pointers and 2t+1 keys.
+ *
+ * If TOTAL_NKEY_SIZE is non-null, what it points to will
+ * be initialized with the total number of bytes required to
+ * hold all the key values in native order.
+ *
+ * Return: Success: Size of node in file.
+ *
+ * Failure: never fails.
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Jul 3 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5B_nodesize (hdf5_file_t *f, const H5B_class_t *type,
+ size_t *total_nkey_size, size_t sizeof_rkey)
+{
+ if (total_nkey_size) {
+ *total_nkey_size = (2 * type->k + 1) * type->sizeof_nkey;
+ }
+
+ return (H5B_HDR_SIZE(f) + /*node header */
+ 2 * type->k * SIZEOF_OFFSET(f) + /*child pointers*/
+ (2*type->k+1) * sizeof_rkey); /*keys */
+}
+
diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h
new file mode 100644
index 0000000..d6ecc7c
--- /dev/null
+++ b/src/H5Bprivate.h
@@ -0,0 +1,85 @@
+/*-------------------------------------------------------------------------
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * Created: H5Bprivate.h
+ * Jul 10 1997
+ * Robb Matzke <matzke@llnl.gov>
+ *
+ * Purpose: Private non-prototype header.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Bprivate_H
+#define _H5Bprivate_H
+
+#include "H5Bproto.h" /*API prototypes */
+
+
+
+#define H5B_MAGIC "TREE" /* tree node magic number */
+#define H5B_HDR_SIZE(F) (8+2*SIZEOF_OFFSET(F))
+
+#define H5B_ANCHOR_LT 0 /* left node is anchored, right is new */
+#define H5B_ANCHOR_RT 1 /* right node is anchored, left is new */
+
+
+/*
+ * Each class of object that can be pointed to by a B-link tree has a
+ * variable of this type that contains class variables and methods.
+ */
+typedef struct H5B_class_t {
+ intn id; /*id as found in file */
+ intn k; /* max children is 2k */
+ size_t sizeof_nkey; /*size of native (memory) key */
+ size_t (*get_sizeof_rkey)(hdf5_file_t*);
+ off_t (*new)(hdf5_file_t*,void*,void*,void*);
+ intn (*cmp)(hdf5_file_t*,void*,void*,void*);
+ herr_t (*found)(hdf5_file_t*,off_t,void*,void*,void*);
+ off_t (*insert)(hdf5_file_t*,off_t,int*,void*,int*,void*,void*,
+ void*,int*);
+ herr_t (*list)(hdf5_file_t*,off_t,void*);
+ void (*decode)(hdf5_file_t*,uint8*,void*);
+ void (*encode)(hdf5_file_t*,uint8*,void*);
+} H5B_class_t;
+
+/*
+ * The B-tree node as stored in memory...
+ */
+typedef struct H5B_key_t {
+ intn dirty; /*native key is more recent than raw key*/
+ uint8 *rkey; /*ptr into node->page for raw key */
+ void *nkey; /*null or ptr into node->native for key */
+} H5B_key_t;
+
+typedef struct H5B_t {
+ const H5B_class_t *type; /*type of tree */
+ size_t sizeof_rkey; /*size of raw (disk) key */
+ intn dirty; /*something in the tree is dirty */
+ intn ndirty; /*num child ptrs to emit */
+ intn level; /*node level */
+ off_t left; /*address of left sibling */
+ off_t right; /*address of right sibling */
+ intn nchildren; /*number of child pointers */
+ uint8 *page; /*disk page */
+ uint8 *native; /*array of keys in native format */
+ H5B_key_t *key; /*2k+1 key entries */
+ off_t *child; /*2k child pointers */
+} H5B_t;
+
+
+/*
+ * Library prototypes.
+ */
+herr_t H5B_debug (hdf5_file_t *f, off_t addr, const H5B_class_t *type);
+off_t H5B_new (hdf5_file_t *f, const H5B_class_t *type, size_t sizeof_rkey);
+herr_t H5B_find (hdf5_file_t *f, const H5B_class_t *type, off_t addr, void *udata);
+off_t H5B_insert (hdf5_file_t *f, const H5B_class_t *type, off_t addr, void *udata);
+herr_t H5B_list (hdf5_file_t *f, const H5B_class_t *type, off_t addr, void *udata);
+
+
+#endif /* !_H5Bprivate_H */
diff --git a/src/H5Bproto.h b/src/H5Bproto.h
new file mode 100644
index 0000000..3869db4
--- /dev/null
+++ b/src/H5Bproto.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * Created: H5Bproto.h
+ * Jul 10 1997
+ * Robb Matzke <robb@maya.nuance.com>
+ *
+ * Purpose: Non-API function prototypes for B-link trees.
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _H5Bproto_H
+#define _H5Bproto_H
+
+#if defined c_plusplus || defined __cplusplus
+extern "C"
+{
+#endif
+
+#if defined c_plusplus || defined __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/H5C.c b/src/H5C.c
new file mode 100644
index 0000000..847f3b5
--- /dev/null
+++ b/src/H5C.c
@@ -0,0 +1,506 @@
+/****************************************************************************
+* NCSA HDF *
+* Software Development Group *
+* National Center for Supercomputing Applications *
+* University of Illinois at Urbana-Champaign *
+* 605 E. Springfield, Champaign IL 61820 *
+* *
+* For conditions of distribution and use, see the accompanying *
+* hdf/COPYING file. *
+* *
+****************************************************************************/
+
+#ifdef RCSID
+static char RcsId[] = "@(#)$Revision$";
+#endif
+
+/* $Id$ */
+
+/*LINTLIBRARY */
+/*+
+ FILE
+ hdf5file.c
+ HDF5 "personality template" routines
+
+ EXPORTED ROUTINES
+ H5Csetparm -- Set a parameter for a template
+ H5Cgetparm -- Get a parameter for a template
+
+ LIBRARY-SCOPED ROUTINES
+
+ LOCAL ROUTINES
+ H5C_init_interface -- initialize the interface
+ + */
+
+#include "hdf5.h"
+
+/* private header files */
+#include "H5private.h" /* Generic Functions */
+#include "H5Cprivate.h" /* Template information */
+
+/*--------------------- Locally scoped variables -----------------------------*/
+
+/* Whether we've installed the library termination function yet for this interface */
+static intn interface_initialize = FALSE;
+
+/* Define the library's default file creation template (constants in hdf5lims.h) */
+const file_create_temp_t default_file_create={
+ HDF5_USERBLOCK_DEFAULT, /* Default user-block size */
+ HDF5_OFFSETSIZE_DEFAULT, /* Default offset size */
+ HDF5_LENGTHSIZE_DEFAULT, /* Default length size */
+ HDF5_BTREEPAGE_DEFAULT, /* Default B-tree page size */
+ HDF5_BOOTBLOCK_VERSION, /* Current Boot-Block version # */
+ HDF5_SMALLOBJECT_VERSION, /* Current Small-Object heap version # */
+ HDF5_FREESPACE_VERSION, /* Current Free-Space info version # */
+ HDF5_OBJECTDIR_VERSION, /* Current Object Directory info version # */
+ HDF5_SHAREDHEADER_VERSION /* Current Shared-Header format version # */
+};
+static hatom_t default_file_id=FAIL; /* Atom for the default file-creation template */
+
+/*--------------------- Local function prototypes ----------------------------*/
+static herr_t H5C_init_interface(void);
+
+/*--------------------------------------------------------------------------
+NAME
+ H5C_init_interface -- Initialize interface-specific information
+USAGE
+ herr_t H5C_init_interface()
+
+RETURNS
+ SUCCEED/FAIL
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+static herr_t H5C_init_interface(void)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5C_init_interface"); /* For HERROR */
+#endif /* LATER */
+ herr_t ret_value = SUCCEED;
+
+ /* Don't use "FUNC_ENTER" macro, to avoid potential infinite recursion */
+ PABLO_TRACE_ON(H5C_mask, ID_H5C_init_interface);
+
+ /* Don't call this routine again... */
+ interface_initialize = TRUE;
+
+ /* Initialize the atom group for the file IDs */
+ ret_value=H5Ainit_group(H5_TEMPLATE,HDF5_TEMPID_HASHSIZE,0);
+
+ FUNC_LEAVE(H5C_mask, ID_H5C_init_interface, ret_value);
+} /* H5C_init_interface */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5C_get_default_atom
+ PURPOSE
+ Retrive an atom for a default HDF5 template.
+ USAGE
+ hatom_t H5C_create(type)
+ hobjtype_t type; IN: Type of object to retrieve default template of
+ RETURNS
+ Returns template ID (atom) of the default object for a template type on
+ success, FAIL on failure
+ DESCRIPTION
+ This is function retrieves atoms for the default templates for the
+ different types of HDF5 templates.
+--------------------------------------------------------------------------*/
+hatom_t H5C_get_default_atom(hobjtype_t type)
+{
+ CONSTR(FUNC, "H5C_create"); /* for HERROR */
+ hatom_t ret_value = FAIL;
+
+ FUNC_ENTER(H5C_mask, ID_H5C_get_default_atom, H5C_init_interface, FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+
+ switch(type)
+ {
+ case H5_TEMPLATE:
+ if(default_file_id==FAIL)
+ {
+ if((default_file_id=H5Aregister_atom(H5_TEMPLATE, (const VOIDP)&default_file_create))==FAIL)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL);
+ } /* end else */
+ HGOTO_DONE(default_file_id);
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+ } /* end switch */
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5C_mask, ID_H5C_get_default_atom, ret_value);
+} /* end H5C_get_default_atom() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5C_init
+ PURPOSE
+ Initialize a new HDF5 template with a copy of an existing template.
+ USAGE
+ herr_t H5C_init(dst_atm, src)
+ hatom_t dst_atm; IN: Atom for the template to initialize
+ file_create_temp_t *src; IN: Template to use to initialize with
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ This function copies the contents of the source template into the
+ newly created destination template.
+--------------------------------------------------------------------------*/
+herr_t H5C_init(hatom_t dst_atm, const file_create_temp_t *src)
+{
+ CONSTR(FUNC, "H5C_init"); /* for HERROR */
+ file_create_temp_t *dst; /* destination template */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ FUNC_ENTER(H5C_mask, ID_H5C_init, H5C_init_interface, FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+ if(src==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+
+ /* Get the template to initialize */
+ if((dst=H5Aatom_object(dst_atm))==NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL);
+
+ /* Copy in the source template */
+ HDmemcpy(dst,src,sizeof(file_create_temp_t));
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5C_mask, ID_H5C_init, ret_value);
+} /* end H5C_init() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5C_create
+ PURPOSE
+ Create a new HDF5 template.
+ USAGE
+ hatom_t H5C_create(owner_id, type, name)
+ hatom_t owner_id; IN: Group/file which owns this template
+ hobjtype_t type; IN: Type of template to create
+ const char *name; IN: Name of the template to create
+ RETURNS
+ Returns template ID (atom) on success, FAIL on failure
+ DESCRIPTION
+ This is the primary function for creating different HDF5 templates.
+ Currently the name of template is not used and may be NULL.
+--------------------------------------------------------------------------*/
+hatom_t H5C_create(hatom_t owner_id, hobjtype_t type, const char *name)
+{
+ CONSTR(FUNC, "H5C_create"); /* for HERROR */
+ hatom_t ret_value = FAIL; /* atom for template object to return */
+
+ FUNC_ENTER(H5C_mask, ID_H5C_create, H5C_init_interface, FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+
+ switch(type)
+ {
+ case H5_TEMPLATE:
+ {
+ file_create_temp_t *new_create_temp; /* new template object to create */
+
+ if((new_create_temp=HDmalloc(sizeof(file_create_temp_t)))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL);
+ if((ret_value=H5Aregister_atom(H5_TEMPLATE, (const VOIDP)new_create_temp))==FAIL)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL);
+ } /* end case/block */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+ } /* end switch */
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5C_mask, ID_H5C_create, ret_value);
+} /* end H5C_create() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5C_release
+ PURPOSE
+ Release access to a template object.
+ USAGE
+ herr_t H5C_release(oid)
+ hatom_t oid; IN: Template object to release access to
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ This function releases access to a template object
+--------------------------------------------------------------------------*/
+herr_t H5C_release(hatom_t oid)
+{
+ CONSTR(FUNC, "H5C_release"); /* for HERROR */
+ file_create_temp_t *template; /* template to destroy */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5C_mask, ID_H5C_release, H5C_init_interface, FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+
+ /* Chuck the object! :-) */
+ if((template=H5Aremove_atom(oid))==NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL);
+ HDfree(template);
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5C_mask, ID_H5C_release, ret_value);
+} /* end H5C_release() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Cgetparm
+ PURPOSE
+ Get a parameter from a template
+ USAGE
+ herr_t H5Cgetparm(tid, parm, buf)
+ hatom_t tid; IN: Template object to retrieve parameter from
+ file_create_param_t parm; IN: Paramter to retrieve
+ VOIDP buf; OUT: Pointer to buffer to store parameter in
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ This function retrieves the value of a specific parameter from a
+ template
+--------------------------------------------------------------------------*/
+herr_t H5Cgetparm(hatom_t tid, file_create_param_t parm, VOIDP buf)
+{
+ CONSTR(FUNC, "H5Cgetparm"); /* for HERROR */
+ file_create_temp_t *template; /* template to query */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5C_mask, ID_H5Cgetparm, H5C_init_interface, FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+ if(buf==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+
+ /* Get a pointer the template to query */
+ if((template=H5Aatom_object(tid))==NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL);
+
+ switch(parm)
+ {
+ case H5_USERBLOCK_SIZE:
+ *(uintn *)buf=template->userblock_size;
+ break;
+
+ case H5_OFFSET_SIZE:
+ *(uintn *)buf=template->offset_size;
+ break;
+
+ case H5_LENGTH_SIZE:
+ *(uintn *)buf=template->length_size;
+ break;
+
+ case H5_BTREE_SIZE:
+ *(uintn *)buf=template->btree_page_size;
+ break;
+
+ case H5_BOOTBLOCK_VER:
+ *(uint8 *)buf=template->bootblock_ver;
+ break;
+
+ case H5_SMALLOBJECT_VER:
+ *(uint8 *)buf=template->smallobject_ver;
+ break;
+
+ case H5_FREESPACE_VER:
+ *(uint8 *)buf=template->freespace_ver;
+ break;
+
+ case H5_OBJECTDIR_VER:
+ *(uint8 *)buf=template->objectdir_ver;
+ break;
+
+ case H5_SHAREDHEADER_VER:
+ *(uint8 *)buf=template->sharedheader_ver;
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+ } /* end switch */
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5C_mask, ID_H5Cgetparm, ret_value);
+} /* end H5Cgetparm() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Csetparm
+ PURPOSE
+ Set a parameter from a template
+ USAGE
+ herr_t H5Csetparm(tid, parm, buf)
+ hatom_t tid; IN: Template object to store parameter in
+ file_create_param_t parm; IN: Parameter to store
+ VOIDP buf; OUT: Pointer to parameter buffer
+ RETURNS
+ SUCCEED/FAIL
+ DESCRIPTION
+ This function stores the value of a specific parameter for a template
+--------------------------------------------------------------------------*/
+herr_t H5Csetparm(hatom_t tid, file_create_param_t parm, const VOIDP buf)
+{
+ CONSTR(FUNC, "H5Csetparm"); /* for HERROR */
+ file_create_temp_t *template; /* template to query */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5C_mask, ID_H5Csetparm, H5C_init_interface, FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+ if(buf==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+
+ /* Get a pointer the template to query */
+ if((template=H5Aatom_object(tid))==NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL);
+
+ switch(parm)
+ {
+ case H5_USERBLOCK_SIZE:
+ template->userblock_size=*(const uintn *)buf;
+ break;
+
+ case H5_OFFSET_SIZE:
+ template->offset_size=*(const uintn *)buf;
+ break;
+
+ case H5_LENGTH_SIZE:
+ template->length_size=*(const uintn *)buf;
+ break;
+
+ case H5_BTREE_SIZE:
+ template->btree_page_size=*(const uintn *)buf;
+ break;
+
+ case H5_BOOTBLOCK_VER:
+ template->bootblock_ver=*(const uint8 *)buf;
+ break;
+
+ case H5_SMALLOBJECT_VER:
+ template->smallobject_ver=*(const uint8 *)buf;
+ break;
+
+ case H5_FREESPACE_VER:
+ template->freespace_ver=*(const uint8 *)buf;
+ break;
+
+ case H5_OBJECTDIR_VER:
+ template->objectdir_ver=*(const uint8 *)buf;
+ break;
+
+ case H5_SHAREDHEADER_VER:
+ template->sharedheader_ver=*(const uint8 *)buf;
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL);
+ } /* end switch */
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5C_mask, ID_H5Csetparm, ret_value);
+} /* end H5Csetparm() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5C_copy
+ PURPOSE
+ Copy a template
+ USAGE
+ hatom_t H5C_copy(tid)
+ hatom_t tid; IN: Template object to copy
+ RETURNS
+ Returns template ID (atom) on success, FAIL on failure
+ DESCRIPTION
+ This function creates a new copy of a template with all the same parameter
+ settings.
+--------------------------------------------------------------------------*/
+hatom_t H5C_copy(hatom_t tid)
+{
+ CONSTR(FUNC, "H5C_copy"); /* for HERROR */
+ file_create_temp_t *template, *new_template; /* template to query */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5C_mask, ID_H5C_copy, H5C_init_interface, FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+
+ /* Get a pointer the template to query */
+ if((template=H5Aatom_object(tid))==NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL);
+
+ /* Allocate space for the new template */
+ if((new_template=HDmalloc(sizeof(file_create_temp_t)))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL);
+
+ /* Copy over the information from the old template */
+ HDmemcpy(new_template,template,sizeof(file_create_temp_t));
+
+ /* Register the atom for the new template */
+ if((ret_value=H5Aregister_atom(H5_TEMPLATE, (const VOIDP)new_template))==FAIL)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL);
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5C_mask, ID_H5C_copy, ret_value);
+} /* end H5C_copy() */
+
diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h
new file mode 100644
index 0000000..4f7357f
--- /dev/null
+++ b/src/H5Cprivate.h
@@ -0,0 +1,25 @@
+/****************************************************************************
+ * NCSA HDF *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * hdf/COPYING file. *
+ * *
+ ****************************************************************************/
+
+/* $Id$ */
+
+/*
+ * This file contains private information about the H5C module
+ */
+
+#ifndef H5CPRIVATE_H
+#define H5CPRIVATE_H
+
+#include "H5Cproto.h"
+
+#endif /* H5CPRIVATE_H */
+
diff --git a/src/H5Cproto.h b/src/H5Cproto.h
new file mode 100644
index 0000000..0d8f26d
--- /dev/null
+++ b/src/H5Cproto.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+ * NCSA HDF *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * hdf/COPYING file. *
+ * *
+ ****************************************************************************/
+
+/* $Id$ */
+
+/*
+ * This file contains function prototypes for each exported function in the H5C module
+ */
+
+#ifndef H5CPROTO_H
+#define H5CPROTO_H
+
+#if defined c_plusplus || defined __cplusplus
+extern "C"
+{
+#endif /* c_plusplus || __cplusplus */
+
+/* Functions in H5C.c */
+hatom_t H5C_create(hatom_t owner_id, hobjtype_t type, const char *name);
+hatom_t H5C_copy(hatom_t tid);
+herr_t H5C_release(hatom_t oid);
+hatom_t H5C_get_default_atom(hobjtype_t type);
+herr_t H5C_init(hatom_t dst_atm, const file_create_temp_t *src);
+herr_t H5Cgetparm(hatom_t tid, file_create_param_t parm, VOIDP buf);
+herr_t H5Csetparm(hatom_t tid, file_create_param_t parm, const VOIDP buf);
+
+#if defined c_plusplus || defined __cplusplus
+}
+#endif /* c_plusplus || __cplusplus */
+
+#endif /* H5CPROTO_H */
+
diff --git a/src/H5E.c b/src/H5E.c
new file mode 100644
index 0000000..a697f39
--- /dev/null
+++ b/src/H5E.c
@@ -0,0 +1,394 @@
+/****************************************************************************
+* NCSA HDF *
+* Software Development Group *
+* National Center for Supercomputing Applications *
+* University of Illinois at Urbana-Champaign *
+* 605 E. Springfield, Champaign IL 61820 *
+* *
+* For conditions of distribution and use, see the accompanying *
+* hdf/COPYING file. *
+* *
+****************************************************************************/
+
+#ifdef RCSID
+static char RcsId[] = "@(#)$Revision$";
+#endif
+
+/* $Id$ */
+
+/*LINTLIBRARY */
+/*+
+ FILE
+ hdf5err.c
+ HDF error reporting routines
+
+ EXPORTED ROUTINES
+ H5Enew_err_stack -- Create a new error stack to push values on
+ H5Epush -- Push an error value on an error stack
+
+ LIBRARY-SCOPED ROUTINES
+
+ LOCAL ROUTINES
+ H5E_init_interface -- initialize the H5E interface
+ + */
+
+#define HDF5_ERR_MASTER
+#include "hdf5.h"
+#include "H5Eprivate.h" /* Private error routines */
+#undef HDF5_ERR_MASTER
+
+#include "H5private.h" /* Generic Functions */
+
+/*--------------------- Locally scoped variables -----------------------------*/
+
+/* Whether we've installed the library termination function yet for this interface */
+static intn interface_initialize = FALSE;
+
+/*------------------_-- Local function prototypes ----------------------------*/
+static herr_t H5E_init_interface(void);
+
+/*--------------------------------------------------------------------------
+NAME
+ H5E_init_interface -- Initialize interface-specific information
+USAGE
+ herr_t H5E_init_interface()
+
+RETURNS
+ SUCCEED/FAIL
+DESCRIPTION
+ Initializes any interface-specific data or routines.
+
+--------------------------------------------------------------------------*/
+static herr_t H5E_init_interface(void)
+{
+#ifdef LATER
+ CONSTR(FUNC, "H5E_init_interface"); /* For HERROR */
+#endif /* LATER */
+ herr_t ret_value = SUCCEED;
+
+ /* Don't use "FUNC_ENTER" macro, to avoid potential infinite recursion */
+ PABLO_TRACE_ON(H5_mask, ID_H5Iinit_interface);
+
+ /* Don't call this routine again... */
+ interface_initialize = TRUE;
+
+ /* Initialize the atom group for the error stacks */
+ ret_value=H5Ainit_group(H5_ERR,HDF5_ERRSTACK_HASHSIZE,0);
+
+ FUNC_LEAVE(H5_mask, ID_H5E_init_interface, ret_value);
+} /* H5E_init_interface */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5Enew_err_stack -- Create a new error stack
+USAGE
+ int32 H5Enew_err_stack(initial_stack_size);
+ uintn initial_stack_size; IN: Starting size of the error stack
+
+RETURNS
+ The ID of the error stack created on success, FAIL on failure.
+
+DESCRIPTION
+ Dynamically creates a new error stack to push error values onto.
+
+--------------------------------------------------------------------------*/
+int32 H5Enew_err_stack(uintn initial_stack_size)
+{
+ CONSTR(FUNC, "H5Enew_err_stack"); /* For HERROR */
+ H5E_errstack_t *new_stack=NULL; /* Pointer to the new error stack */
+ int32 ret_value = FAIL;
+
+ FUNC_ENTER(H5E_mask, ID_H5Enew_err_stack, H5E_init_interface,FAIL);
+
+ /* Allocate the stack header */
+ if((new_stack=HDmalloc(sizeof(H5E_errstack_t)))==NULL)
+ HGOTO_DONE(FAIL);
+
+ /* Initialize the stack header */
+ new_stack->stack_size=initial_stack_size;
+ new_stack->stack_top=0;
+ if((new_stack->err_stack=HDcalloc(initial_stack_size,sizeof(H5E_error_t)))==NULL)
+ {
+ HDfree(new_stack);
+ HGOTO_DONE(FAIL);
+ } /* end if */
+ new_stack->push=H5E_store; /* Set the default error handler */
+
+ /* Get an atom for the error stack */
+ ret_value=H5Aregister_atom(H5_ERR, new_stack);
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5E_mask, ID_H5Enew_err_stack, ret_value);
+} /* H5Enew_err_stack */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5Edelete_err_stack -- Destroy an error stack
+USAGE
+ intn H5Edelete_err_stack(err_stack);
+ int32 err_stack; IN: Error stack to delete
+
+RETURNS
+ SUCCEED/FAIL
+
+DESCRIPTION
+ Destroys an error stack, releasing memory allocated, etc.
+
+--------------------------------------------------------------------------*/
+intn H5Edelete_err_stack(int32 err_stack)
+{
+ CONSTR(FUNC, "H5Edelete_err_stack"); /* For HERROR */
+ H5E_errstack_t *old_stack=NULL; /* Pointer to the new error stack */
+ intn ret_value = SUCCEED;
+
+ FUNC_ENTER(H5E_mask, ID_H5Edelete_err_stack, H5E_init_interface,FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ if (H5Aatom_group(err_stack)!=H5_ERR)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL);
+
+ /* Get the error stack to put the error on */
+ if((old_stack=H5Aremove_atom(err_stack))==NULL)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL);
+
+ /* Clear the error descriptions and reset the stack top */
+ for(; old_stack->stack_top>0; old_stack->stack_top--)
+ {
+ if (old_stack->err_stack[old_stack->stack_top-1].desc)
+ {
+ HDfree(old_stack->err_stack[old_stack->stack_top-1].desc);
+ old_stack->err_stack[old_stack->stack_top-1].desc=NULL;
+ } /* end if */
+ } /* end if */
+
+ HDfree(old_stack->err_stack);
+ HDfree(old_stack);
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5E_mask, ID_H5Edelete_err_stack, ret_value);
+} /* H5Edelete_err_stack */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5Eclear -- Clear an error stack for later error entries
+USAGE
+ void H5Eclear(int32 err_hand)
+ int32 err_hand; IN: The ID of the error stack to push the error onto.
+
+RETURNS
+ none
+DESCRIPTION
+ Clear an error stack to allow errors to be pushed onto it.
+
+--------------------------------------------------------------------------*/
+void H5Eclear(int32 err_hand)
+{
+ CONSTR(FUNC, "H5Eclear"); /* For HERROR */
+ H5E_errstack_t *err_stack=NULL; /* Pointer to the error stack to put value on */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5E_mask, ID_H5Eclear, H5E_init_interface,FAIL);
+
+ /* Get the error stack for this error handler, initialized earlier in H5Enew_err_stack */
+ if (H5Aatom_group(err_hand)!=H5_ERR)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL);
+
+ /* Get the error stack to put the error on */
+ if((err_stack=H5Aatom_object(err_hand))==NULL)
+ HGOTO_ERROR(H5E_BADATOM, H5E_BADATOM, FAIL);
+
+ /* Clear the error descriptions and reset the stack top */
+ for(; err_stack->stack_top>0; err_stack->stack_top--)
+ {
+ if (err_stack->err_stack[err_stack->stack_top-1].desc)
+ {
+ HDfree(err_stack->err_stack[err_stack->stack_top-1].desc);
+ err_stack->err_stack[err_stack->stack_top-1].desc=NULL;
+ } /* end if */
+ } /* end if */
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ PABLO_TRACE_OFF(H5E_mask, ID_H5Eclear); /* ignore ret_value set */
+} /* H5Eclear */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5E_store -- Push an error value on an error stack
+USAGE
+ void H5E_store(hdf_err_code_t err, const char *function_name, const char *file_name, intn line)
+ hdf_err_code_t err; IN: The error code which occurred.
+ const char *function_name; IN: Name of the function the error occurred within.
+ const char *file_name; IN: Name of the file the error occurred within.
+ intn line; IN: Line # in the file the error occurred on.
+
+RETURNS
+ none
+DESCRIPTION
+ Pushes an error onto an error stack for this thread. (This is the default
+ action when errors occur, but can be overridden by user's code)
+
+--------------------------------------------------------------------------*/
+void H5E_store(int32 errid, hdf_maj_err_code_t maj, hdf_min_err_code_t min, const char *function_name, const char *file_name, intn line)
+{
+ CONSTR(FUNC, "H5E_store"); /* For HERROR */
+ H5E_errstack_t *err_stack=NULL; /* Pointer to the error stack to put value on */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5E_mask, ID_H5E_store, H5E_init_interface,FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5Eclear(errid);
+
+ /* Get the error stack to put the error on */
+ if((err_stack=H5Aatom_object(errid))==NULL)
+ HGOTO_ERROR(H5E_BADATOM, H5E_BADATOM, FAIL);
+
+ /* Check if we need to expand the stack */
+ if(err_stack->stack_top>=err_stack->stack_size)
+ {
+ H5E_error_t *old_stack=err_stack->err_stack; /* in case realloc fails */
+
+ /* Ask for new stack that's twice as large */
+ if((err_stack->err_stack=HDrealloc(old_stack,2*err_stack->stack_size))==NULL)
+ {
+ err_stack->err_stack=old_stack;
+ HGOTO_DONE(FAIL);
+ } /* end if */
+ err_stack->stack_size *= 2; /* increase the size of the stack */
+ } /* end if */
+
+ /* Push the error onto the error stack */
+ err_stack->err_stack[err_stack->stack_top].maj=maj;
+ err_stack->err_stack[err_stack->stack_top].min=min;
+ HDstrncpy(err_stack->err_stack[err_stack->stack_top].function_name,function_name,MAX_FUNC_NAME_LEN);
+ err_stack->err_stack[err_stack->stack_top].file_name=file_name;
+ err_stack->err_stack[err_stack->stack_top].line=line;
+
+ /* Increment the top of the error stack */
+ err_stack->stack_top++;
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ PABLO_TRACE_OFF(H5E_mask, ID_H5E_store); /* ignore ret_value set */
+} /* H5E_store */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5Epush -- Push an error value on an error stack
+USAGE
+ void H5Epush(hdf_err_code_t err, const char *function_name, const char *file_name, intn line)
+ hdf_err_code_t err; IN: The error code which occurred.
+ const char *function_name; IN: Name of the function the error occurred within.
+ const char *file_name; IN: Name of the file the error occurred within.
+ intn line; IN: Line # in the file the error occurred on.
+
+RETURNS
+ none
+DESCRIPTION
+ Pushes an error onto an error stack for this thread.
+
+--------------------------------------------------------------------------*/
+void H5Epush(hdf_maj_err_code_t maj, hdf_min_err_code_t min, const char *function_name, const char *file_name, intn line)
+{
+ CONSTR(FUNC, "H5Epush"); /* For HERROR */
+ H5E_errstack_t *err_stack=NULL; /* Pointer to the error stack to put value on */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER(H5E_mask, ID_H5Epush, H5E_init_interface,FAIL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+ if (function_name==NULL || file_name==NULL || H5Aatom_group(thrderrid)!=H5_ERR)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL);
+
+ /* Get the error stack to put the error on */
+ if((err_stack=H5Aatom_object(thrderrid))==NULL)
+ HGOTO_ERROR(H5E_BADATOM, H5E_BADATOM, FAIL);
+
+ err_stack->push(thrderrid, maj, min, function_name, file_name, line);
+
+done:
+ if(ret_value == FAIL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ PABLO_TRACE_OFF(H5E_mask, ID_H5Epush); /* ignore ret_value set */
+} /* H5Epush */
+
+/*--------------------------------------------------------------------------
+NAME
+ H5Eset_push -- Set the function to call when an error value is reported
+USAGE
+ H5E_push_func_t H5Eset_push(H5E_push_func_t func)
+ H5E_push_func_t func; IN: New function to call when an error occurs.
+
+RETURNS
+ The function pointer to the previous error function on success, NULL on
+ failure.
+DESCRIPTION
+ Changes the function which is called for errors on this thread. The thread
+ ID is implicit, ie. this function must be called within each thread whose
+ error function is to be changed.
+
+--------------------------------------------------------------------------*/
+H5E_push_func_t H5Eset_push(H5E_push_func_t func)
+{
+ CONSTR(FUNC, "H5Eset_push"); /* For HERROR */
+ H5E_errstack_t *err_stack=NULL; /* Pointer to the error stack to put value on */
+ H5E_push_func_t ret_value = NULL;
+
+ FUNC_ENTER(H5E_mask, ID_H5Eset_push, H5E_init_interface,NULL);
+
+ /* Clear errors and check args and all the boring stuff. */
+ H5ECLEAR;
+ if (func==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL);
+
+ /* Get the error stack to put the error on */
+ if((err_stack=H5Aatom_object(thrderrid))==NULL)
+ HGOTO_ERROR(H5E_BADATOM, H5E_BADATOM, NULL);
+
+ ret_value=err_stack->push;
+ err_stack->push=func;
+
+done:
+ if(ret_value == NULL)
+ { /* Error condition cleanup */
+
+ } /* end if */
+
+ /* Normal function cleanup */
+
+ FUNC_LEAVE(H5E_mask, ID_H5Eset_push, ret_value);
+} /* H5Eset_push */
+
diff --git a/src/H5Eprivate.h b/src/H5Eprivate.h
new file mode 100644