mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-02-17 16:50:18 +08:00
Add -g option to ncdump and test it
This commit is contained in:
parent
1e02fd4f1d
commit
97c954a859
@ -3439,7 +3439,7 @@ This example is from test program libsrc4/tst_grps.c.
|
||||
@section Find a Group by its Fully-qualified Name: nc_inq_grp_full_ncid
|
||||
@findex nc_inq_grp_parent
|
||||
|
||||
Given a fully qualified group name an an ncid, find the ncid of the
|
||||
Given a fully qualified group name and an ncid, find the ncid of the
|
||||
group id.
|
||||
|
||||
@heading Usage
|
||||
|
@ -2741,7 +2741,7 @@ C Check the parent ncid.
|
||||
@section Find a Group by Name: NF_INQ_GRP_NCID
|
||||
@findex NF_INQ_GRP_PARENT
|
||||
|
||||
Given a group name an an ncid, find the ncid of the group id.
|
||||
Given a group name and an ncid, find the ncid of the group id.
|
||||
|
||||
@heading Usage
|
||||
|
||||
@ -2807,7 +2807,7 @@ C Go to a child group and find the id of our type.
|
||||
@section Find a Group by its Fully-qualified Name: NF_INQ_GRP_FULL_NCID
|
||||
@findex NF_INQ_GRP_PARENT
|
||||
|
||||
Given a fully qualified group name an an ncid, find the ncid of the
|
||||
Given a fully qualified group name and an ncid, find the ncid of the
|
||||
group id.
|
||||
|
||||
@heading Usage
|
||||
|
@ -2248,7 +2248,7 @@ An error was reported by the HDF5 layer.
|
||||
@section Find a Group by Name: NF90_INQ_GRP_NCID
|
||||
@findex NF90_INQ_GRP_PARENT
|
||||
|
||||
Given a group name an an ncid, find the ncid of the group id.
|
||||
Given a group name and an ncid, find the ncid of the group id.
|
||||
|
||||
@heading Usage
|
||||
|
||||
@ -2323,7 +2323,7 @@ This example is from test program nf_test/f90tst_grps.f90.
|
||||
@section Find a Group by its Fully-qualified Name: NF90_INQ_GRP_FULL_NCID
|
||||
@findex NF90_INQ_GRP_PARENT
|
||||
|
||||
Given a fully qualified group name an an ncid, find the ncid of the
|
||||
Given a fully qualified group name and an ncid, find the ncid of the
|
||||
group id.
|
||||
|
||||
@heading Usage
|
||||
|
@ -40,7 +40,8 @@ tst_chunking
|
||||
TESTS += tst_create_files tst_group_data tst_enum_data tst_opaque_data \
|
||||
tst_string_data tst_vlen_data tst_comp tst_comp2 tst_nans \
|
||||
tst_special_atts tst_netcdf4.sh tst_h_rdc0 tst_unicode tst_fillbug \
|
||||
tst_fillbug.sh tst_netcdf4_4.sh tst_compress tst_nccopy4.sh
|
||||
tst_fillbug.sh tst_netcdf4_4.sh tst_compress tst_nccopy4.sh \
|
||||
tst_grp_spec.sh
|
||||
|
||||
if EXTRA_TESTS
|
||||
TESTS += run_back_comp_tests.sh
|
||||
@ -65,7 +66,7 @@ tst_string_data.cdl tst_fillbug.cdl tst_opaque_data.cdl \
|
||||
tst_compounds4.cdl tst_utf8.cdl tst_compounds3.cdl \
|
||||
tst_special_atts.cdl tst_nans.cdl tst_format_att_64.cdl \
|
||||
tst_vlen_data.cdl tst_solar_1.cdl tst_format_att.cdl tst_inflated.nc \
|
||||
tst_inflated4.nc tst_deflated.nc tst_chunking.nc tmp*.nc
|
||||
tmp_subset.cdl tst_inflated4.nc tst_deflated.nc tst_chunking.nc tmp*.nc
|
||||
|
||||
# These files all have to be included with the distribution.
|
||||
EXTRA_DIST = run_tests.sh tst_64bit.sh tst_output.sh test0.cdl \
|
||||
@ -82,7 +83,8 @@ ref_tst_compounds3.nc ref_tst_compounds3.cdl ref_tst_compounds4.nc \
|
||||
ref_tst_compounds4.cdl ref_tst_group_data_v23.cdl tst_mslp.cdl \
|
||||
ref_tst_format_att.cdl ref_tst_format_att_64.cdl tst_nccopy3.sh \
|
||||
tst_nccopy4.sh ref_nc_test_netcdf4_4_0.nc run_back_comp_tests.sh \
|
||||
ref_nc_test_netcdf4.cdl ref_tst_special_atts3.cdl tst_brecs.cdl
|
||||
ref_nc_test_netcdf4.cdl ref_tst_special_atts3.cdl tst_brecs.cdl \
|
||||
ref_tst_grp_spec0.cdl ref_tst_grp_spec.cdl tst_grp_spec.sh
|
||||
|
||||
# Can't run ncgen to generate ctest.c and ctest64.c on cross-compiles.
|
||||
BUILT_SOURCES = ctest.c ctest64.c
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include <netcdf.h>
|
||||
#include "utils.h"
|
||||
#include "nccomps.h"
|
||||
#include "ncdump.h"
|
||||
#include "dumplib.h"
|
||||
#include "ncdump.h"
|
||||
#include "isnan.h"
|
||||
#include "nctime0.h"
|
||||
|
||||
@ -103,7 +103,7 @@ init_epsilons(void)
|
||||
|
||||
|
||||
static char* has_c_format_att(int ncid, int varid);
|
||||
static vnode_t* newvnode(void);
|
||||
static idnode_t* newidnode(void);
|
||||
|
||||
int float_precision_specified = 0; /* -p option specified float precision */
|
||||
int double_precision_specified = 0; /* -p option specified double precision */
|
||||
@ -419,10 +419,10 @@ get_fmt(
|
||||
return get_default_fmt(typeid);
|
||||
}
|
||||
|
||||
static vnode_t*
|
||||
newvnode(void)
|
||||
static idnode_t*
|
||||
newidnode(void)
|
||||
{
|
||||
vnode_t *newvp = (vnode_t*) emalloc(sizeof(vnode_t));
|
||||
idnode_t *newvp = (idnode_t*) emalloc(sizeof(idnode_t));
|
||||
return newvp;
|
||||
}
|
||||
|
||||
@ -430,10 +430,10 @@ newvnode(void)
|
||||
/*
|
||||
* Get a new, empty variable list.
|
||||
*/
|
||||
vnode_t*
|
||||
newvlist(void)
|
||||
idnode_t*
|
||||
newidlist(void)
|
||||
{
|
||||
vnode_t *vp = newvnode();
|
||||
idnode_t *vp = newidnode();
|
||||
|
||||
vp -> next = 0;
|
||||
vp -> id = -1; /* bad id */
|
||||
@ -443,9 +443,9 @@ newvlist(void)
|
||||
|
||||
|
||||
void
|
||||
varadd(vnode_t* vlist, int varid)
|
||||
idadd(idnode_t* vlist, int varid)
|
||||
{
|
||||
vnode_t *newvp = newvnode();
|
||||
idnode_t *newvp = newidnode();
|
||||
|
||||
newvp -> next = vlist -> next;
|
||||
newvp -> id = varid;
|
||||
@ -454,20 +454,34 @@ varadd(vnode_t* vlist, int varid)
|
||||
|
||||
|
||||
/*
|
||||
* return 1 if variable identified by varid is member of variable
|
||||
* list vlist points to.
|
||||
* return true if id is member of list that vlist points to.
|
||||
*/
|
||||
int
|
||||
varmember(const vnode_t* vlist, int varid)
|
||||
boolean
|
||||
idmember(const idnode_t* idlist, int id)
|
||||
{
|
||||
vnode_t *vp = vlist -> next;
|
||||
idnode_t *vp = idlist -> next;
|
||||
|
||||
for (; vp ; vp = vp->next)
|
||||
if (vp->id == varid)
|
||||
return 1;
|
||||
return 0;
|
||||
if (vp->id == id)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* return true if group identified by grpid is member of group
|
||||
* list specified on command line by -g.
|
||||
*/
|
||||
boolean
|
||||
group_wanted(int grpid)
|
||||
{
|
||||
int igrp;
|
||||
|
||||
/* If -g not specified, all groups are wanted */
|
||||
if(formatting_specs.nlgrps == 0)
|
||||
return true;
|
||||
/* if -g specified, look for match in group id list */
|
||||
return idmember(formatting_specs.grpids, grpid);
|
||||
}
|
||||
|
||||
/* Return primitive type name */
|
||||
static const char *
|
||||
@ -1495,9 +1509,6 @@ nc_inq_gvarid(int grpid, const char *varname, int *varidp) {
|
||||
*/
|
||||
|
||||
#ifdef USE_NETCDF4
|
||||
#ifdef UNUSED
|
||||
const char *vp = varname;
|
||||
#endif
|
||||
char *vargroup;
|
||||
char *relname;
|
||||
char *groupname;
|
||||
@ -1723,9 +1734,6 @@ init_types(int ncid) {
|
||||
* recursively on each of them. */
|
||||
{
|
||||
int g, numgrps, *ncids;
|
||||
#ifdef UNUSED
|
||||
int format;
|
||||
#endif
|
||||
|
||||
/* See how many groups there are. */
|
||||
NC_CHECK( nc_inq_grps(ncid, &numgrps, NULL) );
|
||||
|
@ -3,6 +3,8 @@
|
||||
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
||||
* $Header: /upc/share/CVS/netcdf-3/ncdump/dumplib.h,v 1.28 2009/08/13 21:06:13 russ Exp $
|
||||
*********************************************************************/
|
||||
#ifndef _DUMPLIB_H_
|
||||
#define _DUMPLIB_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@ -53,22 +55,25 @@ extern void set_formats ( int flt_digs, int dbl_digs );
|
||||
/* Determine print format to use for each value for this variable. */
|
||||
const char * get_fmt ( int ncid, int varid, nc_type typeid );
|
||||
|
||||
/* structure for list of variables specified with -v option */
|
||||
struct vnode
|
||||
/* structure for list of ids, such as varids or grpids specified with -v or -g option */
|
||||
struct idnode
|
||||
{
|
||||
struct vnode* next;
|
||||
struct idnode* next;
|
||||
int id;
|
||||
};
|
||||
typedef struct vnode vnode_t;
|
||||
typedef struct idnode idnode_t;
|
||||
|
||||
/* Get new variable list */
|
||||
extern vnode_t* newvlist ( void );
|
||||
/* Get new id list */
|
||||
extern idnode_t* newidlist ( void );
|
||||
|
||||
/* Add a variable id to variable list */
|
||||
extern void varadd ( vnode_t* vlist, int varid );
|
||||
/* Add an id to id list */
|
||||
extern void idadd ( idnode_t* idlist, int id );
|
||||
|
||||
/* Test if a variable id is in variable list */
|
||||
extern int varmember ( const vnode_t* vlist, int varid );
|
||||
extern boolean idmember ( const idnode_t* idlist, int id );
|
||||
|
||||
/* Test if a group id is in group list */
|
||||
extern boolean group_wanted ( int grpid );
|
||||
|
||||
/* Add type info to type list */
|
||||
extern void typeadd ( nctype_t *typep );
|
||||
@ -77,7 +82,7 @@ extern void typeadd ( nctype_t *typep );
|
||||
extern nctype_t *get_typeinfo ( int typeid );
|
||||
|
||||
/* From type id, get type name */
|
||||
extern void get_type_name(int ncid, nc_type type, char *name);
|
||||
extern void get_type_name(int ncid, nc_type type, char *name);
|
||||
|
||||
/* set tostring member function */
|
||||
extern void set_tostring_func ( ncvar_t *varp);
|
||||
@ -143,3 +148,5 @@ int nctime_val_tostring(const ncvar_t *varp, safebuf_t *sfbf, const void *valp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_DUMPLIB_H_ */
|
||||
|
211
ncdump/ncdump.c
211
ncdump/ncdump.c
@ -23,8 +23,8 @@ Research/Unidata. See \ref copyright file for more info. */
|
||||
#include "utils.h"
|
||||
#include "nccomps.h"
|
||||
#include "nctime0.h" /* new iso time and calendar stuff */
|
||||
#include "ncdump.h"
|
||||
#include "dumplib.h"
|
||||
#include "ncdump.h"
|
||||
#include "vardata.h"
|
||||
#include "indent.h"
|
||||
#include "isnan.h"
|
||||
@ -46,9 +46,13 @@ fspec_t formatting_specs = /* defaults, overridden by command-line options */
|
||||
false, /* use 'T' separator between date and time values as strings? */
|
||||
false, /* output special attributes, eg chunking? */
|
||||
LANG_C, /* language conventions for indices */
|
||||
0, /* if -v specified, number of variables */
|
||||
false, /* for DAP URLs, client-side cache used */
|
||||
0 /* if -v specified, list of variable names */
|
||||
0, /* if -v specified, number of variables in list */
|
||||
0, /* if -v specified, list of variable names */
|
||||
0, /* if -g specified, number of groups names in list */
|
||||
0, /* if -g specified, list of group names */
|
||||
0, /* if -g specified, list of matching grpids */
|
||||
0 /* kind of netCDF file */
|
||||
};
|
||||
|
||||
static void
|
||||
@ -68,11 +72,12 @@ usage(void)
|
||||
[-s] Output special (virtual) attributes\n\
|
||||
[-t] Output time data as date-time strings\n\
|
||||
[-i] Output time data as date-time strings with ISO-8601 'T' separator\n\
|
||||
[-g grp1[,...]] Data and metadata for group(s) <grp1>,... only\
|
||||
[-w] Without client-side caching of variables for DAP URLs\n\
|
||||
file Name of netCDF file\n"
|
||||
|
||||
(void) fprintf(stderr,
|
||||
"%s [-c|-h] [-v ...] [[-b|-f] [c|f]] [-l len] [-n name] [-p n[,n]] [-k] [-x] [-s] [-t|-i] [-w] file\n%s",
|
||||
"%s [-c|-h] [-v ...] [[-b|-f] [c|f]] [-l len] [-n name] [-p n[,n]] [-k] [-x] [-s] [-t|-i] [-g ...] [-w] file\n%s",
|
||||
progname,
|
||||
USAGE);
|
||||
|
||||
@ -222,21 +227,6 @@ kind_string(int kind)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit kind of netCDF file
|
||||
*/
|
||||
static void
|
||||
do_nckind(int ncid, const char *path)
|
||||
{
|
||||
int nc_kind;
|
||||
|
||||
/*nc_set_log_level(3);*/
|
||||
|
||||
NC_CHECK( nc_inq_format(ncid, &nc_kind) );
|
||||
printf ("%s\n", kind_string(nc_kind));
|
||||
NC_CHECK( nc_close(ncid) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Emit initial line of output for NcML
|
||||
@ -1255,13 +1245,12 @@ get_fill_info(int ncid, int varid, ncvar_t *vp) {
|
||||
}
|
||||
|
||||
|
||||
/* Recursively dump the contents of a group. (Recall that only
|
||||
* netcdf-4 format files can have groups. On all other formats, there
|
||||
* is just a root group, so recursion will not take place.)
|
||||
/* Recursively dump the contents of a group. (Only netcdf-4 format
|
||||
* files can have groups, so recursion will not take place for classic
|
||||
* format files.)
|
||||
*
|
||||
* ncid: id of open file (first call) or group (subsequent recursive calls)
|
||||
* path: file path name (first call)
|
||||
* specp: formatting spec
|
||||
*/
|
||||
static void
|
||||
do_ncdump_rec(int ncid, const char *path)
|
||||
@ -1277,7 +1266,7 @@ do_ncdump_rec(int ncid, const char *path)
|
||||
int id; /* dimension number per variable */
|
||||
int ia; /* attribute number */
|
||||
int iv; /* variable number */
|
||||
vnode_t* vlist = 0; /* list for vars specified with -v option */
|
||||
idnode_t* vlist = 0; /* list for vars specified with -v option */
|
||||
char type_name[NC_MAX_NAME + 1];
|
||||
int kind; /* strings output differently for nc4 files */
|
||||
char dim_name[NC_MAX_NAME + 1];
|
||||
@ -1304,10 +1293,10 @@ do_ncdump_rec(int ncid, const char *path)
|
||||
* "/grp1/grp2/varname" if they are in groups.
|
||||
*/
|
||||
if (formatting_specs.nlvars > 0) {
|
||||
vlist = newvlist(); /* list for vars specified with -v option */
|
||||
vlist = newidlist(); /* list for vars specified with -v option */
|
||||
for (iv=0; iv < formatting_specs.nlvars; iv++) {
|
||||
if(nc_inq_gvarid(ncid, formatting_specs.lvars[iv], &varid) == NC_NOERR)
|
||||
varadd(vlist, varid);
|
||||
idadd(vlist, varid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1530,8 +1519,10 @@ do_ncdump_rec(int ncid, const char *path)
|
||||
pr_att_global_format(ncid, kind);
|
||||
}
|
||||
|
||||
/* output variable data */
|
||||
if (! formatting_specs.header_only) {
|
||||
/* output variable data, unless "-h" option specified header only
|
||||
* or this group is not in list of groups specified by "-g"
|
||||
* option */
|
||||
if (! formatting_specs.header_only && group_wanted(ncid) ) {
|
||||
if (nvars > 0) {
|
||||
indent_out();
|
||||
printf ("data:\n");
|
||||
@ -1539,7 +1530,7 @@ do_ncdump_rec(int ncid, const char *path)
|
||||
for (varid = 0; varid < nvars; varid++) {
|
||||
int no_data;
|
||||
/* if var list specified, test for membership */
|
||||
if (formatting_specs.nlvars > 0 && ! varmember(vlist, varid))
|
||||
if (formatting_specs.nlvars > 0 && ! idmember(vlist, varid))
|
||||
continue;
|
||||
NC_CHECK( nc_inq_varndims(ncid, varid, &var.ndims) );
|
||||
if(var.dims != NULL) free(var.dims);
|
||||
@ -1587,8 +1578,6 @@ do_ncdump_rec(int ncid, const char *path)
|
||||
set_tostring_func(&var);
|
||||
if (vardata(&var, vdims, ncid, varid) == -1) {
|
||||
error("can't output data for variable %s", var.name);
|
||||
NC_CHECK(
|
||||
nc_close(ncid) );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@ -1666,7 +1655,6 @@ do_ncdump(int ncid, const char *path)
|
||||
do_ncdump_rec(ncid, path);
|
||||
indent_out();
|
||||
printf ("}\n");
|
||||
NC_CHECK( nc_close(ncid) );
|
||||
}
|
||||
|
||||
|
||||
@ -1683,17 +1671,17 @@ do_ncdumpx(int ncid, const char *path)
|
||||
ncvar_t var; /* variable */
|
||||
int ia; /* attribute number */
|
||||
int iv; /* variable number */
|
||||
vnode_t* vlist = 0; /* list for vars specified with -v option */
|
||||
idnode_t* vlist = 0; /* list for vars specified with -v option */
|
||||
|
||||
/*
|
||||
* If any vars were specified with -v option, get list of associated
|
||||
* variable ids
|
||||
*/
|
||||
if (formatting_specs.nlvars > 0) {
|
||||
vlist = newvlist(); /* list for vars specified with -v option */
|
||||
vlist = newidlist(); /* list for vars specified with -v option */
|
||||
for (iv=0; iv < formatting_specs.nlvars; iv++) {
|
||||
NC_CHECK( nc_inq_varid(ncid, formatting_specs.lvars[iv], &varid) );
|
||||
varadd(vlist, varid);
|
||||
idadd(vlist, varid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1742,7 +1730,7 @@ do_ncdumpx(int ncid, const char *path)
|
||||
/* header-only specified */
|
||||
(formatting_specs.header_only) ||
|
||||
/* list of variables specified and this variable not in list */
|
||||
(formatting_specs.nlvars > 0 && !varmember(vlist, varid)) ||
|
||||
(formatting_specs.nlvars > 0 && !idmember(vlist, varid)) ||
|
||||
/* coordinate vars only and this is not a coordinate variable */
|
||||
(formatting_specs.coord_vals && !iscoordvar(ncid, varid)) ||
|
||||
/* this is a record variable, but no records have been written */
|
||||
@ -1764,8 +1752,6 @@ do_ncdumpx(int ncid, const char *path)
|
||||
}
|
||||
|
||||
printf ("</netcdf>\n");
|
||||
NC_CHECK(
|
||||
nc_close(ncid) );
|
||||
if (vlist)
|
||||
free(vlist);
|
||||
if(dims)
|
||||
@ -1784,24 +1770,16 @@ make_lvars(char *optarg)
|
||||
while (*cp++)
|
||||
if (*cp == ',')
|
||||
nvars++;
|
||||
|
||||
formatting_specs.nlvars = nvars;
|
||||
formatting_specs.lvars = (char **) emalloc(nvars * sizeof(char*));
|
||||
|
||||
cpp = formatting_specs.lvars;
|
||||
/* copy variable names into list */
|
||||
for (cp = strtok(optarg, ",");
|
||||
cp != NULL;
|
||||
cp = strtok((char *) NULL, ",")) {
|
||||
size_t bufsiz = strlen(cp) + 1;
|
||||
|
||||
*cpp = (char *) emalloc(bufsiz);
|
||||
strncpy(*cpp, cp, bufsiz);
|
||||
for (cp = strtok(optarg, ","); cp != NULL; cp = strtok((char *) NULL, ",")) {
|
||||
*cpp = strdup(cp);
|
||||
cpp++;
|
||||
}
|
||||
formatting_specs.nlvars = nvars;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
make_lgrps(char *optarg)
|
||||
{
|
||||
@ -1809,26 +1787,20 @@ make_lgrps(char *optarg)
|
||||
int ngrps = 1;
|
||||
char ** cpp;
|
||||
|
||||
/* compute number of variable names in comma-delimited list */
|
||||
formatting_specs.nlgrps = 1;
|
||||
/* compute number of group names in comma-delimited list */
|
||||
while (*cp++)
|
||||
if (*cp == ',')
|
||||
ngrps++;
|
||||
|
||||
formatting_specs.nlgrps = ngrps;
|
||||
formatting_specs.lgrps = (char **) emalloc(ngrps * sizeof(char*));
|
||||
|
||||
cpp = formatting_specs.lgrps;
|
||||
/* copy variable names into list */
|
||||
for (cp = strtok(optarg, ",");
|
||||
cp != NULL;
|
||||
cp = strtok((char *) NULL, ",")) {
|
||||
size_t bufsiz = strlen(cp) + 1;
|
||||
|
||||
*cpp = (char *) emalloc(bufsiz);
|
||||
strncpy(*cpp, cp, bufsiz);
|
||||
/* copy group names into list */
|
||||
for (cp = strtok(optarg, ","); cp != NULL; cp = strtok((char *) NULL, ",")) {
|
||||
*cpp = strdup(cp);
|
||||
cpp++;
|
||||
}
|
||||
formatting_specs.nlgrps = ngrps;
|
||||
/* make empty list of grpids, to be filled in after input file opened */
|
||||
formatting_specs.grpids = newidlist();
|
||||
}
|
||||
|
||||
|
||||
@ -1966,63 +1938,90 @@ missing_vars(int ncid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine whether a group named grpname exists in any group in an
|
||||
* open netCDF file with id ncid. If so, return the count of how many
|
||||
* matching groups were found, else return a count of 0. */
|
||||
size_t
|
||||
nc_inq_grpname_count(int ncid, char *grpname) {
|
||||
/*
|
||||
count = 0;
|
||||
status = nc_inq_ncid(ncid, grpname, &grpid);
|
||||
if (status == NC_NOERR)
|
||||
count++;
|
||||
for each subgroup gid {
|
||||
count += nc_inq_grpname_count(gid, grpname);
|
||||
}
|
||||
return count;
|
||||
*/
|
||||
/* Determine whether a group named formatting_specs.lgrps[igrp] exists
|
||||
* in a netCDF file or group with id ncid. If so, return the count of
|
||||
* how many matching groups were found, else return a count of 0. If
|
||||
* the name begins with "/", it is interpreted as an absolute group
|
||||
* name, in which case only 0 or 1 is returned. Otherwise, interpret
|
||||
* it as a relative name, and the total number of occurrences within
|
||||
* the file/group identified by ncid is returned.
|
||||
*
|
||||
* Also has side effect of updating the ngrpids and the associate
|
||||
* grpids array that represent the group list specified by the -g
|
||||
* option. TODO: put this in its own function instead.
|
||||
*/
|
||||
static size_t
|
||||
nc_inq_grpname_count(int ncid, int igrp) {
|
||||
size_t count = 0;
|
||||
#ifdef USE_NETCDF4
|
||||
int numgrps;
|
||||
int *ncids;
|
||||
int g;
|
||||
int grpid;
|
||||
int status;
|
||||
char *grpname=formatting_specs.lgrps[igrp];
|
||||
|
||||
/* permit empty string to also designate root group */
|
||||
if(grpname[0] == '\0' || STREQ(grpname,"/")) {
|
||||
count = 1;
|
||||
idadd(formatting_specs.grpids, ncid);
|
||||
return count;
|
||||
}
|
||||
#ifdef USE_NETCDF4
|
||||
/* Handle absolute group names */
|
||||
if(grpname[0] == '/') {
|
||||
int grpid;
|
||||
status = nc_inq_grp_full_ncid(ncid, grpname, &grpid);
|
||||
if(status == NC_NOERR) {
|
||||
count = 1;
|
||||
idadd(formatting_specs.grpids, grpid);
|
||||
} else if(status == NC_ENOGRP) {
|
||||
count = 0;
|
||||
} else {
|
||||
error("when looking up group %s: %s ", grpname, nc_strerror(status));
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* look in this group */
|
||||
int status = nc_inq_ncid(ncid, grpname, &grpid);
|
||||
if (status == NC_NOERR)
|
||||
status = nc_inq_grp_ncid(ncid, grpname, &grpid);
|
||||
if (status == NC_NOERR) {
|
||||
count++;
|
||||
idadd(formatting_specs.grpids, grpid);
|
||||
}
|
||||
/* if this group has subgroups, call recursively on each of them */
|
||||
NC_CHECK( nc_inq_grps(ncid, &numgrps, NULL) );
|
||||
|
||||
/* Allocate memory to hold the list of group ids. */
|
||||
ncids = emalloc((numgrps + 1) * sizeof(int));
|
||||
|
||||
/* Get the list of group ids. */
|
||||
NC_CHECK( nc_inq_grps(ncid, NULL, ncids) );
|
||||
|
||||
/* Call this function for each group. */
|
||||
for (g = 0; g < numgrps; g++) {
|
||||
count += nc_inq_grpname_count(ncids[g], grpname);
|
||||
if(numgrps > 0) {
|
||||
/* Allocate memory to hold the list of group ids. */
|
||||
ncids = emalloc(numgrps * sizeof(int));
|
||||
/* Get the list of group ids. */
|
||||
NC_CHECK( nc_inq_grps(ncid, NULL, ncids) );
|
||||
/* Call this function recursively for each group. */
|
||||
for (g = 0; g < numgrps; g++) {
|
||||
count += nc_inq_grpname_count(ncids[g], igrp);
|
||||
}
|
||||
free(ncids);
|
||||
}
|
||||
free(ncids);
|
||||
#endif /* USE_NETCDF4 */
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/* Check if any group names specified with "-g grp1,...,grpn" are
|
||||
* missing. Returns 0 if no missing groups detected, otherwise
|
||||
* exits. */
|
||||
* missing. Returns total number of matching groups if no missing
|
||||
* groups detected, otherwise exits. */
|
||||
static int
|
||||
missing_grps(int ncid) {
|
||||
grp_matches(int ncid) {
|
||||
int ig;
|
||||
size_t total = 0;
|
||||
|
||||
for (ig=0; ig < formatting_specs.nlgrps; ig++) {
|
||||
if(nc_inq_grpname_count(ncid, formatting_specs.lgrps[ig]) == 0) {
|
||||
size_t count = nc_inq_grpname_count(ncid, ig);
|
||||
if(count == 0) {
|
||||
error("%s: No such group", formatting_specs.lgrps[ig]);
|
||||
return 0;
|
||||
}
|
||||
total += count;
|
||||
}
|
||||
return 0;
|
||||
return total;
|
||||
}
|
||||
|
||||
#define DAP_CLIENT_CACHE_DIRECTIVE "[cache]"
|
||||
@ -2266,7 +2265,7 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
}
|
||||
|
||||
while ((c = getopt(argc, argv, "b:cd:f:hijkl:n:p:stv:xw")) != EOF)
|
||||
while ((c = getopt(argc, argv, "b:cd:f:g:hijkl:n:p:stv:xw")) != EOF)
|
||||
switch(c) {
|
||||
case 'h': /* dump header only, no data */
|
||||
formatting_specs.header_only = true;
|
||||
@ -2396,23 +2395,31 @@ main(int argc, char *argv[])
|
||||
if (nc_status != NC_NOERR) {
|
||||
error("%s: %s", path, nc_strerror(nc_status));
|
||||
}
|
||||
NC_CHECK( nc_inq_format(ncid, &formatting_specs.nc_kind) );
|
||||
if (kind_out) {
|
||||
do_nckind(ncid, path);
|
||||
printf ("%s\n", kind_string(formatting_specs.nc_kind));
|
||||
} else {
|
||||
/* Initialize list of types. */
|
||||
init_types(ncid);
|
||||
/* Check if any vars in -v don't exist */
|
||||
if(missing_vars(ncid))
|
||||
return EXIT_FAILURE;
|
||||
/* Check if any grps in -g don't exist */
|
||||
if(missing_grps(ncid))
|
||||
return EXIT_FAILURE;
|
||||
if(formatting_specs.nlgrps > 0) {
|
||||
if(formatting_specs.nc_kind != NC_FORMAT_NETCDF4) {
|
||||
error("Group list (-g ...) only permitted for netCDF-4 file");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/* Check if any grps in -g don't exist */
|
||||
if(grp_matches(ncid) == 0)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (xml_out) {
|
||||
do_ncdumpx(ncid, path);
|
||||
} else {
|
||||
do_ncdump(ncid, path);
|
||||
}
|
||||
}
|
||||
NC_CHECK( nc_close(ncid) );
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
@ -50,12 +50,12 @@ typedef struct { /* specification for how to format dump */
|
||||
* column major) or LANG_F (Fortran,
|
||||
* 1-based, row major) */
|
||||
|
||||
int nlvars; /* Number of variables specified with -v
|
||||
* option on command line */
|
||||
|
||||
boolean with_cache; /* For DAP URLs, get data with client-side
|
||||
* caching when each variable is first accessed */
|
||||
|
||||
int nlvars; /* Number of variables specified with -v
|
||||
* option on command line */
|
||||
|
||||
char** lvars; /* list of variable names specified with -v
|
||||
* option on command line */
|
||||
|
||||
@ -64,6 +64,13 @@ typedef struct { /* specification for how to format dump */
|
||||
|
||||
char** lgrps; /* list of group names specified with -g
|
||||
* option on command line */
|
||||
|
||||
idnode_t* grpids; /* list of grpids matching list specified with -g option */
|
||||
|
||||
int nc_kind; /* kind of netCDF file named on
|
||||
* command line, 1 (classic), 2
|
||||
* (64-bit offset), 3 (netCDF-4), 4
|
||||
* (netCDF-4 classic model) */
|
||||
} fspec_t;
|
||||
|
||||
#endif /*_NCDUMP_H_ */
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netcdf.h>
|
||||
#include "utils.h"
|
||||
#include "nciter.h"
|
||||
|
||||
|
@ -23,11 +23,11 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <netcdf.h>
|
||||
#include "utils.h"
|
||||
#include "nccomps.h"
|
||||
#include "dumplib.h" /* for sbuf_... prototypes */
|
||||
#include "ncdump.h" /* for fspec_t def */
|
||||
#include "vardata.h"
|
||||
#include "nctime0.h"
|
||||
|
||||
|
||||
|
64
ncdump/ref_tst_grp_spec.cdl
Normal file
64
ncdump/ref_tst_grp_spec.cdl
Normal file
@ -0,0 +1,64 @@
|
||||
netcdf tmp_subset {
|
||||
dimensions:
|
||||
dim = UNLIMITED ; // (1 currently)
|
||||
variables:
|
||||
float var(dim) ;
|
||||
|
||||
group: g1 {
|
||||
dimensions:
|
||||
dim = 1 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1 ;
|
||||
|
||||
group: g2 {
|
||||
dimensions:
|
||||
dim = 2 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
} // group g2
|
||||
|
||||
group: g3 {
|
||||
dimensions:
|
||||
dim = 3 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
} // group g3
|
||||
} // group g1
|
||||
|
||||
group: g4 {
|
||||
dimensions:
|
||||
dim = 4 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1, 2, 3, 4 ;
|
||||
|
||||
group: g5 {
|
||||
dimensions:
|
||||
dim = 5 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
|
||||
group: g6 {
|
||||
dimensions:
|
||||
dim = 6 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
} // group g6
|
||||
|
||||
group: g1 {
|
||||
dimensions:
|
||||
dim = 1 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 451 ;
|
||||
} // group g1
|
||||
} // group g5
|
||||
} // group g4
|
||||
}
|
79
ncdump/ref_tst_grp_spec0.cdl
Normal file
79
ncdump/ref_tst_grp_spec0.cdl
Normal file
@ -0,0 +1,79 @@
|
||||
netcdf ref_tst_grp_spec0 {
|
||||
dimensions:
|
||||
dim = UNLIMITED ; // (1 currently)
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 0 ;
|
||||
|
||||
group: g1 {
|
||||
dimensions:
|
||||
dim = 1 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1 ;
|
||||
|
||||
group: g2 {
|
||||
dimensions:
|
||||
dim = 2 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1, 2 ;
|
||||
} // group g2
|
||||
|
||||
group: g3 {
|
||||
dimensions:
|
||||
dim = 3 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1, 2, 3 ;
|
||||
} // group g3
|
||||
} // group g1
|
||||
|
||||
group: g4 {
|
||||
dimensions:
|
||||
dim = 4 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1, 2, 3, 4 ;
|
||||
|
||||
group: g5 {
|
||||
dimensions:
|
||||
dim = 5 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1, 2, 3, 4, 5 ;
|
||||
|
||||
group: g6 {
|
||||
dimensions:
|
||||
dim = 6 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 1, 2, 3, 4, 5, 6 ;
|
||||
} // group g6
|
||||
|
||||
group: g1 {
|
||||
dimensions:
|
||||
dim = 1 ;
|
||||
variables:
|
||||
float var(dim) ;
|
||||
data:
|
||||
|
||||
var = 451 ;
|
||||
} // group g1
|
||||
} // group g5
|
||||
} // group g4
|
||||
}
|
18
ncdump/tst_grp_spec.sh
Executable file
18
ncdump/tst_grp_spec.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
# This shell script tests ncdump -g option for specifying groups for
|
||||
# which data is to be output.
|
||||
# $Id$
|
||||
|
||||
set -e
|
||||
echo ""
|
||||
echo "*** Testing ncdump -g output for specifying group subsets"
|
||||
echo "*** creating netcdf file tst_grp_spec.nc from ref_tst_grp_spec0.cdl..."
|
||||
../ncgen/ncgen -k3 -o tmp_all.nc -b $srcdir/ref_tst_grp_spec0.cdl
|
||||
echo "*** creating tmp_subset.cdl from tmp_all.nc with ncdump -g ..."
|
||||
./ncdump -g g1,g4 -n tmp_subset tmp_all.nc > tmp_subset.cdl
|
||||
echo "*** comparing tmp_subset.cdl with ref_tst_grp_spec.cdl..."
|
||||
diff tmp_subset.cdl $srcdir/ref_tst_grp_spec.cdl
|
||||
|
||||
echo
|
||||
echo "*** All ncdump test output for -g option passed!"
|
||||
exit 0
|
@ -5,7 +5,6 @@
|
||||
*********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include <netcdf.h>
|
||||
|
||||
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
#include <netcdf.h>
|
||||
#include "utils.h"
|
||||
#include "nccomps.h"
|
||||
#include "ncdump.h"
|
||||
#include "dumplib.h"
|
||||
#include "ncdump.h"
|
||||
#include "indent.h"
|
||||
#include "vardata.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user