summaryrefslogtreecommitdiffstats
path: root/src/H5system.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5system.c')
-rw-r--r--src/H5system.c1794
1 files changed, 1158 insertions, 636 deletions
diff --git a/src/H5system.c b/src/H5system.c
index 56db380..d6d734f 100644
--- a/src/H5system.c
+++ b/src/H5system.c
@@ -1,25 +1,22 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
- * Copyright by the Board of Trustees of the University of Illinois. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
- * the files COPYING and Copyright.html. COPYING can be found at the root *
- * of the source code distribution tree; Copyright.html can be found at the *
- * root level of an installed copy of the electronic HDF5 document set and *
- * is linked from the top-level documents page. It can also be found at *
- * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
- * access to either file, you may request a copy from help@hdfgroup.org. *
+ * 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. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*-------------------------------------------------------------------------
*
- * Created: H5system.c
- * Aug 21 2006
- * Quincey Koziol <koziol@hdfgroup.org>
+ * Created: H5system.c
+ * Aug 21 2006
+ * Quincey Koziol
*
- * Purpose: System call wrapper implementations.
+ * Purpose: System call wrapper implementations.
*
*-------------------------------------------------------------------------
*/
@@ -27,529 +24,77 @@
/****************/
/* Module Setup */
/****************/
-
+#include "H5module.h" /* This source code file is part of the H5 module */
/***********/
/* Headers */
/***********/
-#include "H5private.h" /* Generic Functions */
-#include "H5Fprivate.h" /* File access */
-#include "H5MMprivate.h" /* Memory management */
-#include "H5Eprivate.h"
-
-
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5MMprivate.h" /* Memory management */
/****************/
/* Local Macros */
/****************/
-
/******************/
/* Local Typedefs */
/******************/
-
/********************/
/* Package Typedefs */
/********************/
-
/********************/
/* Local Prototypes */
/********************/
-
/*********************/
/* Package Variables */
/*********************/
-
/*****************************/
/* Library Private Variables */
/*****************************/
-
/*******************/
/* Local Variables */
/*******************/
-
-/*-------------------------------------------------------------------------
- * Function: HDfprintf
- *
- * Purpose: Prints the optional arguments under the control of the format
- * string FMT to the stream STREAM. This function takes the
- * same format as fprintf(3c) with a few added features:
- *
- * The conversion modifier `H' refers to the size of an
- * `hsize_t' or `hssize_t' type. For instance, "0x%018Hx"
- * prints an `hsize_t' value as a hex number right justified and
- * zero filled in an 18-character field.
- *
- * The conversion `a' refers to an `haddr_t' type.
- *
- * Return: Success: Number of characters printed
- *
- * Failure: -1
- *
- * Programmer: Robb Matzke
- * Thursday, April 9, 1998
- *
- * Modifications:
- * Robb Matzke, 1999-07-27
- * The `%a' format refers to an argument of `haddr_t' type
- * instead of `haddr_t*' and the return value is correct.
- *-------------------------------------------------------------------------
- */
-int
-HDfprintf(FILE *stream, const char *fmt, ...)
-{
- int n=0, nout = 0;
- int fwidth, prec;
- int zerofill;
- int leftjust;
- int plussign;
- int ldspace;
- int prefix;
- char modifier[8];
- int conv;
- char *rest, format_templ[128];
- int len;
- const char *s;
- va_list ap;
-
- HDassert(stream);
- HDassert(fmt);
-
- va_start (ap, fmt);
- while (*fmt) {
- fwidth = prec = 0;
- zerofill = 0;
- leftjust = 0;
- plussign = 0;
- prefix = 0;
- ldspace = 0;
- modifier[0] = '\0';
-
- if ('%'==fmt[0] && '%'==fmt[1]) {
- HDputc ('%', stream);
- fmt += 2;
- nout++;
- } else if ('%'==fmt[0]) {
- s = fmt + 1;
-
- /* Flags */
- while(HDstrchr("-+ #", *s)) {
- switch(*s) {
- case '-':
- leftjust = 1;
- break;
-
- case '+':
- plussign = 1;
- break;
-
- case ' ':
- ldspace = 1;
- break;
-
- case '#':
- prefix = 1;
- break;
-
- default:
- HDassert(0 && "Unknown format flag");
- } /* end switch */ /*lint !e744 Switch statement doesn't _need_ default */
- s++;
- } /* end while */
-
- /* Field width */
- if(HDisdigit(*s)) {
- zerofill = ('0' == *s);
- fwidth = (int)HDstrtol (s, &rest, 10);
- s = rest;
- } /* end if */
- else if ('*'==*s) {
- fwidth = va_arg (ap, int);
- if(fwidth < 0) {
- leftjust = 1;
- fwidth = -fwidth;
- }
- s++;
- }
-
- /* Precision */
- if('.'==*s) {
- s++;
- if(HDisdigit(*s)) {
- prec = (int)HDstrtol(s, &rest, 10);
- s = rest;
- } else if('*'==*s) {
- prec = va_arg(ap, int);
- s++;
- }
- if(prec < 1)
- prec = 1;
- }
+/* Track whether tzset routine was called */
+static hbool_t H5_ntzset = FALSE;
- /* Extra type modifiers */
- if(HDstrchr("zZHhlqLI", *s)) {
- switch(*s) {
- /*lint --e{506} Don't issue warnings about constant value booleans */
- /*lint --e{774} Don't issue warnings boolean within 'if' always evaluates false/true */
- case 'H':
- if(sizeof(hsize_t) < sizeof(long))
- modifier[0] = '\0';
- else if(sizeof(hsize_t) == sizeof(long)) {
- HDstrncpy(modifier, "l", sizeof(modifier));
- modifier[sizeof(modifier) - 1] = '\0';
- } /* end if */
- else {
- HDstrncpy(modifier, H5_PRINTF_LL_WIDTH, sizeof(modifier));
- modifier[sizeof(modifier) - 1] = '\0';
- } /* end else */
- break;
-
- case 'Z':
- case 'z':
- if(sizeof(size_t) < sizeof(long))
- modifier[0] = '\0';
- else if(sizeof(size_t) == sizeof(long)) {
- HDstrncpy(modifier, "l", sizeof(modifier));
- modifier[sizeof(modifier) - 1] = '\0';
- } /* end if */
- else {
- HDstrncpy(modifier, H5_PRINTF_LL_WIDTH, sizeof(modifier));
- modifier[sizeof(modifier) - 1] = '\0';
- } /* end else */
- break;
-
- default:
- /* Handle 'I64' modifier for Microsoft's "__int64" type */
- if(*s=='I' && *(s+1)=='6' && *(s+2)=='4') {
- modifier[0] = *s;
- modifier[1] = *(s+1);
- modifier[2] = *(s+2);
- modifier[3] = '\0';
- s += 2; /* Increment over 'I6', the '4' is taken care of below */
- } /* end if */
- else {
- /* Handle 'll' for long long types */
- if(*s=='l' && *(s+1)=='l') {
- modifier[0] = *s;
- modifier[1] = *s;
- modifier[2] = '\0';
- s++; /* Increment over first 'l', second is taken care of below */
- } /* end if */
- else {
- modifier[0] = *s;
- modifier[1] = '\0';
- } /* end else */
- } /* end else */
- break;
- }
- s++;
- }
-
- /* Conversion */
- conv = *s++;
-
- /* Create the format template */
- len = 0;
- len += HDsnprintf(format_templ, (sizeof(format_templ) - (size_t)(len + 1)), "%%%s%s%s%s%s", (leftjust ? "-" : ""),
- (plussign ? "+" : ""), (ldspace ? " " : ""),
- (prefix ? "#" : ""), (zerofill ? "0" : ""));
- if(fwidth > 0)
- len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth);
- if(prec > 0)
- len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), ".%d", prec);
- if(*modifier)
- len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%s", modifier);
- HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%c", conv);
-
-
- /* Conversion */
- switch (conv) {
- case 'd':
- case 'i':
- if(!HDstrcmp(modifier, "h")) {
- short x = (short)va_arg (ap, int);
- n = fprintf (stream, format_templ, x);
- } else if(!*modifier) {
- int x = va_arg (ap, int);
- n = fprintf (stream, format_templ, x);
- } else if(!HDstrcmp (modifier, "l")) {
- long x = va_arg (ap, long);
- n = fprintf (stream, format_templ, x);
- } else {
- int64_t x = va_arg(ap, int64_t);
- n = fprintf (stream, format_templ, x);
- }
- break;
-
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if(!HDstrcmp(modifier, "h")) {
- unsigned short x = (unsigned short)va_arg (ap, unsigned int);
- n = fprintf(stream, format_templ, x);
- } else if(!*modifier) {
- unsigned int x = va_arg (ap, unsigned int); /*lint !e732 Loss of sign not really occuring */
- n = fprintf(stream, format_templ, x);
- } else if(!HDstrcmp(modifier, "l")) {
- unsigned long x = va_arg (ap, unsigned long); /*lint !e732 Loss of sign not really occuring */
- n = fprintf(stream, format_templ, x);
- } else {
- uint64_t x = va_arg(ap, uint64_t); /*lint !e732 Loss of sign not really occuring */
- n = fprintf(stream, format_templ, x);
- }
- break;
-
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- if(!HDstrcmp(modifier, "h")) {
- float x = (float)va_arg(ap, double);
- n = fprintf(stream, format_templ, (double)x);
- } else if(!*modifier || !HDstrcmp(modifier, "l")) {
- double x = va_arg(ap, double);
- n = fprintf(stream, format_templ, x);
- } else {
- /*
- * Some compilers complain when `long double' and
- * `double' are the same thing.
- */
-#if H5_SIZEOF_LONG_DOUBLE != H5_SIZEOF_DOUBLE
- long double x = va_arg(ap, long double);
- n = fprintf(stream, format_templ, x);
-#else
- double x = va_arg(ap, double);
- n = fprintf(stream, format_templ, x);
-#endif
- }
- break;
-
- case 'a':
- {
- haddr_t x = va_arg (ap, haddr_t); /*lint !e732 Loss of sign not really occuring */
-
- if(H5F_addr_defined(x)) {
- len = 0;
- len += HDsnprintf(format_templ, (sizeof(format_templ) - (size_t)(len + 1)), "%%%s%s%s%s%s",
- (leftjust ? "-" : ""), (plussign ? "+" : ""),
- (ldspace ? " " : ""), (prefix ? "#" : ""),
- (zerofill ? "0" : ""));
- if(fwidth > 0)
- len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth);
-
- /*lint --e{506} Don't issue warnings about constant value booleans */
- /*lint --e{774} Don't issue warnings boolean within 'if' always evaluates false/true */
- if(sizeof(x) == H5_SIZEOF_INT) {
- HDstrncat(format_templ, "u", (sizeof(format_templ) - (size_t)(len + 1)));
- len++;
- } /* end if */
- else if(sizeof(x) == H5_SIZEOF_LONG) {
- HDstrncat(format_templ, "lu", (sizeof(format_templ) - (size_t)(len + 1)));
- len++;
- } /* end if */
- else if(sizeof(x) == H5_SIZEOF_LONG_LONG) {
- HDstrncat(format_templ, H5_PRINTF_LL_WIDTH, (sizeof(format_templ) - (size_t)(len + 1)));
- len += (int)sizeof(H5_PRINTF_LL_WIDTH);
- HDstrncat(format_templ, "u", (sizeof(format_templ) - (size_t)(len + 1)));
- len++;
- }
- n = fprintf(stream, format_templ, x);
- } else {
- len = 0;
- HDstrncpy(format_templ, "%", (sizeof(format_templ) - (size_t)(len + 1)));
- len++;
- if(leftjust) {
- HDstrncat(format_templ, "-", (sizeof(format_templ) - (size_t)(len + 1)));
- len++;
- } /* end if */
- if(fwidth)
- len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth);
- HDstrncat(format_templ, "s", (sizeof(format_templ) - (size_t)(len + 1)));
- fprintf(stream, format_templ, "UNDEF");
- }
- }
- break;
-
- case 'c':
- {
- char x = (char)va_arg(ap, int);
- n = fprintf(stream, format_templ, x);
- }
- break;
-
- case 's':
- case 'p':
- {
- char *x = va_arg(ap, char*); /*lint !e64 Type mismatch not really occuring */
- n = fprintf(stream, format_templ, x);
- }
- break;
-
- case 'n':
- format_templ[HDstrlen(format_templ) - 1] = 'u';
- n = fprintf(stream, format_templ, nout);
- break;
-
- case 't':
- {
- htri_t tri_var = va_arg(ap, htri_t);
-
- if(tri_var > 0)
- fprintf (stream, "TRUE");
- else if(!tri_var)
- fprintf(stream, "FALSE");
- else
- fprintf(stream, "FAIL(%d)", (int)tri_var);
- }
- break;
-
- default:
- HDfputs(format_templ, stream);
- n = (int)HDstrlen(format_templ);
- break;
- }
- nout += n;
- fmt = s;
- } else {
- HDputc(*fmt, stream);
- fmt++;
- nout++;
- }
- }
- va_end(ap);
- return nout;
-} /* end HDfprintf() */
-
-
-/*-------------------------------------------------------------------------
- * Function: HDstrtoll
- *
- * Purpose: Converts the string S to an int64_t value according to the
- * given BASE, which must be between 2 and 36 inclusive, or be
- * the special value zero.
- *
- * The string must begin with an arbitrary amount of white space
- * (as determined by isspace(3c)) followed by a single optional
- * `+' or `-' sign. If BASE is zero or 16 the string may then
- * include a `0x' or `0X' prefix, and the number will be read in
- * base 16; otherwise a zero BASE is taken as 10 (decimal)
- * unless the next character is a `0', in which case it is taken
- * as 8 (octal).
- *
- * The remainder of the string is converted to an int64_t in the
- * obvious manner, stopping at the first character which is not
- * a valid digit in the given base. (In bases above 10, the
- * letter `A' in either upper or lower case represetns 10, `B'
- * represents 11, and so forth, with `Z' representing 35.)
- *
- * If REST is not null, the address of the first invalid
- * character in S is stored in *REST. If there were no digits
- * at all, the original value of S is stored in *REST. Thus, if
- * *S is not `\0' but **REST is `\0' on return the entire string
- * was valid.
- *
- * Return: Success: The result.
- *
- * Failure: If the input string does not contain any
- * digits then zero is returned and REST points
- * to the original value of S. If an overflow
- * or underflow occurs then the maximum or
- * minimum possible value is returned and the
- * global `errno' is set to ERANGE. If BASE is
- * incorrect then zero is returned.
- *
- * Programmer: Robb Matzke
- * Thursday, April 9, 1998
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
+#ifndef H5_HAVE_VASPRINTF
+/* HDvasprintf provides vasprintf-like function on targets where it is
+ * unavailable.
*/
-int64_t
-HDstrtoll(const char *s, const char **rest, int base)
+int
+HDvasprintf(char **bufp, const char *fmt, va_list _ap)
{
- int64_t sign=1, acc=0;
- hbool_t overflow = FALSE;
-
- errno = 0;
- if (!s || (base && (base<2 || base>36))) {
- if (rest)
- *rest = s;
- return 0;
- }
-
- /* Skip white space */
- while (HDisspace (*s)) s++;
-
- /* Optional minus or plus sign */
- if ('+'==*s) {
- s++;
- } else if ('-'==*s) {
- sign = -1;
- s++;
- }
-
- /* Zero base prefix */
- if (0==base && '0'==*s && ('x'==s[1] || 'X'==s[1])) {
- base = 16;
- s += 2;
- } else if (0==base && '0'==*s) {
- base = 8;
- s++;
- } else if (0==base) {
- base = 10;
- }
-
- /* Digits */
- while ((base<=10 && *s>='0' && *s<'0'+base) ||
- (base>10 && ((*s>='0' && *s<='9') ||
- (*s>='a' && *s<'a'+base-10) ||
- (*s>='A' && *s<'A'+base-10)))) {
- if (!overflow) {
- int64_t digit = 0;
-
- if (*s>='0' && *s<='9')
- digit = *s - '0';
- else if (*s>='a' && *s<='z')
- digit = (*s-'a')+10;
- else
- digit = (*s-'A')+10;
-
- if (acc*base+digit < acc) {
- overflow = TRUE;
- } else {
- acc = acc*base + digit;
- }
+ char *buf; /* buffer to receive formatted string */
+ size_t bufsz; /* size of buffer to allocate */
+
+ for (bufsz = 32; (buf = HDmalloc(bufsz)) != NULL;) {
+ int ret;
+ va_list ap;
+
+ HDva_copy(ap, _ap);
+ ret = HDvsnprintf(buf, bufsz, fmt, ap);
+ va_end(ap);
+ if (ret >= 0 && (size_t)ret < bufsz) {
+ *bufp = buf;
+ return ret;
}
- s++;
+ HDfree(buf);
+ if (ret < 0)
+ return ret;
+ bufsz = (size_t)ret + 1;
}
+ return -1;
+}
+#endif /* H5_HAVE_VASPRINTF */
- /* Overflow */
- if (overflow) {
- if (sign>0) {
- acc = ((uint64_t)1<<(8*sizeof(int64_t)-1))-1;
- } else {
- acc = (int64_t)((uint64_t)1<<(8*sizeof(int64_t)-1));
- }
- errno = ERANGE;
- }
-
- /* Return values */
- acc *= sign;
- if (rest)
- *rest = s;
- return acc;
-} /* end HDstrtoll() */
-
-
/*-------------------------------------------------------------------------
* Function: HDrand/HDsrand
*
@@ -573,55 +118,164 @@ HDstrtoll(const char *s, const char **rest, int base)
static unsigned int g_seed = 42;
-int HDrand(void)
+int
+HDrand(void)
{
return rand_r(&g_seed);
}
-void HDsrand(unsigned int seed)
+void
+HDsrand(unsigned int seed)
{
g_seed = seed;
}
-#endif
+#endif /* H5_HAVE_RAND_R */
-
/*-------------------------------------------------------------------------
- * Function: HDremove_all
+ * Function: Pflock
*
- * Purpose: Wrapper function for remove on VMS systems
+ * Purpose: Wrapper function for POSIX systems where flock(2) is not
+ * available.
*
- * This function deletes all versions of a file
+ * Return: Success: 0
+ * Failure: -1
*
- * Return: Success: 0;
+ *-------------------------------------------------------------------------
+ */
+/* NOTE: Compile this all the time on POSIX systems, even when flock(2) is
+ * present so that it's less likely to become dead code.
+ */
+#ifdef H5_HAVE_FCNTL
+int
+Pflock(int fd, int operation)
+{
+
+ struct flock flk;
+
+ /* Set the lock type */
+ if (operation & LOCK_UN)
+ flk.l_type = F_UNLCK;
+ else if (operation & LOCK_SH)
+ flk.l_type = F_RDLCK;
+ else
+ flk.l_type = F_WRLCK;
+
+ /* Set the other flock struct values */
+ flk.l_whence = SEEK_SET;
+ flk.l_start = 0;
+ flk.l_len = 0; /* to EOF */
+ flk.l_pid = 0; /* not used with set */
+
+ /* Lock or unlock */
+ if (HDfcntl(fd, F_SETLK, &flk) < 0)
+ return -1;
+
+ return 0;
+
+} /* end Pflock() */
+#endif /* H5_HAVE_FCNTL */
+
+/*-------------------------------------------------------------------------
+ * Function: Nflock
*
- * Failure: -1
+ * Purpose: Wrapper function for systems where no file locking is
+ * available.
*
- * Programmer: Elena Pourmal
- * March 22, 2006
+ * Return: 0 (success)
*
*-------------------------------------------------------------------------
*/
-#ifdef H5_VMS
-int
-HDremove_all(const char *fname)
+int H5_ATTR_CONST
+Nflock(int H5_ATTR_UNUSED fd, int H5_ATTR_UNUSED operation)
{
- int ret_value = -1;
- size_t fname_len;
- char *_fname;
-
- fname_len = HDstrlen(fname) + 3; /* to accomodate ";*" and null terminator */
- _fname = (char *)H5MM_malloc(fname_len);
- if(_fname) {
- HDsnprintf(_fname, fname_len, "%s;*", fname);
- /* Do not use HDremove; function becomes recursive (see H5private.h file)*/
- remove(_fname);
- H5MM_xfree(_fname);
- ret_value = 0;
- }
- return ret_value;
-}
+ /* just succeed */
+ return 0;
+} /* end Nflock() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_make_time
+ *
+ * Purpose: Portability routine to abstract converting a 'tm' struct into
+ * a time_t value.
+ *
+ * Note: This is a little problematic because mktime() operates on
+ * local times. We convert to local time and then figure out the
+ * adjustment based on the local time zone and daylight savings
+ * setting.
+ *
+ * Return: Success: The value of timezone
+ * Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ * November 18, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+time_t
+H5_make_time(struct tm *tm)
+{
+ time_t the_time; /* The converted time */
+#if defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) /* VS 2015 */
+ /* In gcc and in Visual Studio prior to VS 2015 'timezone' is a global
+ * variable declared in time.h. That variable was deprecated and in
+ * VS 2015 is removed, with _get_timezone replacing it.
+ */
+ long timezone = 0;
+#endif /* defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) */
+ time_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(tm);
+
+ /* Initialize timezone information */
+ if (!H5_ntzset) {
+ HDtzset();
+ H5_ntzset = TRUE;
+ } /* end if */
+
+ /* Perform base conversion */
+ if ((time_t)-1 == (the_time = HDmktime(tm)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCONVERT, FAIL, "badly formatted modification time message")
+
+ /* Adjust for timezones */
+#if defined(H5_HAVE_TM_GMTOFF)
+ /* BSD-like systems */
+ the_time += tm->tm_gmtoff;
+#elif defined(H5_HAVE_TIMEZONE)
+#if defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) /* VS 2015 */
+ /* In gcc and in Visual Studio prior to VS 2015 'timezone' is a global
+ * variable declared in time.h. That variable was deprecated and in
+ * VS 2015 is removed, with _get_timezone replacing it.
+ */
+ _get_timezone(&timezone);
+#endif /* defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) */
+
+ the_time -= timezone - (tm->tm_isdst ? 3600 : 0);
+#else
+ /*
+ * The catch-all. If we can't convert a character string universal
+ * coordinated time to a time_t value reliably then we can't decode the
+ * modification time message. This really isn't as bad as it sounds -- the
+ * only way a user can get the modification time is from our internal
+ * query routines, which can gracefully recover.
+ */
+ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "unable to obtain local timezone information")
#endif
+ /* Set return value */
+ ret_value = the_time;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_make_time() */
+
+#ifdef H5_HAVE_WIN32_API
+
+/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosecond units */
+#define _W32_FT_OFFSET (116444736000000000ULL)
+
/*-------------------------------------------------------------------------
* Function: Wgettimeofday
*
@@ -643,114 +297,355 @@ HDremove_all(const char *fname)
*
*-------------------------------------------------------------------------
*/
-#ifdef H5_HAVE_VISUAL_STUDIO
-
-/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosecond units */
-#define _W32_FT_OFFSET (116444736000000000ULL)
-
int
Wgettimeofday(struct timeval *tv, struct timezone *tz)
- {
- union {
- unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
- FILETIME ft;
- } _now;
+{
+ union {
+ unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
+ FILETIME ft;
+ } _now;
static int tzsetflag;
- if(tv) {
- GetSystemTimeAsFileTime (&_now.ft);
- tv->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
- tv->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
+ if (tv) {
+ GetSystemTimeAsFileTime(&_now.ft);
+ tv->tv_usec = (long)((_now.ns100 / 10ULL) % 1000000ULL);
+ tv->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
}
- if(tz) {
- if(!tzsetflag) {
+ if (tz) {
+ if (!tzsetflag) {
_tzset();
tzsetflag = 1;
}
tz->tz_minuteswest = _timezone / 60;
- tz->tz_dsttime = _daylight;
+ tz->tz_dsttime = _daylight;
}
- /* Always return 0 as per Open Group Base Specifications Issue 6.
- Do not set errno on error. */
- return 0;
-}
+ /* Always return 0 as per Open Group Base Specifications Issue 6.
+ Do not set errno on error. */
+ return 0;
+} /* end Wgettimeofday() */
+
+/*-------------------------------------------------------------------------
+ * Function: Wsetenv
+ *
+ * Purpose: Wrapper function for setenv on Windows systems.
+ * Interestingly, getenv *is* available in the Windows
+ * POSIX layer, just not setenv.
+ *
+ * Note: Passing an empty string ("") for the value will remove
+ * the variable from the environment (like unsetenv(3))
+ *
+ * Return: Success: 0
+ * Failure: non-zero error code
+ *
+ * Programmer: Dana Robinson
+ * February 2016
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+Wsetenv(const char *name, const char *value, int overwrite)
+{
+ /* If we're not overwriting, check if the environment variable exists.
+ * If it does (i.e.: the required buffer size to store the variable's
+ * value is non-zero), then return an error code.
+ */
+ if (!overwrite) {
+ size_t bufsize;
+ errno_t err;
-#ifdef H5_HAVE_WINSOCK2_H
+ err = getenv_s(&bufsize, NULL, 0, name);
+ if (err || bufsize)
+ return (int)err;
+ } /* end if */
+
+ return (int)_putenv_s(name, value);
+} /* end Wsetenv() */
+
+#ifdef H5_HAVE_WIN32_API
#pragma comment(lib, "advapi32.lib")
#endif
-#define WloginBuffer_count 256
-static char Wlogin_buffer[WloginBuffer_count];
+/*-------------------------------------------------------------------------
+ * Function: H5_get_win32_times
+ *
+ * Purpose: Gets the elapsed, system and user times on Windows platforms.
+ * All time values are in seconds.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * May 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef H5_HAVE_WIN32_API
+int
+H5_get_win32_times(H5_timevals_t *tvs /*in,out*/)
+{
+ static HANDLE process_handle;
+ ULARGE_INTEGER kernel_start;
+ ULARGE_INTEGER user_start;
+ FILETIME KernelTime;
+ FILETIME UserTime;
+ FILETIME CreationTime;
+ FILETIME ExitTime;
+ LARGE_INTEGER counts_start;
+ static LARGE_INTEGER counts_freq;
+ static hbool_t is_initialized = FALSE;
+ BOOL err;
+
+ HDassert(tvs);
+
+ if (!is_initialized) {
+ /* NOTE: This is just a pseudo handle and does not need to be closed. */
+ process_handle = GetCurrentProcess();
+ err = QueryPerformanceFrequency(&counts_freq);
+ if (0 == err)
+ return -1;
+ is_initialized = TRUE;
+ } /* end if */
+
+ /*************************
+ * System and user times *
+ *************************/
+
+ err = GetProcessTimes(process_handle, &CreationTime, &ExitTime, &KernelTime, &UserTime);
+ if (0 == err)
+ return -1;
+
+ /* The 1.0E7 factor seems strange but it's due to the clock
+ * ticking in 100 ns increments.
+ */
+ kernel_start.HighPart = KernelTime.dwHighDateTime;
+ kernel_start.LowPart = KernelTime.dwLowDateTime;
+ tvs->system = (double)(kernel_start.QuadPart / 1.0E7F);
+
+ user_start.HighPart = UserTime.dwHighDateTime;
+ user_start.LowPart = UserTime.dwLowDateTime;
+ tvs->user = (double)(user_start.QuadPart / 1.0E7F);
+
+ /****************
+ * Elapsed time *
+ ****************/
+
+ err = QueryPerformanceCounter(&counts_start);
+ if (0 == err)
+ return -1;
+
+ tvs->elapsed = (double)(counts_start.QuadPart) / (double)counts_freq.QuadPart;
-char*
-Wgetlogin()
+ return 0;
+} /* end H5_get_win32_times() */
+#endif
+
+/*-------------------------------------------------------------------------
+ * Function: Wflock
+ *
+ * Purpose: Wrapper function for flock on Windows systems
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+Wflock(int fd, int operation)
{
-#ifdef H5_HAVE_WINSOCK2_H
- long bufferCount = WloginBuffer_count;
- if (GetUserName(Wlogin_buffer, &bufferCount) == 0)
- return (Wlogin_buffer);
- else
-#endif /* H5_HAVE_WINSOCK2_H */
- return NULL;
-}
+ HANDLE hFile;
+ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
+ DWORD dwReserved = 0;
+ /* MAXDWORD locks the entire file */
+ DWORD nNumberOfBytesToLockLow = MAXDWORD;
+ DWORD nNumberOfBytesToLockHigh = MAXDWORD;
+ /* Must initialize OVERLAPPED struct */
+ OVERLAPPED overlapped = {0};
+
+ /* Get Windows HANDLE */
+ if (INVALID_HANDLE_VALUE == (hFile = (HANDLE)_get_osfhandle(fd)))
+ return -1;
+
+ /* Convert to Windows flags */
+ if (operation & LOCK_EX)
+ dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+
+ /* Lock or unlock */
+ if (operation & LOCK_UN) {
+ if (0 ==
+ UnlockFileEx(hFile, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, &overlapped)) {
+ /* Attempting to unlock an already unlocked file will fail and this can happen
+ * in H5Fstart_swmr_write(). For now, just ignore the "error" (error code: 0x9e / 158).
+ */
+ if (GetLastError() != 158)
+ return -1;
+ }
+ }
+ else {
+ if (0 == LockFileEx(hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
+ &overlapped))
+ return -1;
+ }
-int c99_snprintf(char* str, size_t size, const char* format, ...)
+ return 0;
+} /* end Wflock() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_get_utf16_str
+ *
+ * Purpose: Gets a UTF-16 string from an UTF-8 (or ASCII) string.
+ *
+ * Return: Success: A pointer to a UTF-16 string
+ * This must be freed by the caller using H5MM_xfree()
+ * Failure: NULL
+ *
+ * Programmer: Dana Robinson
+ * Spring 2019
+ *
+ *-------------------------------------------------------------------------
+ */
+wchar_t *
+H5_get_utf16_str(const char *s)
{
- int count;
- va_list ap;
+ int nwchars = -1; /* Length of the UTF-16 buffer */
+ wchar_t *ret_s = NULL; /* UTF-16 version of the string */
- va_start(ap, format);
- count = c99_vsnprintf(str, size, format, ap);
- va_end(ap);
+ /* Get the number of UTF-16 characters needed */
+ if (0 == (nwchars = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0)))
+ goto error;
- return count;
-}
+ /* Allocate a buffer for the UTF-16 string */
+ if (NULL == (ret_s = (wchar_t *)H5MM_calloc(sizeof(wchar_t) * (size_t)nwchars)))
+ goto error;
+
+ /* Convert the input UTF-8 string to UTF-16 */
+ if (0 == MultiByteToWideChar(CP_UTF8, 0, s, -1, ret_s, nwchars))
+ goto error;
+
+ return ret_s;
+
+error:
+ if (ret_s)
+ H5MM_xfree((void *)ret_s);
+ return NULL;
+} /* end H5_get_utf16_str() */
-int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
+/*-------------------------------------------------------------------------
+ * Function: Wopen_utf8
+ *
+ * Purpose: UTF-8 equivalent of open(2) for use on Windows.
+ * Converts a UTF-8 input path to UTF-16 and then opens the
+ * file via _wopen() under the hood
+ *
+ * Return: Success: A POSIX file descriptor
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * Spring 2019
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+Wopen_utf8(const char *path, int oflag, ...)
{
- int count = -1;
+ int fd = -1; /* POSIX file descriptor to be returned */
+ wchar_t *wpath = NULL; /* UTF-16 version of the path */
+ int pmode = 0; /* mode (optionally set via variable args) */
- if (size != 0)
- count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
- if (count == -1)
- count = _vscprintf(format, ap);
+ /* Convert the input UTF-8 path to UTF-16 */
+ if (NULL == (wpath = H5_get_utf16_str(path)))
+ goto done;
- return count;
-}
+ /* _O_BINARY must be set in Windows to avoid CR-LF <-> LF EOL
+ * transformations when performing I/O. Note that this will
+ * produce Unix-style text files, though.
+ */
+ oflag |= _O_BINARY;
-#endif
+ /* Get the mode, if O_CREAT was specified */
+ if (oflag & O_CREAT) {
+ va_list vl;
+
+ HDva_start(vl, oflag);
+ pmode = HDva_arg(vl, int);
+ HDva_end(vl);
+ }
+
+ /* Open the file */
+ fd = _wopen(wpath, oflag, pmode);
+
+done:
+ if (wpath)
+ H5MM_xfree((void *)wpath);
+
+ return fd;
+} /* end Wopen_utf8() */
-
/*-------------------------------------------------------------------------
- * Function: H5_build_extpath
+ * Function: Wremove_utf8
+ *
+ * Purpose: UTF-8 equivalent of remove(3) for use on Windows.
+ * Converts a UTF-8 input path to UTF-16 and then opens the
+ * file via _wremove() under the hood
*
- * Purpose: To build the path for later searching of target file for external
- * link. This path can be either:
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * Spring 2019
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+Wremove_utf8(const char *path)
+{
+ wchar_t *wpath = NULL; /* UTF-16 version of the path */
+ int ret = -1;
+
+ /* Convert the input UTF-8 path to UTF-16 */
+ if (NULL == (wpath = H5_get_utf16_str(path)))
+ goto done;
+
+ /* Open the file */
+ ret = _wremove(wpath);
+
+done:
+ if (wpath)
+ H5MM_xfree((void *)wpath);
+
+ return ret;
+} /* end Wremove_utf8() */
+
+#endif /* H5_HAVE_WIN32_API */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_build_extpath
+ *
+ * Purpose: To build the path for later searching of target file for external
+ * links and external files. This path can be either:
* 1. The absolute path of NAME
* or
* 2. The current working directory + relative path of NAME
*
- * Return: Success: 0
- * Failure: -1
+ * Return: SUCCEED/FAIL
*
* Programmer: Vailin Choi
- * April 2, 2008
+ * April 2, 2008
*
*-------------------------------------------------------------------------
*/
-#define MAX_PATH_LEN 1024
+#define MAX_PATH_LEN 1024
herr_t
-H5_build_extpath(const char *name, char **extpath/*out*/)
+H5_build_extpath(const char *name, char **extpath /*out*/)
{
- char *full_path = NULL; /* Pointer to the full path, as built or passed in */
- char *cwdpath = NULL; /* Pointer to the current working directory path */
- char *new_name = NULL; /* Pointer to the name of the file */
- herr_t ret_value = SUCCEED; /* Return value */
+ char *full_path = NULL; /* Pointer to the full path, as built or passed in */
+ char *cwdpath = NULL; /* Pointer to the current working directory path */
+ char *new_name = NULL; /* Pointer to the name of the file */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT
@@ -764,53 +659,49 @@ H5_build_extpath(const char *name, char **extpath/*out*/)
/*
* Unix: name[0] is a "/"
* Windows: name[0-2] is "<drive letter>:\" or "<drive-letter>:/"
- * OpenVMS: <disk name>$<partition>:[path]<file name>
- * i.g. SYS$SYSUSERS:[LU.HDF5.SRC]H5system.c
*/
- if(H5_CHECK_ABSOLUTE(name)) {
- if(NULL == (full_path = (char *)H5MM_strdup(name)))
+ if (H5_CHECK_ABSOLUTE(name)) {
+ if (NULL == (full_path = (char *)H5MM_strdup(name)))
HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
- } /* end if */
+ } /* end if */
else { /* relative pathname */
- char *retcwd;
+ char *retcwd;
size_t name_len;
- int drive;
+ int drive;
- if(NULL == (cwdpath = (char *)H5MM_malloc(MAX_PATH_LEN)))
+ if (NULL == (cwdpath = (char *)H5MM_malloc(MAX_PATH_LEN)))
HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
name_len = HDstrlen(name) + 1;
- if(NULL == (new_name = (char *)H5MM_malloc(name_len)))
+ if (NULL == (new_name = (char *)H5MM_malloc(name_len)))
HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
/*
* Windows: name[0-1] is "<drive-letter>:"
* Get current working directory on the drive specified in NAME
* Unix: does not apply
- * OpenVMS: does not apply
*/
- if(H5_CHECK_ABS_DRIVE(name)) {
- drive = name[0] - 'A' + 1;
+ if (H5_CHECK_ABS_DRIVE(name)) {
+ drive = HDtoupper(name[0]) - 'A' + 1;
retcwd = HDgetdcwd(drive, cwdpath, MAX_PATH_LEN);
HDstrncpy(new_name, &name[2], name_len);
} /* end if */
- /*
- * Windows: name[0] is a '/' or '\'
- * Get current drive
- * Unix: does not apply
- * OpenVMS: does not apply
- */
- else if(H5_CHECK_ABS_PATH(name) && (0 != (drive = HDgetdrive()))) {
+ /*
+ * Windows: name[0] is a '/' or '\'
+ * Get current drive
+ * Unix: does not apply
+ */
+ else if (H5_CHECK_ABS_PATH(name) && (0 != (drive = HDgetdrive()))) {
HDsnprintf(cwdpath, MAX_PATH_LEN, "%c:%c", (drive + 'A' - 1), name[0]);
retcwd = cwdpath;
HDstrncpy(new_name, &name[1], name_len);
}
- /* totally relative for Unix, Windows, and OpenVMS: get current working directory */
+ /* totally relative for Unix and Windows: get current working directory */
else {
retcwd = HDgetcwd(cwdpath, MAX_PATH_LEN);
HDstrncpy(new_name, name, name_len);
} /* end if */
- if(retcwd != NULL) {
+ if (retcwd != NULL) {
size_t cwdlen;
size_t path_len;
@@ -819,50 +710,681 @@ H5_build_extpath(const char *name, char **extpath/*out*/)
HDassert(cwdlen);
HDassert(new_name);
path_len = cwdlen + HDstrlen(new_name) + 2;
- if(NULL == (full_path = (char *)H5MM_malloc(path_len)))
+ if (NULL == (full_path = (char *)H5MM_malloc(path_len)))
HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed")
HDstrncpy(full_path, cwdpath, cwdlen + 1);
-#ifdef H5_VMS
- /* If the file name contains relative path, cut off the beginning bracket. Also cut off the
- * ending bracket of CWDPATH to combine the full path name. i.g.
- * cwdpath = SYS$SYSUSERS:[LU.HDF5.TEST]
- * new_name = [.tmp]extlinks.h5
- * full_path = SYS$SYSUSERS:[LU.HDF5.TEST.tmp]extlinks.h5
- */
- if(new_name[0] == '[') {
- char *tmp = new_name;
-
- full_path[cwdlen - 1] = '\0';
- HDstrncat(full_path, ++tmp, HDstrlen(tmp));
- } /* end if */
- else
- HDstrncat(full_path, new_name, HDstrlen(new_name));
-#else
- if(!H5_CHECK_DELIMITER(cwdpath[cwdlen - 1]))
- HDstrncat(full_path, H5_DIR_SEPS, HDstrlen(H5_DIR_SEPS));
- HDstrncat(full_path, new_name, HDstrlen(new_name));
-#endif
+ if (!H5_CHECK_DELIMITER(cwdpath[cwdlen - 1]))
+ HDstrncat(full_path, H5_DIR_SEPS, path_len - (cwdlen + 1));
+ HDstrncat(full_path, new_name, path_len - (cwdlen + 1) - HDstrlen(H5_DIR_SEPS));
} /* end if */
- } /* end else */
+ } /* end else */
/* strip out the last component (the file name itself) from the path */
- if(full_path) {
+ if (full_path) {
char *ptr = NULL;
H5_GET_LAST_DELIMITER(full_path, ptr)
HDassert(ptr);
- *++ptr = '\0';
+ *++ptr = '\0';
*extpath = full_path;
} /* end if */
done:
/* Release resources */
- if(cwdpath)
+ if (cwdpath)
H5MM_xfree(cwdpath);
- if(new_name)
+ if (new_name)
H5MM_xfree(new_name);
FUNC_LEAVE_NOAPI(ret_value)
-} /* H5_build_extpath() */
+} /* end H5_build_extpath() */
+/*--------------------------------------------------------------------------
+ * Function: H5_combine_path
+ *
+ * Purpose: If path2 is relative, interpret path2 as relative to path1
+ * and store the result in full_name. Otherwise store path2
+ * in full_name.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Steffen Kiess
+ * June 22, 2015
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5_combine_path(const char *path1, const char *path2, char **full_name /*out*/)
+{
+ size_t path1_len = 0; /* length of path1 */
+ size_t path2_len; /* length of path2 */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(path2);
+
+ if (path1)
+ path1_len = HDstrlen(path1);
+ path2_len = HDstrlen(path2);
+
+ if (path1 == NULL || *path1 == '\0' || H5_CHECK_ABSOLUTE(path2)) {
+
+ /* If path1 is empty or path2 is absolute, simply use path2 */
+ if (NULL == (*full_name = (char *)H5MM_strdup(path2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ } /* end if */
+ else if (H5_CHECK_ABS_PATH(path2)) {
+
+ /* On windows path2 is a path absolute name */
+ if (H5_CHECK_ABSOLUTE(path1) || H5_CHECK_ABS_DRIVE(path1)) {
+ /* path1 is absolute or drive absolute and path2 is path absolute.
+ * Use the drive letter of path1 + path2
+ */
+ if (NULL == (*full_name = (char *)H5MM_malloc(path2_len + 3)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate path2 buffer")
+ HDsnprintf(*full_name, (path2_len + 3), "%c:%s", path1[0], path2);
+ } /* end if */
+ else {
+ /* On windows path2 is path absolute name ("\foo\bar"),
+ * path1 does not have a drive letter (i.e. is "a\b" or "\a\b").
+ * Use path2.
+ */
+ if (NULL == (*full_name = (char *)H5MM_strdup(path2)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ } /* end else */
+
+ } /* end else if */
+ else {
+
+ /* Relative path2:
+ * Allocate a buffer to hold path1 + path2 + possibly the delimiter
+ * + terminating null byte
+ */
+ if (NULL ==
+ (*full_name = (char *)H5MM_malloc(path1_len + path2_len + 2 +
+ 2))) /* Extra "+2" to quiet GCC warning - 2019/07/05, QAK */
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer")
+
+ /* Compose the full file name */
+ HDsnprintf(*full_name, (path1_len + path2_len + 2 + 2), "%s%s%s",
+ path1, /* Extra "+2" to quiet GCC warning - 2019/07/05, QAK */
+ (H5_CHECK_DELIMITER(path1[path1_len - 1]) ? "" : H5_DIR_SEPS), path2);
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_combine_path() */
+
+/*--------------------------------------------------------------------------
+ * Function: H5_nanosleep
+ *
+ * Purpose: Sleep for a given # of nanoseconds
+ *
+ * Note that commodity hardware is probably going to have a
+ * resolution of milliseconds, not nanoseconds.
+ *
+ * Return: void
+ *--------------------------------------------------------------------------
+ */
+void
+H5_nanosleep(uint64_t nanosec)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifdef H5_HAVE_WIN32_API
+ DWORD dwMilliseconds = (DWORD)HDceil(nanosec / 1.0e6);
+ DWORD ignore;
+
+ /* Windows can't sleep at a ns resolution. Best we can do is ~1 ms. We
+ * don't care about the return value since the second parameter
+ * (bAlertable) is FALSE, so it will always be zero.
+ */
+ ignore = SleepEx(dwMilliseconds, FALSE);
+
+#else
+
+ const uint64_t nanosec_per_sec = 1000 * 1000L * 1000;
+ struct timespec sleeptime; /* Struct to hold time to sleep */
+
+ /* Set up time to sleep
+ *
+ * Assuming ILP32 or LP64 or wider architecture, (long)operand
+ * satisfies 0 <= operand < nanosec_per_sec < LONG_MAX.
+ *
+ * It's harder to be sure that we don't overflow time_t.
+ */
+ sleeptime.tv_sec = (time_t)(nanosec / nanosec_per_sec);
+ sleeptime.tv_nsec = (long)(nanosec % nanosec_per_sec);
+
+ /* Sleep for up to `sleeptime` and, in the event of an interruption,
+ * save the unslept time back to `sleeptime`.
+ */
+ while (HDnanosleep(&sleeptime, &sleeptime) == -1) {
+ /* If we were just interrupted, sleep for the remaining time.
+ * Otherwise, the error was essentially impossible, so just stop
+ * sleeping.
+ */
+ if (errno != EINTR)
+ break;
+ }
+#endif
+
+ FUNC_LEAVE_NOAPI_VOID
+} /* end H5_nanosleep() */
+
+#ifdef H5_HAVE_WIN32_API
+
+#define H5_WIN32_ENV_VAR_BUFFER_SIZE 32767
+
+/*-------------------------------------------------------------------------
+ * Function: H5_expand_windows_env_vars()
+ *
+ * Purpose: Replaces windows environment variables of the form %foo%
+ * with user-specific values.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5_expand_windows_env_vars(char **env_var)
+{
+ long n_chars = 0;
+ char *temp_buf = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Allocate buffer for expanded environment variable string */
+ if (NULL == (temp_buf = (char *)H5MM_calloc((size_t)H5_WIN32_ENV_VAR_BUFFER_SIZE)))
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for expanded path")
+
+ /* Expand the environment variable string */
+ if ((n_chars = ExpandEnvironmentStringsA(*env_var, temp_buf, H5_WIN32_ENV_VAR_BUFFER_SIZE)) >
+ H5_WIN32_ENV_VAR_BUFFER_SIZE)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "expanded path is too long")
+
+ if (0 == n_chars)
+ HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "failed to expand path")
+
+ *env_var = (char *)H5MM_xfree(*env_var);
+ *env_var = temp_buf;
+
+done:
+ if (FAIL == ret_value && temp_buf)
+ temp_buf = (char *)H5MM_xfree(temp_buf);
+
+ 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 */
+const char *H5_optarg; /* Flag argument (or value) */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_get_option
+ *
+ * Purpose: Determine the command-line options a user specified. We can
+ * accept both short and long type command-lines.
+ *
+ * Return: Success: The short valued "name" of the command line
+ * parameter or EOF if there are no more
+ * parameters to process.
+ *
+ * Failure: A question mark.
+ *-------------------------------------------------------------------------
+ */
+int
+H5_get_option(int argc, const char *const *argv, const char *opts, const struct h5_long_options *l_opts)
+{
+ static int sp = 1; /* character index in current token */
+ int optchar = '?'; /* option character passed back to user */
+
+ if (sp == 1) {
+ /* check for more flag-like tokens */
+ if (H5_optind >= argc || argv[H5_optind][0] != '-' || argv[H5_optind][1] == '\0') {
+ return EOF;
+ }
+ else if (HDstrcmp(argv[H5_optind], "--") == 0) {
+ H5_optind++;
+ return EOF;
+ }
+ }
+
+ if (sp == 1 && argv[H5_optind][0] == '-' && argv[H5_optind][1] == '-') {
+ /* long command line option */
+ int i;
+ const char ch = '=';
+ char *arg = HDstrdup(&argv[H5_optind][2]);
+ size_t arg_len = 0;
+
+ H5_optarg = strchr(&argv[H5_optind][2], ch);
+ arg_len = HDstrlen(&argv[H5_optind][2]);
+ if (H5_optarg) {
+ arg_len -= HDstrlen(H5_optarg);
+ H5_optarg++; /* skip the equal sign */
+ }
+ arg[arg_len] = 0;
+
+ for (i = 0; l_opts && l_opts[i].name; i++) {
+ if (HDstrcmp(arg, l_opts[i].name) == 0) {
+ /* we've found a matching long command line flag */
+ optchar = l_opts[i].shortval;
+
+ if (l_opts[i].has_arg != no_arg) {
+ if (H5_optarg == NULL) {
+ if (l_opts[i].has_arg != optional_arg) {
+ if (H5_optind < (argc - 1))
+ if (argv[H5_optind + 1][0] != '-')
+ H5_optarg = argv[++H5_optind];
+ }
+ else if (l_opts[i].has_arg == require_arg) {
+ if (H5_opterr)
+ HDfprintf(stderr, "%s: option required for \"--%s\" flag\n", argv[0], arg);
+
+ optchar = '?';
+ }
+ }
+ }
+ else {
+ if (H5_optarg) {
+ if (H5_opterr)
+ HDfprintf(stderr, "%s: no option required for \"%s\" flag\n", argv[0], arg);
+
+ optchar = '?';
+ }
+ }
+ break;
+ }
+ }
+
+ if (l_opts[i].name == NULL) {
+ /* exhausted all of the l_opts we have and still didn't match */
+ if (H5_opterr)
+ HDfprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], arg);
+
+ optchar = '?';
+ }
+
+ H5_optind++;
+ sp = 1;
+
+ HDfree(arg);
+ }
+ else {
+ char *cp; /* pointer into current token */
+
+ /* short command line option */
+ optchar = argv[H5_optind][sp];
+
+ if (optchar == ':' || (cp = HDstrchr(opts, optchar)) == 0) {
+ if (H5_opterr)
+ HDfprintf(stderr, "%s: unknown option \"%c\"\n", argv[0], optchar);
+
+ /* if no chars left in this token, move to next token */
+ if (argv[H5_optind][++sp] == '\0') {
+ H5_optind++;
+ sp = 1;
+ }
+ return '?';
+ }
+
+ if (*++cp == ':') {
+ /* if a value is expected, get it */
+ if (argv[H5_optind][sp + 1] != '\0') {
+ /* flag value is rest of current token */
+ H5_optarg = &argv[H5_optind++][sp + 1];
+ }
+ else if (++H5_optind >= argc) {
+ if (H5_opterr)
+ HDfprintf(stderr, "%s: value expected for option \"%c\"\n", argv[0], optchar);
+
+ optchar = '?';
+ }
+ else {
+ /* flag value is next token */
+ H5_optarg = argv[H5_optind++];
+ }
+
+ sp = 1;
+ }
+ /* wildcard argument */
+ else if (*cp == '*') {
+ /* check the next argument */
+ H5_optind++;
+ /* we do have an extra argument, check if not last */
+ if ((H5_optind + 1) < argc) {
+ if (argv[H5_optind][0] != '-') {
+ H5_optarg = argv[H5_optind++];
+ }
+ else {
+ H5_optarg = NULL;
+ }
+ }
+ else {
+ H5_optarg = NULL;
+ }
+ }
+ else {
+ /* set up to look at next char in token, next time */
+ if (argv[H5_optind][++sp] == '\0') {
+ /* no more in current token, so setup next token */
+ H5_optind++;
+ sp = 1;
+ }
+ H5_optarg = NULL;
+ }
+ }
+
+ /* return the current flag character found */
+ return optchar;
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5_strcasestr
+ *
+ * Purpose: Find the first occurrence of the substring needle in the
+ * string haystack ignoring case.
+ *
+ * Return: Success: Pointer to the beginning of the located substring
+ *
+ * Failure: NULL
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5_strcasestr(const char *haystack, const char *needle)
+{
+ /* Check arguments. */
+ HDassert(haystack);
+ HDassert(needle);
+
+ /* begin once from each character of haystack, until needle is found */
+ do {
+ const char *h = haystack;
+ const char *n = needle;
+ /* loop while lowercase strings match, or needle ends */
+ while (HDtolower(*h) == HDtolower(*n) && *n) {
+ h++;
+ n++;
+ }
+ /* if all characters in needle matched we found it */
+ if (*n == 0) {
+ /* must discard const qualifier here, so turn off the warning */
+ H5_GCC_CLANG_DIAG_OFF("cast-qual")
+ return (char *)haystack;
+ H5_GCC_CLANG_DIAG_ON("cast-qual")
+ }
+ } while (*haystack++);
+ return 0;
+} /* end H5_strcasestr() */