/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Programmer: Bill Wendling * Tuesday, 6. March 2001 */ /* * Portions of this work are derived from _Obfuscated C and Other Mysteries_, * by Don Libes, copyright (c) 1993 by John Wiley & Sons, Inc. */ #include #include #include #include #include "h5tools_utils.h" #include "H5private.h" /* global variables */ int nCols = 80; /* ``get_option'' variables */ int opt_err = 1; /*get_option prints errors if this is on */ int opt_ind = 1; /*token pointer */ const char *opt_arg; /*flag argument (or value) */ /* local functions */ static void init_table(table_t **tbl); #ifdef H5DUMP_DEBUG static void dump_table(char* tablename, table_t *table); #endif /* H5DUMP_DEBUG */ static void add_obj(table_t *table, haddr_t objno, char *objname, hbool_t recorded); static char * build_obj_path_name(const char *prefix, const char *name); static herr_t find_objs_cb(hid_t group, const char *name, const H5L_info_t *info, void *op_data); /*------------------------------------------------------------------------- * Function: error_msg * * Purpose: Print a nicely formatted error message to stderr flushing the * stdout stream first. * * Return: Nothing * * Programmer: Bill Wendling * Tuesday, 20. February 2001 * * Modifications: * *------------------------------------------------------------------------- */ void error_msg(const char *progname, const char *fmt, ...) { va_list ap; va_start(ap, fmt); HDfflush(stdout); HDfprintf(stderr, "%s error: ", progname); HDvfprintf(stderr, fmt, ap); va_end(ap); } /*------------------------------------------------------------------------- * Function: warn_msg * * Purpose: Print a nicely formatted warning message to stderr flushing * the stdout stream first. * * Return: Nothing * * Programmer: Bill Wendling * Tuesday, 20. February 2001 * * Modifications: * *------------------------------------------------------------------------- */ void warn_msg(const char *progname, const char *fmt, ...) { va_list ap; va_start(ap, fmt); HDfflush(stdout); #ifdef _WIN32 HDfprintf(stdout, "%s warning: ", progname); HDvfprintf(stdout, fmt, ap); #else /* _WIN32 */ HDfprintf(stderr, "%s warning: ", progname); HDvfprintf(stderr, fmt, ap); #endif /* _WIN32 */ va_end(ap); } /*------------------------------------------------------------------------- * Function: 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. * * Programmer: Bill Wendling * Friday, 5. January 2001 * * Modifications: * *------------------------------------------------------------------------- */ int get_option(int argc, const char **argv, const char *opts, const struct long_options *l_opts) { static int sp = 1; /* character index in current token */ int opt_opt = '?'; /* option character passed back to user */ if (sp == 1) { /* check for more flag-like tokens */ if (opt_ind >= argc || argv[opt_ind][0] != '-' || argv[opt_ind][1] == '\0') { return EOF; } else if (HDstrcmp(argv[opt_ind], "--") == 0) { opt_ind++; return EOF; } } if (sp == 1 && argv[opt_ind][0] == '-' && argv[opt_ind][1] == '-') { /* long command line option */ const char *arg = &argv[opt_ind][2]; int i; for (i = 0; l_opts && l_opts[i].name; i++) { size_t len = HDstrlen(l_opts[i].name); if (HDstrncmp(arg, l_opts[i].name, len) == 0) { /* we've found a matching long command line flag */ opt_opt = l_opts[i].shortval; if (l_opts[i].has_arg != no_arg) { if (arg[len] == '=') { opt_arg = &arg[len + 1]; } else if (opt_ind < (argc - 1) && argv[opt_ind + 1][0] != '-') { opt_arg = argv[++opt_ind]; } else if (l_opts[i].has_arg == require_arg) { if (opt_err) HDfprintf(stderr, "%s: option required for \"--%s\" flag\n", argv[0], arg); opt_opt = '?'; } } else { if (arg[len] == '=') { if (opt_err) HDfprintf(stderr, "%s: no option required for \"%s\" flag\n", argv[0], arg); opt_opt = '?'; } opt_arg = NULL; } break; } } if (l_opts[i].name == NULL) { /* exhausted all of the l_opts we have and still didn't match */ if (opt_err) HDfprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], arg); opt_opt = '?'; } opt_ind++; sp = 1; } else { register char *cp; /* pointer into current token */ /* short command line option */ opt_opt = argv[opt_ind][sp]; if (opt_opt == ':' || (cp = strchr(opts, opt_opt)) == 0) { if (opt_err) HDfprintf(stderr, "%s: unknown option \"%c\"\n", argv[0], opt_opt); /* if no chars left in this token, move to next token */ if (argv[opt_ind][++sp] == '\0') { opt_ind++; sp = 1; } return '?'; } if (*++cp == ':') { /* if a value is expected, get it */ if (argv[opt_ind][sp + 1] != '\0') { /* flag value is rest of current token */ opt_arg = &argv[opt_ind++][sp + 1]; } else if (++opt_ind >= argc) { if (opt_err) HDfprintf(stderr, "%s: value expected for option \"%c\"\n", argv[0], opt_opt); opt_opt = '?'; } else { /* flag value is next token */ opt_arg = argv[opt_ind++]; } sp = 1; } else { /* set up to look at next char in token, next time */ if (argv[opt_ind][++sp] == '\0') { /* no more in current token, so setup next token */ opt_ind++; sp = 1; } opt_arg = NULL; } } /* return the current flag character found */ return opt_opt; } /*------------------------------------------------------------------------- * Function: indentation * * Purpose: Print spaces for indentation * * Return: void * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ void indentation(int x) { if (x < nCols) { while (x-- > 0) printf(" "); } else { HDfprintf(stderr, "error: the indentation exceeds the number of cols.\n"); exit(1); } } /*------------------------------------------------------------------------- * Function: print_version * * Purpose: Print the program name and the version information which is * defined the same as the HDF5 library version. * * Return: void * * Programmer: unknown * * Modifications: * *------------------------------------------------------------------------- */ void print_version(const char *progname) { printf("%s: Version %u.%u.%u%s%s\n", progname, H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE, H5_VERS_SUBRELEASE[0] ? "-" : "", H5_VERS_SUBRELEASE); } /*------------------------------------------------------------------------- * Function: init_table * * Purpose: allocate and initialize tables for shared groups, datasets, * and committed types * * Return: void * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ static void init_table(table_t **tbl) { table_t *table = HDmalloc(sizeof(table_t)); table->size = 20; table->nobjs = 0; table->objs = HDmalloc(table->size * sizeof(obj_t)); *tbl = table; } /*------------------------------------------------------------------------- * Function: free_table * * Purpose: free tables for shared groups, datasets, * and committed types * * Return: void * * Programmer: Paul Harten * * Modifications: * *------------------------------------------------------------------------- */ void free_table(table_t *table) { unsigned u; /* Local index value */ /* Free the names for the objects in the table */ for(u = 0; u < table->nobjs; u++) if(table->objs[u].objname) HDfree(table->objs[u].objname); HDfree(table->objs); } #ifdef H5DUMP_DEBUG /*------------------------------------------------------------------------- * Function: dump_table * * Purpose: display the contents of tables for debugging purposes * * Return: void * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ static void dump_table(char* tablename, table_t *table) { unsigned u; printf("%s: # of entries = %d\n", tablename,table->nobjs); for (u = 0; u < table->nobjs; u++) HDfprintf(stdout,"%a %s %d %d\n", table->objs[u].objno, table->objs[u].objname, table->objs[u].displayed, table->objs[u].recorded); } /*------------------------------------------------------------------------- * Function: dump_tables * * Purpose: display the contents of tables for debugging purposes * * Return: void * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ void dump_tables(find_objs_t *info) { dump_table("group_table", info->group_table); dump_table("dset_table", info->dset_table); dump_table("type_table", info->type_table); } #endif /* H5DUMP_DEBUG */ /*------------------------------------------------------------------------- * Function: search_obj * * Purpose: search the object specified by objno in the table * * Return: Success: an integer, the location of the object * * Failure: FAIL if object is not found * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ obj_t * search_obj(table_t *table, haddr_t objno) { unsigned u; for (u = 0; u < table->nobjs; u++) if (table->objs[u].objno == objno) return &(table->objs[u]); return NULL; } /*------------------------------------------------------------------------- * Function: build_obj_path_name * * Purpose: Allocate space & build path name from prefix & name * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Quincey Koziol * * Modifications: * *------------------------------------------------------------------------- */ static char * build_obj_path_name(const char *prefix, const char *name) { char *path; path = HDmalloc(HDstrlen(prefix) + HDstrlen(name) + 2); HDstrcpy(path, prefix); HDstrcat(path,"/"); HDstrcat(path,name); /* absolute name of the data set */ return(path); } /* end build_obj_path_name() */ /*------------------------------------------------------------------------- * Function: find_objs_cb * * Purpose: Callback to find objects, committed types and store them in tables * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ static herr_t find_objs_cb(hid_t group, const char *name, const H5L_info_t UNUSED *linfo, void *op_data) { H5O_info_t oinfo; find_objs_t *info = (find_objs_t*)op_data; herr_t ret_value = 0; if(H5Oget_info(group, name, &oinfo, H5P_DEFAULT) < 0) ; /* keep going */ else { switch(oinfo.type) { char *tmp; size_t tmp_len; case H5O_TYPE_GROUP: if(search_obj(info->group_table, oinfo.addr) == NULL) { char *old_prefix; tmp = build_obj_path_name(info->prefix, name); add_obj(info->group_table, oinfo.addr, tmp, TRUE); old_prefix = info->prefix; tmp_len = HDstrlen(tmp); info->prefix = HDmalloc(tmp_len+1); HDstrcpy(info->prefix, tmp); if(H5Literate(group, name, H5_INDEX_NAME, H5_ITER_INC, NULL, find_objs_cb, (void *)info, H5P_DEFAULT) < 0) ret_value = FAIL; info->prefix = old_prefix; } /* end if */ break; case H5O_TYPE_DATASET: if(search_obj(info->dset_table, oinfo.addr) == NULL) { hid_t dset; tmp = build_obj_path_name(info->prefix, name); add_obj(info->dset_table, oinfo.addr, tmp, TRUE); if((dset = H5Dopen (group, name)) >= 0) { hid_t type; type = H5Dget_type(dset); if(H5Tcommitted(type) > 0) { H5Oget_info(type, ".", &oinfo, H5P_DEFAULT); if (search_obj(info->type_table, oinfo.addr) == NULL) { char *type_name = HDstrdup(tmp); add_obj(info->type_table, oinfo.addr, type_name, FALSE); } /* end if */ } /* end if */ H5Tclose(type); H5Dclose(dset); } /* end if */ else ret_value = FAIL; } /* end if */ break; case H5O_TYPE_NAMED_DATATYPE: { obj_t *found_obj; tmp = build_obj_path_name(info->prefix, name); if((found_obj = search_obj(info->type_table, oinfo.addr)) == NULL) add_obj(info->type_table, oinfo.addr, tmp, TRUE); else { /* Use latest version of name */ HDfree(found_obj->objname); found_obj->objname = HDstrdup(tmp); /* Mark named datatype as having valid name */ found_obj->recorded = TRUE; } /* end else */ break; } default: /* Ignore links, etc. */ break; } } /* end else */ return ret_value; } /*------------------------------------------------------------------------- * Function: init_objs * * Purpose: Initialize tables for groups, datasets & named datatypes * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ herr_t init_objs(hid_t fid, find_objs_t *info, table_t **group_table, table_t **dset_table, table_t **type_table) { H5O_info_t oinfo; /* Initialize the tables */ init_table(group_table); init_table(dset_table); init_table(type_table); /* Init the find_objs_t */ info->prefix = HDcalloc(1, 1); info->group_table = *group_table; info->type_table = *type_table; info->dset_table = *dset_table; /* add the root group as an object, it may have hard links to it */ if(H5Oget_info(fid, "/", &oinfo, H5P_DEFAULT) < 0) return FAIL; else { /* call with an empty string, it appends '/' group separator */ char *tmp = build_obj_path_name(info->prefix, ""); add_obj(info->group_table, oinfo.addr, tmp, TRUE); } /* end else */ /* Find all shared objects */ return(H5Literate(fid, "/", H5_INDEX_NAME, H5_ITER_INC, NULL, find_objs_cb, (void *)info, H5P_DEFAULT)); } /*------------------------------------------------------------------------- * Function: add_obj * * Purpose: add a shared object to the table * realloc the table if necessary * * Return: void * * Programmer: Ruey-Hsia Li * * Modifications: * *------------------------------------------------------------------------- */ static void add_obj(table_t *table, haddr_t objno, char *objname, hbool_t record) { unsigned u; /* See if we need to make table larger */ if (table->nobjs == table->size) { table->size *= 2; table->objs = HDrealloc(table->objs, table->size * sizeof(obj_t)); } /* Increment number of objects in table */ u = table->nobjs++; /* Set information about object */ table->objs[u].objno = objno; table->objs[u].objname = objname; table->objs[u].recorded = record; table->objs[u].displayed = 0; } #ifndef H5_HAVE_TMPFILE /*------------------------------------------------------------------------- * Function: tmpfile * * Purpose: provide tmpfile() function when it is not supported by the * system. Always return NULL for now. * * Return: a stream description when succeeds. * NULL if fails. * * Programmer: Albert Cheng, 2005/8/9 * * Modifications: * *------------------------------------------------------------------------- */ FILE * tmpfile(void) { return NULL; } #endif