summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDana Robinson <43805+derobins@users.noreply.github.com>2022-08-05 23:11:13 (GMT)
committerGitHub <noreply@github.com>2022-08-05 23:11:13 (GMT)
commitb22984600a04120088f59bb5876c9d5258fd64b7 (patch)
tree9324ab3744739b1b10b5e35a659dbe32edd51baa
parent54f116b42db2d2aabd6fdb58cebb99f04f106310 (diff)
downloadhdf5-b22984600a04120088f59bb5876c9d5258fd64b7.zip
hdf5-b22984600a04120088f59bb5876c9d5258fd64b7.tar.gz
hdf5-b22984600a04120088f59bb5876c9d5258fd64b7.tar.bz2
Adds platform-independent basename and dirname (#1951)
* Adds platform-independent basename and dirname * Tidy up H5_dirname and H5_basename implementations and add tests * Committing clang-format changes * Fix misspelling * Several fixes for H5_dirname/H5_basename from review * Committing clang-format changes * Add reason to VERIFY_STR macros in th5_system.c * Use H5MM_free instead of HDfree in H5_dirname/H5_basename tests Co-authored-by: Jordan Henderson <jhenderson@hdfgroup.org> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
-rw-r--r--src/H5MM.c47
-rw-r--r--src/H5MMprivate.h1
-rw-r--r--src/H5private.h5
-rw-r--r--src/H5system.c266
-rw-r--r--src/H5win32defs.h2
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/Makefile.am2
-rw-r--r--test/testhdf5.c1
-rw-r--r--test/testhdf5.h2
-rw-r--r--test/th5_system.c505
10 files changed, 831 insertions, 1 deletions
diff --git a/src/H5MM.c b/src/H5MM.c
index 6943887..9c03ceb 100644
--- a/src/H5MM.c
+++ b/src/H5MM.c
@@ -504,6 +504,53 @@ done:
} /* end H5MM_strdup() */
/*-------------------------------------------------------------------------
+ * Function: H5MM_strndup
+ *
+ * Purpose: Duplicates a string, including memory allocation, but only
+ * copies at most `n` bytes from the string to be duplicated.
+ * If the string to be duplicated is longer than `n`, only `n`
+ * bytes are copied and a terminating null byte is added.
+ * NULL is NOT an acceptable value for the input string.
+ *
+ * If the string to be duplicated is the NULL pointer, then
+ * an error will be raised.
+ *
+ * Return: Success: Pointer to a new string
+ * Failure: NULL
+ *-------------------------------------------------------------------------
+ */
+char *
+H5MM_strndup(const char *s, size_t n)
+{
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ size_t len;
+#endif
+ char *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ if (!s)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "NULL string not allowed")
+
+#if defined H5_MEMORY_ALLOC_SANITY_CHECK
+ for (len = 0; len < n && s[len] != '\0'; len++)
+ ;
+
+ if (NULL == (ret_value = H5MM_malloc(len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ H5MM_memcpy(ret_value, s, len);
+ ret_value[len] = '\0';
+#else
+ if (NULL == (ret_value = HDstrndup(s, n)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "string duplication failed")
+#endif
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5MM_strndup() */
+
+/*-------------------------------------------------------------------------
* Function: H5MM_xfree
*
* Purpose: Just like free(3) except null pointers are allowed as
diff --git a/src/H5MMprivate.h b/src/H5MMprivate.h
index f05a3da..0a5a011 100644
--- a/src/H5MMprivate.h
+++ b/src/H5MMprivate.h
@@ -44,6 +44,7 @@ H5_DLL void *H5MM_calloc(size_t size) H5_ATTR_MALLOC;
H5_DLL void *H5MM_realloc(void *mem, size_t size);
H5_DLL char *H5MM_xstrdup(const char *s);
H5_DLL char *H5MM_strdup(const char *s);
+H5_DLL char *H5MM_strndup(const char *s, size_t n);
H5_DLL void *H5MM_xfree(void *mem);
H5_DLL void *H5MM_xfree_const(const void *mem);
H5_DLL void *H5MM_memcpy(void *dest, const void *src, size_t n);
diff --git a/src/H5private.h b/src/H5private.h
index f9e7aff..3130bb1 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -1411,6 +1411,9 @@ H5_DLL H5_ATTR_CONST int Nflock(int fd, int operation);
#ifndef HDstrncpy
#define HDstrncpy(X, Y, Z) strncpy(X, Y, Z)
#endif
+#ifndef HDstrndup
+#define HDstrndup(S, N) strndup(S, N)
+#endif
#ifndef HDstrpbrk
#define HDstrpbrk(X, Y) strpbrk(X, Y)
#endif
@@ -2544,6 +2547,8 @@ H5_DLL double H5_get_time(void);
/* Functions for building paths, etc. */
H5_DLL herr_t H5_build_extpath(const char *name, char **extpath /*out*/);
H5_DLL herr_t H5_combine_path(const char *path1, const char *path2, char **full_name /*out*/);
+H5_DLL herr_t H5_dirname(const char *path, char **dirname /*out*/);
+H5_DLL herr_t H5_basename(const char *path, char **basename /*out*/);
/* getopt(3) equivalent that papers over the lack of long options on BSD
* and lack of Windows support.
diff --git a/src/H5system.c b/src/H5system.c
index 677452d..9a19860 100644
--- a/src/H5system.c
+++ b/src/H5system.c
@@ -919,8 +919,274 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5_expand_windows_env_vars() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_strndup
+ *
+ * Purpose: Similar to strndup() for use on Windows. Allocates a new
+ * string and copies at most `n` bytes from the original
+ * string into the new string. If the original string is
+ * longer than `n`, only `n` bytes are copied from the
+ * original string. In either case, the string being returned
+ * is guaranteed to be terminated with a null byte.
+ *
+ * The returned pointer is allocated by H5MM_malloc in this
+ * routine and must be freed by the caller with H5MM_free or
+ * H5MM_xfree.
+ *
+ * Return: Pointer to copied string on success
+ * NULL on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5_strndup(const char *s, size_t n)
+{
+ size_t len;
+ char *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if (!s)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "string cannot be NULL")
+
+ for (len = 0; len < n && s[len] != '\0'; len++)
+ ;
+
+ if (NULL == (ret_value = H5MM_malloc(len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate buffer for string")
+
+ H5MM_memcpy(ret_value, s, len);
+ ret_value[len] = '\0';
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
#endif /* H5_HAVE_WIN32_API */
+/* dirname() and basename() are not easily ported to Windows and basename
+ * behavior varies depending on if you get POSIX vs. GNU. As a more
+ * platform-indpendent work-around, we've implemented H5_ versions of
+ * dirname() and basename().
+ *
+ * - The input string is never modified.
+ *
+ * - The out parameter is a new string that was allocated with H5MM routines
+ * and must be freed by the caller via H5MM_free()/H5MM_xfree().
+ *
+ * - NULL pointers are errors.
+ *
+ * - On errors, FAIL will be returned and the output parameter will be
+ * undefined.
+ *
+ * - Assumes the file separator is \ on Win32 and / everywhere else,
+ * including Cygwin.
+ */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_dirname
+ *
+ * Purpose: Similar to dirname(3) but more portable across platforms.
+ * Returns a pointer to the directory component of a specified
+ * pathname. The returned pointer is allocated by this routine
+ * and must be freed by the caller with H5MM_free or
+ * H5MM_xfree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5_dirname(const char *path, char **dirname)
+{
+ char *sep;
+ char *out = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if (!path)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "path can't be NULL")
+ if (!dirname)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dirname can't be NULL")
+
+ if (NULL == (sep = HDstrrchr(path, H5_DIR_SEPC))) {
+ /* Pathname with no file separator characters */
+ out = H5MM_strdup(".");
+ }
+ else if (sep == path) {
+ /* Pathname of form "/" or "/filename" */
+ out = H5MM_strdup(H5_DIR_SEPS);
+ }
+ else {
+ if (sep[1] == '\0') {
+ /*
+ * Last file separator character is last character in
+ * pathname. Skip this and any other preceding trailing
+ * file separator characters
+ */
+ while (sep != path && sep[-1] == H5_DIR_SEPC)
+ sep--;
+
+ if (sep == path) {
+ /* Contrived case: "//", "///" and similar */
+ out = H5MM_strdup(H5_DIR_SEPS);
+ sep = NULL;
+ }
+ else {
+ /*
+ * Must have found the filename component. Search
+ * backwards to a previous file separator character,
+ * if any.
+ */
+ while (sep != path && sep[-1] != H5_DIR_SEPC)
+ sep--;
+
+ if (sep == path) {
+ /* No directory component found, just return "." */
+ out = H5MM_strdup(".");
+ sep = NULL;
+ }
+ }
+ }
+
+ if (sep) {
+ ptrdiff_t len;
+
+ /* Skip a possible run of duplicate file separator characters */
+ while (sep != path && sep[-1] == H5_DIR_SEPC)
+ sep--;
+
+ if (sep == path)
+ /* Pathname of form "/usr/" */
+ out = H5MM_strdup(H5_DIR_SEPS);
+ else {
+ /* Pathname of form "dir/filename" */
+ len = sep - path;
+ HDassert(len >= 0);
+
+ out = H5MM_strndup(path, (size_t)len);
+ }
+ }
+ }
+
+ if (NULL == out)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer for dirname");
+
+ *dirname = out;
+
+done:
+ if (FAIL == ret_value) {
+ H5MM_free(out);
+ if (dirname)
+ *dirname = NULL;
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_dirname() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_basename
+ *
+ * Purpose: Similar to basename(3) but more portable across platforms.
+ * Returns a pointer to the filename component of a specified
+ * pathname. The returned pointer is allocated by this routine
+ * and must be freed by the caller with H5MM_free or
+ * H5MM_xfree.
+ *
+ * NOTE: This routine follows the POSIX semantics for
+ * basename(3). That is, passing the path string "/" ("\" on
+ * Windows) returns the string "/" (again, "\" on Windows) and
+ * passing a path string with trailing file separator
+ * characters returns the filename component with the trailing
+ * file separator characters being ignored.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5_basename(const char *path, char **basename)
+{
+ const char *sep;
+ char *out = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if (!path)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "path can't be NULL")
+ if (!basename)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "basename can't be NULL")
+
+ if (NULL == (sep = HDstrrchr(path, H5_DIR_SEPC))) {
+ if (*path == '\0')
+ /* Empty pathname */
+ out = H5MM_strdup(".");
+ else
+ /* Pathname with no file separator characters */
+ out = H5MM_strdup(path);
+ }
+ else if (sep == path) {
+ if (sep[1] == '\0')
+ /* Pathname of form "/" */
+ out = H5MM_strdup(H5_DIR_SEPS);
+ else
+ /* Pathname of form "/filename" */
+ out = H5MM_strdup(sep + 1);
+ }
+ else {
+ if (sep[1] != '\0')
+ /* Pathname of form "dir/filename" */
+ out = H5MM_strdup(sep + 1);
+ else {
+ /* Pathname of form "filename/", "/dir/filename/", etc. */
+
+ /*
+ * Last file separator character is last character in
+ * pathname. Skip this and any other preceding trailing
+ * file separator characters
+ */
+ while (sep != path && sep[-1] == H5_DIR_SEPC)
+ sep--;
+
+ if (sep == path)
+ /* Contrived case: "//", "///" and similar */
+ out = H5MM_strdup(H5_DIR_SEPS);
+ else {
+ const char *c_ptr = sep;
+ ptrdiff_t len;
+
+ /*
+ * Skip back to a previous file separator character,
+ * if any, and form final filename component
+ */
+ while (c_ptr != path && c_ptr[-1] != H5_DIR_SEPC)
+ c_ptr--;
+
+ len = sep - c_ptr;
+ HDassert(len >= 0);
+
+ out = H5MM_strndup(c_ptr, (size_t)len);
+ }
+ }
+ }
+
+ if (NULL == out)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer for basename");
+
+ *basename = out;
+
+done:
+ if (FAIL == ret_value) {
+ H5MM_free(out);
+ if (basename)
+ *basename = NULL;
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_basename() */
+
/* Global variables */
int H5_opterr = 1; /* Get_option prints errors if this is on */
int H5_optind = 1; /* Token pointer */
diff --git a/src/H5win32defs.h b/src/H5win32defs.h
index 5f384bb..1039f23 100644
--- a/src/H5win32defs.h
+++ b/src/H5win32defs.h
@@ -82,6 +82,7 @@ struct timezone {
#define HDsleep(S) Sleep(S * 1000)
#define HDstat(S, B) _stati64(S, B)
#define HDstrcasecmp(A, B) _stricmp(A, B)
+#define HDstrndup(S, N) H5_strndup(S, N)
#define HDstrtok_r(X, Y, Z) strtok_s(X, Y, Z)
#define HDtzset() _tzset()
#define HDunlink(S) _unlink(S)
@@ -104,6 +105,7 @@ H5_DLL wchar_t *H5_get_utf16_str(const char *s);
H5_DLL int Wopen_utf8(const char *path, int oflag, ...);
H5_DLL int Wremove_utf8(const char *path);
H5_DLL int H5_get_win32_times(H5_timevals_t *tvs);
+H5_DLL char *H5_strndup(const char *s, size_t n);
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index b9d1208..3149454 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -267,6 +267,7 @@ set (testhdf5_SOURCES
${HDF5_TEST_SOURCE_DIR}/tattr.c
${HDF5_TEST_SOURCE_DIR}/tchecksum.c
${HDF5_TEST_SOURCE_DIR}/tconfig.c
+ ${HDF5_TEST_SOURCE_DIR}/th5_system.c
${HDF5_TEST_SOURCE_DIR}/tcoords.c
${HDF5_TEST_SOURCE_DIR}/tfile.c
${HDF5_TEST_SOURCE_DIR}/tgenprop.c
diff --git a/test/Makefile.am b/test/Makefile.am
index 22510dc..d441113 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -231,7 +231,7 @@ CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offse
# Sources for testhdf5 executable
testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \
- tgenprop.c th5o.c th5s.c tcoords.c tid.c titerate.c tmeta.c tmisc.c \
+ tgenprop.c th5o.c th5s.c th5_system.c tcoords.c tid.c titerate.c tmeta.c tmisc.c \
trefer.c trefer_deprec.c trefstr.c tselect.c tskiplist.c tsohm.c ttime.c tunicode.c \
tvlstr.c tvltypes.c
diff --git a/test/testhdf5.c b/test/testhdf5.c
index b5db71b..2329354 100644
--- a/test/testhdf5.c
+++ b/test/testhdf5.c
@@ -43,6 +43,7 @@ main(int argc, char *argv[])
/* Tests are generally arranged from least to most complexity... */
AddTest("config", test_configure, cleanup_configure, "Configure definitions", NULL);
+ AddTest("h5system", test_h5_system, cleanup_h5_system, "H5system routines", NULL);
AddTest("metadata", test_metadata, cleanup_metadata, "Encoding/decoding metadata", NULL);
AddTest("checksum", test_checksum, cleanup_checksum, "Checksum algorithm", NULL);
AddTest("skiplist", test_skiplist, NULL, "Skip Lists", NULL);
diff --git a/test/testhdf5.h b/test/testhdf5.h
index d5c2d21..e72e08e 100644
--- a/test/testhdf5.h
+++ b/test/testhdf5.h
@@ -221,6 +221,7 @@ void test_iterate(void);
void test_array(void);
void test_genprop(void);
void test_configure(void);
+void test_h5_system(void);
void test_misc(void);
void test_ids(void);
void test_skiplist(void);
@@ -245,6 +246,7 @@ void cleanup_iterate(void);
void cleanup_array(void);
void cleanup_genprop(void);
void cleanup_configure(void);
+void cleanup_h5_system(void);
void cleanup_sohm(void);
void cleanup_misc(void);
void cleanup_unicode(void);
diff --git a/test/th5_system.c b/test/th5_system.c
new file mode 100644
index 0000000..09570cf
--- /dev/null
+++ b/test/th5_system.c
@@ -0,0 +1,505 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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 COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://www.hdfgroup.org/licenses. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define H5_SYSTEM_TEST_PATH_MAX 4096
+
+/***********************************************************
+ *
+ * Test program: th5_system
+ *
+ * Testing for the routines available in H5system.c
+ *
+ *************************************************************/
+
+#include "testhdf5.h"
+
+#include "H5MMprivate.h"
+
+static void
+test_h5_dirname(void)
+{
+ herr_t ret;
+ char *path = NULL;
+ char *dirname = NULL;
+
+ MESSAGE(5, ("Testing H5_dirname\n"));
+
+ path = HDmalloc(H5_SYSTEM_TEST_PATH_MAX);
+ CHECK_PTR(path, "HDmalloc");
+ if (!path)
+ return;
+
+ /* Check that H5_dirname fails for a NULL path */
+ dirname = NULL;
+ H5E_BEGIN_TRY
+ {
+ ret = H5_dirname(NULL, &dirname);
+ }
+ H5E_END_TRY;
+ VERIFY(ret, FAIL, "H5_dirname with NULL path");
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check that H5_dirname fails for a NULL dirname pointer */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "topdir%sunderdir%sfinaldir", H5_DIR_SEPS, H5_DIR_SEPS);
+ H5E_BEGIN_TRY
+ {
+ ret = H5_dirname(path, NULL);
+ }
+ H5E_END_TRY;
+ VERIFY(ret, FAIL, "H5_dirname with NULL dirname pointer");
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check that H5_dirname returns "." for an empty path string */
+ *path = '\0';
+ dirname = NULL;
+ ret = H5_dirname(path, &dirname);
+ CHECK(ret, FAIL, "H5_dirname with empty string");
+ VERIFY_STR(dirname, ".", "comparing H5_dirname with empty string to \".\"");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns "." for a path that
+ * doesn't contain the system file separator character
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "testdirname");
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, ".", "comparing H5_dirname with non-separated path to \".\"");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the system file separator
+ * for the simple path containing just the system file separator
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS, "comparing H5_dirname with file separator path to file separator");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the system file separator
+ * for a path which contains a leading separator and a path
+ * component
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stestdir", H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS, "comparing H5_dirname with leading separator path to file separator");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the system file separator
+ * for a path which contains several leading separators and
+ * a path component
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%s%s%s%stestdir", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS, "comparing H5_dirname with leading separators path to file separator");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the "." for a path which
+ * contains a path component and a trailing separator
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "testdir%s", H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, ".", "comparing H5_dirname with trailing separator path to \".\"");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the "." for a path which
+ * contains a path component and several trailing separators
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "testdir%s%s%s%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, ".", "comparing H5_dirname with trailing separators path to \".\"");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the system file separator
+ * for a path which contains a leading separator, a path
+ * component and a trailing separator
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stestdir%s", H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS,
+ "comparing H5_dirname with leading and trailing separator path to file separator");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the system file separator
+ * for a path which contains several leading separators, a
+ * path component and a trailing separator
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%s%s%s%stestdir%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(
+ dirname, H5_DIR_SEPS,
+ "comparing H5_dirname with leading separators and a trailing separator path to file separator");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the system file separator
+ * for a path which contains a leading separator, a path
+ * component and several trailing separators
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stestdir%s%s%s%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS,
+ "comparing H5_dirname with leading separator and trailing separators path to file separator");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns the system file separator
+ * for a path which contains several leading separators, a
+ * path component and several trailing separators
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%s%s%s%stestdir%s%s%s%s", H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS,
+ "comparing H5_dirname with leading and trailing separators path to file separator");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns a proper dirname with a
+ * "normal" pathname that has no leading separator
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "topdir%sunderdir", H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, "topdir", "comparing H5_dirname with normal path to proper dirname");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns a proper dirname with a
+ * "normal" pathname that has a leading separator
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stopdir%sunderdir", H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS "topdir", "comparing H5_dirname with normal path to proper dirname");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns a proper dirname with a
+ * "normal" pathname that has a leading and trailing separator
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stopdir%sunderdir%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS "topdir", "comparing H5_dirname with normal path to proper dirname");
+ H5MM_free(dirname);
+
+ /*
+ * Check that H5_dirname returns a proper dirname with a
+ * contrived pathname
+ */
+ dirname = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stopdir%sunderdir%s%s%sfinaldir%s", H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_dirname(path, &dirname);
+ VERIFY_STR(dirname, H5_DIR_SEPS "topdir" H5_DIR_SEPS "underdir",
+ "comparing H5_dirname with contrived path to proper dirname");
+ H5MM_free(dirname);
+
+ HDfree(path);
+}
+
+static void
+test_h5_basename(void)
+{
+ herr_t ret;
+ char *path = NULL;
+ char *basename = NULL;
+
+ MESSAGE(5, ("Testing H5_basename\n"));
+
+ path = HDmalloc(H5_SYSTEM_TEST_PATH_MAX);
+ CHECK_PTR(path, "HDmalloc");
+ if (!path)
+ return;
+
+ /* Check that H5_basename fails for a NULL path */
+ basename = NULL;
+ H5E_BEGIN_TRY
+ {
+ ret = H5_basename(NULL, &basename);
+ }
+ H5E_END_TRY;
+ VERIFY(ret, FAIL, "H5_basename with NULL path");
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check that H5_basename fails for a NULL basename pointer */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "topdir%sunderdir%sfinaldir", H5_DIR_SEPS, H5_DIR_SEPS);
+ H5E_BEGIN_TRY
+ {
+ ret = H5_basename(path, NULL);
+ }
+ H5E_END_TRY;
+ VERIFY(ret, FAIL, "H5_basename with NULL basename pointer");
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check that H5_basename returns "." for an empty path string */
+ *path = '\0';
+ basename = NULL;
+ ret = H5_basename(path, &basename);
+ CHECK(ret, FAIL, "H5_basename with empty string");
+ VERIFY_STR(basename, ".", "comparing H5_basename with empty string to \".\"");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the specified path for a
+ * path that doesn't contain the system file separator character
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "testdirname");
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "testdirname", "comparing H5_basename with non-separated path to same path");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the system file separator
+ * for the simple path containing just the system file separator
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, H5_DIR_SEPS, "comparing H5_basename with file separator path to file separator");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains a leading separator and a path
+ * component
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stestdir", H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "testdir",
+ "comparing H5_basename with leading separator path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains several leading separators and a path
+ * component
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%s%s%s%stestdir", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "testdir",
+ "comparing H5_basename with leading separators path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains a path component and a trailing separator
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "testdir%s", H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "testdir",
+ "comparing H5_basename with trailing separator path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains a path component and several trailing
+ * separators
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "testdir%s%s%s%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "testdir",
+ "comparing H5_basename with trailing separators path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains a leading separator, a path component
+ * and a trailing separator
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stestdir%s", H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "testdir",
+ "comparing H5_basename with leading and trailing separator path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains several leading separators, a path
+ * component and a trailing separator
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%s%s%s%stestdir%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(
+ basename, "testdir",
+ "comparing H5_basename with leading separators and a trailing separator path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains a leading separator, a path component
+ * and several trailing separators
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stestdir%s%s%s%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(
+ basename, "testdir",
+ "comparing H5_basename with leading separator and trailing separators path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns the proper basename for a
+ * path which contains several leading separators, a path
+ * component and several trailing separators
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%s%s%s%stestdir%s%s%s%s", H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "testdir",
+ "comparing H5_basename with leading and trailing separators path to filename component");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns a proper basename with
+ * a "normal" pathname that has no leading separator
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "topdir%sunderdir", H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "underdir", "comparing H5_basename with normal path to proper basename");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns a proper basename with
+ * a "normal" pathname that has a leading separator
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stopdir%sunderdir", H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "underdir", "comparing H5_basename with normal path to proper basename");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns a proper basename with
+ * a "normal" pathname that has a leading and trailing separator
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stopdir%sunderdir%s", H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "underdir", "comparing H5_basename with normal path to proper basename");
+ H5MM_free(basename);
+
+ /*
+ * Check that H5_basename returns a proper basename with a
+ * contrived pathname
+ */
+ basename = NULL;
+ HDsnprintf(path, H5_SYSTEM_TEST_PATH_MAX, "%stopdir%sunderdir%s%s%sfinaldir%s", H5_DIR_SEPS, H5_DIR_SEPS,
+ H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS, H5_DIR_SEPS);
+ ret = H5_basename(path, &basename);
+ VERIFY_STR(basename, "finaldir", "comparing H5_basename with contrived path to proper basename");
+ H5MM_free(basename);
+
+ HDfree(path);
+}
+
+static void
+test_h5_strndup(void)
+{
+#ifdef H5_HAVE_WIN32_API
+ const char *const teststr = "myteststring";
+ char *str = NULL;
+
+ MESSAGE(5, ("Testing H5_strndup\n"));
+
+ /* Check that H5_strndup fails for a NULL string pointer */
+ H5E_BEGIN_TRY
+ {
+ str = H5_strndup(NULL, 20);
+ }
+ H5E_END_TRY;
+ CHECK_PTR_NULL(str, "H5_strndup with NULL string pointer");
+ H5Eclear2(H5E_DEFAULT);
+
+ /* Check that H5_strndup correctly performs a 0-byte copy */
+ str = H5_strndup(teststr, 0);
+ CHECK_PTR(str, "H5_strndup for 0-byte copy");
+ if (str)
+ VERIFY_STR(str, "", "comparing H5_strndup for 0-byte copy to empty string");
+ str = H5MM_xfree(str);
+
+ /* Check that H5_strndup correctly performs partial copies */
+ str = H5_strndup(teststr, 6);
+ CHECK_PTR(str, "H5_strndup for partial copy");
+ if (str)
+ VERIFY_STR(str, "mytest", "comparing H5_strndup for partial copy to partial string");
+ str = H5MM_xfree(str);
+
+ /* Check that H5_strndup correctly performs identical copies */
+ str = H5_strndup(teststr, HDstrlen(teststr));
+ CHECK_PTR(str, "H5_strndup for identical copy");
+ if (str)
+ VERIFY_STR(str, teststr, "comparing H5_strndup for identical copy to original string");
+ str = H5MM_xfree(str);
+
+ /*
+ * Check that H5_strndup correctly performs copies when
+ * `n` is greater than the original string
+ */
+ str = H5_strndup(teststr, HDstrlen(teststr) + 2);
+ CHECK_PTR(str, "H5_strndup for larger 'n'");
+ if (str)
+ VERIFY_STR(str, teststr, "comparing H5_strndup with larger 'n' value to original string");
+ str = H5MM_xfree(str);
+#endif /* H5_HAVE_WIN32_API */
+}
+
+void
+test_h5_system(void)
+{
+ MESSAGE(5, ("Testing H5system routines\n"));
+
+ test_h5_dirname();
+ test_h5_basename();
+ test_h5_strndup();
+}
+
+void
+cleanup_h5_system(void)
+{
+ /* Nothing to cleanup yet */
+}