diff --git a/libsrc4/nc4grp.c b/libsrc4/nc4grp.c index 7ea43357d5..a422fd729c 100644 --- a/libsrc4/nc4grp.c +++ b/libsrc4/nc4grp.c @@ -1,14 +1,13 @@ +/* Copyright 2005-2018, University Corporation for Atmospheric + * Research. See COPYRIGHT file for copying and redistribution + * conditions. */ /** * @file * @internal This file is part of netcdf-4, a netCDF-like interface * for HDF5, or a HDF5 backend for netCDF, depending on your point of * view. * - * This file handles the nc4 groups. - * - * Copyright 2005, University Corporation for Atmospheric Research. See - * netcdf-4/docs/COPYRIGHT file for copying and redistribution - * conditions. + * This file handles groups. * * @author Ed Hartnett */ @@ -16,7 +15,7 @@ #include "nc4dispatch.h" /** - * @internal Create a group. It's ncid is returned in the new_ncid + * @internal Create a group. Its ncid is returned in the new_ncid * pointer. * * @param parent_ncid Parent group. @@ -42,8 +41,7 @@ NC4_def_grp(int parent_ncid, const char *name, int *new_ncid) /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(parent_ncid, &grp, &h5))) return retval; - if (!h5) - return NC_ENOTNC4; + assert(h5); /* Check and normalize the name. */ if ((retval = nc4_check_name(name, norm_name))) @@ -103,22 +101,22 @@ NC4_rename_grp(int grpid, const char *name) /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(grpid, &grp, &h5))) return retval; - if (!h5) - return NC_ENOTNC4; + assert(h5); if (h5->no_write) return NC_EPERM; /* attempt to write to a read-only file */ /* Do not allow renaming the root group */ - if(grp->parent == NULL) + if (grp->parent == NULL) return NC_EBADGRPID; /* Check and normalize the name. */ if ((retval = nc4_check_name(name, norm_name))) return retval; - /* Check that this name is not in use as a var, grp, or type. */ - if ((retval = nc4_check_dup_name(grp, norm_name))) + /* Check that this name is not in use as a var, grp, or type in the + * parent group (i.e. the group that grp is in). */ + if ((retval = nc4_check_dup_name(grp->parent, norm_name))) return retval; /* If it's not in define mode, switch to define mode. */ @@ -184,10 +182,7 @@ NC4_inq_ncid(int ncid, const char *name, int *grp_ncid) /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) return retval; - - /* Groups only work with netCDF-4/HDF5 files... */ - if (!h5) - return NC_ENOTNC4; + assert(h5); /* Normalize name. */ if ((retval = nc4_normalize_name(name, norm_name))) @@ -231,14 +226,7 @@ NC4_inq_grps(int ncid, int *numgrps, int *ncids) /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) return retval; - - /* For netCDF-3 files, just report zero groups. */ - if (!h5) - { - if (numgrps) - *numgrps = 0; - return NC_NOERR; - } + assert(h5); /* Count the number of groups in this group. */ for (g = grp->children; g; g = g->l.next) @@ -283,13 +271,11 @@ NC4_inq_grpname(int ncid, char *name) /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) return retval; + assert(h5); + + /* Copy the name. */ if (name) - { - if (!h5) - strcpy(name, "/"); - else - strcpy(name, grp->name); - } + strcpy(name, grp->name); return NC_NOERR; } @@ -388,11 +374,8 @@ NC4_inq_grp_parent(int ncid, int *parent_ncid) /* Find info for this file and group. */ if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) return retval; - - /* Groups only work with netCDF-4/HDF5 files... */ - if (!h5) - return NC_ENOGRP; - + assert(h5); + /* Set the parent ncid, if there is one. */ if (grp->parent) { @@ -434,6 +417,7 @@ NC4_inq_grp_full_ncid(int ncid, const char *full_name, int *grp_ncid) /* Find info for this file and group, and set pointer to each. */ if ((ret = nc4_find_grp_h5(ncid, &grp, &h5))) return ret; + assert(h5); /* Copy full_name because strtok messes with the value it works * with, and we don't want to mess up full_name. */ @@ -503,29 +487,17 @@ NC4_inq_varids(int ncid, int *nvars, int *varids) /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) return retval; + assert(h5); - if (!h5) + /* This is a netCDF-4 group. Round up them doggies and count + * 'em. The list is in correct (i.e. creation) order. */ + for (i=0; i < grp->vars.nelems; i++) { - /* If this is a netcdf-3 file, there is only one group, the root - * group, and its vars have ids 0 thru nvars - 1. */ - if ((retval = NC4_inq(ncid, NULL, &num_vars, NULL, NULL))) - return retval; + var = grp->vars.value[i]; + if (!var) continue; if (varids) - for (v = 0; v < num_vars; v++) - varids[v] = v; - } - else - { - /* This is a netCDF-4 group. Round up them doggies and count - * 'em. The list is in correct (i.e. creation) order. */ - for (i=0; i < grp->vars.nelems; i++) - { - var = grp->vars.value[i]; - if (!var) continue; - if (varids) - varids[num_vars] = var->varid; - num_vars++; - } + varids[num_vars] = var->varid; + num_vars++; } /* If the user wants to know how many vars in the group, tell @@ -584,44 +556,32 @@ NC4_inq_dimids(int ncid, int *ndims, int *dimids, int include_parents) /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) return retval; + assert(h5); - if (!h5) - { - /* If this is a netcdf-3 file, then the dimids are going to be 0 - * thru ndims-1, so just provide them. */ - if ((retval = NC4_inq(ncid, &num, NULL, NULL, NULL))) - return retval; - if (dimids) - for (d = 0; d < num; d++) - dimids[d] = d; - } - else + /* First count them. */ + for (dim = grp->dim; dim; dim = dim->l.next) + num++; + if (include_parents) + for (g = grp->parent; g; g = g->parent) + for (dim = g->dim; dim; dim = dim->l.next) + num++; + + /* If the user wants the dimension ids, get them. */ + if (dimids) { - /* First count them. */ + int n = 0; + + /* Get dimension ids from this group. */ for (dim = grp->dim; dim; dim = dim->l.next) - num++; + dimids[n++] = dim->dimid; + + /* Get dimension ids from parent groups. */ if (include_parents) - for (g = grp->parent; g; g = g->parent) - for (dim = g->dim; dim; dim = dim->l.next) - num++; + for (g = grp->parent; g; g = g->parent) + for (dim = g->dim; dim; dim = dim->l.next) + dimids[n++] = dim->dimid; - /* If the user wants the dimension ids, get them. */ - if (dimids) - { - int n = 0; - - /* Get dimension ids from this group. */ - for (dim = grp->dim; dim; dim = dim->l.next) - dimids[n++] = dim->dimid; - - /* Get dimension ids from parent groups. */ - if (include_parents) - for (g = grp->parent; g; g = g->parent) - for (dim = g->dim; dim; dim = dim->l.next) - dimids[n++] = dim->dimid; - - qsort(dimids, num, sizeof(int), int_cmp); - } + qsort(dimids, num, sizeof(int), int_cmp); } /* If the user wants the number of dims, give it. */ diff --git a/libsrc4/nc4internal.c b/libsrc4/nc4internal.c index 41d0d7ba3a..3e0ba89753 100644 --- a/libsrc4/nc4internal.c +++ b/libsrc4/nc4internal.c @@ -93,6 +93,7 @@ nc4_hdf5_initialize(void) * * @return ::NC_NOERR No error. * @return ::NC_EMAXNAME Name too long. + * @return ::NC_EINVAL Invalid parameter. * @author Dennis Heimbigner */ int @@ -100,6 +101,10 @@ nc4_check_name(const char *name, char *norm_name) { char *temp; int retval; + + /* Check for NULL. */ + if (!name) + return NC_EINVAL; /* Check the length. */ if (strlen(name) > NC_MAX_NAME) diff --git a/nc_test4/Makefile.am b/nc_test4/Makefile.am index 3bcb00d6ca..882990deae 100644 --- a/nc_test4/Makefile.am +++ b/nc_test4/Makefile.am @@ -97,6 +97,7 @@ check_PROGRAMS += tst_interops2 tst_chunk_hdf4 tst_h4_lendian if BUILD_UTILITIES # This test script depends on ncdump. TESTS += tst_interops2 tst_formatx_hdf4.sh +tst_formatx_hdf4.log: tst_interops2.log endif # BUILD_UTILITIES TESTS += run_chunk_hdf4.sh tst_h4_lendian diff --git a/nc_test4/tst_grps.c b/nc_test4/tst_grps.c index 2cadc038d5..a404214ad4 100644 --- a/nc_test4/tst_grps.c +++ b/nc_test4/tst_grps.c @@ -3,7 +3,8 @@ See COPYRIGHT file for conditions of use. Test netcdf-4 group code. - $Id: tst_grps.c,v 1.37 2010/04/07 15:21:28 ed Exp $ + + Ed Hartnett */ #include @@ -11,13 +12,17 @@ #include "netcdf.h" #define FILE_NAME "tst_grps.nc" +#define FILE_NAME_CLASSIC "tst_grps_classic.nc" +#define FILE_NAME_CLASSIC_MODEL "tst_grps_classic_model.nc" #define DIM1_NAME "kingdom" #define DIM1_LEN 3 #define DIM2_NAME "year" #define DIM2_LEN 5 #define VAR1_NAME "Number_of_Beheadings_in_Family" #define DYNASTY "Tudor" +#define HENRY_IV "Henry_IV" #define HENRY_VII "Henry_VII" +#define HENRY_VIII "Henry_VIII" #define MARGARET "Margaret" #define JAMES_V_OF_SCOTLAND "James_V_of_Scotland" #define MARY_I_OF_SCOTLAND "Mary_I_of_Scotland" @@ -31,15 +36,21 @@ main(int argc, char **argv) printf("\n*** Testing netcdf-4 group functions.\n"); printf("*** testing simple group create..."); { - int ncid; + int ncid, ncid2; char name_in[NC_MAX_NAME + 1]; int henry_vii_id; + int henry_viii_id; int grpid_in[MAX_SIBLING_GROUPS], varids_in[MAX_SIBLING_GROUPS]; int dimids_in[MAX_SIBLING_GROUPS], nvars_in, ndims_in, ncid_in; int parent_ncid; char name_out[NC_MAX_NAME + 1]; int num_grps; + /* Create a netCDF classic file. Groups will not be allowed. */ + if (nc_create(FILE_NAME_CLASSIC, 0, &ncid2)) ERR; + if (nc_def_grp(ncid2, name_out, &henry_vii_id) != NC_ENOTNC4) ERR; + if (nc_close(ncid2)) ERR; + /* Create a file with one group, a group to contain data about * Henry VII. */ if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; @@ -47,7 +58,16 @@ main(int argc, char **argv) /* This should also work as simple "is this the root group" test */ if (nc_inq_grp_parent(ncid, NULL) != NC_ENOGRP) ERR; strcpy(name_out, HENRY_VII); + + /* These will not work. */ + if (nc_def_grp(ncid + TEST_VAL_42, name_out, &henry_vii_id) != NC_EBADID) ERR; + if (nc_def_grp(ncid, NULL, &henry_vii_id) != NC_EINVAL) ERR; + if (nc_def_grp(ncid, BAD_NAME, &henry_vii_id) != NC_EBADNAME) ERR; + + /* Define the group. */ if (nc_def_grp(ncid, name_out, &henry_vii_id)) ERR; + + /* Check it out. */ if (nc_inq_grp_parent(henry_vii_id, &parent_ncid)) ERR; if (parent_ncid != ncid) ERR; if (nc_inq_ncid(ncid, HENRY_VII, &ncid_in)) ERR; @@ -69,10 +89,77 @@ main(int argc, char **argv) if (strcmp(name_in, HENRY_VII)) ERR; if (nc_inq_varids(grpid_in[0], &nvars_in, varids_in)) ERR; if (nvars_in != 0) ERR; - if (nc_inq_varids(grpid_in[0], &ndims_in, dimids_in)) ERR; - if (ndims_in != 0) ERR; + if (nc_inq_varids(grpid_in[0], NULL, varids_in)) ERR; + if (nc_inq_varids(grpid_in[0], &nvars_in, NULL)) ERR; + if (nc_inq_varids(grpid_in[0], NULL, NULL)) ERR; + if (nc_inq_ncid(ncid, HENRY_VII, &ncid_in)) ERR; if (ncid_in != grpid_in[0]) ERR; + + /* These should fail - file is read-only. */ + if (nc_def_grp(ncid, HENRY_VIII, &henry_viii_id) != NC_EPERM) ERR; + if (nc_rename_grp(grpid_in[0], HENRY_VIII) != NC_EPERM) ERR; + + /* Close the file. */ + if (nc_close(ncid)) ERR; + } + SUMMARIZE_ERR; + printf("*** testing simple group rename..."); + { + int ncid, ncid2; + int grpid_in; + char name_in[NC_MAX_NAME + 1]; + int henry_vii_id; + + /* Create a classic model file. No groups will be allowed. */ + if (nc_create(FILE_NAME_CLASSIC_MODEL, NC_NETCDF4|NC_CLASSIC_MODEL, &ncid2)) ERR; + if (nc_def_grp(ncid2, HENRY_VII, &henry_vii_id) != NC_ESTRICTNC3) ERR; + if (nc_def_var(ncid2, HENRY_IV, NC_INT, 0, NULL, NULL)); + if (nc_close(ncid2)) ERR; + + /* Create a file with one group, a group to contain data about + * Henry VII. */ + if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; + if (nc_def_var(ncid, HENRY_IV, NC_INT, 0, NULL, NULL)); + + /* Turn off define mode. It will automatically be turned back on + * when nc_def_grp is called. */ + if (nc_enddef(ncid)) ERR; + if (nc_def_grp(ncid, HENRY_VII, &henry_vii_id)) ERR; + + /* Check it out. */ + if (nc_inq_grpname(henry_vii_id, name_in)) ERR; + if (strcmp(name_in, HENRY_VII)) ERR; + + /* These will not work. */ + if (nc_rename_grp(henry_vii_id, BAD_NAME) != NC_EBADNAME) ERR; + if (nc_rename_grp(henry_vii_id, HENRY_IV) != NC_ENAMEINUSE) ERR; + if (nc_rename_grp(ncid, HENRY_IV) != NC_EBADGRPID) ERR; + + /* Rename the group. */ + if (nc_rename_grp(henry_vii_id, HENRY_VIII)) ERR; + + /* Check it out. */ + if (nc_inq_grpname(henry_vii_id, name_in)) ERR; + if (strcmp(name_in, HENRY_VIII)) ERR; + + /* Close the file. */ + if (nc_close(ncid)) ERR; + + /* Re-open the file. */ + if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR; + + /* Check it out. */ + if (nc_inq_grps(ncid, NULL, &grpid_in)) ERR; + if (nc_inq_grpname(grpid_in, name_in)) ERR; + if (strcmp(name_in, HENRY_VIII)) ERR; + + /* Rename it. */ + if (nc_rename_grp(grpid_in, HENRY_VII)) ERR; + if (nc_inq_grpname(grpid_in, name_in)) ERR; + if (strcmp(name_in, HENRY_VII)) ERR; + + /* Close the file. */ if (nc_close(ncid)) ERR; } SUMMARIZE_ERR; @@ -121,6 +208,9 @@ main(int argc, char **argv) if (nc_def_var(henry_vii_id, VAR_NAME2, NC_INT64, NDIMS_IN_VAR, &dimid1, &varid2)) ERR; if (nc_def_var(henry_vii_id, VAR_NAME3, NC_INT64, NDIMS_IN_VAR, &dimid2, &varid3)) ERR; + /* These won't work. */ + if (nc_inq_ncid(ncid + TEST_VAL_42, HENRY_VII, &grpid_in) != NC_EBADID) ERR; + /* Check it out. Find the group by name. */ if (nc_inq_ncid(ncid, HENRY_VII, &grpid_in)) ERR; @@ -220,15 +310,26 @@ main(int argc, char **argv) printf("*** testing simple nested group creates..."); { + char root_name[] = "/"; int ncid, grp_ncid; int henry_vii_id, margaret_id, james_v_of_scotland_id, mary_i_of_scotland_id; - int james_i_of_england_id; char name_in[NC_MAX_NAME + 1]; char full_name[NC_MAX_NAME * 10], full_name_in[NC_MAX_NAME * 10]; + char full_name_in1[NC_MAX_NAME * 10]; + char wrong_name[NC_MAX_NAME * 10]; int grpid_in[MAX_SIBLING_GROUPS]; int grp_in; + int grp_in2; int num_grps; - size_t len; + size_t len, len1; + + /* This name is wrong. */ + strcpy(wrong_name, "/"); + strcat(wrong_name, HENRY_VII); + strcpy(wrong_name, "/"); + strcat(wrong_name, MARGARET); + strcpy(wrong_name, "/"); + strcat(wrong_name, MARGARET); /* Create a file with some nested groups in it, suitable * to storing information about the Tudor dynasty of England. */ @@ -237,16 +338,37 @@ main(int argc, char **argv) if (nc_def_grp(henry_vii_id, MARGARET, &margaret_id)) ERR; if (nc_def_grp(margaret_id, JAMES_V_OF_SCOTLAND, &james_v_of_scotland_id)) ERR; if (nc_def_grp(james_v_of_scotland_id, MARY_I_OF_SCOTLAND, &mary_i_of_scotland_id)) ERR; - if (nc_def_grp(mary_i_of_scotland_id, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &james_i_of_england_id)) ERR; + /* nc_def_grp will accept NULL as ID pointer. Group will be + * created, but ID not returned. */ + if (nc_def_grp(mary_i_of_scotland_id, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, NULL)) ERR; strcpy(full_name, "/"); if (nc_inq_grpname_full(ncid, &len, full_name_in)) ERR; if (len != 1 || strcmp(full_name_in, full_name)) ERR; if (nc_inq_grpname_len(ncid, &len)) ERR; if (len != 1) ERR; + + /* These won't work. */ + if (nc_inq_grp_full_ncid(ncid + TEST_VAL_42, full_name, &grp_in) != NC_EBADID) ERR; + if (nc_inq_grp_full_ncid(ncid, NULL, &grp_in) != NC_EINVAL) ERR; + + /* Get the ncid from the full name. */ if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR; if (grp_in != ncid) ERR; + /* Works (pretty pointlessly) with NULL for ID pointer. */ + if (nc_inq_grp_full_ncid(ncid, full_name, NULL)) ERR; + + /* Get the root group ID from '/'. */ + if (nc_inq_grp_full_ncid(ncid, root_name, &grp_in2)) ERR; + if (grp_in2 != ncid) ERR; + + /* But the root group does not exist within another group. */ + if (nc_inq_grp_full_ncid(mary_i_of_scotland_id, root_name, &grp_in2) != NC_ENOGRP) ERR; + + /* This name is wrong. */ + if (nc_inq_grp_full_ncid(ncid, wrong_name, &grp_in2) != NC_ENOGRP) ERR; + if (nc_inq_grp_ncid(ncid, HENRY_VII, NULL)) ERR; if (nc_inq_grp_ncid(ncid, HENRY_VII, &grp_ncid)) ERR; if (nc_inq_grps(ncid, &num_grps, NULL)) ERR; @@ -254,6 +376,7 @@ main(int argc, char **argv) if (nc_inq_grps(ncid, NULL, grpid_in)) ERR; if (nc_inq_grpname(grpid_in[0], name_in)) ERR; if (strcmp(name_in, HENRY_VII)) ERR; + if (nc_inq_grpname(grpid_in[0], NULL)) ERR; if (grpid_in[0] != grp_ncid) ERR; strcat(full_name, HENRY_VII); if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in)) ERR; @@ -261,6 +384,9 @@ main(int argc, char **argv) if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR; if (grp_in != grpid_in[0]) ERR; + /* Also works with NULL last param. */ + if (nc_inq_grp_full_ncid(ncid, full_name, NULL)) ERR; + if (nc_inq_grp_ncid(grpid_in[0], MARGARET, &grp_ncid)) ERR; if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR; if (num_grps != 1) ERR; @@ -312,6 +438,11 @@ main(int argc, char **argv) if (len != strlen(full_name) || strcmp(full_name_in, full_name)) ERR; if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR; if (grp_in != grpid_in[0]) ERR; + if (nc_inq_grpname_full(grpid_in[0], NULL, NULL)) ERR; + if (nc_inq_grpname_full(grpid_in[0], &len1, NULL)) ERR; + if (len1 != strlen(full_name)) ERR; + if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in1)) ERR; + if (strcmp(full_name_in1, full_name)) ERR; if (nc_close(ncid)) ERR;