Skip to content

Commit

Permalink
Merge pull request #1959 from DennisHeimbigner/typescope.dmh
Browse files Browse the repository at this point in the history
Regularize the scoping of types
  • Loading branch information
WardF committed May 27, 2021
2 parents 73e7b84 + 2c26f94 commit 3d997de
Show file tree
Hide file tree
Showing 14 changed files with 451 additions and 81 deletions.
2 changes: 2 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ Release Notes {#RELEASE_NOTES}
\brief Release notes file for the netcdf-c package.

This file contains a high-level description of this package's evolution. Releases are in reverse chronological order (most recent first). Note that, as of netcdf 4.2, the `netcdf-c++` and `netcdf-fortran` libraries have been separated into their own libraries.

## 4.8.1 - TBD

* [Bug Fixes] The netcdf-c library was incorrectly determining the scope of types referred to by nc_inq_type_equal. See [Github #1959](https://github.com/Unidata/netcdf-c/pull/1959) for more information.
* [Bug Fix] Fix bug in use of XGetopt when building under Mingw. See [Github #2009](https://github.com/Unidata/netcdf-c/issues/2009).
* [Enhancement] Improve the error reporting when attempting to use a filter for which no implementation can be found in HDF5_PLUGIN_PATH. See [Github #2000](https://github.com/Unidata/netcdf-c/pull/2000) for more information.
* [Bug Fix] Fix `make distcheck` issue in `nczarr_test/` directory. See [Github #2007](https://github.com/Unidata/netcdf-c/issues/2007).
Expand Down
3 changes: 3 additions & 0 deletions include/ncconfigure.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif

/*
This is included in bottom
Expand Down
3 changes: 3 additions & 0 deletions include/ncpathmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ EXTERNL int NChasdriveletter(const char* path);
/* Canonicalize and make absolute by prefixing the current working directory */
EXTERNL char* NCpathabsolute(const char* name);

/* Check if this path appears to start with a windows drive letter */
EXTERNL int NChasdriveletter(const char* path);

/* Convert from the local coding (e.g. ANSI) to utf-8;
note that this can produce unexpected results for Windows
because it first converts to wide character and then to utf8. */
Expand Down
187 changes: 127 additions & 60 deletions libdispatch/dcopy.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
#include "config.h"
#include "ncdispatch.h"
#include "nc_logging.h"
#include "nclist.h"

#ifdef USE_NETCDF4

static int searchgroup(int ncid1, int tid1, int grp, int* tid2);
static int searchgrouptree(int ncid1, int tid1, int grp, int* tid2);

/**
* @internal Compare two netcdf types for equality. Must have the
* ncids as well, to find user-defined types.
Expand All @@ -27,8 +32,7 @@
* @author Ed Hartnett
*/
static int
NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2,
int *equalp)
NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2, int *equalp)
{
int ret = NC_NOERR;

Expand Down Expand Up @@ -152,77 +156,51 @@ NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2,
}

/**
* @internal Recursively hunt for a netCDF type id. (Code from
* nc4internal.c); Return matching typeid or 0 if not found.
* @internal Recursively hunt for a netCDF type id, tid2, that is "equal" to tid1.
* Question is: what search order do we use? Ncgen uses root group tree in pre-order.
* But NC4_inq_typeid uses these rules:
* 1. ncid2
* 2. parents of ncid2 (up the tree to root)
* 3. root group tree in pre-order.
* We will leave ncgen for another day and use the nc_inq_typeid rule.
*
* Return matching typeid or 0 if not found.
*
* @param ncid1 File ID.
* @param tid1 Type ID.
* @param ncid2 File ID.
* @param tid2 Pointer that gets type ID of equal type.
*
* @return ::NC_NOERR No error.
* @author Ed Hartnett
* @author Ed Hartnett, Dennis Heimbigner
*/
static int
NC_rec_find_nc_type(int ncid1, nc_type tid1, int ncid2, nc_type* tid2)
{
int i,ret = NC_NOERR;
int nids;
int* ids = NULL;

/* Get all types in grp ncid2 */
if(tid2)
*tid2 = 0;
if ((ret = nc_inq_typeids(ncid2, &nids, NULL)))
return ret;
if (nids)
{
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
return NC_ENOMEM;
if ((ret = nc_inq_typeids(ncid2, &nids, ids)))
return ret;
for(i = 0; i < nids; i++)
{
int equal = 0;
if ((ret = NC_compare_nc_types(ncid1, tid1, ncid2, ids[i], &equal)))
return ret;
if(equal)
{
if(tid2)
*tid2 = ids[i];
free(ids);
return NC_NOERR;
}
}
free(ids);
int ret = NC_NOERR;
int parent;

if((ret = searchgroup(ncid1,tid1,ncid2,tid2)))
goto done;
if(*tid2 != 0)
goto done; /* found */

/* Look in the parents of ncid2 upto the root */
switch (ret = nc_inq_grp_parent(ncid2,&parent)) {
case NC_NOERR:
/* Recurse up using parent grp */
ret = NC_rec_find_nc_type(ncid1, tid1, parent, tid2);
break;
case NC_ENOGRP:
/* do the breadth-first pre-order search of the whole tree */
/* ncid2 should be root group */
ret = searchgrouptree(ncid1,tid1,ncid2,tid2);
break;
default: break;
}

/* recurse */
if ((ret = nc_inq_grps(ncid1, &nids, NULL)))
return ret;
if (nids)
{
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
return NC_ENOMEM;
if ((ret = nc_inq_grps(ncid1, &nids, ids)))
{
free(ids);
return ret;
}
for (i = 0; i < nids; i++)
{
ret = NC_rec_find_nc_type(ncid1, tid1, ids[i], tid2);
if (ret && ret != NC_EBADTYPE)
break;
if (tid2 && *tid2 != 0) /* found */
{
free(ids);
return NC_NOERR;
}
}
free(ids);
}
return NC_EBADTYPE; /* not found */
done:
return ret;
}

/**
Expand Down Expand Up @@ -711,3 +689,92 @@ nc_copy_att(int ncid_in, int varid_in, const char *name,

return NC_NOERR;
}

#ifdef USE_NETCDF4

/* Helper function for NC_rec_find_nc_type();
search a specified group for matching type.
*/
static int
searchgroup(int ncid1, int tid1, int grp, int* tid2)
{
int i,ret = NC_NOERR;
int nids;
int* ids = NULL;

/* Get all types in grp */
if(tid2)
*tid2 = 0;
if ((ret = nc_inq_typeids(grp, &nids, NULL)))
goto done;
if (nids)
{
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
{ret = NC_ENOMEM; goto done;}
if ((ret = nc_inq_typeids(grp, &nids, ids)))
goto done;
for(i = 0; i < nids; i++)
{
int equal = 0;
if ((ret = NC_compare_nc_types(ncid1, tid1, grp, ids[i], &equal)))
goto done;
if(equal)
{
if(tid2)
*tid2 = ids[i];
goto done;
}
}
}

done:
nullfree(ids);
return ret;
}

/* Helper function for NC_rec_find_nc_type();
search a tree of groups for a matching type
using a breadth first queue
*/
static int
searchgrouptree(int ncid1, int tid1, int grp, int* tid2)
{
int i,ret = NC_NOERR;
int nids;
int* ids = NULL;
NClist* queue = nclistnew();
int gid;
uintptr_t id;

id = grp;
nclistpush(queue,(void*)id); /* prime the queue */
while(nclistlength(queue) > 0) {
id = (uintptr_t)nclistremove(queue,0);
gid = (int)id;
if((ret = searchgroup(ncid1,tid1,gid,tid2)))
goto done;
if(*tid2 != 0)
goto done; /*we found it*/
/* Get subgroups of gid and push onto front of the queue (for breadth first) */
if((ret = nc_inq_grps(gid,&nids,NULL)))
goto done;
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
{ret = NC_ENOMEM; goto done;}
if ((ret = nc_inq_grps(gid, &nids, ids)))
goto done;
/* push onto the end of the queue */
for(i=0;i<nids;i++) {
id = ids[i];
nclistpush(queue,(void*)id);
}
}
/* Not found */
ret = NC_EBADTYPE;

done:
nclistfree(queue);
nullfree(ids);
return ret;
}

#endif
2 changes: 1 addition & 1 deletion libdispatch/dinfermodel.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct MagicFile {
struct NCURI* uri;
int omode;
NCmodel* model;
long long filelen;
size64_t filelen;
int use_parallel;
void* parameters; /* !NULL if inmemory && !diskless */
FILE* fp;
Expand Down
46 changes: 33 additions & 13 deletions libsrc4/nc4type.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,36 +554,56 @@ NC4_inq_typeid(int ncid, const char *name, nc_type *typeidp)
NC_GRP_INFO_T *grptwo;
NC_FILE_INFO_T *h5;
NC_TYPE_INFO_T *type = NULL;
char *norm_name;
int i, retval;
char *norm_name = NULL;
int i, retval = NC_NOERR;

/* Handle atomic types. */
for (i = 0; i < NUM_ATOMIC_TYPES; i++)
if (!strcmp(name, nc4_atomic_name[i]))
{
if (typeidp)
*typeidp = i;
return NC_NOERR;
goto done;
}

/* Find info for this file and group, and set pointer to each. */
if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
return retval;
goto done;
assert(h5 && grp);

/* If the first char is a /, this is a fully-qualified
* name. Otherwise, this had better be a local name (i.e. no / in
* the middle). */
if (name[0] != '/' && strstr(name, "/"))
return NC_EINVAL;
{retval = NC_EINVAL; goto done;}

/* Normalize name. */
if (!(norm_name = (char*)malloc(strlen(name) + 1)))
return NC_ENOMEM;
if ((retval = nc4_normalize_name(name, norm_name))) {
free(norm_name);
return retval;
{retval = NC_ENOMEM; goto done;}
if ((retval = nc4_normalize_name(name, norm_name)))
goto done;

/* If this is a fqn, then walk the sequence of parent groups to the last group
and see if that group has a type of the right name */
if(name[0] == '/') { /* FQN */
int rootncid = (grp->nc4_info->root_grp->hdr.id | grp->nc4_info->controller->ext_ncid);
int parent = 0;
char* lastname = strrchr(norm_name,'/'); /* break off the last segment: the type name */
if(lastname == norm_name)
{retval = NC_EINVAL; goto done;}
*lastname++ = '\0'; /* break off the lastsegment */
if((retval = NC4_inq_grp_full_ncid(rootncid,norm_name,&parent)))
goto done;
/* Get parent info */
if((retval=nc4_find_nc4_grp(parent,&grp)))
goto done;
/* See if type exists in this group */
type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,lastname);
if(type == NULL)
{retval = NC_EBADTYPE; goto done;}
goto done;
}

/* Is the type in this group? If not, search parents. */
for (grptwo = grp; grptwo; grptwo = grptwo->parent) {
type = (NC_TYPE_INFO_T*)ncindexlookup(grptwo->type,norm_name);
Expand All @@ -602,13 +622,13 @@ NC4_inq_typeid(int ncid, const char *name, nc_type *typeidp)
if (typeidp)
*typeidp = type->hdr.id;

free(norm_name);

/* OK, I give up already! */
if (!type)
return NC_EBADTYPE;
{retval = NC_EBADTYPE; goto done;}

return NC_NOERR;
done:
nullfree(norm_name);
return retval;
}

/**
Expand Down
Loading

0 comments on commit 3d997de

Please sign in to comment.