Skip to content

Commit

Permalink
Simplify FORTRAN access to the new plugin path mechanism
Browse files Browse the repository at this point in the history
The new plugin path API uses char** to represent
a variable lenght vector of variable length strings.
FORTRAN is not capable of accessing such structures.
So, this PR extends the API to provide a counted string-based
API to the plugin path functionality.

The new functions are inserted in the netcdf_aux.h/daux.c files.
The new functions are just wrappers around other plugin path API
function; they are just (I hope) more convenient for FORTRAN users.

The new functions are as follows:

### *ncaux_plugin_path_stringlen(void)*
* Return the length (as in strlen) of the current plugin path directories encoded as a string. Return -1 if the request fails.

### *int ncaux_plugin_path_stringget(int pathlen, char* path)*
* Get the current sequence of directories in the internal global plugin path list encoded as a string path using ';' as a path separator. As an example, it might return "/a/b/c;/home/user/me;/tmp". The arguments are as follows:
    * *pathlen* -- the length of the path argument.
    * *path* -- a string into which the current plugin path as a string is stored.
* Return NC_NOERR | NC_EINVAL

### *int ncaux_plugin_path_stringset(int pathlen, const char* path)*
* Set the current sequence of directories in the internal global plugin path list. As an example, it might take "/a/b/c;/home/user/me;/tmp". The arguments are as follows:
    * *pathlen* -- the length of the path argument.
    * *path* -- a string that is parsed to obtain the sequence of directories for the current plugin path.
* Return NC_NOERR | NC_EINVAL
  • Loading branch information
DennisHeimbigner committed Dec 1, 2024
1 parent e8d23ea commit 2133052
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 17 deletions.
55 changes: 54 additions & 1 deletion include/netcdf_aux.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,15 @@ EXTERNL int ncaux_add_field(void* tag, const char *name, nc_type field_type,
struct NCPluginList;

/**
Parse a string into a sequence of path directories.
Parse a counted string into a sequence of path directories.
The pathlist argument has the following syntax:
paths := <empty> | dirlist
dirlist := dir | dirlist separator dir
separator := ';' | ':'
dir := <OS specific directory path>
@param pathlen length of pathlist arg
@param pathlist a string encoding a list of directories
@param sep one of ';' | ':' | '\0' where '\0' means use the platform's default separator.
@param dirs a pointer to an NCPluginPath object for returning the number and vector of directories from the parse.
Expand All @@ -121,6 +122,17 @@ 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_parsen(size_t pathlen, const char* pathlist, char sep, struct NCPluginList* dirs);

/**
Parse a nul-terminated string into a sequence of path directories.
@param pathlist a string encoding a list of directories
@param sep one of ';' | ':' | '\0' where '\0' means use the platform's default separator.
@param dirs a pointer to an NCPluginPath object for returning the number and vector of directories from the parse.
@return ::NC_NOERR | NC_EXXX
See also the comments for ncaux_plugin_path_parsen
Author: Dennis Heimbigner
*/
EXTERNL int ncaux_plugin_path_parse(const char* pathlist, char sep, struct NCPluginList* dirs);
Expand Down Expand Up @@ -192,6 +204,47 @@ Author: Dennis Heimbigner
*/
EXTERNL int ncaux_plugin_path_prepend(struct NCPluginList* dirs, const char* dir);

/**************************************************/
/* FORTRAN is not good at manipulating C char** vectors,
so provide some wrappers for use by netcdf-fortran
that read/write plugin path as a single string.
For simplicity, the path separator is always semi-colon.
*/

/**
* Return the length (as in strlen) of the current plugin path directories encoded as a string.
* @return length of the string encoded plugin path.
* @author Dennis Heimbigner
*
* @author: Dennis Heimbigner
*/
EXTERNL int ncaux_plugin_path_stringlen(void);

/**
* Return the current sequence of directories in the internal global
* plugin path list encoded as a string path using ';' as a path separator.
* @param pathlen the length of the path argument.
* @param path a string into which the current plugin paths are encodeded.
* @return NC_NOERR | NC_EXXX
* @author Dennis Heimbigner
*
* @author: Dennis Heimbigner
*/
EXTERNL int ncaux_plugin_path_stringget(int pathlen, char* path);

/**
* Set the current sequence of directories in the internal global
* plugin path list to the sequence of directories encoded as a
* string path using ';' as a path separator.
* @param pathlen the length of the path argument.
* @param path a string encoding the sequence of directories and using ';' to separate them.
* @return NC_NOERR | NC_EXXX
* @author Dennis Heimbigner
*
* @author: Dennis Heimbigner
*/
EXTERNL int ncaux_plugin_path_stringset(int pathlen, const char* path);

#if defined(__cplusplus)
}
#endif
Expand Down
134 changes: 120 additions & 14 deletions libdispatch/daux.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ EXTERNL int
ncaux_abort_compound(void* tag)
{
#ifdef USE_NETCDF4
int i;
size_t i;
struct NCAUX_CMPD* cmpd = (struct NCAUX_CMPD*)tag;
if(cmpd == NULL) goto done;
if(cmpd->name) free(cmpd->name);
Expand Down Expand Up @@ -164,7 +164,7 @@ EXTERNL int
ncaux_end_compound(void* tag, nc_type* idp)
{
#ifdef USE_NETCDF4
int i;
size_t i;
int status = NC_NOERR;
struct NCAUX_CMPD* cmpd = (struct NCAUX_CMPD*)tag;

Expand Down Expand Up @@ -247,7 +247,7 @@ getpadding(size_t offset, size_t alignment)
static size_t
dimproduct(size_t ndims, int* dimsizes)
{
int i;
size_t i;
size_t product = 1;
for(i=0;i<ndims;i++) product *= (size_t)dimsizes[i];
return product;
Expand All @@ -256,7 +256,7 @@ dimproduct(size_t ndims, int* dimsizes)
static int
computefieldinfo(struct NCAUX_CMPD* cmpd)
{
int i;
size_t i;
int status = NC_NOERR;
size_t offset = 0;
size_t totaldimsize;
Expand All @@ -272,7 +272,7 @@ computefieldinfo(struct NCAUX_CMPD* cmpd)

for(offset=0,i=0;i<cmpd->nfields;i++) {
struct NCAUX_FIELD* field = &cmpd->fields[i];
int alignment = 0;
size_t alignment = 0;
nc_type firsttype = findfirstfield(cmpd->ncid,field->fieldtype);

/* only support 'c' alignment for now*/
Expand Down Expand Up @@ -432,7 +432,8 @@ and the parameters themselves (hence the unsigned int** paramsp).
EXTERNL int
ncaux_h5filterspec_parse(const char* txt, unsigned int* idp, size_t* nparamsp, unsigned int** paramsp)
{
int i,stat = NC_NOERR;
int stat = NC_NOERR;
size_t i;
char* p;
char* sdata0 = NULL; /* what to free */
char* sdata = NULL; /* sdata0 with leading prefix skipped */
Expand Down Expand Up @@ -595,7 +596,7 @@ ncaux_h5filterspec_parselist(const char* txt0, int* formatp, size_t* nspecsp, NC
p = q + 1;
}
if(nspecs > 0) {
int count = 0;
size_t count = 0;
if((vector = (NC_H5_Filterspec**)calloc(sizeof(NC_H5_Filterspec*),nspecs)) == NULL)
{stat = NC_ENOMEM; goto done;}
/* pass 2: parse */
Expand Down Expand Up @@ -961,6 +962,7 @@ ncaux_dump_data(int ncid, int xtype, void* memory, size_t count, char** bufp)
/* Path List Utilities */

/* Path-list Parser:
@param pathlen length of the pathlist0 arg
@param pathlist0 the string to parse
@param dirs return the parsed directories -- see note below.
@param sep the separator parsing: one of ';' | ':' | '\0', where zero means use platform default.
Expand All @@ -972,19 +974,18 @@ 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, NCPluginList* dirs)
ncaux_plugin_path_parsen(size_t pathlen, const char* pathlist0, char sep, NCPluginList* dirs)
{
int stat = NC_NOERR;
size_t i;
char* path = NULL;
char* p;
size_t count;
size_t plen;
char seps[2] = "\0\0"; /* will contain all allowable separators */

if(dirs == NULL) {stat = NC_EINVAL; goto done;}

if(pathlist0 == NULL || pathlist0[0] == '\0') {dirs->ndirs = 0; goto done;}
if(pathlen == 0 || pathlist0 == NULL) {dirs->ndirs = 0; goto done;}

/* If a separator is specified, use it, otherwise search for ';' or ':' */
seps[0] = sep;
Expand All @@ -995,10 +996,9 @@ ncaux_plugin_path_parse(const char* pathlist0, char sep, NCPluginList* dirs)
else
seps[0] = ':';
}
plen = strlen(pathlist0); /* assert plen > 0 */
if((path = malloc(plen+1+1))==NULL) {stat = NC_ENOMEM; goto done;}
memcpy(path,pathlist0,plen);
path[plen] = '\0'; path[plen+1] = '\0'; /* double null term */
if((path = malloc(pathlen+1+1))==NULL) {stat = NC_ENOMEM; goto done;}
memcpy(path,pathlist0,pathlen);
path[pathlen] = '\0'; path[pathlen+1] = '\0'; /* double null term */

for(count=0,p=path;*p;p++) {
if(strchr(seps,*p) == NULL)
Expand Down Expand Up @@ -1029,6 +1029,20 @@ ncaux_plugin_path_parse(const char* pathlist0, char sep, NCPluginList* dirs)
return stat;
}

/* Wrapper around ncaux_plugin_path_parsen
to allow passing a nul-terminated string to parse.
@param pathlist0 the nul-termiated string to parse
@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
See also the comments for ncaux_plugin_path_parsen.
*/
EXTERNL int
ncaux_plugin_path_parse(const char* pathlist0, char sep, NCPluginList* dirs)
{
return ncaux_plugin_path_parsen(nulllen(pathlist0),pathlist0,sep,dirs);
}

/*
Path-list concatenator where given a vector of directories,
concatenate all dirs with specified separator.
Expand Down Expand Up @@ -1168,3 +1182,95 @@ ncaux_plugin_path_prepend(struct NCPluginList* dirs, const char* dir)
done:
return stat;
}

/* FORTRAN is not good at manipulating C char** vectors,
so provide some wrappers for use by netcdf-fortran
that read/write plugin path as a single string.
For simplicity, the path separator is always semi-colon.
*/

/**
* Return the length (as in strlen) of the current plugin path directories encoded as a string.
* @return length of the string encoded plugin path or -1 if failed.
* @author Dennis Heimbigner
*
* @author: Dennis Heimbigner
*/
int
ncaux_plugin_path_stringlen(void)
{
int len = 0;
int stat = NC_NOERR;
struct NCPluginList npl = {0,NULL};
char* buf = NULL;

/* Get the list of dirs */
if((stat = nc_plugin_path_get(&npl))) goto done;
/* Convert to a string path separated by ';' */
if((stat = ncaux_plugin_path_tostring(&npl,';',&buf))) goto done;
len = nulllen(buf);

done:
if(npl.dirs != NULL) {(void)ncaux_plugin_path_clear(&npl);}
nullfree(buf);
if(stat) return -1; else return len;
}

/**
* Return the current sequence of directories in the internal global
* plugin path list encoded as a string path using ';' as a path separator.
* @param pathlen the length of the path argument.
* @param path a string into which the current plugin paths are encodeded.
* @return NC_NOERR | NC_EXXX
* @author Dennis Heimbigner
*
* @author: Dennis Heimbigner
*/
int
ncaux_plugin_path_stringget(int pathlen, char* path)
{
int stat = NC_NOERR;
struct NCPluginList npl = {0,NULL};
char* buf = NULL;

if(pathlen == 0 || path == NULL) {stat = NC_EINVAL; goto done;}

/* Get the list of dirs */
if((stat = nc_plugin_path_get(&npl))) goto done;
/* Convert to a string path separated by ';' */
if((stat = ncaux_plugin_path_tostring(&npl,';',&buf))) goto done;
strncpy(path,buf,(size_t)pathlen);

done:
nullfree(buf);
if(npl.dirs != NULL) {(void)ncaux_plugin_path_clear(&npl);}
return stat;
}

/**
* Set the current sequence of directories in the internal global
* plugin path list to the sequence of directories encoded as a
* string path using ';' as a path separator.
* @param pathlen the length of the path argument.
* @param path a string encoding the sequence of directories and using ';' to separate them.
* @return NC_NOERR | NC_EXXX
* @author Dennis Heimbigner
*
* @author: Dennis Heimbigner
*/
int
ncaux_plugin_path_stringset(int pathlen, const char* path)
{
int stat = NC_NOERR;
struct NCPluginList npl = {0,NULL};

if(pathlen == 0 || path == NULL) {stat = NC_EINVAL; goto done;}
/* Parse the incoming path */
if((stat = ncaux_plugin_path_parsen((size_t)pathlen,path,';',&npl))) goto done;
/* set the list of dirs */
if((stat = nc_plugin_path_set(&npl))) goto done;

done:
if(npl.dirs != NULL) {(void)ncaux_plugin_path_clear(&npl);}
return stat;
}
1 change: 1 addition & 0 deletions unit_test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ endif
EXTRA_DIST = CMakeLists.txt run_s3sdk.sh run_reclaim_tests.sh run_aws_config.sh run_pluginpaths.sh run_dfaltpluginpath.sh
EXTRA_DIST += nctest_netcdf4_classic.nc reclaim_tests.cdl
EXTRA_DIST += ref_get.txt ref_set.txt
EXTRA_DIST += ref_xget.txt ref_xset.txt

CLEANFILES = reclaim_tests*.txt reclaim_tests.nc tmp_*.txt

Expand Down
1 change: 1 addition & 0 deletions unit_test/ref_xget.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
testxget(global): /zero;/one;/two;/three;/four
2 changes: 2 additions & 0 deletions unit_test/ref_xset.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
testxset(global): before: /zero;/one;/two;/three;/four
testxset(global): after: /zero;/one;/mod;/two;/three;/four
18 changes: 17 additions & 1 deletion unit_test/run_pluginpaths.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ testset() {
printf "testset(nczarr): after: %s\n" `${TP} -x "set:${DFALT},set:${DFALTSET},get:nczarr"` >> ${filename}.txt
}

# Test the ncaux set/get/clear functions */
testxget() {
filenamefor tmp xget
# print out the global state
printf "testxget(global): %s\n" `${TP} -x "xset:${DFALT},xget:global"` >> ${filename}.txt
}

testxset() {
filenamefor tmp xset
# print out the global state, modify it and print again
printf "testxset(global): before: %s\n" `${TP} -x "xset:${DFALT},xget:global"` >> ${filename}.txt
printf "testxset(global): after: %s\n" `${TP} -x "xset:${DFALT},xset:${DFALTSET},xget:global"` >> ${filename}.txt
}

#########################

cleanup() {
Expand All @@ -98,7 +112,7 @@ init() {

# Verify output for a specific action
verify() {
for action in get set ; do
for action in get set xget xset; do
if diff -wBb ${srcdir}/ref_${action}.txt tmp_${action}.txt ; then
echo "***PASS: $action"
else
Expand All @@ -111,5 +125,7 @@ verify() {
init
testget
testset
testxget
testxset
verify
cleanup
Loading

0 comments on commit 2133052

Please sign in to comment.