/**************************************************************************** * NCSA HDF * * Software Development Group * * National Center for Supercomputing Applications * * University of Illinois at Urbana-Champaign * * 605 E. Springfield, Champaign IL 61820 * * * * For conditions of distribution and use, see the accompanying * * hdf/COPYING file. * * * ****************************************************************************/ #ifdef RCSID static char RcsId[] = "@(#)$Revision$"; #endif /* $Id$ */ /* private headers */ #include /*library */ #include /*cache */ #include /*B-link trees */ #include /*error handling */ #include /*atoms */ #include /*memory management */ #include /*property lists */ #include /*references */ #include /*data spaces */ #include /*data types */ #include /*filters */ /* We need this on Irix64 even though we've included stdio.h as documented */ FILE *fdopen(int fd, const char *mode); #define PABLO_MASK H5_mask hbool_t H5_libinit_g = FALSE; hbool_t dont_atexit_g = FALSE; H5_debug_t H5_debug_g; /*debugging info */ static void H5_debug_mask(const char*); /* Interface initialization */ static intn interface_initialize_g = 0; #define INTERFACE_INIT NULL /*-------------------------------------------------------------------------- NAME H5_init_library -- Initialize library-global information USAGE herr_t H5_init_library() RETURNS Non-negative on success/Negative on failure DESCRIPTION Initializes any library-global data or routines. --------------------------------------------------------------------------*/ herr_t H5_init_library(void) { FUNC_ENTER_INIT(H5_init_library, NULL, FAIL); /* * Make sure the package information is updated. */ HDmemset(&H5_debug_g, 0, sizeof H5_debug_g); H5_debug_g.pkg[H5_PKG_A].name = "a"; H5_debug_g.pkg[H5_PKG_AC].name = "ac"; H5_debug_g.pkg[H5_PKG_B].name = "b"; H5_debug_g.pkg[H5_PKG_D].name = "d"; H5_debug_g.pkg[H5_PKG_E].name = "e"; H5_debug_g.pkg[H5_PKG_F].name = "f"; H5_debug_g.pkg[H5_PKG_G].name = "g"; H5_debug_g.pkg[H5_PKG_HG].name = "hg"; H5_debug_g.pkg[H5_PKG_HL].name = "hl"; H5_debug_g.pkg[H5_PKG_I].name = "i"; H5_debug_g.pkg[H5_PKG_MF].name = "mf"; H5_debug_g.pkg[H5_PKG_MM].name = "mm"; H5_debug_g.pkg[H5_PKG_O].name = "o"; H5_debug_g.pkg[H5_PKG_P].name = "p"; H5_debug_g.pkg[H5_PKG_S].name = "s"; H5_debug_g.pkg[H5_PKG_T].name = "t"; H5_debug_g.pkg[H5_PKG_V].name = "v"; H5_debug_g.pkg[H5_PKG_Z].name = "z"; /* * Install atexit() library cleanup routine unless the H5dont_atexit() * has been called. Once we add something to the atexit() list it stays * there permanently, so we set dont_atexit_g after we add it to prevent * adding it again later if the library is cosed and reopened. */ if (!dont_atexit_g) { atexit(H5_term_library); dont_atexit_g = TRUE; } /* * Initialize interfaces that might not be able to initialize themselves * soon enough. */ if (H5T_init()<0) { HRETURN_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL, "unable to initialize type interface"); } /* Debugging? */ H5_debug_mask("-all"); H5_debug_mask(HDgetenv("HDF5_DEBUG")); FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5_term_library * * Purpose: Terminate interfaces in a well-defined order due to * dependencies among the interfaces, then terminate * library-specific data. * * Return: void * * Programmer: Robb Matzke * Friday, November 20, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5_term_library(void) { /* Don't do anything if the library is already closed */ if (!H5_libinit_g) return; /* * Close interfaces in a well-defined order based on dependencies. The * goal is that closing one interface doesn't reopen another that was * just closed. In order to help us track down dependencies that we * didn't know about, we close the interfaces in a two step process. The * first step does the real work and makes the interface unusable. The * second step doesn't do any work but makes it possible to reopen the * interface later. */ /* * Cycles: The H5F layer participates in quite a few dependency cycles * because it's cache depends on almost all other meta object * packages and those packages depend on H5O which depends on H5F * (because H5F_close() can delay until all object headers are * closed). We handle this cycle by closing the H5F interface, * which flushes the cache of all files, breaking any cycles. */ H5F_term_interface(-1); H5F_term_interface(0); /* Function What depends on it? */ /*------------------------- ------------------------------- */ H5D_term_interface(-1); /* */ H5TB_term_interface(-1); /* */ H5Z_term_interface(-1); /* */ H5A_term_interface(-1); /* */ H5RA_term_interface(-1); /* */ H5G_term_interface(-1); /* */ H5R_term_interface(-1); /* */ H5S_term_interface(-1); /* */ H5T_native_close(-1); /* D RA */ H5T_term_interface(-1); /* D RA */ H5F_term_interface(-1); /* G T */ H5P_term_interface(-1); /* D */ H5I_term_interface(-1); /* A D F G P RA S T TB Z */ /*------------------------- --------------------------------- */ /* * Finalize the closing by calling all the functions again but with an * argument of zero. This allows the interface to be reopened later. */ H5A_term_interface(0); H5D_term_interface(0); H5F_term_interface(0); H5G_term_interface(0); H5I_term_interface(0); H5P_term_interface(0); H5RA_term_interface(0); H5R_term_interface(0); H5S_term_interface(0); H5TB_term_interface(0); H5T_native_close(0); H5T_term_interface(0); H5Z_term_interface(0); /* Mark library as closed */ H5_libinit_g = FALSE; } /*------------------------------------------------------------------------- * Function: H5dont_atexit * * Purpose: Indicates that the library is not to clean up after itself * when the application exits by calling exit() or returning * from main(). This function must be called before any other * HDF5 function or constant is used or it will have no effect. * * If this function is used then certain memory buffers will not * be de-allocated nor will open files be flushed automatically. * The application may still call H5close() explicitly to * accomplish these things. * * Return: Success: non-negative * * Failure: negative if this function is called more than * once or if it is called too late. * * Programmer: Robb Matzke * Friday, November 20, 1998 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5dont_atexit(void) { /* FUNC_ENTER_INIT() should not be called */ H5_trace(FALSE, "H5dont_atexit", ""); if (dont_atexit_g) return FAIL; dont_atexit_g = TRUE; H5_trace(TRUE, NULL, "e", SUCCEED); return(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5_debug_mask * * Purpose: Set runtime debugging flags according to the string S. The * string should contain file numbers and package names * separated by other characters. A file number applies to all * following package names up to the next file number. The * initial file number is `2' (the standard error stream). Each * package name can be preceded by a `+' or `-' to add or remove * the package from the debugging list (`+' is the default). The * special name `all' means all packages. * * The name `trace' indicates that API tracing is to be turned * on or off. * * Return: void * * Programmer: Robb Matzke * Wednesday, August 19, 1998 * * Modifications: * *------------------------------------------------------------------------- */ static void H5_debug_mask(const char *s) { FILE *stream = stderr; char pkg_name[32], *rest; size_t i; int clear; while (s && *s) { if (HDisalpha(*s) || '-'==*s || '+'==*s) { /* Enable or Disable debugging? */ if ('-'==*s) { clear = TRUE; s++; } else if ('+'==*s) { clear = FALSE; s++; } else { clear = FALSE; } /* Get the name */ for (i=0; HDisalpha(*s); i++, s++) { if (i=H5_NPKGS) { fprintf(stderr, "HDF5_DEBUG: ignored %s\n", pkg_name); } } } else if (HDisdigit(*s)) { int fd = (int)HDstrtol (s, &rest, 0); if ((stream=HDfdopen(fd, "w"))) { HDsetvbuf (stream, NULL, _IOLBF, 0); } s = rest; } else { s++; } } } /*------------------------------------------------------------------------- * Function: H5get_libversion * * Purpose: Returns the library version numbers through arguments. MAJNUM * will be the major revision number of the library, MINNUM the * minor revision number, and RELNUM the release revision number. * * Note: When printing an HDF5 version number it should be printed as * * printf("%u.%u.%u", maj, min, rel) or * printf("version %u.%u release %u", maj, min, rel) * * Return: Non-negative on success/Negative on failure * * Programmer: Unknown * * Modifications: * Robb Matzke, 4 Mar 1998 * Now use "normal" data types for the interface. Any of the arguments * may be null pointers * *------------------------------------------------------------------------- */ herr_t H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *relnum) { herr_t ret_value = SUCCEED; FUNC_ENTER(H5get_libversion, FAIL); /* Set the version information */ if (majnum) *majnum = H5_VERS_MAJOR; if (minnum) *minnum = H5_VERS_MINOR; if (relnum) *relnum = H5_VERS_RELEASE; FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5check_version * * Purpose: Verifies that the arguments match the version numbers * compiled into the library. This function is intended to be * called from user to verify that the versions of header files * compiled into the application match the version of the hdf5 * library. * * Return: Success: SUCCEED * * Failure: abort() * * Programmer: Robb Matzke * Tuesday, April 21, 1998 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5check_version (unsigned majnum, unsigned minnum, unsigned relnum) { /* Don't initialize the library quite yet */ if (H5_VERS_MAJOR!=majnum || H5_VERS_MINOR!=minnum || H5_VERS_RELEASE!=relnum) { HDfputs ("Warning! The HDF5 header files included by this application " "do not match the\nversion used by the HDF5 library to which " "this application is linked. Data\ncorruption or " "segmentation faults would be likely if the application " "were\nallowed to continue.\n", stderr); fprintf (stderr, "Headers are %u.%u.%u, library is %u.%u.%u\n", majnum, minnum, relnum, H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE); HDfputs ("Bye...\n", stderr); HDabort (); } return SUCCEED; } /*------------------------------------------------------------------------- * Function: H5open * * Purpose: Initialize the library. This is normally called * automatically, but if you find that an HDF5 library function * is failing inexplicably, then try calling this function * first. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Tuesday, December 9, 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5open(void) { FUNC_ENTER(H5open, FAIL); /* all work is done by FUNC_ENTER() */ FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5close * * Purpose: Terminate the library and release all resources. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Friday, January 30, 1998 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5close (void) { /* * Don't call FUNC_ENTER() since we don't want to initialize the whole * thing just to release it all right away. It is safe to call this * function for an uninitialized library. */ H5_term_library(); return SUCCEED; } /*------------------------------------------------------------------------- * Function: HDsnprintf * * Purpose: Writes output to the string BUF under control of the format * FMT that specifies how subsequent arguments are converted for * output. It is similar to sprintf except that SIZE specifies * the maximum number of characters to produce. The trailing * null character is counted towards this limit, so you should * allocated at least SIZE characters for the string BUF. * * Note: This function is for compatibility on systems that don't have * snprintf(3). It doesn't actually check for overflow like the * real snprintf() would. * * Return: Success: Number of characters stored, not including * the terminating null. If this value equals * SIZE then there was not enough space in BUF * for all the output. * * Failure: -1 * * Programmer: Robb Matzke * Tuesday, November 24, 1998 * * Modifications: * *------------------------------------------------------------------------- */ int HDsnprintf(char *buf, size_t __unused__ size, const char *fmt, ...) { int n; va_list ap; va_start(ap, fmt); n = vsprintf(buf, fmt, ap); va_end(ap); return n; } /*------------------------------------------------------------------------- * 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. * * Bugs: Return value will be incorrect if `%a' appears in the format * string. * * Return: Success: Number of characters printed * * Failure: -1 * * Programmer: Robb Matzke * Thursday, April 9, 1998 * * Modifications: * *------------------------------------------------------------------------- */ 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, template[128]; const char *s; va_list ap; assert (stream); assert (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; } s++; } /* Field width */ if (HDisdigit (*s)) { zerofill = ('0'==*s); fwidth = (int)HDstrtol (s, &rest, 10); s = rest; } 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; } /* Type modifier */ if (HDstrchr ("ZHhlq", *s)) { switch (*s) { case 'H': if (sizeof(hsize_t)0) { sprintf (template+HDstrlen(template), "%d", fwidth); } if (prec>0) { sprintf (template+HDstrlen(template), ".%d", prec); } if (*modifier) { sprintf (template+HDstrlen(template), "%s", modifier); } sprintf (template+HDstrlen(template), "%c", conv); /* Conversion */ switch (conv) { case 'd': case 'i': if (!HDstrcmp(modifier, "h")) { short x = va_arg (ap, short); n = fprintf (stream, template, x); } else if (!*modifier) { int x = va_arg (ap, int); n = fprintf (stream, template, x); } else if (!HDstrcmp (modifier, "l")) { long x = va_arg (ap, long); n = fprintf (stream, template, x); } else { int64_t x = va_arg(ap, int64_t); n = fprintf (stream, template, x); } break; case 'o': case 'u': case 'x': case 'X': if (!HDstrcmp (modifier, "h")) { unsigned short x = va_arg (ap, unsigned short); n = fprintf (stream, template, x); } else if (!*modifier) { unsigned int x = va_arg (ap, unsigned int); n = fprintf (stream, template, x); } else if (!HDstrcmp (modifier, "l")) { unsigned long x = va_arg (ap, unsigned long); n = fprintf (stream, template, x); } else { uint64_t x = va_arg(ap, uint64_t); n = fprintf (stream, template, x); } break; case 'f': case 'e': case 'E': case 'g': case 'G': if (!HDstrcmp (modifier, "h")) { float x = va_arg (ap, float); n = fprintf (stream, template, x); } else if (!*modifier || !HDstrcmp (modifier, "l")) { double x = va_arg (ap, double); n = fprintf (stream, template, x); } else { /* * Some compilers complain when `long double' and * `double' are the same thing. */ #if SIZEOF_LONG_DOUBLE != SIZEOF_DOUBLE long double x = va_arg (ap, long double); n = fprintf (stream, template, x); #else double x = va_arg (ap, double); n = fprintf (stream, template, x); #endif } break; case 'a': if (1) { haddr_t *x = va_arg (ap, haddr_t*); if (x && H5F_addr_defined(x)) { sprintf(template, "%%%s%s%s%s%s", leftjust?"-":"", plussign?"+":"", ldspace?" ":"", prefix?"#":"", zerofill?"0":""); if (fwidth>0) { sprintf(template+HDstrlen(template), "%d", fwidth); } if (sizeof(x->offset)==SIZEOF_INT) { HDstrcat(template, "d"); } else if (sizeof(x->offset)==SIZEOF_LONG) { HDstrcat(template, "ld"); } else if (sizeof(x->offset)==SIZEOF_LONG_LONG) { HDstrcat(template, PRINTF_LL_WIDTH); HDstrcat(template, "d"); } n = fprintf(stream, template, x->offset); } else { HDstrcpy(template, "%"); if (leftjust) HDstrcat(template, "-"); if (fwidth) { sprintf(template+HDstrlen(template), "%d", fwidth); } HDstrcat(template, "s"); fprintf(stream, template, x?"UNDEF":"NULL"); } } break; case 'c': if (1) { char x = (char)va_arg (ap, int); n = fprintf (stream, template, x); } break; case 's': case 'p': if (1) { char *x = va_arg (ap, char*); n = fprintf (stream, template, x); } break; case 'n': if (1) { template[HDstrlen(template)-1] = 'u'; n = fprintf (stream, template, nout); } break; default: HDfputs (template, stream); n = (int)HDstrlen (template); break; } nout += n; fmt = s; } else { HDputc (*fmt, stream); fmt++; nout++; } } va_end (ap); return nout; } /*------------------------------------------------------------------------- * 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 = (uint64_t)1<<(8*sizeof(int64_t)-1); } errno = ERANGE; } /* Return values */ acc *= sign; if (rest) *rest = s; return acc; } /*------------------------------------------------------------------------- * Function: H5_timer_reset * * Purpose: Resets the timer struct to zero. Use this to reset a timer * that's being used as an accumulator for summing times. * * Return: void * * Programmer: Robb Matzke * Thursday, April 16, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5_timer_reset (H5_timer_t *timer) { assert (timer); HDmemset (timer, 0, sizeof *timer); } /*------------------------------------------------------------------------- * Function: H5_timer_begin * * Purpose: Initialize a timer to time something. * * Return: void * * Programmer: Robb Matzke * Thursday, April 16, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5_timer_begin (H5_timer_t *timer) { #ifdef HAVE_GETRUSAGE struct rusage rusage; #endif #ifdef HAVE_GETTIMEOFDAY struct timeval etime; #endif assert (timer); #ifdef HAVE_GETRUSAGE getrusage (RUSAGE_SELF, &rusage); timer->utime = (double)rusage.ru_utime.tv_sec + (double)rusage.ru_utime.tv_usec/1e6; timer->stime = (double)rusage.ru_stime.tv_sec + (double)rusage.ru_stime.tv_usec/1e6; #else timer->utime = 0.0; timer->stime = 0.0; #endif #ifdef HAVE_GETTIMEOFDAY gettimeofday (&etime, NULL); timer->etime = (double)etime.tv_sec + (double)etime.tv_usec/1e6; #else timer->etime = 0.0; #endif } /*------------------------------------------------------------------------- * Function: H5_timer_end * * Purpose: This function should be called at the end of a timed region. * The SUM is an optional pointer which will accumulate times. * TMS is the same struct that was passed to H5_timer_start(). * On return, TMS will contain total times for the timed region. * * Return: void * * Programmer: Robb Matzke * Thursday, April 16, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5_timer_end (H5_timer_t *sum/*in,out*/, H5_timer_t *timer/*in,out*/) { H5_timer_t now; assert (timer); H5_timer_begin (&now); timer->utime = MAX(0.0, now.utime - timer->utime); timer->stime = MAX(0.0, now.stime - timer->stime); timer->etime = MAX(0.0, now.etime - timer->etime); if (sum) { sum->utime += timer->utime; sum->stime += timer->stime; sum->etime += timer->etime; } } /*------------------------------------------------------------------------- * Function: H5_bandwidth * * Purpose: Prints the bandwidth (bytes per second) in a field 10 * characters wide widh four digits of precision like this: * * NaN If <=0 seconds * 1234. TB/s * 123.4 TB/s * 12.34 GB/s * 1.234 MB/s * 4.000 kB/s * 1.000 B/s * 0.000 B/s If NBYTES==0 * 1.2345e-10 For bandwidth less than 1 * 6.7893e+94 For exceptionally large values * 6.678e+106 For really big values * * Return: void * * Programmer: Robb Matzke * Wednesday, August 5, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5_bandwidth(char *buf/*out*/, double nbytes, double nseconds) { double bw; if (nseconds<=0.0) { HDstrcpy(buf, " NaN"); } else { bw = nbytes/nseconds; if (bw==0.0) { HDstrcpy(buf, "0.000 B/s"); } else if (bw<1.0) { sprintf(buf, "%10.4e", bw); } else if (bw<1024.0) { sprintf(buf, "%05.4f", bw); HDstrcpy(buf+5, " B/s"); } else if (bw<1024.0*1024.0) { sprintf(buf, "%05.4f", bw/1024.0); HDstrcpy(buf+5, " kB/s"); } else if (bw<1024.0*1024.0*1024.0) { sprintf(buf, "%05.4f", bw/(1024.0*1024.0)); HDstrcpy(buf+5, " MB/s"); } else if (bw<1024.0*1024.0*1024.0*1024.0) { sprintf(buf, "%05.4f", bw/(1024.0*1024.0*1024.0)); HDstrcpy(buf+5, " GB/s"); } else if (bw<1024.0*1024.0*1024.0*1024.0*1024.0) { sprintf(buf, "%05.4f", bw/(1024.0*1024.0*1024.0*1024.0)); HDstrcpy(buf+5, " TB/s"); } else { sprintf(buf, "%10.4e", bw); if (HDstrlen(buf)>10) { sprintf(buf, "%10.3e", bw); } } } } /*------------------------------------------------------------------------- * Function: H5_trace * * Purpose: This function is called whenever an API function is called * and tracing is turned on. If RETURNING is non-zero then * the caller is about to return. Otherwise we print the * function name and the arguments. * * The TYPE argument is a string which gives the type of each of * the following argument pairs. Each type is zero or more * asterisks (one for each level of indirection, although some * types have one level of indirection already implied) followed * by either one letter (lower case) or two letters (first one * uppercase). * * The variable argument list consists of pairs of values. Each * pair is a string which is the formal argument name in the * calling function, followed by the argument value. The type * of the argument value is given by the TYPE string. * * Note: The TYPE string is meant to be terse and is generated by a * separate perl script. * * WARNING: DO NOT CALL ANY HDF5 FUNCTION THAT CALLS FUNC_ENTER(). DOING * SO MAY CAUSE H5_trace() TO BE INVOKED RECURSIVELY OR MAY * CAUSE LIBRARY INITIALIZATIONS THAT ARE NOT DESIRED. DO NOT * USE THE H5T_*_* CONSTANTS SINCE THEY CALL H5_open() WHICH * INVOKES FUNC_ENTER(). * * Return: void * * Programmer: Robb Matzke * Tuesday, June 16, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void H5_trace (hbool_t returning, const char *func, const char *type, ...) { va_list ap; char buf[64], *rest; const char *argname; intn argno=0, ptr, n, asize_idx; hssize_t asize[16]; hssize_t i; void *vp = NULL; FILE *out = H5_debug_g.trace; /* FUNC_ENTER() should not be called */ if (!out) return; /*tracing is off*/ va_start (ap, type); if (returning) { fprintf (out, " = "); } else { fprintf (out, "%s(", func); } /* Clear array sizes */ for (i=0; i<(hssize_t)NELMTS(asize); i++) asize[i] = -1; /* Parse the argument types */ for (argno=0; *type; argno++, type+=HDisupper(*type)?2:1) { /* Count levels of indirection */ for (ptr=0; '*'==*type; type++) ptr++; if ('['==*type) { if ('a'==type[1]) { asize_idx = (int)HDstrtol(type+2, &rest, 10); assert(']'==*rest); type = rest+1; } else { rest = HDstrchr(type, ']'); assert(rest); type = rest+1; asize_idx = -1; } } else { asize_idx = -1; } /* * The argument name. Leave off the `_id' part. If the argument * name is the null pointer then don't print the argument or the * following `='. This is used for return values. */ argname = va_arg (ap, char*); if (argname) { n = MAX (0, (int)HDstrlen(argname)-3); if (!HDstrcmp (argname+n, "_id")) { HDstrncpy (buf, argname, MIN ((int)sizeof(buf)-1, n)); buf[MIN((int)sizeof(buf)-1, n)] = '\0'; argname = buf; } fprintf (out, "%s%s=", argno?", ":"", argname); } else { argname = ""; } /* The value */ if (ptr) vp = va_arg (ap, void*); switch (type[0]) { case 'b': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { hbool_t bool = va_arg (ap, hbool_t); if (TRUE==bool) fprintf (out, "TRUE"); else if (!bool) fprintf (out, "FALSE"); else fprintf (out, "TRUE(%u)", (unsigned)bool); } break; case 'd': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { double dbl = va_arg (ap, double); fprintf (out, "%g", dbl); } break; case 'D': switch (type[1]) { case 'l': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5D_layout_t layout = va_arg (ap, H5D_layout_t); switch (layout) { case H5D_LAYOUT_ERROR: fprintf (out, "H5D_LAYOUT_ERROR"); break; case H5D_COMPACT: fprintf (out, "H5D_COMPACT"); break; case H5D_CONTIGUOUS: fprintf (out, "H5D_CONTIGUOUS"); break; case H5D_CHUNKED: fprintf (out, "H5D_CHUNKED"); break; default: fprintf (out, "%ld", (long)layout); break; } } break; case 't': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5D_transfer_t transfer = va_arg (ap, H5D_transfer_t); switch (transfer) { case H5D_XFER_INDEPENDENT: fprintf (out, "H5D_XFER_INDEPENDENT"); break; case H5D_XFER_COLLECTIVE: fprintf (out, "H5D_XFER_COLLECTIVE"); break; case H5D_XFER_DFLT: fprintf (out, "H5D_XFER_DFLT"); break; default: fprintf (out, "%ld", (long)transfer); break; } } break; default: fprintf (out, "BADTYPE(D%c)", type[1]); goto error; } break; case 'e': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { herr_t status = va_arg (ap, herr_t); if (status>=0) fprintf (out, "SUCCEED"); else if (status<0) fprintf (out, "FAIL"); else fprintf (out, "%d", (int)status); } break; case 'E': switch (type[1]) { case 'd': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5E_direction_t direction = va_arg (ap, H5E_direction_t); switch (direction) { case H5E_WALK_UPWARD: fprintf (out, "H5E_WALK_UPWARD"); break; case H5E_WALK_DOWNWARD: fprintf (out, "H5E_WALK_DOWNWARD"); break; default: fprintf (out, "%ld", (long)direction); break; } } break; case 'e': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5E_error_t *error = va_arg (ap, H5E_error_t*); fprintf (out, "0x%lx", (unsigned long)error); } break; default: fprintf (out, "BADTYPE(E%c)", type[1]); goto error; } break; case 'F': switch (type[1]) { case 'd': if (ptr) { if (vp) { fprintf(out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5F_driver_t driver = va_arg(ap, H5F_driver_t); switch (driver) { case H5F_LOW_ERROR: fprintf(out, "H5F_LOW_ERROR"); break; case H5F_LOW_STDIO: fprintf(out, "H5F_LOW_STDIO"); break; case H5F_LOW_SEC2: fprintf(out, "H5F_LOW_SEC2"); break; case H5F_LOW_MPIO: fprintf(out, "H5F_LOW_MPIO"); break; case H5F_LOW_CORE: fprintf(out, "H5F_LOW_CORE"); break; case H5F_LOW_SPLIT: fprintf(out, "H5F_LOW_SPLIT"); break; case H5F_LOW_FAMILY: fprintf(out, "H5F_LOW_FAMILY"); break; default: fprintf(out, "%ld", (long)driver); break; } } break; case 's': if (ptr) { if (vp) { fprintf(out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5F_scope_t scope = va_arg(ap, H5F_scope_t); switch (scope) { case H5F_SCOPE_LOCAL: fprintf(out, "H5F_SCOPE_LOCAL"); break; case H5F_SCOPE_GLOBAL: fprintf(out, "H5F_SCOPE_GLOBAL"); break; case H5F_SCOPE_DOWN: fprintf(out, "H5F_SCOPE_DOWN " "/*FOR INTERNAL USE ONLY!*/"); break; } } break; default: fprintf(out, "BADTYPE(F%c)", type[1]); goto error; } break; case 'G': switch (type[1]) { case 'l': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5G_link_t link_type = va_arg (ap, H5G_link_t); switch (link_type) { case H5G_LINK_ERROR: fprintf (out, "H5G_LINK_ERROR"); break; case H5G_LINK_HARD: fprintf (out, "H5G_LINK_HARD"); break; case H5G_LINK_SOFT: fprintf (out, "H5G_LINK_SOFT"); break; default: fprintf (out, "%ld", (long)link_type); break; } } break; case 's': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); } else { fprintf(out, "NULL"); } } else { H5G_stat_t *statbuf = va_arg (ap, H5G_stat_t*); fprintf (out, "0x%lx", (unsigned long)statbuf); } break; default: fprintf (out, "BADTYPE(G%c)", type[1]); goto error; } break; case 'h': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); if (asize_idx>=0 && asize[asize_idx]>=0) { hsize_t *p = (hsize_t*)vp; fprintf(out, " {"); for (i=0; i=0 && asize[asize_idx]>=0) { hssize_t *p = (hssize_t*)vp; fprintf(out, " {"); for (i=0; iextent.type) { asize[argno] = space->extent.u.simple.rank; } } break; case H5I_DATASET: fprintf(out, "%ld", (long)obj); if (HDstrcmp (argname, "dset")) { fprintf (out, " (dset)"); } break; case H5I_ATTR: fprintf(out, "%ld", (long)obj); if (HDstrcmp (argname, "attr")) { fprintf (out, " (attr)"); } break; case H5I_TEMPBUF: fprintf(out, "%ld", (long)obj); if (HDstrcmp(argname, "tbuf")) { fprintf(out, " (tbuf"); } break; case H5I_RAGGED: fprintf(out, "%ld", (long)obj); if (HDstrcmp(argname, "array")) { fprintf(out, " (array)"); } break; default: fprintf(out, "%ld", (long)obj); fprintf (out, " (unknown class)"); break; } } } break; case 'I': switch (type[1]) { case 's': if (ptr) { if (vp) { fprintf (out, "0x%lx", (unsigned long)vp); if (asize_idx>=0 && asize[asize_idx]>=0) { int *p = (int*)vp; fprintf(out, " {"); for (i=0; i=0 && asize[asize_idx]>=0) { int *p = (int*)vp; fprintf(out, " {"); for (i=0; i=0 && asize[asize_idx]>=0) { void **p = (void**)vp; fprintf(out, " {"); for (i=0; i=0 && asize[asize_idx]>=0) { size_t *p = (size_t*)vp; fprintf(out, " {"); for (i=0; i=0 && asize[asize_idx]>=0) { ssize_t *p = (ssize_t*)vp; fprintf(out, " {"); for (i=0; i