From fa406155ab6ab2903d856f8e20502caef2df0996 Mon Sep 17 00:00:00 2001
From: Binh-Minh Ribler <bmribler@hdfgroup.org>
Date: Tue, 20 Oct 2009 13:14:34 -0500
Subject: [svn-r17690] Purpose: Code improvement Description:     Fixed
 CommonFG::getComment and CommonFG::getLinkval to provide     default values
 for buffer size to improve usability.

    Added test file tlinks.cpp, which only contains test for getLinkval
    and will expand when C++ wrappers for H5L functions are implemented.

Platforms tested:
    Linux/32 2.6 (jam)
    FreeBSD/64 6.3 (liberty)
    SunOS 5.10 (linew)
---
 c++/src/H5CommonFG.cpp | 106 ++++----
 c++/src/H5CommonFG.h   |  11 +-
 c++/test/Makefile.am   |   2 +-
 c++/test/Makefile.in   |   7 +-
 c++/test/h5cpputil.h   |  36 +--
 c++/test/testhdf5.cpp  |   1 +
 c++/test/tlinks.cpp    | 722 +++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 800 insertions(+), 85 deletions(-)
 create mode 100644 c++/test/tlinks.cpp

diff --git a/c++/src/H5CommonFG.cpp b/c++/src/H5CommonFG.cpp
index 80efc5d..f9311c6 100644
--- a/c++/src/H5CommonFG.cpp
+++ b/c++/src/H5CommonFG.cpp
@@ -15,11 +15,6 @@
 
 #include <string>
 
-// remove when done
-#include <iostream>
-    using std::cerr;
-    using std::endl;
-
 #include "H5Include.h"
 #include "H5Exception.h"
 #include "H5IdComponent.h"
@@ -430,16 +425,37 @@ void CommonFG::getObjinfo( const H5std_string& name, H5G_stat_t& statbuf ) const
 //--------------------------------------------------------------------------
 H5std_string CommonFG::getLinkval( const char* name, size_t size ) const
 {
-   char* value_C = new char[size+1];  // temporary C-string for C API
+    H5L_info_t linkinfo;
+    char *value_C;	// value in C string
+    size_t val_size = size;
+    H5std_string value = "";
+    herr_t ret_value;
 
-   herr_t ret_value = H5Lget_val( getLocId(), name, value_C, size, H5P_DEFAULT );
-   if( ret_value < 0 )
-   {
-      throwException("getLinkval", "H5Lget_val failed");
-   }
-   H5std_string value = H5std_string( value_C );
-   delete []value_C;
-   return( value );
+    // if user doesn't provide buffer size, determine it
+    if (size == 0)
+    {
+	ret_value = H5Lget_info(getLocId(), name, &linkinfo, H5P_DEFAULT);
+	if( ret_value < 0 )
+	{
+	    throwException("getLinkval", "H5Lget_info to find buffer size failed");
+	}
+	val_size = linkinfo.u.val_size;
+    }
+
+    // if link has value, retrieve the value, otherwise, return null string
+    if (val_size > 0)
+    {
+	value_C = new char[val_size+1];  // temporary C-string for C API
+
+	ret_value = H5Lget_val(getLocId(), name, value_C, val_size, H5P_DEFAULT);
+	if( ret_value < 0 )
+	{
+	    throwException("getLinkval", "H5Lget_val failed");
+	}
+	value = H5std_string(value_C);
+	delete []value_C;
+    }
+    return(value);
 }
 
 //--------------------------------------------------------------------------
@@ -529,33 +545,38 @@ void CommonFG::removeComment(const H5std_string& name) const
 
 //--------------------------------------------------------------------------
 // Function:	CommonFG::getComment
-///\brief	Retrieves comment for the specified object.
+///\brief	Retrieves comment for the specified object and its comment's
+///		length.
 ///\param	name  - IN: Name of the object
+///\param	bufsize - IN: Length of the comment to retrieve
 ///\return	Comment string
 ///\exception	H5::FileIException or H5::GroupIException
-// Programmer	Binh-Minh Ribler - May 2005
+// Programmer	Binh-Minh Ribler - 2000
 //	2007: QAK modified to use H5O APIs; however the first parameter is
 //		no longer just file or group, this function should be moved
 //		to another class to accommodate attribute, dataset, and named
 //		datatype. - BMR
 //--------------------------------------------------------------------------
-H5std_string CommonFG::getComment (const H5std_string& name) const
+H5std_string CommonFG::getComment( const char* name, size_t bufsize ) const
 {
-   size_t bufsize = 256;        // anticipating the comment's length
+   // bufsize is default to 256
+   // temporary variable
    hid_t loc_id = getLocId();   // temporary variable
 
-   // temporary C-string for the object's comment
-   char* comment_C = new char[bufsize+1];
-   ssize_t ret_value = H5Oget_comment_by_name(loc_id, name.c_str(), comment_C, bufsize, H5P_DEFAULT);
+   // temporary C-string for the object's comment; bufsize already including
+   // null character
+   char* comment_C = new char[bufsize];
+   ssize_t ret_value = H5Oget_comment_by_name(loc_id, name, comment_C, bufsize, H5P_DEFAULT);
 
-   // if the actual length of the comment is longer than the anticipated
-   // value, then call H5Oget_comment_by_name again with the correct value
-   if ((size_t)ret_value > bufsize)
+   // if the actual length of the comment is longer than bufsize and bufsize
+   // was the default value, i.e., not given by the user, then call
+   // H5Oget_comment_by_name again with the correct value
+   if ((size_t)ret_value > bufsize && bufsize == 256)
    {
-	bufsize = ret_value;
+	size_t new_size = ret_value;
 	delete []comment_C;
-	comment_C = new char[bufsize+1];
-	ret_value = H5Oget_comment_by_name(loc_id, name.c_str(), comment_C, bufsize, H5P_DEFAULT);
+	comment_C = new char[new_size];	// new_size including null terminator
+	ret_value = H5Oget_comment_by_name(loc_id, name, comment_C, new_size, H5P_DEFAULT);
    }
 
    // if H5Oget_comment_by_name returns SUCCEED, return the string comment,
@@ -571,37 +592,6 @@ H5std_string CommonFG::getComment (const H5std_string& name) const
 
 //--------------------------------------------------------------------------
 // Function:	CommonFG::getComment
-///\brief	Retrieves comment for the specified object and its comment's
-///		length.
-///\param	name  - IN: Name of the object
-///\param	bufsize - IN: Length of the comment to retrieve
-///\return	Comment string
-///\exception	H5::FileIException or H5::GroupIException
-// Programmer	Binh-Minh Ribler - 2000
-//	2007: QAK modified to use H5O APIs; however the first parameter is
-//		no longer just file or group, this function should be moved
-//		to another class to accommodate attribute, dataset, and named
-//		datatype. - BMR
-//--------------------------------------------------------------------------
-H5std_string CommonFG::getComment( const char* name, size_t bufsize ) const
-{
-   // temporary C-string for the object's comment
-   char* comment_C = new char[bufsize+1];
-
-   herr_t ret_value = H5Oget_comment_by_name( getLocId(), name, comment_C, bufsize, H5P_DEFAULT );
-
-   // if H5Oget_comment_by_name returns SUCCEED, return the string comment
-   if( ret_value < 0 )
-   {
-      throwException("getComment", "H5Oget_comment_by_name failed");
-   }
-   H5std_string comment = H5std_string(comment_C);
-   delete []comment_C;
-   return( comment );
-}
-
-//--------------------------------------------------------------------------
-// Function:	CommonFG::getComment
 ///\brief	This is an overloaded member function, provided for convenience.
 ///		It differs from the above function in that it takes an
 ///		\c std::string for \a name.
diff --git a/c++/src/H5CommonFG.h b/c++/src/H5CommonFG.h
index 87c0615..d472d42 100644
--- a/c++/src/H5CommonFG.h
+++ b/c++/src/H5CommonFG.h
@@ -50,9 +50,8 @@ class H5_DLLCPP CommonFG {
 	DataSet openDataSet(const H5std_string& name) const;
 
 	// Retrieves comment for the HDF5 object specified by its name.
-	H5std_string getComment(const H5std_string& name) const;
-	H5std_string getComment(const char* name, size_t bufsize) const;
-	H5std_string getComment(const H5std_string& name, size_t bufsize) const;
+	H5std_string getComment(const char* name, size_t bufsize=256) const;
+	H5std_string getComment(const H5std_string& name, size_t bufsize=256) const;
 
 	// Removes the comment for the HDF5 object specified by its name.
 	void removeComment(const char* name) const;
@@ -62,9 +61,9 @@ class H5_DLLCPP CommonFG {
 	void setComment(const char* name, const char* comment) const;
 	void setComment(const H5std_string& name, const H5std_string& comment) const;
 
-	// Returns the name of the HDF5 object that the symbolic link points to.
-	H5std_string getLinkval(const char* name, size_t size) const;
-	H5std_string getLinkval(const H5std_string& name, size_t size) const;
+	// Returns the value of a symbolic link.
+	H5std_string getLinkval(const char* link_name, size_t size=0) const;
+	H5std_string getLinkval(const H5std_string& link_name, size_t size=0) const;
 
 	// Returns the number of objects in this group.
 	hsize_t getNumObjs() const;
diff --git a/c++/test/Makefile.am b/c++/test/Makefile.am
index 7799fd6..fdfdd61 100644
--- a/c++/test/Makefile.am
+++ b/c++/test/Makefile.am
@@ -39,7 +39,7 @@ LDADD=$(LIBH5TEST) $(LIBH5CPP) $(LIBHDF5)
 
 dsets_SOURCES=dsets.cpp h5cpputil.cpp
 testhdf5_SOURCES=testhdf5.cpp tattr.cpp tcompound.cpp tfile.cpp tfilter.cpp \
-	th5s.cpp trefer.cpp ttypes.cpp tvlstr.cpp h5cpputil.cpp
+	th5s.cpp tlinks.cpp trefer.cpp ttypes.cpp tvlstr.cpp h5cpputil.cpp
 
 # Tell conclude.am that these are C++ tests.
 CXX_API=yes
diff --git a/c++/test/Makefile.in b/c++/test/Makefile.in
index 909abb8..6384eec 100644
--- a/c++/test/Makefile.in
+++ b/c++/test/Makefile.in
@@ -74,8 +74,8 @@ dsets_LDADD = $(LDADD)
 dsets_DEPENDENCIES = $(LIBH5TEST) $(LIBH5CPP) $(LIBHDF5)
 am_testhdf5_OBJECTS = testhdf5.$(OBJEXT) tattr.$(OBJEXT) \
 	tcompound.$(OBJEXT) tfile.$(OBJEXT) tfilter.$(OBJEXT) \
-	th5s.$(OBJEXT) trefer.$(OBJEXT) ttypes.$(OBJEXT) \
-	tvlstr.$(OBJEXT) h5cpputil.$(OBJEXT)
+	th5s.$(OBJEXT) tlinks.$(OBJEXT) trefer.$(OBJEXT) \
+	ttypes.$(OBJEXT) tvlstr.$(OBJEXT) h5cpputil.$(OBJEXT)
 testhdf5_OBJECTS = $(am_testhdf5_OBJECTS)
 testhdf5_LDADD = $(LDADD)
 testhdf5_DEPENDENCIES = $(LIBH5TEST) $(LIBH5CPP) $(LIBHDF5)
@@ -368,7 +368,7 @@ TEST_PROG = dsets testhdf5
 LDADD = $(LIBH5TEST) $(LIBH5CPP) $(LIBHDF5)
 dsets_SOURCES = dsets.cpp h5cpputil.cpp
 testhdf5_SOURCES = testhdf5.cpp tattr.cpp tcompound.cpp tfile.cpp tfilter.cpp \
-	th5s.cpp trefer.cpp ttypes.cpp tvlstr.cpp h5cpputil.cpp
+	th5s.cpp tlinks.cpp trefer.cpp ttypes.cpp tvlstr.cpp h5cpputil.cpp
 
 
 # Tell conclude.am that these are C++ tests.
@@ -453,6 +453,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tfile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tfilter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/th5s.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tlinks.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trefer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttypes.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tvlstr.Po@am__quote@
diff --git a/c++/test/h5cpputil.h b/c++/test/h5cpputil.h
index d22a4d3..c547070 100644
--- a/c++/test/h5cpputil.h
+++ b/c++/test/h5cpputil.h
@@ -113,25 +113,27 @@ template <class Type1, class Type2>
 #ifdef __cplusplus
 extern "C" {
 #endif
-void test_attr(void);
-void test_compound(void);
-void test_file(void);
-void test_filters(void);
-void test_h5s(void);
-void test_reference(void);
-void test_types(void);
-void test_vlstrings(void);
+void test_attr();
+void test_compound();
+void test_file();
+void test_filters();
+void test_links();
+void test_h5s();
+void test_reference();
+void test_types();
+void test_vlstrings();
 
 /* Prototypes for the cleanup routines */
-void cleanup_attr(void);
-void cleanup_compound(void);
-void cleanup_dsets(void);
-void cleanup_file(void);
-void cleanup_filters(void);
-void cleanup_h5s(void);
-void cleanup_reference(void);
-void cleanup_types(void);
-void cleanup_vlstrings(void);
+void cleanup_attr();
+void cleanup_compound();
+void cleanup_dsets();
+void cleanup_file();
+void cleanup_filters();
+void cleanup_links();
+void cleanup_h5s();
+void cleanup_reference();
+void cleanup_types();
+void cleanup_vlstrings();
 
 #ifdef __cplusplus
 }
diff --git a/c++/test/testhdf5.cpp b/c++/test/testhdf5.cpp
index 02b427e..d61babf 100644
--- a/c++/test/testhdf5.cpp
+++ b/c++/test/testhdf5.cpp
@@ -85,6 +85,7 @@ main(int argc, char *argv[])
     AddTest("types", test_types, cleanup_types,  "Generic Data Types", NULL);
     AddTest("compound", test_compound, cleanup_compound,  "Compound Data Types", NULL);
     AddTest("filter", test_filters, cleanup_filters,  "Various Filters", NULL);
+    AddTest("links", test_links, cleanup_links,  "Various Links", NULL);
 /* Comment out tests that are not done yet. - BMR, Feb 2001
     AddTest("select", test_select, cleanup_select,  "Selections", NULL);
     AddTest("time", test_time, cleanup_time,  "Time Datatypes", NULL);
diff --git a/c++/test/tlinks.cpp b/c++/test/tlinks.cpp
new file mode 100644
index 0000000..83e33e1
--- /dev/null
+++ b/c++/test/tlinks.cpp
@@ -0,0 +1,722 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group.                                               *
+ * All rights reserved.                                                      *
+ *                                                                           *
+ * This file is part of HDF5.  The full HDF5 copyright notice, including     *
+ * terms governing use, modification, and redistribution, is contained in    *
+ * the files COPYING and Copyright.html.  COPYING can be found at the root   *
+ * of the source code distribution tree; Copyright.html can be found at the  *
+ * root level of an installed copy of the electronic HDF5 document set and   *
+ * is linked from the top-level documents page.  It can also be found at     *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
+ * access to either file, you may request a copy from help@hdfgroup.org.     *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*****************************************************************************
+   FILE
+   tlinks.cpp - HDF5 C++ testing functionalities associated with the
+        C attribute interface (H5L)
+
+ ***************************************************************************/
+
+#ifdef OLD_HEADER_FILENAME
+#include <iostream.h>
+#else
+#include <iostream>
+#endif
+#include <string>
+
+#ifndef H5_NO_NAMESPACE
+#ifndef H5_NO_STD
+    using std::cerr;
+    using std::endl;
+#endif  // H5_NO_STD
+#endif
+
+#include "testhdf5.h"   // C test header file
+#include "H5Cpp.h"      // C++ API header file
+
+#ifndef H5_NO_NAMESPACE
+    using namespace H5;
+#endif
+
+#include "h5cpputil.h"  // C++ test utilility header file
+
+// A lot of the definition inherited from C test links.c is left here until
+// the H5L API is implemented and tests are completed - BMR 10/19/2009
+/*
+ * This file needs to access private information from the H5G package.
+ * This file also needs to access the group testing code.
+ */
+//#define H5G_PACKAGE
+//#define H5G_TESTING
+
+//#include "h5test.h"
+//#include "H5Gpkg.h"		/* Groups 				*/
+//#include "H5Iprivate.h"		/* IDs			  		*/
+//#include "H5Lprivate.h"         /* Links                                */
+
+/* File for external link test.  Created with gen_udlinks.c */
+#define LINKED_FILE  "be_extlink2.h5"
+
+#ifdef H5_VMS
+#if 0
+const char *FILENAME[] = {
+    "links0",
+    "links1",
+    "links2",
+    "links3",
+    "links4a", /* 4 */
+    "links4b", /* 5 */
+    "links4c", /* 6 */
+    "links4d", /* 7 */
+    "links5",  /* 8 */
+    "links6",  /* 9 */
+    "links7",  /* 10 */
+    "links8",  /* 11 */
+    "extlinks0",	/* 12: main files */
+    "[.tmp]extlinks0",	/* 13: */
+    "extlinks1",	/* 14: target files */
+    "[.tmp]extlinks1",	/* 15: */
+    "extlinks2",	/* 16: */
+    "[.tmp]extlinks2",	/* 17: */
+    "extlinks3",	/* 18: */
+    "[.tmp]extlinks3",	/* 19: */
+    "extlinks4",	/* 20: */
+    "[.tmp]extlinks4",	/* 21: */
+    "extlinks5",	/* 22: */
+    "[.tmp]extlinks6",	/* 23: */
+    "extlinks7",	/* 24: */
+    "[.tmp]extlinks7",	/* 25: */
+    "[.tmp]extlinks8",	/* 26: */
+    "extlinks9",	/* 27: */
+    "[.tmp]extlinks9",	/* 28: */
+    "extlinks10",	/* 29: */ /* TESTS for windows */
+    "[.tmp]extlinks10",	/* 30: */
+    "[.tmp]extlinks11",	/* 31: */
+    "[.tmp]extlinks12",	/* 32: */
+    "extlinks13",	/* 33: */
+    "[.tmp]extlinks13",	/* 34: */
+    "[.tmp]extlinks14",	/* 35: */
+    "[.tmp]extlinks15",	/* 36: */
+    "extlinks16A",	/* 37: */ /* TESTS for H5P_set_elink_fapl */
+    "extlinks16B",	/* 38: */
+    "extlinks17",	/* 39: */
+    "extlinks18A",	/* 40: */
+    "extlinks18B",	/* 41: */
+    "extlinks19A",	/* 42: */
+    "extlinks19B",	/* 43: */
+    "extlinks20",	/* 44: */
+    NULL
+};
+#endif // 0
+
+#define TMPDIR          "[.tmp]"
+#else
+#if 0
+const char *FILENAME[] = {
+    "links0",
+    "links1",
+    "links2",
+    "links3",
+    "links4a", /* 4 */
+    "links4b", /* 5 */
+    "links4c", /* 6 */
+    "links4d", /* 7 */
+    "links5",  /* 8 */
+    "links6",  /* 9 */
+    "links7",  /* 10 */
+    "links8",  /* 11 */
+    "extlinks0",	/* 12: main files */
+    "tmp/extlinks0",	/* 13: */
+    "extlinks1",	/* 14: target files */
+    "tmp/extlinks1",	/* 15: */
+    "extlinks2",	/* 16: */
+    "tmp/extlinks2",	/* 17: */
+    "extlinks3",	/* 18: */
+    "tmp/extlinks3",	/* 19: */
+    "extlinks4",	/* 20: */
+    "tmp/extlinks4",	/* 21: */
+    "extlinks5",	/* 22: */
+    "tmp/extlinks6",	/* 23: */
+    "extlinks7",	/* 24: */
+    "tmp/extlinks7",	/* 25: */
+    "tmp/extlinks8",	/* 26: */
+    "extlinks9",	/* 27: */
+    "tmp/extlinks9",	/* 28: */
+    "extlinks10",	/* 29: */ /* TESTS for windows */
+    "tmp/extlinks10",	/* 30: */
+    "tmp/extlinks11",	/* 31: */
+    "tmp/extlinks12",	/* 32: */
+    "extlinks13",	/* 33: */
+    "tmp/extlinks13",	/* 34: */
+    "tmp/extlinks14",	/* 35: */
+    "tmp/extlinks15",	/* 36: */
+    "extlinks16A",	/* 37: */ /* TESTS for H5P_set_elink_fapl */
+    "extlinks16B",	/* 38: */
+    "extlinks17",	/* 39: */
+    "extlinks18A",	/* 40: */
+    "extlinks18B",	/* 41: */
+    "extlinks19A",	/* 42: */
+    "extlinks19B",	/* 43: */
+    "extlinks20",	/* 44: */
+    NULL
+};
+
+#endif // 0
+
+#define TMPDIR          "tmp"
+#endif
+
+#define FAMILY_SIZE	1024
+#define CORE_INCREMENT  1024
+#define NUM400		400
+
+/* do not do check_all_closed() for "ext*" files and "tmp/ext*" */
+#define EXTSTOP		12
+
+#define LINK_BUF_SIZE   1024
+#define NAME_BUF_SIZE   1024
+#define MAX_NAME_LEN    ((64*1024)+1024)
+
+/* Link type IDs */
+#define UD_HARD_TYPE 201
+#define UD_CB_TYPE H5L_TYPE_MAX
+#define UD_PLIST_TYPE 128
+#define UD_CBFAIL_TYPE UD_PLIST_TYPE
+#define UD_ERROR_TYPE 189
+#define UD_BAD_TYPE1 H5L_TYPE_HARD
+#define UD_BAD_TYPE2 (H5L_TYPE_UD_MIN - 5)
+#define UD_BAD_VERS (H5L_LINK_CLASS_T_VERS + 1)
+
+#define DEST_PROP_NAME "destination_group"
+#define REREG_TARGET_NAME "rereg_target"
+
+#define UD_CB_LINK_NAME "ud_callback_link"
+#define NEW_UD_CB_LINK_NAME "ud_callback_link2"
+#define UD_CB_TARGET "ud_target"
+#define UD_CB_TARGET_LEN 10
+
+#define LE_FILENAME "le_extlink1.h5"
+#define BE_FILENAME "be_extlink1.h5"
+
+#define ELINK_CB_FAM_SIZE (hsize_t) 100
+
+#define H5L_DIM1 100
+#define H5L_DIM2 100
+
+/* Creation order macros */
+#define CORDER_GROUP_NAME       "corder_group"
+#define CORDER_SOFT_GROUP_NAME  "corder_soft_group"
+#define CORDER_NLINKS               18
+#define CORDER_ITER_STOP            3
+#define CORDER_EST_ENTRY_LEN        9
+
+/* Timestamp macros */
+#define TIMESTAMP_GROUP_1       "timestamp1"
+#define TIMESTAMP_GROUP_2       "timestamp2"
+
+/* Link iteration struct */
+typedef struct {
+    H5_iter_order_t order;      /* Direction of iteration */
+    unsigned ncalled;           /* # of times callback is entered */
+    unsigned nskipped;          /* # of links skipped */
+    int stop;                   /* # of iterations to stop after */
+    int64_t curr;               /* Current creation order value */
+    size_t max_visit;           /* Size of "visited link" flag array */
+    hbool_t *visited;           /* Pointer to array of "visited link" flags */
+} link_iter_info_t;
+
+/* Link visit structs */
+typedef struct {
+    const char *path;           /* Path to link */
+    H5L_type_t type;            /* Type of link */
+} link_visit_t;
+static const link_visit_t lvisit0[] = {
+    {"Dataset_zero", H5L_TYPE_HARD},
+    {"Group1", H5L_TYPE_HARD},
+    {"Group1/Dataset_one", H5L_TYPE_HARD},
+    {"Group1/Group2", H5L_TYPE_HARD},
+    {"Group1/Group2/Dataset_two", H5L_TYPE_HARD},
+    {"Group1/Group2/Type_two", H5L_TYPE_HARD},
+    {"Group1/Group2/hard_zero", H5L_TYPE_HARD},
+    {"Group1/Type_one", H5L_TYPE_HARD},
+    {"Group1/hard_one", H5L_TYPE_HARD},
+    {"Type_zero", H5L_TYPE_HARD},
+    {"ext_dangle", H5L_TYPE_EXTERNAL},
+    {"ext_one", H5L_TYPE_EXTERNAL},
+    {"hard_one", H5L_TYPE_HARD},
+    {"hard_two", H5L_TYPE_HARD},
+    {"hard_zero", H5L_TYPE_HARD},
+    {"soft_dangle", H5L_TYPE_SOFT},
+    {"soft_one", H5L_TYPE_SOFT},
+    {"soft_two", H5L_TYPE_SOFT}
+};
+static const link_visit_t lvisit1[] = {
+    {"Dataset_one", H5L_TYPE_HARD},
+    {"Group2", H5L_TYPE_HARD},
+    {"Group2/Dataset_two", H5L_TYPE_HARD},
+    {"Group2/Type_two", H5L_TYPE_HARD},
+    {"Group2/hard_zero", H5L_TYPE_HARD},
+    {"Group2/hard_zero/Dataset_zero", H5L_TYPE_HARD},
+    {"Group2/hard_zero/Group1", H5L_TYPE_HARD},
+    {"Group2/hard_zero/Type_zero", H5L_TYPE_HARD},
+    {"Group2/hard_zero/ext_dangle", H5L_TYPE_EXTERNAL},
+    {"Group2/hard_zero/ext_one", H5L_TYPE_EXTERNAL},
+    {"Group2/hard_zero/hard_one", H5L_TYPE_HARD},
+    {"Group2/hard_zero/hard_two", H5L_TYPE_HARD},
+    {"Group2/hard_zero/hard_zero", H5L_TYPE_HARD},
+    {"Group2/hard_zero/soft_dangle", H5L_TYPE_SOFT},
+    {"Group2/hard_zero/soft_one", H5L_TYPE_SOFT},
+    {"Group2/hard_zero/soft_two", H5L_TYPE_SOFT},
+    {"Type_one", H5L_TYPE_HARD},
+    {"hard_one", H5L_TYPE_HARD}
+};
+static const link_visit_t lvisit2[] = {
+    {"Dataset_two", H5L_TYPE_HARD},
+    {"Type_two", H5L_TYPE_HARD},
+    {"hard_zero", H5L_TYPE_HARD},
+    {"hard_zero/Dataset_zero", H5L_TYPE_HARD},
+    {"hard_zero/Group1", H5L_TYPE_HARD},
+    {"hard_zero/Group1/Dataset_one", H5L_TYPE_HARD},
+    {"hard_zero/Group1/Group2", H5L_TYPE_HARD},
+    {"hard_zero/Group1/Type_one", H5L_TYPE_HARD},
+    {"hard_zero/Group1/hard_one", H5L_TYPE_HARD},
+    {"hard_zero/Type_zero", H5L_TYPE_HARD},
+    {"hard_zero/ext_dangle", H5L_TYPE_EXTERNAL},
+    {"hard_zero/ext_one", H5L_TYPE_EXTERNAL},
+    {"hard_zero/hard_one", H5L_TYPE_HARD},
+    {"hard_zero/hard_two", H5L_TYPE_HARD},
+    {"hard_zero/hard_zero", H5L_TYPE_HARD},
+    {"hard_zero/soft_dangle", H5L_TYPE_SOFT},
+    {"hard_zero/soft_one", H5L_TYPE_SOFT},
+    {"hard_zero/soft_two", H5L_TYPE_SOFT}
+};
+
+typedef struct {
+    unsigned idx;               /* Index in link visit structure */
+    const link_visit_t *info;   /* Pointer to the link visit structure to use */
+} lvisit_ud_t;
+
+
+/* Object visit structs */
+typedef struct {
+    const char *path;           /* Path to object */
+    H5O_type_t type;            /* Type of object */
+} obj_visit_t;
+static const obj_visit_t ovisit0_old[] = {
+    {".", H5O_TYPE_GROUP},
+    {"Dataset_zero", H5O_TYPE_DATASET},
+    {"Group1", H5O_TYPE_GROUP},
+    {"Group1/Dataset_one", H5O_TYPE_DATASET},
+    {"Group1/Group2", H5O_TYPE_GROUP},
+    {"Group1/Group2/Dataset_two", H5O_TYPE_DATASET},
+    {"Group1/Group2/Type_two", H5O_TYPE_NAMED_DATATYPE},
+    {"Group1/Type_one", H5O_TYPE_NAMED_DATATYPE},
+    {"Type_zero", H5O_TYPE_NAMED_DATATYPE}
+};
+static const obj_visit_t ovisit0_new[] = {
+    {".", H5O_TYPE_GROUP},
+    {"Dataset_zero", H5O_TYPE_DATASET},
+    {"Group1", H5O_TYPE_GROUP},
+    {"Group1/Dataset_one", H5O_TYPE_DATASET},
+    {"Group1/Group2", H5O_TYPE_GROUP},
+    {"Group1/Group2/Dataset_two", H5O_TYPE_DATASET},
+    {"Group1/Group2/Type_two", H5O_TYPE_NAMED_DATATYPE},
+    {"Group1/Type_one", H5O_TYPE_NAMED_DATATYPE},
+    {"Type_zero", H5O_TYPE_NAMED_DATATYPE}
+};
+static const obj_visit_t ovisit1_old[] = {
+    {".", H5O_TYPE_GROUP},
+    {"Dataset_one", H5O_TYPE_DATASET},
+    {"Group2", H5O_TYPE_GROUP},
+    {"Group2/Dataset_two", H5O_TYPE_DATASET},
+    {"Group2/Type_two", H5O_TYPE_NAMED_DATATYPE},
+    {"Group2/hard_zero", H5O_TYPE_GROUP},
+    {"Group2/hard_zero/Dataset_zero", H5O_TYPE_DATASET},
+    {"Group2/hard_zero/Type_zero", H5O_TYPE_NAMED_DATATYPE},
+    {"Type_one", H5O_TYPE_NAMED_DATATYPE}
+};
+static const obj_visit_t ovisit1_new[] = {
+    {".", H5O_TYPE_GROUP},
+    {"Dataset_one", H5O_TYPE_DATASET},
+    {"Group2", H5O_TYPE_GROUP},
+    {"Group2/Dataset_two", H5O_TYPE_DATASET},
+    {"Group2/Type_two", H5O_TYPE_NAMED_DATATYPE},
+    {"Group2/hard_zero", H5O_TYPE_GROUP},
+    {"Group2/hard_zero/Dataset_zero", H5O_TYPE_DATASET},
+    {"Group2/hard_zero/Type_zero", H5O_TYPE_NAMED_DATATYPE},
+    {"Type_one", H5O_TYPE_NAMED_DATATYPE}
+};
+static const obj_visit_t ovisit2_old[] = {
+    {".", H5O_TYPE_GROUP},
+    {"Dataset_two", H5O_TYPE_DATASET},
+    {"Type_two", H5O_TYPE_NAMED_DATATYPE},
+    {"hard_zero", H5O_TYPE_GROUP},
+    {"hard_zero/Dataset_zero", H5O_TYPE_DATASET},
+    {"hard_zero/Group1", H5O_TYPE_GROUP},
+    {"hard_zero/Group1/Dataset_one", H5O_TYPE_DATASET},
+    {"hard_zero/Group1/Type_one", H5O_TYPE_NAMED_DATATYPE},
+    {"hard_zero/Type_zero", H5O_TYPE_NAMED_DATATYPE}
+};
+static const obj_visit_t ovisit2_new[] = {
+    {".", H5O_TYPE_GROUP},
+    {"Dataset_two", H5O_TYPE_DATASET},
+    {"Type_two", H5O_TYPE_NAMED_DATATYPE},
+    {"hard_zero", H5O_TYPE_GROUP},
+    {"hard_zero/Dataset_zero", H5O_TYPE_DATASET},
+    {"hard_zero/Group1", H5O_TYPE_GROUP},
+    {"hard_zero/Group1/Dataset_one", H5O_TYPE_DATASET},
+    {"hard_zero/Group1/Type_one", H5O_TYPE_NAMED_DATATYPE},
+    {"hard_zero/Type_zero", H5O_TYPE_NAMED_DATATYPE}
+};
+
+typedef struct {
+    unsigned idx;               /* Index in object visit structure */
+    const obj_visit_t *info;    /* Pointer to the object visit structure to use */
+} ovisit_ud_t;
+
+static const char *FILENAME[] = {
+    "link0",
+    "link1.h5",
+    "link2.h5",
+    NULL
+};
+
+
+/*-------------------------------------------------------------------------
+ * Function:	test_basic_links
+ *
+ * Purpose:	Test building a file with assorted links.
+ *
+ * Return:	Success:	0
+ *
+ *		Failure:	-1
+ *
+ * Programmer:	Binh-Minh Ribler
+ *		October 16, 2009
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void test_basic_links(hid_t fapl_id, hbool_t new_format)
+{
+    hsize_t	        size[1] = {1};
+    char		filename[NAME_BUF_SIZE];
+    char* tconv_buf = new char [1000];
+
+    // Use the file access template id to create a file access prop. list.
+    FileAccPropList fapl(fapl_id);
+
+    try
+    {
+	if(new_format)
+	    SUBTEST("Link creation (w/new group format)")
+	else
+	    SUBTEST("Link creation")
+
+	h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
+	H5File file(filename, H5F_ACC_TRUNC, FileCreatPropList::DEFAULT, fapl);
+
+	// Create simple dataspace
+	DataSpace scalar (1, size, size);
+
+	// Create a group then close it by letting the object go out of scope
+	{
+	    Group group(file.createGroup("grp1", 0));
+	}
+
+	// Create a dataset then close it by letting the object go out of scope
+	{
+	    DataSet dset1(file.createDataSet("dset1", PredType::NATIVE_INT, scalar));
+	}
+
+	hid_t file_id = file.getId();
+
+	// Because these are not implemented in the C++ API yet, they are
+	// used so CommonFG::getLinkval can be tested.
+	// Create a hard link
+	if(H5Lcreate_hard(
+		file_id, "dset1", H5L_SAME_LOC, "grp1/hard1",
+		H5P_DEFAULT, H5P_DEFAULT) < 0)
+	    throw Exception("test_basic_links", "H5Lcreate_hard failed");
+
+	// Create a symbolic link
+	if(H5Lcreate_soft(
+		"/dset1", file_id, "grp1/soft", H5P_DEFAULT, H5P_DEFAULT) < 0)
+	    throw Exception("test_basic_links", "H5Lcreate_soft failed");
+
+	// Create a symbolic link to something that doesn't exist
+	if(H5Lcreate_soft(
+		"foobar", file_id, "grp1/dangle", H5P_DEFAULT, H5P_DEFAULT) < 0)
+	    throw Exception("test_basic_links", "H5Lcreate_soft failed");
+
+	// Create a recursive symbolic link
+	if(H5Lcreate_soft(
+		"/grp1/recursive", file_id, "/grp1/recursive",
+		H5P_DEFAULT, H5P_DEFAULT) < 0)
+	    throw Exception("test_basic_links", "H5Lcreate_soft failed");
+
+	// Verify link values before closing the file
+
+	H5std_string softlink_val = file.getLinkval("grp1/soft");
+	verify_val(softlink_val, "/dset1", "H5File::getLinkval grp1/soft", __LINE__, __FILE__);
+
+	H5std_string dngllink_val = file.getLinkval("grp1/dangle");
+	verify_val(dngllink_val, "foobar", "H5File::getLinkval grp1/dangle", __LINE__, __FILE__);
+
+	H5std_string reclink_val = file.getLinkval("grp1/recursive");
+	verify_val(reclink_val, "/grp1/recursive", "H5File::getLinkval grp1/recursive", __LINE__, __FILE__);
+
+    } // end of try block
+    catch (Exception E)
+    {
+	issue_fail_msg("test_basic_links()", __LINE__, __FILE__, E.getCDetailMsg());
+    }
+
+    // Open the file and check on the links in it
+    try
+    {
+	// Open the file above
+	H5File file(filename, H5F_ACC_RDWR, FileCreatPropList::DEFAULT, fapl);
+
+	// Verify link existence
+	if(H5Lexists(file.getId(), "dset1", H5P_DEFAULT) != TRUE)
+	    throw InvalidActionException("H5Lexists", "dset1 doesn't exist");
+	if(H5Lexists(file.getId(), "grp1/soft", H5P_DEFAULT) != TRUE) 
+	    throw InvalidActionException("H5Lexists", "grp1/soft doesn't exist");
+
+	// Verify link values
+	H5std_string softlink_val = file.getLinkval("grp1/soft");
+	verify_val(softlink_val, "/dset1", "H5File::getLinkval grp1/soft", __LINE__, __FILE__);
+
+	H5std_string reclink_val = file.getLinkval("grp1/recursive");
+	verify_val(reclink_val, "/grp1/recursive", "H5File::getLinkval grp1/recursive", __LINE__, __FILE__);
+
+	PASSED();
+    } // end of try block
+    catch (Exception E)
+    {
+	issue_fail_msg("test_basic_links()", __LINE__, __FILE__, E.getCDetailMsg());
+    }
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function:	test_links
+ *
+ * Purpose:	Test links
+ *
+ * Return:	None
+ *
+ * Programmer:	Binh-Minh Ribler
+ *              October 16, 2009
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+void test_links()
+{
+    hid_t	fapl_id, fapl2_id;    /* File access property lists */
+    hbool_t new_format;     /* Whether to use the new format or not */
+    const char  *envval;
+
+    envval = HDgetenv("HDF5_DRIVER");
+    if(envval == NULL)
+        envval = "nomatch";
+
+    fapl_id = h5_fileaccess();
+
+    // Output message about test being performed
+    MESSAGE(5, ("Testing Various Links\n"));
+    try
+    {
+	/* Copy the file access property list */
+	if((fapl2_id = H5Pcopy(fapl_id)) < 0)
+	    throw Exception("test_links", "H5Pcopy failed");
+
+	/* Set the "use the latest version of the format" bounds for creating objects in the file */
+	if(H5Pset_libver_bounds(fapl2_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
+	throw Exception("test_links", "H5Pset_libver_bounds failed");
+
+	/* Loop over using new group format */
+	for(new_format = FALSE; new_format <= TRUE; new_format++)
+	{
+	    hid_t my_fapl_id;
+
+	    /* Check for FAPL to use */
+	    if(new_format)
+		my_fapl_id = fapl2_id;
+	    else
+		my_fapl_id = fapl_id;
+
+	    /* General tests... (on both old & new format groups */
+	    // FileAccPropList may be passed in instead of fapl id
+	    test_basic_links(my_fapl_id, new_format);
+#if 0
+// these tests are from the C test links.c and left here for future
+// implementation of H5L API
+	nerrors += test_basic_links(fapl_id, new_format) < 0 ? 1 : 0;
+	nerrors += cklinks(my_fapl, new_format) < 0 ? 1 : 0;
+	nerrors += new_links(my_fapl, new_format) < 0 ? 1 : 0;
+	nerrors += ck_new_links(my_fapl, new_format) < 0 ? 1 : 0;
+	nerrors += long_links(my_fapl, new_format) < 0 ? 1 : 0;
+	nerrors += toomany(my_fapl, new_format) < 0 ? 1 : 0;
+
+	/* Test new H5L link creation routine */
+	nerrors += test_lcpl(my_fapl, new_format);
+        nerrors += test_move(my_fapl, new_format);
+        nerrors += test_copy(my_fapl, new_format);
+        nerrors += test_move_preserves(my_fapl, new_format);
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+        nerrors += test_deprec(my_fapl, new_format);
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+#ifndef H5_CANNOT_OPEN_TWICE
+        nerrors += external_link_root(my_fapl, new_format) < 0 ? 1 : 0;
+#endif /* H5_CANNOT_OPEN_TWICE */
+        nerrors += external_link_path(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_mult(my_fapl, new_format) < 0 ? 1 : 0;
+#ifndef H5_CANNOT_OPEN_TWICE
+        nerrors += external_link_self(envval, my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_pingpong(envval, my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_toomany(my_fapl, new_format) < 0 ? 1 : 0;
+#endif /* H5_CANNOT_OPEN_TWICE */
+        nerrors += external_link_dangling(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_recursive(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_query(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_unlink_compact(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_unlink_dense(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_move(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_ride(my_fapl, new_format) < 0 ? 1 : 0;
+#ifndef H5_CANNOT_OPEN_TWICE
+        nerrors += external_link_closing(envval, my_fapl, new_format) < 0 ? 1 : 0;
+#endif /* H5_CANNOT_OPEN_TWICE */
+        nerrors += external_link_endian(new_format) < 0 ? 1 : 0;
+        nerrors += external_link_strong(my_fapl, new_format) < 0 ? 1 : 0;
+
+        /* tests for external link */
+        nerrors += external_link_env(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_prefix(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_abs_mainpath(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_rel_mainpath(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_cwd(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_abstar(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_abstar_cur(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_reltar(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_chdir(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_set_elink_fapl1(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_set_elink_fapl2(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_set_elink_fapl3(new_format) < 0 ? 1 : 0;
+        nerrors += external_set_elink_acc_flags(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_set_elink_cb(my_fapl, new_format) < 0 ? 1 : 0;
+
+#ifdef H5_HAVE_WINDOW_PATH
+        nerrors += external_link_win1(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win2(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win3(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win4(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win5(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win6(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win7(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win8(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += external_link_win9(my_fapl, new_format) < 0 ? 1 : 0;
+#endif
+        /* These tests assume that external links are a form of UD links,
+         * so assume that everything that passed for external links
+         * above has already been tested for UD links.
+         */
+        if(new_format == TRUE) {
+            nerrors += ud_hard_links(fapl2) < 0 ? 1 : 0;     /* requires new format groups */
+            nerrors += ud_link_reregister(fapl2) < 0 ? 1 : 0;        /* requires new format groups */
+        } /* end if */
+
+        nerrors += ud_callbacks(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += ud_link_errors(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += lapl_udata(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += lapl_nlinks(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += linkinfo(my_fapl, new_format) < 0 ? 1 : 0;
+
+        /* Misc. extra tests, useful for both new & old format files */
+        nerrors += link_visit(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += link_visit_by_name(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += obj_visit(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += obj_visit_by_name(my_fapl, new_format) < 0 ? 1 : 0;
+        nerrors += obj_visit_stop(my_fapl, new_format) < 0 ? 1 : 0;
+
+        /* Keep this test last, it's testing files that are used above */
+        /* do not do this for files used by external link tests */
+        nerrors += check_all_closed(my_fapl, new_format, EXTSTOP) < 0 ? 1 : 0;
+#endif // 0
+	} /* end for */
+
+#if 0
+    /* New group revision feature tests */
+    nerrors += corder_create_empty(fapl2) < 0 ? 1 : 0;
+/* XXX: when creation order indexing is fully working, go back and add checks
+*      to these tests to make certain that the creation order values are
+*      correct.
+*/
+    nerrors += corder_create_compact(fapl2) < 0 ? 1 : 0;
+    nerrors += corder_create_dense(fapl2) < 0 ? 1 : 0;
+    nerrors += corder_transition(fapl2) < 0 ? 1 : 0;
+    nerrors += corder_delete(fapl2) < 0 ? 1 : 0;
+    nerrors += link_info_by_idx(fapl2) < 0 ? 1 : 0;
+    nerrors += delete_by_idx(fapl2) < 0 ? 1 : 0;
+    nerrors += link_iterate(fapl2) < 0 ? 1 : 0;
+    nerrors += open_by_idx(fapl2) < 0 ? 1 : 0;
+    nerrors += object_info(fapl2) < 0 ? 1 : 0;
+    nerrors += group_info(fapl2) < 0 ? 1 : 0;
+    nerrors += timestamps(fapl2) < 0 ? 1 : 0;
+
+    /* Test new API calls on old-style groups */
+    nerrors += link_info_by_idx_old(fapl) < 0 ? 1 : 0;
+    nerrors += delete_by_idx_old(fapl) < 0 ? 1 : 0;
+    nerrors += link_iterate_old(fapl) < 0 ? 1 : 0;
+    nerrors += open_by_idx_old(fapl) < 0 ? 1 : 0;
+    nerrors += object_info_old(fapl) < 0 ? 1 : 0;
+    nerrors += group_info_old(fapl) < 0 ? 1 : 0;
+
+#endif
+	/* Close 2nd FAPL */
+	H5Pclose(fapl2_id);
+
+	h5_cleanup(FILENAME, fapl_id);
+
+	/* Test that external links can be used after a library reset.  MUST be
+	* called last so the reset doesn't interfere with the property lists.  This
+	* routine will delete its own file. */
+	/* nerrors += external_reset_register() < 0 ? 1 : 0;
+ */ 
+    }
+    catch (Exception E)
+    {
+	issue_fail_msg("test_links()", __LINE__, __FILE__, E.getCDetailMsg());
+    }
+
+}
+
+/*-------------------------------------------------------------------------
+ * Function:	cleanup_links
+ *
+ * Purpose:	Cleanup temporary test files
+ *
+ * Return:	none
+ *
+ * Programmer:	Binh-Minh Ribler
+ *		October 16, 2009
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+void cleanup_links()
+{
+    HDremove(FILENAME[0]);
+}
+
-- 
cgit v0.12