diff --git a/include/ncplugins.h b/include/ncplugins.h index b82a174f19..d01e5a72e9 100644 --- a/include/ncplugins.h +++ b/include/ncplugins.h @@ -11,6 +11,9 @@ For internal use only. #ifndef NCPLUGINS_H #define NCPLUGINS_H +/* Opaque */ +struct NCPluginList; + #if defined(__cplusplus) extern "C" { #endif @@ -18,15 +21,14 @@ extern "C" { EXTERNL int NCZ_plugin_path_initialize(void); EXTERNL int NCZ_plugin_path_finalize(void); -EXTERNL int NCZ_plugin_path_get(size_t* ndirsp, char** dirs); -EXTERNL int NCZ_plugin_path_set(size_t ndirs, char** const dirs); +EXTERNL int NCZ_plugin_path_get(struct NCPluginList* dirs); +EXTERNL int NCZ_plugin_path_set(struct NCPluginList* dirs); EXTERNL int NC4_hdf5_plugin_path_initialize(void); EXTERNL int NC4_hdf5_plugin_path_finalize(void); -EXTERNL int NC4_hdf5_plugin_path_get(size_t* ndirsp, char** dirs); -EXTERNL int NC4_hdf5_plugin_path_set(size_t ndirs, char** const dirs); - +EXTERNL int NC4_hdf5_plugin_path_get(struct NCPluginList* dirs); +EXTERNL int NC4_hdf5_plugin_path_set(struct NCPluginList* dirs); #if defined(__cplusplus) } diff --git a/include/netcdf_aux.h b/include/netcdf_aux.h index 3b577b95a7..d025ce6aa9 100644 --- a/include/netcdf_aux.h +++ b/include/netcdf_aux.h @@ -99,6 +99,9 @@ EXTERNL int ncaux_add_field(void* tag, const char *name, nc_type field_type, /**************************************************/ /* Path-list Utilities */ +/* Opaque */ +struct NCPluginList; + /** Parse a string into a sequence of path directories. @@ -110,17 +113,17 @@ The pathlist argument has the following syntax: @param pathlist a string encoding a list of directories @param sep one of ';' | ':' | '\0' where '\0' means use the platform's default separator. -@param ndirsp return the number of directories in dirsp -@param dirsp return a vector of strings representing the directories parsed from pathlist; caller frees -@return ::NC_NOERR +@param dirs a pointer to an NCPluginPath object for returning the number and vector of directories from the parse. +@return ::NC_NOERR | NC_EXXX -Note that this function is called twice: first time to get the number of directories -and second to get the directories. +Note: If dirs->dirs is not NULL, then this function +will allocate the space for the vector of directory path. +The user is then responsible for free'ing that vector +(or call ncaux_plugin_path_reclaim). Author: Dennis Heimbigner */ - -EXTERNL int ncaux_plugin_path_parse(const char* pathlist, char sep, size_t* ndirsp, char** dirs); +EXTERNL int ncaux_plugin_path_parse(const char* pathlist, char sep, struct NCPluginList* dirs); /** Concatenate a vector of directories with the separator between. @@ -132,37 +135,65 @@ The resulting string has following syntax: separator := ';' | ':' dir := -@param ndirs the number of directories -@param dirsp the directory vector to concatenate +@param dirs a pointer to an NCPluginList object giving the number and vector of directories to concatenate. @param sep one of ';', ':', or '\0' @param catlen length of the cat arg including a nul terminator @param cat user provided space for holding the concatenation; nul termination guaranteed if catlen > 0. @return ::NC_NOERR @return ::NC_EINVAL for illegal arguments -Note that this function is called twice: first time to get the expected size of -the concatenated string and second to get the contents of the concatenation. +Note: If dirs->dirs is not NULL, then this function +will allocate the space for the vector of directory path. +The user is then responsible for free'ing that vector +(or call ncaux_plugin_path_reclaim). Author: Dennis Heimbigner */ +EXTERNL int ncaux_plugin_path_tostring(const struct NCPluginList* dirs, char sep, char** catp); -EXTERNL int ncaux_plugin_path_tostring(size_t ndirs, char** const dirs, char sep, size_t* catlen, char* cat); +/* +Clear the contents of a NCPluginList object. +@param dirs a pointer to an NCPluginList object giving the number and vector of directories to reclaim +@return ::NC_NOERR +@return ::NC_EINVAL for illegal arguments +Author: Dennis Heimbigner +*/ +EXTERNL int ncaux_plugin_path_clear(struct NCPluginList* dirs); /* -Reclaim a char** object possibly produced by ncaux_plugin_parse function. +Reclaim a NCPluginList object possibly produced by ncaux_plugin_parse function. +WARNING: do not call with a static or stack allocated object. +@param dirs a pointer to an NCPluginList object giving the number and vector of directories to reclaim +@return ::NC_NOERR +@return ::NC_EINVAL for illegal arguments -@param veclen the number of entries in vec -@param vec a char** vectore +Author: Dennis Heimbigner +*/ +EXTERNL int ncaux_plugin_path_reclaim(struct NCPluginList* dirs); + +/* +Modify a plugin path set to append a new directory to the end. +@param dirs a pointer to an NCPluginList object giving the number and vector of directories to which 'dir' argument is appended. @return ::NC_NOERR @return ::NC_EINVAL for illegal arguments + +Author: Dennis Heimbigner */ +EXTERNL int ncaux_plugin_path_append(struct NCPluginList* dirs, const char* dir); -EXTERNL int ncaux_plugin_path_freestringvec(size_t veclen, char** vec); +/* +Modify a plugin path set to prepend a new directory to the front. +@param dirs a pointer to an NCPluginList object giving the number and vector of directories to which 'dir' argument is appended. +@return ::NC_NOERR +@return ::NC_EINVAL for illegal arguments + +Author: Dennis Heimbigner +*/ +EXTERNL int ncaux_plugin_path_prepend(struct NCPluginList* dirs, const char* dir); #if defined(__cplusplus) } #endif #endif /*NCAUX_H*/ - diff --git a/include/netcdf_filter.h b/include/netcdf_filter.h index 83afad7d70..eefddf581f 100644 --- a/include/netcdf_filter.h +++ b/include/netcdf_filter.h @@ -113,39 +113,51 @@ EXTERNL int nc_inq_var_blosc(int ncid, int varid, int* hasfilterp, unsigned* sub /* Filter path query/set */ EXTERNL int nc_filter_path_query(int id); +#if defined(__cplusplus) +} +#endif + /**************************************************/ /* API for libdispatch/dplugin.c */ +/* Combine the vector of directory path plus it's length in a single struct. */ +typedef struct NCPluginList { + size_t ndirs; /* |dirs| */ + char** dirs; +} NCPluginList; + /* Externally visible plugin path functions */ +#if defined(__cplusplus) +extern "C" { +#endif /** - * Return the current sequence of directories in the internal plugin path list. - * Since this function does not modify the plugin path, it can be called at any time. - * @param ndirsp return the number of dirs in the internal path list - * @param dirs memory for storing the sequence of directies in the internal path list. - * @return NC_NOERR + * Return the current sequence of directories in the internal global + * plugin path list. Since this function does not modify the plugin path, + * it can be called at any time. + * @param dirs pointer to an NCPluginList object + * @return NC_NOERR | NC_EXXX * @author Dennis Heimbigner * - * As a rule, this function needs to be called twice. - * The first time with npaths not NULL and pathlist set to NULL - * to get the size of the path list. - * The second time with pathlist not NULL to get the actual sequence of paths. + * WARNING: if dirs->dirs is NULL, then space for the directory + * vector will be allocated. If not NULL, then the specified space will + * be overwritten with the vector. + * + * Author: Dennis Heimbigner */ - -EXTERNL int nc_plugin_path_get(size_t* ndirsp, char** dirs); +EXTERNL int nc_plugin_path_get(NCPluginList* dirs); /** * Empty the current internal path sequence * and replace with the sequence of directories argument. * * Using a paths argument of NULL or npaths argument of 0 will clear the set of plugin paths. - * @param ndirs length of the dirs argument - * @param dirs to overwrite the current internal path list - * @return NC_NOERR + * @param dirs pointer to an NCPluginList object containing + * the number and vector of directory paths + * @return NC_NOERR | NC_EXXX * @author Dennis Heimbigner */ - -EXTERNL int nc_plugin_path_set(size_t ndirs, char** const dirs); +EXTERNL int nc_plugin_path_set(NCPluginList* dirs); #if defined(__cplusplus) } diff --git a/libdispatch/daux.c b/libdispatch/daux.c index c1bf2b185e..728fb59b20 100644 --- a/libdispatch/daux.c +++ b/libdispatch/daux.c @@ -961,13 +961,17 @@ ncaux_dump_data(int ncid, int xtype, void* memory, size_t count, char** bufp) /* Path-list Parser: @param pathlist0 the string to parse -@param ndirsp return the number of parsed directories -@param dirs return the parsed directories; caller must free +@param dirs return the parsed directories -- see note below. @param sep the separator parsing: one of ';' | ':' | '\0', where zero means use platform default. @return NC_NOERR || NC_EXXX + +Note: If dirs->dirs is not NULL, then this function +will allocate the space for the vector of directory path. +The user is then responsible for free'ing that vector +(or call ncaux_plugin_path_reclaim). */ EXTERNL int -ncaux_plugin_path_parse(const char* pathlist0, char sep, size_t* ndirsp, char** dirs) +ncaux_plugin_path_parse(const char* pathlist0, char sep, NCPluginList* dirs) { int stat = NC_NOERR; size_t i; @@ -975,11 +979,11 @@ ncaux_plugin_path_parse(const char* pathlist0, char sep, size_t* ndirsp, char** char* p; size_t count; size_t plen; - NClist* vec = nclistnew(); char seps[3] = "\0\0\0"; /* will contain all allowable separators */ - if(pathlist0 == NULL || pathlist0[0] == '\0') {if(ndirsp) *ndirsp = 0; goto done;} + if(dirs == NULL) {stat = NC_EINVAL; goto done;} + if(pathlist0 == NULL || pathlist0[0] == '\0') {dirs->ndirs = 0; goto done;} /* If a separator is specified, use it, otherwise search for ';' or ':' */ seps[0] = sep; @@ -1000,23 +1004,22 @@ ncaux_plugin_path_parse(const char* pathlist0, char sep, size_t* ndirsp, char** } count++; /* count last piece */ + /* Save and allocate */ + dirs->ndirs = count; + if(dirs->dirs == NULL) { + if((dirs->dirs = (char**)calloc(count,sizeof(char*)))==NULL) + {stat = NC_ENOMEM; goto done;} + } + /* capture the parsed pieces */ for(p=path,i=0;i 0) - nclistpush(vec, p); /* use the contents of path */ + dirs->dirs[i] = strdup(p); p = p+len+1; /* point to next piece */ } - if(dirs) { - for(i=0;i 0. +@param catp return the concatenation; WARNING: caller frees. @return ::NC_NOERR @return ::NC_EINVAL for illegal arguments - -Note that this function is called twice: first time to get the expected size of -the concatenated string and second to get the contents of the concatenation. */ EXTERNL int -ncaux_plugin_path_tostring(size_t ndirs, char** const dirs, char sep, size_t* catlen, char* cat) +ncaux_plugin_path_tostring(const NCPluginList* dirs, char sep, char** catp) { int stat = NC_NOERR; NCbytes* buf = ncbytesnew(); size_t i; + if(dirs == NULL) {stat = NC_EINVAL; goto done;} + if(dirs->ndirs > 0 && dirs->dirs == NULL) {stat = NC_EINVAL; goto done;} + if(sep == '\0') #ifdef _WIN32 sep = ';'; #else sep = ':'; #endif - if(cat != NULL) *cat = '\0'; /* Make sure it is nul terminated */ - if(ndirs > 0) { - for(i=0;indirs > 0) { + for(i=0;indirs;i++) { if(i>0) ncbytesappend(buf,sep); - if(dirs[i] != NULL) ncbytescat(buf,dirs[i]); + if(dirs->dirs[i] != NULL) ncbytescat(buf,dirs->dirs[i]); } } ncbytesnull(buf); - if(cat) - memcpy(cat,ncbytescontents(buf),ncbyteslength(buf)+1); /* include nul termiator */ - if(catlen) *catlen = ncbyteslength(buf)+1; /* overwrite with the true cat length */ + if(catp) *catp = ncbytesextract(buf); +done: ncbytesfree(buf); return stat; } /* -Reclaim a char** object possibly produced by ncaux_plugin_parse function. - -@param veclen the number of entries in vec -@param vec a char** vectore +Clear an NCPluginList object possibly produced by ncaux_plugin_parse function. +@param dirs the object to clear @return ::NC_NOERR @return ::NC_EINVAL for illegal arguments */ EXTERNL int -ncaux_plugin_path_freestringvec(size_t veclen, char** vec) +ncaux_plugin_path_clear(NCPluginList* dirs) { int stat = NC_NOERR; size_t i; - if(vec == NULL) goto done; - for(i=0;indirs == 0 || dirs->dirs == NULL) goto done; + for(i=0;indirs;i++) { + if(dirs->dirs[i] != NULL) free(dirs->dirs[i]); + dirs->dirs[i] = NULL; } - free(vec); + free(dirs->dirs); + dirs->dirs = NULL; + dirs->ndirs = 0; +done: + return stat; +} + +/* +Reclaim an NCPluginList object. +@param dir the object to reclaim +@return ::NC_NOERR +@return ::NC_EINVAL for illegal arguments +*/ +EXTERNL int +ncaux_plugin_path_reclaim(NCPluginList* dirs) +{ + int stat = NC_NOERR; + if((stat = ncaux_plugin_path_clear(dirs))) goto done; + nullfree(dirs); +done: + return stat; +} + +/* +Modify a plugin path set to append a new directory to the end. +@param dirs a pointer to an NCPluginPath object giving the number and vector of directories to which 'dir' argument is appended. +@return ::NC_NOERR +@return ::NC_EINVAL for illegal arguments + +WARNING: dirs->dirs may be reallocated. + +Author: Dennis Heimbigner +*/ + +EXTERNL int +ncaux_plugin_path_append(NCPluginList* dirs, const char* dir) +{ + int stat = NC_NOERR; + char** newdirs = NULL; + char** olddirs = NULL; + if(dirs == NULL || dir == NULL) {stat = NC_EINVAL; goto done;} + olddirs = dirs->dirs; dirs->dirs = NULL; + if((newdirs = (char**)calloc(dirs->ndirs+1,sizeof(char*)))==NULL) + {stat = NC_ENOMEM; goto done;} + if(dirs->ndirs > 0) + memcpy(newdirs,olddirs,sizeof(char*)*dirs->ndirs); + nullfree(olddirs); + dirs->dirs = newdirs; newdirs = NULL; + dirs->dirs[dirs->ndirs] = nulldup(dir); + dirs->ndirs++; +done: + return stat; +} + +/* +Modify a plugin path set to prepend a new directory to the front. +@param dirs a pointer to an NCPluginList object giving the number and vector of directories to which 'dir' argument is appended. +@return ::NC_NOERR +@return ::NC_EINVAL for illegal arguments + +WARNING: dirs->dirs may be reallocated. + +Author: Dennis Heimbigner +*/ +EXTERNL int +ncaux_plugin_path_prepend(struct NCPluginList* dirs, const char* dir) +{ + int stat = NC_NOERR; + char** newdirs = NULL; + char** olddirs = NULL; + if(dirs == NULL || dir == NULL) {stat = NC_EINVAL; goto done;} + olddirs = dirs->dirs; dirs->dirs = NULL; + if((newdirs = (char**)calloc(dirs->ndirs+1,sizeof(char*)))==NULL) + {stat = NC_ENOMEM; goto done;} + if(dirs->ndirs > 0) + memcpy(&newdirs[1],olddirs,sizeof(char*)*dirs->ndirs); + nullfree(olddirs); + dirs->dirs = newdirs; newdirs = NULL; + dirs->dirs[0] = nulldup(dir); + dirs->ndirs++; done: return stat; } diff --git a/libdispatch/dinfermodel.c b/libdispatch/dinfermodel.c index 938dc00089..adb3f13779 100644 --- a/libdispatch/dinfermodel.c +++ b/libdispatch/dinfermodel.c @@ -1642,7 +1642,6 @@ isdaoscontainer(const char* path) #else (void)getxattr(path, p, xvalue, (size_t)xlen); #endif -fprintf(stderr,"@@@ %s=|%s|\n",p,xvalue); /* Look for '.daos' in the value */ if(strstr(xvalue,".daos") != NULL) {rc = 1; break;} /* success */ } diff --git a/libdispatch/dpathmgr.c b/libdispatch/dpathmgr.c index 85b6c353a8..4e0a5fd631 100644 --- a/libdispatch/dpathmgr.c +++ b/libdispatch/dpathmgr.c @@ -729,7 +729,7 @@ NCstdbinary(void) if(_setmode(fd,_O_BINARY)<0) return NC_EINVAL; fd = _fileno(stdout); if(_setmode(fd,_O_BINARY)<0) return NC_EINVAL; - fd = _fileno(stdout); + fd = _fileno(stderr); if(_setmode(fd,_O_BINARY)<0) return NC_EINVAL; return NC_NOERR; } diff --git a/libdispatch/dplugins.c b/libdispatch/dplugins.c index 48b7281259..4044b44f42 100644 --- a/libdispatch/dplugins.c +++ b/libdispatch/dplugins.c @@ -42,6 +42,9 @@ Unified plugin related code /* Control path verification */ #define PLUGINPATHVERIFY "NC_PLUGIN_PATH_VERIFY" +/*Forward*/ +static int builddefault(NCPluginList* dirs); + static int NC_plugin_path_initialized = 0; static int NC_plugin_path_verify = 1; @@ -59,10 +62,8 @@ nc_plugin_path_initialize(void) { int stat = NC_NOERR; struct NCglobalstate* gs = NULL; - char* defaultpluginpath = NULL; - const char* pluginroots = NULL; - NClist* dirs = NULL; - size_t ndirs; + NCPluginList dirs = {0,NULL}; + int hdf5found = 0; /* 1 => we got a legit plugin path set from HDF5 */ if(!NC_initialized) nc_initialize(); if(NC_plugin_path_initialized != 0) goto done; @@ -71,42 +72,31 @@ nc_plugin_path_initialize(void) if(getenv(PLUGINPATHVERIFY) != NULL) NC_plugin_path_verify = 1; gs = NC_getglobalstate(); - dirs = nclistnew(); - - /* Setup the plugin path default */ - { -#ifdef _WIN32 - const char* win32_root; - char dfalt[4096]; - win32_root = getenv(WIN32_ROOT_ENV); - if(win32_root != NULL && strlen(win32_root) > 0) { - snprintf(dfalt,sizeof(dfalt),PLUGIN_DIR_WIN,win32_root); - defaultpluginpath = strdup(dfalt); - } -#else /*!_WIN32*/ - defaultpluginpath = strdup(PLUGIN_DIR_UNIX); -#endif - } - - /* Find the plugin directory root(s) */ - pluginroots = getenv(PLUGIN_ENV); /* Usually HDF5_PLUGIN_PATH */ - if(pluginroots != NULL && strlen(pluginroots) == 0) pluginroots = NULL; - if((stat = ncaux_plugin_path_parse(pluginroots,'\0',&ndirs,NULL))) goto done; - if(ndirs > 0) { - nclistsetlength(dirs,ndirs); - if((stat = ncaux_plugin_path_parse(pluginroots,'\0',&ndirs,(char**)nclistcontents(dirs)))) goto done; - } - /* Add the default to end of the dirs list if not already there */ - if(defaultpluginpath != NULL && !nclistmatch(dirs,defaultpluginpath,0)) { - nclistpush(dirs,defaultpluginpath); - defaultpluginpath = NULL; - } - - /* Set the current plugin dirs sequence */ - assert(gs->pluginpaths == NULL); - gs->pluginpaths = dirs; dirs = NULL; - /* Sync to the actual implementations */ + /** + * At startup, we have several potential plugin paths sources: + * 1. initial state of the HDF5 path + * 2. initial state of the NCZarr path + * 3. /usr/local/hdf5/plugin | %ALLUSERSPROFILE%/hdf5/lib/plugin + * 4. HDF5_PLUGIN_PATH + * + * On startup, we will have the following: + * a. HDF5 (via libhdf5) will combine (3) with (4) + * to produce some initial plugin path. + * b. If HDF5 is enabled, then the initial global plugin path + * will be the output of (a). + * c. If HDF5 is not enabled, then the initial global plugin path + * will be the following initial path: + * - For Windows: ${HDF5_PLUGIN_PATH};%ALLUSERSPROFILE%/hdf5/lib/plugin; + * - For *nix: ${HDF5_PLUGIN_PATH}:/usr/local/hdf5/plugin + * d. NCZarr will always be the same as the initial value of the + * global plugin path. + * + * Of course, if HDF5 is not enabled and NCZarr is not enabled, then + * the initial global plugin path is empty. + */ + + /* Initialize the implementations */ #ifdef NETCDF_ENABLE_NCZARR_FILTERS if((stat = NCZ_plugin_path_initialize())) goto done; #endif @@ -114,9 +104,30 @@ nc_plugin_path_initialize(void) if((stat = NC4_hdf5_plugin_path_initialize())) goto done; #endif +#ifdef USE_HDF5 + /* Case (a,b): Get the initial HDF5 plugin path set */ + if((stat = NC4_hdf5_plugin_path_get(&dirs))) goto done; + if(dirs.ndirs > 0) hdf5found = 1; +#endif /*USE_HDF5*/ + + if(!hdf5found) { /* Case: (c) HDF5 not enabled or otherwise empty */ + if((stat = builddefault(&dirs))) goto done; /* Construct a default */ + } + + /* Sync to the actual implementations */ +#ifdef USE_HDF5 + if(!hdf5found) + {if((stat = NC4_hdf5_plugin_path_set(&dirs))) goto done;} +#endif +#ifdef NETCDF_ENABLE_NCZARR_FILTERS + if((stat = NCZ_plugin_path_set(&dirs))) goto done; +#endif + /* Set the global plugin dirs sequence */ + assert(gs->pluginpaths == NULL); + gs->pluginpaths = nclistnew(); + nclistsetlength(gs->pluginpaths,dirs.ndirs); + memcpy(((char**)gs->pluginpaths->content),dirs.dirs,dirs.ndirs*sizeof(char*)); done: - nullfree(defaultpluginpath); - nclistfreeall(dirs); return NCTHROW(stat); } @@ -154,115 +165,152 @@ nc_plugin_path_finalize(void) } /** - * Return the current sequence of directories in the internal plugin path list. - * Since this function does not modify the plugin path, it can be called at any time. - * @param ndirsp return the number of dirs in the internal path list - * @param dirs memory for storing the sequence of directies in the internal path list. - * @return NC_NOERR + * Return the current sequence of directories in the internal global + * plugin path list. Since this function does not modify the plugin path, + * it can be called at any time. + * @param dirs pointer to an NCPluginList object + * @return NC_NOERR | NC_EXXX * @author Dennis Heimbigner * - * As a rule, this function needs to be called twice. - * The first time with npaths not NULL and pathlist set to NULL - * to get the size of the path list. - * The second time with pathlist not NULL to get the actual sequence of paths. + * WARNING: if dirs->dirs is NULL, then space for the directory + * vector will be allocated. If not NULL, then the specified space will + * be overwritten with the vector. + * + * @author: Dennis Heimbigner */ int -nc_plugin_path_get(size_t* ndirsp, char** dirs) +nc_plugin_path_get(NCPluginList* dirs) { int stat = NC_NOERR; struct NCglobalstate* gs = NC_getglobalstate(); - size_t ndirs; + size_t i; if(gs->pluginpaths == NULL) gs->pluginpaths = nclistnew(); /* suspenders and belt */ - ndirs = nclistlength(gs->pluginpaths); - if(ndirsp) *ndirsp = ndirs; - if(dirs != NULL && ndirs > 0) { - size_t i; - for(i=0;ipluginpaths,i); - dirs[i] = nulldup(dir); - } + if(dirs == NULL) goto done; + dirs->ndirs = nclistlength(gs->pluginpaths); + if(dirs->dirs == NULL) { + if((dirs->dirs = (char**)calloc(dirs->ndirs,sizeof(char*)))==NULL) + {stat = NC_ENOMEM; goto done;} + } + for(i=0;indirs;i++) { + const char* dir = nclistget(gs->pluginpaths,i); + dirs->dirs[i] = nulldup(dir); } /* Verify that the implementation plugin paths are consistent */ if(NC_plugin_path_verify) { #ifdef NETCDF_ENABLE_HDF5 { - size_t i,impl_ndirs; - char** impl_dirs = NULL; - NC4_hdf5_plugin_path_get(&impl_ndirs,NULL); - assert(impl_ndirs == ndirs); - if(dirs != NULL) { - impl_dirs = (char**)calloc(ndirs,sizeof(char*)); /* Assume verify will succeed */ - NC4_hdf5_plugin_path_get(&impl_ndirs,impl_dirs); - for(i=0;ipluginpaths)); + for(i=0;idirs[i],l5.dirs[i])==0); + nullfree(l5.dirs[i]); } - nullfree(impl_dirs); } #endif /*NETCDF_ENABLE_HDF5*/ #ifdef NETCDF_ENABLE_HDF5 { - size_t i,impl_ndirs; - char** impl_dirs = NULL; - NC4_hdf5_plugin_path_get(&impl_ndirs,NULL); - assert(impl_ndirs == ndirs); - if(dirs != NULL) { - impl_dirs = (char**)calloc(ndirs,sizeof(char*)); /* Assume verify will succeed */ - NC4_hdf5_plugin_path_get(&impl_ndirs,impl_dirs); - for(i=0;ipluginpaths)); + for(i=0;idirs[i],lz.dirs[i])==0); + nullfree(lz.dirs[i]); } - nullfree(impl_dirs); } #endif /*NETCDF_ENABLE_HDF5*/ } - +done: return NCTHROW(stat); } /** * Empty the current internal path sequence * and replace with the sequence of directories argument. + * Using a dirs->ndirs argument of 0 will clear the set of plugin dirs. * - * Using a dirs argument of NULL or ndirs argument of 0 will clear the set of plugin dirs. - * @param ndirs length of the dirs argument * @param dirs to overwrite the current internal dir list - * @return NC_NOERR + * @return NC_NOERR | NC_EXXX + * * @author Dennis Heimbigner */ - int -nc_plugin_path_set(size_t ndirs, char** const dirs) +nc_plugin_path_set(NCPluginList* dirs) { int stat = NC_NOERR; struct NCglobalstate* gs = NC_getglobalstate(); + if(dirs == NULL) {stat = NC_EINVAL; goto done;} + /* Clear the current dir list */ nclistfreeall(gs->pluginpaths); gs->pluginpaths = nclistnew(); - if(ndirs > 0) { + if(dirs->ndirs > 0) { size_t i; assert(gs->pluginpaths != NULL); - for(i=0;ipluginpaths,nulldup(dirs[i])); + for(i=0;indirs;i++) { + nclistpush(gs->pluginpaths,nulldup(dirs->dirs[i])); } } /* Sync the global plugin path set to the individual implementations */ #ifdef NETCDF_ENABLE_HDF5 - if((stat = NC4_hdf5_plugin_path_set(ndirs,dirs))) goto done; + if((stat = NC4_hdf5_plugin_path_set(dirs))) goto done; #endif #ifdef NETCDF_ENABLE_NCZARR_FILTERS - if((stat = NCZ_plugin_path_set(ndirs,dirs))) goto done; + if((stat = NCZ_plugin_path_set(dirs))) goto done; #endif done: return NCTHROW(stat); } + +/* Setup the plugin path default */ +static int +builddefault(NCPluginList* dirs) +{ + int stat = NC_NOERR; + char* hdf5defaultpluginpath = NULL; + const char* pluginroots = NULL; + size_t i; +#ifdef _WIN32 + const char* win32_root; + char dfalt[4096]; +#endif + + /* Find the plugin directory root(s) */ + pluginroots = getenv(PLUGIN_ENV); /* Usually HDF5_PLUGIN_PATH */ + if(pluginroots != NULL) { + if((stat = ncaux_plugin_path_parse(pluginroots,'\0',dirs))) goto done; + } +#ifdef _WIN32 + win32_root = getenv(WIN32_ROOT_ENV); + if(win32_root != NULL && strlen(win32_root) > 0) { + snprintf(dfalt,sizeof(dfalt),PLUGIN_DIR_WIN,win32_root); + hdf5defaultpluginpath = strdup(dfalt); + } +#else /*!_WIN32*/ + hdf5defaultpluginpath = strdup(PLUGIN_DIR_UNIX); +#endif + /* Add the default to the end of the dirs list if not already there */ + if(hdf5defaultpluginpath != NULL) { + int found = 0; + for(i=0;indirs;i++) { + if(strcmp(dirs->dirs[i],hdf5defaultpluginpath)==0) + {found=1; break;} + } + if(!found) { + if((stat=ncaux_plugin_path_append(dirs,hdf5defaultpluginpath))) + goto done; + } + } +done: + nullfree(hdf5defaultpluginpath); + return stat; +} diff --git a/libhdf5/hdf5plugins.c b/libhdf5/hdf5plugins.c index 6f91203172..a070b14772 100644 --- a/libhdf5/hdf5plugins.c +++ b/libhdf5/hdf5plugins.c @@ -30,27 +30,21 @@ /**************************************************/ /** - * Return the current sequence of directories in the internal plugin path list - * maintained by the HDF5 library. Since this function does not modify the plugin path, + * Return the current sequence of directories in the internal global + * plugin path list. Since this function does not modify the plugin path, * it can be called at any time. - * @param ndirsp return the number of dirs in the internal path list - * @param dirs memory for storing the sequence of directies in the internal path list. - * @return NC_NOERR + * @param dirs pointer to an NCPluginList object + * @return NC_NOERR | NC_EXXX * @author Dennis Heimbigner * - * As a rule, this function needs to be called twice. - * The first time with npaths not NULL and pathlist set to NULL - * to get the size of the path list. - * The second time with pathlist not NULL to get the actual sequence of paths. + * WARNING: if dirs->dirs is NULL, then space for the directory + * vector will be allocated. If not NULL, then the specified space will + * be overwritten with the vector. * - * Technically, this function is not needed at all since in an ideal world - * the only way that the HDF5 path set can be changed is via the NC4_hdf5_plugin_path_set() - * function. However, this function is useful as a way to verify that someone has not - * been modifying the plugin path set directly through the HDF5 API. + * @author: Dennis Heimbigner */ - int -NC4_hdf5_plugin_path_get(size_t* ndirsp, char** dirs) +NC4_hdf5_plugin_path_get(NCPluginList* dirs) { int stat = NC_NOERR; unsigned i; @@ -59,20 +53,24 @@ NC4_hdf5_plugin_path_get(size_t* ndirsp, char** dirs) ssize_t dirlen; char* dirbuf = NULL; + if(dirs == NULL) {stat = NC_EINVAL; goto done;} + /* Get the length of the HDF5 plugin path set */ if((hstat = H5PLsize(&undirs))<0) goto done; - if(ndirsp) *ndirsp = (size_t)undirs; + dirs->ndirs = (size_t)undirs; /* Copy out the paths from the HDF5 library */ /* Watch out for nul term handling WRT dir string length */ - if(dirs != NULL) { - for(i=0;idirs == NULL) { + if((dirs->dirs=(char**)calloc(dirs->ndirs,sizeof(char*)))==NULL) + {stat = NC_ENOMEM; goto done;} + } + for(i=0;idirs[i] = dirbuf; dirbuf = NULL; } done: @@ -83,16 +81,15 @@ NC4_hdf5_plugin_path_get(size_t* ndirsp, char** dirs) /** * Empty the current internal path sequence * and replace with the sequence of directories argument. + * Using a dirs->ndirs argument of 0 will clear the set of plugin dirs. * - * Using a dirs argument of NULL or ndirs argument of 0 will clear the set of plugin dirs. - * @param ndirs length of the dirs argument * @param dirs to overwrite the current internal dir list - * @return NC_NOERR + * @return NC_NOERR | NC_EXXX + * * @author Dennis Heimbigner */ - int -NC4_hdf5_plugin_path_set(size_t ndirs, char** const dirs) +NC4_hdf5_plugin_path_set(NCPluginList* dirs) { int stat = NC_NOERR; size_t i; @@ -100,7 +97,8 @@ NC4_hdf5_plugin_path_set(size_t ndirs, char** const dirs) unsigned undirs = 0; /* validate */ - if(ndirs > 0 && dirs == NULL) {stat = NC_EINVAL; goto done;} + if(dirs == NULL || (dirs->ndirs > 0 && dirs->dirs == NULL)) + {stat = NC_EINVAL; goto done;} /* Clear the current path list */ if((hstat = H5PLsize(&undirs))<0) goto done; @@ -112,9 +110,10 @@ NC4_hdf5_plugin_path_set(size_t ndirs, char** const dirs) } /* Insert the new path list */ - for(i=0;indirs;i++) { /* Always append */ - if((hstat = H5PLappend(dirs[i]))<0) {stat = NC_EINVAL; goto done;} + if((hstat = H5PLappend(dirs->dirs[i]))<0) + {stat = NC_EINVAL; goto done;} } done: diff --git a/libnczarr/zplugins.c b/libnczarr/zplugins.c index 9399d16247..bfd7cf1368 100644 --- a/libnczarr/zplugins.c +++ b/libnczarr/zplugins.c @@ -119,73 +119,75 @@ NCZ_plugin_path_finalize(void) } /** - * Return the current sequence of directories in the internal plugin path list. - * Since this function does not modify the plugin path, it can be called at any time. - * @param ndirsp return the number of dirs in the internal path list - * @param dirs memory for storing the sequence of directies in the internal path list. - * @return NC_NOERR + * Return the current sequence of directories in the internal global + * plugin path list. Since this function does not modify the plugin path, + * it can be called at any time. + * @param dirs pointer to an NCPluginList object + * @return NC_NOERR | NC_EXXX * @author Dennis Heimbigner * - * As a rule, this function needs to be called twice. - * The first time with npaths not NULL and pathlist set to NULL - * to get the size of the path list. - * The second time with pathlist not NULL to get the actual sequence of paths. + * WARNING: if dirs->dirs is NULL, then space for the directory + * vector will be allocated. If not NULL, then the specified space will + * be overwritten with the vector. * - * Technically, this function is not needed at all since in an ideal world - * the only way that the NCZarr path set can be changed is via the NCZ_plugin_path_set() - * function. However, this function is useful as a way to verify that someone has not - * been modifying the plugin path set in some other fashion. + * @author: Dennis Heimbigner */ - int -NCZ_plugin_path_get(size_t* ndirsp, char** dirs) +NCZ_plugin_path_get(NCPluginList* dirs) { int stat = NC_NOERR; struct NCglobalstate* gs = NC_getglobalstate(); - size_t ndirs; + + if(dirs == NULL) {stat = NC_EINVAL; goto done;} if(gs->zarr.pluginpaths == NULL) gs->zarr.pluginpaths = nclistnew(); /* suspenders and belt */ - ndirs = nclistlength(gs->zarr.pluginpaths); - if(ndirsp) *ndirsp = ndirs; - if(dirs != NULL && ndirs > 0) { + + dirs->ndirs = nclistlength(gs->zarr.pluginpaths); + if(dirs->dirs == NULL && dirs->ndirs > 0) { + if((dirs->dirs = (char**)calloc(dirs->ndirs,sizeof(char*)))==NULL) + {stat = NC_ENOMEM; goto done;} + } + if(dirs->ndirs > 0) { size_t i; - for(i=0;indirs;i++) { const char* dir = (const char*)nclistget(gs->zarr.pluginpaths,i); - dirs[i] = nulldup(dir); + dirs->dirs[i] = nulldup(dir); } } - +done: return THROW(stat); } /** * Empty the current internal path sequence * and replace with the sequence of directories argument. + * Using a dirs->ndirs argument of 0 will clear the set of plugin dirs. * - * Using a dirs argument of NULL or ndirs argument of 0 will clear the set of plugin dirs. - * @param ndirs length of the dirs argument * @param dirs to overwrite the current internal dir list - * @return NC_NOERR + * @return NC_NOERR | NC_EXXX + * * @author Dennis Heimbigner */ - int -NCZ_plugin_path_set(size_t ndirs, char** const dirs) +NCZ_plugin_path_set(NCPluginList* dirs) { int stat = NC_NOERR; struct NCglobalstate* gs = NC_getglobalstate(); + if(dirs == NULL) {stat = NC_EINVAL; goto done;} + if(dirs->ndirs > 0 && dirs->dirs == NULL) {stat = NC_EINVAL; goto done;} + /* Clear the current dir list */ nclistfreeall(gs->zarr.pluginpaths); gs->zarr.pluginpaths = nclistnew(); - if(ndirs > 0) { + if(dirs->ndirs > 0) { size_t i; - assert(gs->zarr.pluginpaths != NULL); - for(i=0;izarr.pluginpaths,nulldup(dirs[i])); + for(i=0;indirs;i++) { + nclistpush(gs->zarr.pluginpaths,nulldup(dirs->dirs[i])); } } +done: return THROW(stat); } diff --git a/nc_test/tst_atts3.c b/nc_test/tst_atts3.c index 9428c9d5ed..2176606de6 100644 --- a/nc_test/tst_atts3.c +++ b/nc_test/tst_atts3.c @@ -189,7 +189,7 @@ main(int argc, char **argv) size_t att_len; int i; - char *speech_in; + char *speech_in = NULL; /* This won't work, because classic files can't create these types. */ #ifdef TEST_PNETCDF diff --git a/ncdump/echon.c b/ncdump/echon.c index 6e50e6d05a..301ac83ff7 100644 --- a/ncdump/echon.c +++ b/ncdump/echon.c @@ -1,3 +1,7 @@ +/* + * Copyright 2018, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ #ifdef HAVE_CONFIG_H #include @@ -33,9 +37,7 @@ main(int argc, char** argv) char* q = NULL; char c; -#ifdef _WIN32 - _setmode(_fileno(stdout),_O_BINARY); -#endif + NCstdbinary(); /* avoid \r\n for windows */ opterr = 1; while ((c = getopt(argc, argv,"enEN")) != EOF) { diff --git a/nczarr_test/CMakeLists.txt b/nczarr_test/CMakeLists.txt index ee95c64a8d..5a75e9d678 100644 --- a/nczarr_test/CMakeLists.txt +++ b/nczarr_test/CMakeLists.txt @@ -130,13 +130,17 @@ IF(NETCDF_ENABLE_TESTS) ENDIF() # Helper programs for testing - BUILD_BIN_TEST(zhex) + build_bin_test(zhex) build_bin_test_with_util_lib(zisjson ut_util) TARGET_INCLUDE_DIRECTORIES(zisjson PUBLIC ../libnczarr) build_bin_test_with_util_lib(zs3parse ut_util) TARGET_INCLUDE_DIRECTORIES(zs3parse PUBLIC ../libnczarr) build_bin_test_with_util_lib(zmapio ut_util) + set(ncpluginpath_FILES ncpluginpath.c ${XGETOPTSRC}) + add_executable(ncpluginpath ${ncpluginpath_FILES}) + target_link_libraries(ncvalidator netcdf ${ALL_TLL_LIBS}) + IF(NETCDF_ENABLE_S3 AND NOT WITH_S3_TESTING STREQUAL "NO") # Helper programs for testing BUILD_BIN_TEST(s3util ${COMMONSRC}) diff --git a/nczarr_test/Makefile.am b/nczarr_test/Makefile.am index 7054eeb42b..66893513b1 100644 --- a/nczarr_test/Makefile.am +++ b/nczarr_test/Makefile.am @@ -181,6 +181,8 @@ noinst_PROGRAMS += zmapio zmapio_SOURCES = zmapio.c noinst_PROGRAMS += zs3parse zs3parse_SOURCES = zs3parse.c +noinst_PROGRAMS += ncpluginpath +ncpluginpath_SOURCES = ncpluginpath.c if NETCDF_ENABLE_S3 noinst_PROGRAMS += s3util diff --git a/nczarr_test/ncpluginpath.c b/nczarr_test/ncpluginpath.c new file mode 100644 index 0000000000..df1ace3c4e --- /dev/null +++ b/nczarr_test/ncpluginpath.c @@ -0,0 +1,145 @@ +/* + * Copyright 2018, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef HAVE_GETOPT_H +#include +#endif + +#if defined(_WIN32) && !defined(__MINGW32__) +#include "XGetopt.h" +#else +#include +#endif + +#include "netcdf.h" +#include "netcdf_filter.h" +#include "netcdf_aux.h" +#include "ncplugins.h" + +static const char* USAGE = +"ncpluginpath [-f global|hdf5|nczarr]" +"Options\n" +" -f which plugin path to print.\n" +" global - print the global plugin path\n" +" hdf5 - print the hdf5 plugin path\n" +" nczarr - print the nczarr plugin path\n" +" If -f is not specified, then it defaults to 'global'\n" +"\n" +; + +#undef DEBUG + +static void usage(const char* msg); + +static void +usage(const char* msg) +{ + if(msg != NULL) fprintf(stderr,"%s\n",msg); + fprintf(stderr,"%s",USAGE); + if(msg == NULL) exit(0); else exit(1); +} + +static int +getformatx(const char* sformat) +{ + if(sformat != NULL && strlen(sformat) > 0) { + if(strcmp(sformat,"global")==0) return NC_FORMATX_UNDEFINED; + if(strcmp(sformat,"hdf5")==0) return NC_FORMATX_NC_HDF5; + if(strcmp(sformat,"nczarr")==0) return NC_FORMATX_NCZARR; + } + return NC_FORMATX_UNDEFINED; +} + +#if 0 +static const char* +getsource(int formatx) +{ + switch (formatx) { + case NC_FORMATX_NC_HDF5: return "hdf5"; + case NC_FORMATX_NCZARR: return "nczarr"; + default: break; + } + return "global"; +} +#endif + +static int +getfrom(int formatx, char** textp) +{ + int stat = NC_NOERR; + NCPluginList dirs = {0,NULL}; + char* text = NULL; + + /* Get a plugin path */ + switch (formatx) { + case 0: /* Global */ + if((stat=nc_plugin_path_get(&dirs))) goto done; + break; + case NC_FORMATX_NCZARR: + if((stat=NCZ_plugin_path_get(&dirs))) goto done; + break; + case NC_FORMATX_NC_HDF5: + if((stat=NC4_hdf5_plugin_path_get(&dirs))) goto done; + break; + default: abort(); + } + if((stat = ncaux_plugin_path_tostring(&dirs,';',&text))) goto done; + *textp = text; text = NULL; +done: + nullfree(text); + ncaux_plugin_path_clear(&dirs); + return stat; +} + +int +main(int argc, char** argv) +{ + int stat = NC_NOERR; + int c; + int formatx = NC_FORMATX_UNDEFINED; + char* text = NULL; + + NCstdbinary(); /* avoid \r\n on windows */ + + nc_initialize(); + + while ((c = getopt(argc, argv, "f:")) != EOF) { + switch(c) { + case 'f': + formatx = getformatx(optarg); + break; + case '?': + usage("unknown option"); + break; + } + } + + if((stat = getfrom(formatx,&text))) goto done; + printf("%s",text); /* suppress trailing eol */ +done: + nullfree(text); + nc_finalize(); + return (stat?1:0); +} + diff --git a/unit_test/tst_pluginpaths.c b/unit_test/tst_pluginpaths.c index 9b702c96cd..90a380e7ab 100644 --- a/unit_test/tst_pluginpaths.c +++ b/unit_test/tst_pluginpaths.c @@ -223,37 +223,28 @@ static int getfrom(int formatx, char** textp) { int stat = NC_NOERR; - size_t ndirs; - char** dirs = NULL; + NCPluginList dirs = {0,NULL}; char* text = NULL; - size_t textlen; /* Get a plugin path */ switch (formatx) { case 0: /* Global */ - if((stat=nc_plugin_path_get(&ndirs,NULL))) goto done; - if((dirs = (char**)calloc(ndirs,sizeof(char*)))==NULL) {stat = NC_ENOMEM; goto done;} - if((stat = nc_plugin_path_get(&ndirs,dirs))) goto done; + if((stat=nc_plugin_path_get(&dirs))) goto done; break; case NC_FORMATX_NCZARR: - if((stat=NCZ_plugin_path_get(&ndirs,NULL))) goto done; - if((dirs = (char**)calloc(ndirs,sizeof(char*)))==NULL) {stat = NC_ENOMEM; goto done;} - if((stat = NCZ_plugin_path_get(&ndirs,dirs))) goto done; + if((stat=NCZ_plugin_path_get(&dirs))) goto done; break; case NC_FORMATX_NC_HDF5: - if((stat=NC4_hdf5_plugin_path_get(&ndirs,NULL))) goto done; - if((dirs = (char**)calloc(ndirs,sizeof(char*)))==NULL) {stat = NC_ENOMEM; goto done;} - if((stat = NC4_hdf5_plugin_path_get(&ndirs,dirs))) goto done; + if((stat=NC4_hdf5_plugin_path_get(&dirs))) goto done; break; default: abort(); } - if((stat = ncaux_plugin_path_tostring(ndirs,dirs,SEP,&textlen,NULL))) goto done; - if((text = (char*)malloc(textlen))==NULL) {stat = NC_ENOMEM; goto done;} - if((stat = ncaux_plugin_path_tostring(ndirs,dirs,SEP,&textlen,text))) goto done; - *textp = text; text = NULL; + if((stat = ncaux_plugin_path_tostring(&dirs,SEP,&text))) goto done; + if(textp) {*textp = text; text = NULL;} + done: nullfree(text); - ncaux_plugin_path_freestringvec(ndirs,dirs); + ncaux_plugin_path_clear(&dirs); return NCCHECK(stat); } @@ -263,7 +254,8 @@ static int actionclear(const struct Execute* action) { int stat = NC_NOERR; - if((stat=nc_plugin_path_set(0,NULL))) goto done; + NCPluginList dirs = {0,NULL}; + if((stat=nc_plugin_path_set(&dirs))) goto done; done: return NCCHECK(stat); } @@ -289,19 +281,14 @@ actionset(const struct Execute* action) { int stat = NC_NOERR; const char* text = action->arg; - size_t ndirs; - char** dirs = NULL; + NCPluginList dirs = {0,NULL}; if(text == NULL) text = ""; - if((stat=ncaux_plugin_path_parse(text,0,&ndirs,NULL))) goto done; - if(ndirs > 0) { - if((dirs = (char**)calloc(ndirs,sizeof(char*)))==NULL) {stat = NC_ENOMEM; goto done;} - if((stat=ncaux_plugin_path_parse(text,0,&ndirs,dirs))) goto done; - } - if((stat=nc_plugin_path_set(ndirs,dirs))) goto done; + if((stat=ncaux_plugin_path_parse(text,0,&dirs))) goto done; + if((stat=nc_plugin_path_set(&dirs))) goto done; done: - ncaux_plugin_path_freestringvec(ndirs,dirs); + ncaux_plugin_path_clear(&dirs); return NCCHECK(stat); }