/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*------------------------------------------------------------------------- * * Created: H5system.c * Aug 21 2006 * Quincey Koziol * * Purpose: System call wrapper implementations. * *------------------------------------------------------------------------- */ /****************/ /* Module Setup */ /****************/ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Fprivate.h" /* File access */ #include "H5MMprivate.h" /* Memory management */ #include "H5Eprivate.h" /****************/ /* 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; } /* 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, 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: * *------------------------------------------------------------------------- */ int64_t HDstrtoll(const char *s, const char **rest, int base) { 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; } } s++; } /* 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 * * Purpose: Wrapper function for rand. If rand_r exists on this system, * use it. * * Wrapper function for srand. If rand_r is available, it will keep * track of the seed locally instead of using srand() which modifies * global state and can break other programs. * * Return: Success: Random number from 0 to RAND_MAX * * Failure: Cannot fail. * * Programmer: Leon Arber * March 6, 2006. * *------------------------------------------------------------------------- */ #ifdef H5_HAVE_RAND_R static unsigned int g_seed = 42; int HDrand(void) { return rand_r(&g_seed); } void HDsrand(unsigned int seed) { g_seed = seed; } #endif /* H5_HAVE_RAND_R */ /*------------------------------------------------------------------------- * Function: Wgettimeofday * * Purpose: Wrapper function for gettimeofday on Windows systems * * This function can get the time as well as a timezone * * Return: 0 * * This implementation is taken from the Cygwin source distribution at * src/winsup/mingw/mingwex/gettimeofday.c * * The original source code was contributed by * Danny Smith * and released in the public domain. * * Programmer: Scott Wegner * May 19, 2009 * *------------------------------------------------------------------------- */ #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; 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(tz) { if(!tzsetflag) { _tzset(); tzsetflag = 1; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } /* 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. * * Return: Success: 0 * Failure: non-zero error code * * Programmer: Dana Robinson * February 2016 * *------------------------------------------------------------------------- */ int Wsetenv(const char *name, const char *value, int overwrite) { size_t bufsize; errno_t err; /* 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) { 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_WINSOCK2_H #pragma comment(lib, "advapi32.lib") #endif #define WloginBuffer_count 256 static char Wlogin_buffer[WloginBuffer_count]; char* Wgetlogin() { #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; } int c99_snprintf(char* str, size_t size, const char* format, ...) { int count; va_list ap; va_start(ap, format); count = c99_vsnprintf(str, size, format, ap); va_end(ap); return count; } int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) { int count = -1; if (size != 0) count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); if (count == -1) count = _vscprintf(format, ap); return count; } #endif /*------------------------------------------------------------------------- * 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: SUCCEED/FAIL * * Programmer: Vailin Choi * April 2, 2008 * *------------------------------------------------------------------------- */ #define MAX_PATH_LEN 1024 herr_t 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 */ FUNC_ENTER_NOAPI_NOINIT /* Sanity check */ HDassert(name); HDassert(extpath); /* Clear external path pointer to begin with */ *extpath = NULL; /* * Unix: name[0] is a "/" * Windows: name[0-2] is ":\" or ":/" */ 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 */ else { /* relative pathname */ char *retcwd; size_t name_len; int drive; 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))) HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed") /* * Windows: name[0-1] is ":" * Get current working directory on the drive specified in NAME * Unix: does not apply */ if(H5_CHECK_ABS_DRIVE(name)) { drive = 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 */ 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 and Windows: get current working directory */ else { retcwd = HDgetcwd(cwdpath, MAX_PATH_LEN); HDstrncpy(new_name, name, name_len); } /* end if */ if(retcwd != NULL) { size_t cwdlen; size_t path_len; HDassert(cwdpath); cwdlen = HDstrlen(cwdpath); HDassert(cwdlen); HDassert(new_name); path_len = cwdlen + HDstrlen(new_name) + 2; 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); 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)); } /* end if */ } /* end else */ /* strip out the last component (the file name itself) from the path */ if(full_path) { char *ptr = NULL; H5_GET_LAST_DELIMITER(full_path, ptr) HDassert(ptr); *++ptr = '\0'; *extpath = full_path; } /* end if */ done: /* Release resources */ if(cwdpath) H5MM_xfree(cwdpath); if(new_name) H5MM_xfree(new_name); FUNC_LEAVE_NOAPI(ret_value) } /* 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; /* length of path1 */ size_t path2_len; /* length of path2 */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT HDassert(path1); HDassert(path2); path1_len = HDstrlen(path1); path2_len = HDstrlen(path2); if(*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))) 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), "%s%s%s", path1, (H5_CHECK_DELIMITER(path1[path1_len - 1]) ? "" : H5_DIR_SEPS), path2); } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5_combine_name() */