mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-21 08:39:46 +08:00
1021 lines
38 KiB
C
1021 lines
38 KiB
C
/* This is part of the netCDF package.
|
|
Copyright 2018 University Corporation for Atmospheric Research/Unidata
|
|
See COPYRIGHT file for conditions of use.
|
|
|
|
Test netcdf-4 compound type feature.
|
|
|
|
Ed Hartnett
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <stdlib.h>
|
|
#include <nc_tests.h>
|
|
#include "err_macros.h"
|
|
|
|
#define FILE_NAME "tst_compounds.nc"
|
|
#define SVC_REC "Service_Record"
|
|
#define BATTLES_WITH_KLINGONS "Number_of_Battles_with_Klingons"
|
|
#define DATES_WITH_ALIENS "Dates_with_Alien_Hotties"
|
|
#define STARDATE "Stardate"
|
|
#define RANK 1
|
|
#define DIM_LEN 3
|
|
#define SERVICE_RECORD "Kirk_Service_Record"
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
printf("\n*** Testing netcdf-4 user defined type functions.\n");
|
|
printf("*** testing simple compound scalar variable create...");
|
|
{
|
|
int ncid, typeid, varid;
|
|
size_t nfields;
|
|
int ndims, nvars, natts, unlimdimid;
|
|
char name[NC_MAX_NAME + 1];
|
|
size_t size;
|
|
nc_type xtype, field_xtype;
|
|
int dimids[] = {0}, fieldid;
|
|
int field_ndims, field_sizes[NC_TESTS_MAX_DIMS];
|
|
size_t offset;
|
|
struct s1
|
|
{
|
|
int i1;
|
|
int i2;
|
|
};
|
|
struct s1 data, data_in;
|
|
|
|
/* Create some phony data. */
|
|
data.i1 = 5;
|
|
data.i2 = 10;
|
|
|
|
/* Create a file with a compound type. Write a little data. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
if (nc_def_compound(ncid, sizeof(struct s1), SVC_REC, &typeid)) ERR;
|
|
if (nc_inq_compound(ncid, typeid, name, &size, &nfields)) ERR;
|
|
if (size != sizeof(struct s1) || strcmp(name, SVC_REC) || nfields) ERR;
|
|
if (nc_insert_compound(ncid, typeid, BATTLES_WITH_KLINGONS,
|
|
NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, DATES_WITH_ALIENS,
|
|
NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR;
|
|
|
|
/* This won't work due to bad typeid. */
|
|
if (nc_def_var(ncid, SERVICE_RECORD, typeid + TEST_VAL_42, 0, NULL,
|
|
&varid) != NC_EBADTYPE) ERR;
|
|
|
|
/* Define the variable. */
|
|
if (nc_def_var(ncid, SERVICE_RECORD, typeid, 0, NULL, &varid)) ERR;
|
|
if (nc_put_var(ncid, varid, &data)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Open the file and take a peek. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR;
|
|
if (ndims != 0 || nvars != 1 || natts != 0 || unlimdimid != -1) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Reopen the file and take a more detailed look at the compound
|
|
* type. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq_var(ncid, 0, name, &xtype, &ndims, dimids, &natts)) ERR;
|
|
if (strcmp(name, SERVICE_RECORD) || ndims != 0 || natts != 0) ERR;
|
|
if (nc_inq_compound(ncid, xtype, name, &size, &nfields)) ERR;
|
|
if (nfields != 2 || size != sizeof(struct s1) || strcmp(name, SVC_REC)) ERR;
|
|
if (nc_inq_compound_name(ncid, xtype, name)) ERR;
|
|
if (strcmp(name, SVC_REC)) ERR;
|
|
if (nc_inq_compound_size(ncid, xtype, &size)) ERR;
|
|
if (size != sizeof(struct s1)) ERR;
|
|
if (nc_inq_compound_nfields(ncid, xtype, &nfields)) ERR;
|
|
if (nfields != 2) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 0, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (field_ndims) ERR;
|
|
if (strcmp(name, BATTLES_WITH_KLINGONS) || offset != 0 || (field_xtype != NC_INT || field_ndims != 0)) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 1, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, DATES_WITH_ALIENS) || offset != 4 || field_xtype != NC_INT) ERR;
|
|
if (nc_inq_compound_fieldname(ncid, xtype, 1, name)) ERR;
|
|
if (strcmp(name, DATES_WITH_ALIENS)) ERR;
|
|
if (nc_inq_compound_fieldindex(ncid, xtype, BATTLES_WITH_KLINGONS, &fieldid)) ERR;
|
|
if (fieldid != 0) ERR;
|
|
if (nc_inq_compound_fieldoffset(ncid, xtype, 1, &offset)) ERR;
|
|
if (offset != 4) ERR;
|
|
if (nc_inq_compound_fieldtype(ncid, xtype, 1, &field_xtype)) ERR;
|
|
if (field_xtype != NC_INT) ERR;
|
|
if (nc_get_var(ncid, varid, &data_in)) ERR;
|
|
if (data.i1 != data_in.i1 || data.i2 != data_in.i2) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing simple compound variable create...");
|
|
{
|
|
int ncid, typeid, varid;
|
|
size_t nfields;
|
|
int dimid;
|
|
int ndims, nvars, natts, unlimdimid;
|
|
char name[NC_MAX_NAME + 1];
|
|
size_t size;
|
|
nc_type xtype, field_xtype;
|
|
int dimids[] = {0}, fieldid;
|
|
int field_ndims, field_sizes[NC_TESTS_MAX_DIMS];
|
|
size_t offset;
|
|
int i;
|
|
struct s1
|
|
{
|
|
int i1;
|
|
int i2;
|
|
};
|
|
struct s1 data[DIM_LEN], data_in[DIM_LEN];
|
|
char *dummy;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct s1), DIM_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)data, (void *)dummy, sizeof(struct s1) * DIM_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (i = 0; i < DIM_LEN; i++)
|
|
{
|
|
data[i].i1 = 5;
|
|
data[i].i2 = 10;
|
|
}
|
|
|
|
/* Create a file with a compound type. Write a little data. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
if (nc_def_compound(ncid, sizeof(struct s1), SVC_REC, &typeid)) ERR;
|
|
if (nc_inq_compound(ncid, typeid, name, &size, &nfields)) ERR;
|
|
if (size != sizeof(struct s1) || strcmp(name, SVC_REC) || nfields) ERR;
|
|
if (nc_insert_compound(ncid, typeid, BATTLES_WITH_KLINGONS,
|
|
NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, DATES_WITH_ALIENS,
|
|
NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR;
|
|
if (nc_def_dim(ncid, STARDATE, DIM_LEN, &dimid)) ERR;
|
|
if (nc_def_var(ncid, SERVICE_RECORD, typeid, 1, dimids, &varid)) ERR;
|
|
if (nc_put_var(ncid, varid, data)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Open the file and take a peek. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR;
|
|
if (ndims != 1 || nvars != 1 || natts != 0 || unlimdimid != -1) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Reopen the file and take a more detailed look at the compound
|
|
* type. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq_var(ncid, 0, name, &xtype, &ndims, dimids, &natts)) ERR;
|
|
if (strcmp(name, SERVICE_RECORD) || ndims != 1 || natts != 0 || dimids[0] != 0) ERR;
|
|
if (nc_inq_compound(ncid, xtype, name, &size, &nfields)) ERR;
|
|
if (nfields != 2 || size != sizeof(struct s1) || strcmp(name, SVC_REC)) ERR;
|
|
if (nc_inq_compound_name(ncid, xtype, name)) ERR;
|
|
if (strcmp(name, SVC_REC)) ERR;
|
|
if (nc_inq_compound_size(ncid, xtype, &size)) ERR;
|
|
if (size != sizeof(struct s1)) ERR;
|
|
if (nc_inq_compound_nfields(ncid, xtype, &nfields)) ERR;
|
|
if (nfields != 2) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 0, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (field_ndims) ERR;
|
|
if (strcmp(name, BATTLES_WITH_KLINGONS) || offset != 0 || (field_xtype != NC_INT || field_ndims != 0)) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 1, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, DATES_WITH_ALIENS) || offset != 4 || field_xtype != NC_INT) ERR;
|
|
if (nc_inq_compound_fieldname(ncid, xtype, 1, name)) ERR;
|
|
if (strcmp(name, DATES_WITH_ALIENS)) ERR;
|
|
if (nc_inq_compound_fieldindex(ncid, xtype, BATTLES_WITH_KLINGONS, &fieldid)) ERR;
|
|
if (fieldid != 0) ERR;
|
|
if (nc_inq_compound_fieldoffset(ncid, xtype, 1, &offset)) ERR;
|
|
if (offset != 4) ERR;
|
|
if (nc_inq_compound_fieldtype(ncid, xtype, 1, &field_xtype)) ERR;
|
|
if (field_xtype != NC_INT) ERR;
|
|
if (nc_get_var(ncid, varid, data_in)) ERR;
|
|
for (i=0; i<DIM_LEN; i++)
|
|
if (data[i].i1 != data_in[i].i1 || data[i].i2 != data_in[i].i2) ERR;
|
|
|
|
{ /* Test if we can read/write with get_vars */
|
|
# define STRIDE_S 2
|
|
# define DIM_LEN_S ((1+DIM_LEN) / STRIDE_S)
|
|
size_t start[RANK] = {0};
|
|
size_t edges[RANK] = {2};
|
|
ptrdiff_t stride[RANK] = {2};
|
|
struct s1 datas[DIM_LEN_S];
|
|
memcpy(datas,data,sizeof(datas));
|
|
datas[0].i1 = 13; datas[0].i2 = 23;
|
|
datas[1].i1 = 111; datas[1].i2 = 222;
|
|
memset(data,0,sizeof(data));
|
|
if (nc_get_var(ncid, varid, data)) ERR;
|
|
if (nc_put_vars(ncid, varid, start, edges, stride, datas)) ERR;
|
|
memset(data,0,sizeof(data));
|
|
if (nc_get_var(ncid, varid, data)) ERR;
|
|
for (i=0; i<DIM_LEN_S; i++) { /* verify the write */
|
|
if(data[i*STRIDE_S].i1 != datas[i].i1 || data[i*STRIDE_S].i2 != datas[i].i2) ERR;
|
|
}
|
|
/* Do a strided read */
|
|
memset(data,0,sizeof(data));
|
|
if (nc_get_vars(ncid, varid, start, edges, stride, data)) ERR;
|
|
for (i=0; i<DIM_LEN_S; i++) {
|
|
if(data[i].i1 != datas[i].i1 || data[i].i2 != datas[i].i2) ERR;
|
|
}
|
|
}
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing REALLY simple compound variable create...");
|
|
{
|
|
int ncid, typeid, varid;
|
|
int ndims, nvars, natts, unlimdimid;
|
|
nc_type xtype;
|
|
size_t size_in, nfields_in;
|
|
char name_in[NC_MAX_NAME + 1];
|
|
|
|
/* Create a file with a compound type. Write a little data. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
if (nc_def_compound(ncid, sizeof(int), SVC_REC, &typeid)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, BATTLES_WITH_KLINGONS, 0, NC_INT)) ERR;
|
|
if (nc_def_var(ncid, SERVICE_RECORD, typeid, 0, NULL, &varid)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Open the file and take a peek. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR;
|
|
if (ndims != 0 || nvars != 1 || natts != 0 || unlimdimid != -1) ERR;
|
|
if (nc_inq_vartype(ncid, 0, &xtype)) ERR;
|
|
if (nc_inq_compound(ncid, xtype, name_in, &size_in, &nfields_in)) ERR;
|
|
if (strcmp(name_in, SVC_REC) || size_in != sizeof(int) || nfields_in != 1) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing simple compound attribute create...");
|
|
{
|
|
int ncid, typeid;
|
|
size_t nfields;
|
|
int ndims, nvars, natts, unlimdimid;
|
|
char name[NC_MAX_NAME + 1];
|
|
size_t size, len;
|
|
nc_type xtype, field_xtype;
|
|
int fieldid;
|
|
int field_ndims, field_sizes[NC_TESTS_MAX_DIMS];
|
|
size_t offset;
|
|
int i;
|
|
struct s1
|
|
{
|
|
int i1;
|
|
int i2;
|
|
};
|
|
struct s1 data[DIM_LEN], data_in[DIM_LEN];
|
|
char *dummy;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct s1), DIM_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)data, (void *)dummy, sizeof(struct s1) * DIM_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (i=0; i<DIM_LEN; i++)
|
|
{
|
|
data[i].i1 = 5;
|
|
data[i].i2 = 10;
|
|
}
|
|
|
|
/* Create a file with a global attribute of compound type. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
if (nc_def_compound(ncid, sizeof(struct s1), SVC_REC, &typeid)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, BATTLES_WITH_KLINGONS,
|
|
NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, DATES_WITH_ALIENS,
|
|
NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR;
|
|
if (nc_put_att(ncid, NC_GLOBAL, SERVICE_RECORD, typeid, 3, data)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Open the file and take a peek. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR;
|
|
if (ndims != 0 || nvars != 0 || natts != 1 || unlimdimid != -1) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Reopen the file and take a more detailed look at the compound
|
|
* type. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_get_att(ncid, NC_GLOBAL, SERVICE_RECORD, data_in)) ERR;
|
|
for (i = 0; i < DIM_LEN; i++)
|
|
if (data[i].i1 != data_in[i].i1 || data[i].i2 != data_in[i].i2) ERR;;
|
|
if (nc_inq_att(ncid, NC_GLOBAL, SERVICE_RECORD, &xtype, &len)) ERR;
|
|
if (len != 3) ERR;
|
|
if (nc_inq_compound(ncid, xtype, name, &size, &nfields)) ERR;
|
|
if (nfields != 2 || size != 8 || strcmp(name, SVC_REC)) ERR;
|
|
if (nc_inq_compound_nfields(ncid, xtype, &nfields)) ERR;
|
|
if (nfields != 2) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 0, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, BATTLES_WITH_KLINGONS) || offset != 0 || field_xtype != NC_INT) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 1, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, DATES_WITH_ALIENS) || offset != 4 || field_xtype != NC_INT) ERR;
|
|
if (nc_inq_compound_fieldindex(ncid, xtype, BATTLES_WITH_KLINGONS, &fieldid)) ERR;
|
|
if (fieldid != 0) ERR;
|
|
if (nc_inq_compound_fieldoffset(ncid, xtype, 1, &offset)) ERR;
|
|
if (offset != 4) ERR;
|
|
if (nc_inq_compound_fieldtype(ncid, xtype, 1, &field_xtype)) ERR;
|
|
if (field_xtype != NC_INT) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing compound variable with new atomic types...");
|
|
{
|
|
int ncid, typeid, dimid, varid;
|
|
size_t nfields;
|
|
int ndims, natts;
|
|
char name[NC_MAX_NAME + 1];
|
|
size_t size;
|
|
nc_type xtype, field_xtype;
|
|
int dimids[] = {0};
|
|
int field_ndims, field_sizes[NC_TESTS_MAX_DIMS];
|
|
size_t offset;
|
|
int i;
|
|
|
|
/* StarFleet Medical Record. */
|
|
struct sf_med_rec
|
|
{
|
|
unsigned char num_heads;
|
|
unsigned short num_arms;
|
|
unsigned int num_toes;
|
|
long long ago; /* in a galaxy far far away... */
|
|
unsigned long long num_hairs;
|
|
};
|
|
struct sf_med_rec med_data_out[DIM_LEN], med_data_in[DIM_LEN];
|
|
char *dummy;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct sf_med_rec), DIM_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)med_data_out, (void *)dummy, sizeof(struct sf_med_rec) * DIM_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (i=0; i<DIM_LEN; i++)
|
|
{
|
|
/* medical data */
|
|
med_data_out[i].num_heads = 254;
|
|
med_data_out[i].num_arms = NC_FILL_USHORT - 1;
|
|
med_data_out[i].num_toes = NC_FILL_UINT - 1;
|
|
med_data_out[i].ago = NC_FILL_INT64 + 1;
|
|
med_data_out[i].num_hairs = NC_FILL_UINT64 - 1;
|
|
}
|
|
|
|
/* Create a file with a compound type. Write a little data. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
if (nc_def_compound(ncid, sizeof(struct sf_med_rec), "SFMedRec", &typeid)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "num_heads",
|
|
NC_COMPOUND_OFFSET(struct sf_med_rec, num_heads), NC_UBYTE)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "num_arms",
|
|
NC_COMPOUND_OFFSET(struct sf_med_rec, num_arms), NC_USHORT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "num_toes",
|
|
NC_COMPOUND_OFFSET(struct sf_med_rec, num_toes), NC_UINT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "ago",
|
|
NC_COMPOUND_OFFSET(struct sf_med_rec, ago), NC_INT64)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "num_hairs",
|
|
NC_COMPOUND_OFFSET(struct sf_med_rec, num_hairs), NC_UINT64)) ERR;
|
|
if (nc_def_dim(ncid, STARDATE, DIM_LEN, &dimid)) ERR;
|
|
if (nc_def_var(ncid, "starbase_13", typeid, 1, dimids, &varid)) ERR;
|
|
if (nc_put_var(ncid, varid, med_data_out)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Open the file and take a look. */
|
|
{
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq_var(ncid, 0, name, &xtype, &ndims, dimids, &natts)) ERR;
|
|
if (strcmp(name, "starbase_13") || ndims != 1 || natts != 0 || dimids[0] != 0) ERR;
|
|
if (nc_inq_compound(ncid, xtype, name, &size, &nfields)) ERR;
|
|
if (nfields != 5 || size != sizeof(struct sf_med_rec) || strcmp(name, "SFMedRec")) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 0, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "num_heads") || offset != 0 || field_xtype != NC_UBYTE) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 1, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "num_arms") || offset != NC_COMPOUND_OFFSET(struct sf_med_rec, num_arms) ||
|
|
field_xtype != NC_USHORT) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 2, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "num_toes") || offset != NC_COMPOUND_OFFSET(struct sf_med_rec, num_toes) ||
|
|
field_xtype != NC_UINT) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 3, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "ago") || offset != NC_COMPOUND_OFFSET(struct sf_med_rec, ago) ||
|
|
field_xtype != NC_INT64) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 4, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "num_hairs") || offset != NC_COMPOUND_OFFSET(struct sf_med_rec, num_hairs) ||
|
|
field_xtype != NC_UINT64) ERR;
|
|
if (nc_get_var(ncid, varid, med_data_in)) ERR;
|
|
for (i=0; i<DIM_LEN; i++)
|
|
if (med_data_in[i].num_heads != med_data_out[i].num_heads ||
|
|
med_data_in[i].num_arms != med_data_out[i].num_arms ||
|
|
med_data_in[i].num_toes != med_data_out[i].num_toes ||
|
|
med_data_in[i].ago != med_data_out[i].ago ||
|
|
med_data_in[i].num_hairs != med_data_out[i].num_hairs) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
}
|
|
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing compound variable containing an array of ints...");
|
|
{
|
|
#define NUM_DIMENSIONS 7
|
|
|
|
int ncid, typeid, varid;
|
|
size_t nfields;
|
|
int dimid;
|
|
int ndims, natts;
|
|
char name[NC_MAX_NAME + 1];
|
|
size_t size;
|
|
nc_type xtype;
|
|
int dimids[] = {0};
|
|
int field_ndims, field_sizes[NC_TESTS_MAX_DIMS];
|
|
size_t offset;
|
|
nc_type field_typeid;
|
|
int dim_sizes[] = {NUM_DIMENSIONS};
|
|
int i, j;
|
|
|
|
/* Since some aliens exists in different, or more than one,
|
|
* dimensions, StarFleet keeps track of the dimensional
|
|
* abilities of everyone on 7 dimensions. */
|
|
struct dim_rec
|
|
{
|
|
int starfleet_id;
|
|
int abilities[NUM_DIMENSIONS];
|
|
};
|
|
struct dim_rec dim_data_out[DIM_LEN], dim_data_in[DIM_LEN];
|
|
char *dummy;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct dim_rec), DIM_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)dim_data_out, (void *)dummy, sizeof(struct dim_rec) * DIM_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (i=0; i<DIM_LEN; i++)
|
|
{
|
|
dim_data_out[i].starfleet_id = i;
|
|
for (j = 0; j < NUM_DIMENSIONS; j++)
|
|
dim_data_out[i].abilities[j] = j;
|
|
}
|
|
|
|
|
|
/* Create a file with a compound type which contains an array of
|
|
* int. Write a little data. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
if (nc_def_compound(ncid, sizeof(struct dim_rec), "SFDimRec", &typeid)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "starfleet_id",
|
|
NC_COMPOUND_OFFSET(struct dim_rec, starfleet_id), NC_INT)) ERR;
|
|
if (nc_insert_array_compound(ncid, typeid, "abilities",
|
|
NC_COMPOUND_OFFSET(struct dim_rec, abilities), NC_INT, 1, dim_sizes)) ERR;
|
|
if (nc_inq_compound_field(ncid, typeid, 1, name, &offset, &field_typeid,
|
|
&field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "abilities") || offset != 4 || field_typeid != NC_INT ||
|
|
field_ndims != 1 || field_sizes[0] != dim_sizes[0]) ERR;
|
|
if (nc_def_dim(ncid, STARDATE, DIM_LEN, &dimid)) ERR;
|
|
if (nc_def_var(ncid, "dimension_data", typeid, 1, dimids, &varid)) ERR;
|
|
if (nc_put_var(ncid, varid, dim_data_out)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Open the file and take a look. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_inq_var(ncid, 0, name, &xtype, &ndims, dimids, &natts)) ERR;
|
|
if (strcmp(name, "dimension_data") || ndims != 1 || natts != 0 || dimids[0] != 0) ERR;
|
|
if (nc_inq_compound(ncid, xtype, name, &size, &nfields)) ERR;
|
|
if (nfields != 2 || size != sizeof(struct dim_rec) || strcmp(name, "SFDimRec")) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 1, name, &offset, &field_typeid,
|
|
&field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "abilities") || offset != 4 || field_typeid != NC_INT ||
|
|
field_ndims != 1 || field_sizes[0] != NUM_DIMENSIONS) ERR;
|
|
if (nc_get_var(ncid, varid, dim_data_in)) ERR;
|
|
for (i=0; i<DIM_LEN; i++)
|
|
{
|
|
if (dim_data_in[i].starfleet_id != dim_data_out[i].starfleet_id) ERR;
|
|
for (j = 0; j < NUM_DIMENSIONS; j++)
|
|
if (dim_data_in[i].abilities[j] != dim_data_out[i].abilities[j]) ERR;
|
|
}
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing compound var containing compound type...");
|
|
{
|
|
int ncid;
|
|
size_t nfields;
|
|
char name[NC_MAX_NAME + 1];
|
|
size_t size, len;
|
|
nc_type xtype, field_xtype;
|
|
int field_ndims, field_sizes[NC_TESTS_MAX_DIMS];
|
|
size_t offset;
|
|
nc_type svc_recid, hr_recid;
|
|
int dim_sizes[] = {NC_MAX_NAME + 1};
|
|
int i;
|
|
|
|
/* The following structs are written and read as compound types by
|
|
* the tests below. */
|
|
struct s1
|
|
{
|
|
int i1;
|
|
int i2;
|
|
};
|
|
struct s1 data[DIM_LEN];
|
|
|
|
/* StarFleet Human Resources Department has data records for all
|
|
* employees. */
|
|
struct hr_rec
|
|
{
|
|
int starfleet_id;
|
|
struct s1 svc_rec;
|
|
char name[NC_MAX_NAME + 1];
|
|
float max_temp, min_temp; /* temperature range */
|
|
double percent_transporter_errosion;
|
|
};
|
|
struct hr_rec hr_data_out[DIM_LEN], hr_data_in[DIM_LEN];
|
|
char *dummy;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct hr_rec), DIM_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)hr_data_out, (void *)dummy, sizeof(struct hr_rec) * DIM_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (i=0; i<DIM_LEN; i++)
|
|
{
|
|
data[i].i1 = 5;
|
|
data[i].i2 = 10;
|
|
/* hr data */
|
|
hr_data_out[i].starfleet_id = i;
|
|
hr_data_out[i].svc_rec = data[i];
|
|
if (sprintf(hr_data_out[i].name, "alien_%d", i) < 0) ERR;
|
|
hr_data_out[i].max_temp = 99.99;
|
|
hr_data_out[i].min_temp = -9.99;
|
|
hr_data_out[i].percent_transporter_errosion = .030303;
|
|
}
|
|
|
|
/* Create a file with a nested compound type attribute and variable. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
|
|
/* Define the inner type first. */
|
|
if (nc_def_compound(ncid, sizeof(struct s1), SVC_REC, &svc_recid)) ERR;
|
|
if (nc_insert_compound(ncid, svc_recid, BATTLES_WITH_KLINGONS,
|
|
NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR;
|
|
if (nc_insert_compound(ncid, svc_recid, DATES_WITH_ALIENS,
|
|
NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR;
|
|
|
|
/* Now define the containing type. */
|
|
if (nc_def_compound(ncid, sizeof(struct hr_rec), "SF_HR_Record", &hr_recid)) ERR;
|
|
if (nc_insert_compound(ncid, hr_recid, "StarFleet_ID",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, starfleet_id), NC_INT)) ERR;
|
|
if (nc_insert_compound(ncid, hr_recid, "Service_Record",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, svc_rec), svc_recid)) ERR;
|
|
if (nc_insert_array_compound(ncid, hr_recid, "Name",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, name), NC_CHAR, 1, dim_sizes)) ERR;
|
|
if (nc_insert_compound(ncid, hr_recid, "Max_Temp",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, max_temp), NC_FLOAT)) ERR;
|
|
if (nc_insert_compound(ncid, hr_recid, "Min_Temp",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, min_temp), NC_FLOAT)) ERR;
|
|
if (nc_insert_compound(ncid, hr_recid, "Percent_Transporter_Erosian",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, percent_transporter_errosion),
|
|
NC_DOUBLE)) ERR;
|
|
|
|
/* Write it as an attribute. */
|
|
if (nc_put_att(ncid, NC_GLOBAL, "HR_Records", hr_recid, DIM_LEN,
|
|
hr_data_out)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Read the att and check values. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_get_att(ncid, NC_GLOBAL, "HR_Records", hr_data_in)) ERR;
|
|
for (i=0; i<DIM_LEN; i++)
|
|
{
|
|
if (hr_data_in[i].starfleet_id != hr_data_out[i].starfleet_id ||
|
|
hr_data_in[i].svc_rec.i1 != hr_data_out[i].svc_rec.i1 ||
|
|
hr_data_in[i].svc_rec.i2 != hr_data_out[i].svc_rec.i2 ||
|
|
strcmp(hr_data_in[i].name, hr_data_out[i].name) ||
|
|
hr_data_in[i].max_temp != hr_data_out[i].max_temp ||
|
|
hr_data_in[i].min_temp != hr_data_out[i].min_temp ||
|
|
hr_data_in[i].percent_transporter_errosion !=
|
|
hr_data_out[i].percent_transporter_errosion) ERR;
|
|
}
|
|
|
|
/* Use the inq functions to learn about nested compound type. */
|
|
if (nc_inq_att(ncid, NC_GLOBAL, "HR_Records", &xtype, &len)) ERR;
|
|
if (len != DIM_LEN) ERR;
|
|
if (nc_inq_compound(ncid, xtype, name, &size, &nfields)) ERR;
|
|
if (nfields != 6 || size != sizeof(struct hr_rec) || strcmp(name, "SF_HR_Record")) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 0, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "StarFleet_ID") || offset != 0 || field_xtype != NC_INT) ERR;
|
|
if (nc_inq_compound_field(ncid, xtype, 1, name, &offset, &field_xtype, &field_ndims, field_sizes)) ERR;
|
|
if (strcmp(name, "Service_Record") || offset != NC_COMPOUND_OFFSET(struct hr_rec, svc_rec)) ERR;
|
|
/* Check the internal compound type. */
|
|
|
|
/* Finish checking the containing compound type. */
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
|
|
SUMMARIZE_ERR;
|
|
printf("*** creating compound test file...");
|
|
|
|
{
|
|
#define TYPE6_NAME "obs_t"
|
|
#define DIM6_NAME "n"
|
|
#define DIM6_LEN 3
|
|
#define VAR6_NAME "obs"
|
|
#define VAR6_RANK 1
|
|
#define ATT6_NAME "_FillValue"
|
|
#define ATT6_LEN 1
|
|
int ncid;
|
|
int dimid, varid;
|
|
nc_type typeid;
|
|
char name_in[NC_MAX_NAME+1];
|
|
int i;
|
|
|
|
int var_dims[VAR6_RANK];
|
|
|
|
typedef struct obs_t {
|
|
char day ;
|
|
short elev;
|
|
int count;
|
|
float relhum;
|
|
double time;
|
|
} obs_t ;
|
|
obs_t obsdata[DIM6_LEN];
|
|
char *dummy;
|
|
|
|
obs_t missing_val;
|
|
obs_t val_in;
|
|
size_t size_in;
|
|
size_t nfields_in;
|
|
nc_type class_in;
|
|
int ntypes;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct obs_t), DIM6_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)obsdata, (void *)dummy, sizeof(struct obs_t) * DIM6_LEN);
|
|
memcpy((void *)&missing_val, (void *)dummy, sizeof(struct obs_t));
|
|
free(dummy);
|
|
|
|
/* Initialize data. */
|
|
for (i = 0; i < DIM6_LEN; i++)
|
|
{
|
|
obsdata[i].day = 15 * i + 1;
|
|
obsdata[i].elev = 2 * i + 1;
|
|
obsdata[i].count = 2 * i + 1;
|
|
obsdata[i].relhum = 2.0 * i + 1;
|
|
obsdata[i].time = 2.0 * i + 1;
|
|
}
|
|
missing_val.day = 99;
|
|
missing_val.elev = 99;
|
|
missing_val.count = 99;
|
|
missing_val.relhum = 99.;
|
|
missing_val.time = 99.;
|
|
|
|
if (nc_create(FILE_NAME, NC_CLOBBER | NC_NETCDF4, &ncid)) ERR;
|
|
|
|
/* Create a compound type. */
|
|
if (nc_def_compound(ncid, sizeof(obs_t), TYPE6_NAME, &typeid)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "day", NC_COMPOUND_OFFSET(struct obs_t, day),
|
|
NC_BYTE)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "elev", NC_COMPOUND_OFFSET(struct obs_t, elev),
|
|
NC_SHORT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "count", NC_COMPOUND_OFFSET(struct obs_t, count),
|
|
NC_INT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "relhum", NC_COMPOUND_OFFSET(struct obs_t, relhum),
|
|
NC_FLOAT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "time", NC_COMPOUND_OFFSET(struct obs_t, time),
|
|
NC_DOUBLE)) ERR;
|
|
|
|
/* Declare a dimension for number of obs */
|
|
if (nc_def_dim(ncid, DIM6_NAME, DIM6_LEN, &dimid)) ERR;
|
|
|
|
/* Declare a variable of the compound type */
|
|
var_dims[0] = dimid;
|
|
if (nc_def_var(ncid, VAR6_NAME, typeid, VAR6_RANK, var_dims, &varid)) ERR;
|
|
|
|
/* Create and write a variable attribute of the compound type */
|
|
if (nc_put_att(ncid, varid, ATT6_NAME, typeid, ATT6_LEN, (void *) &missing_val)) ERR;
|
|
if (nc_enddef(ncid)) ERR;
|
|
|
|
/* Store data, writing all values in one call */
|
|
if(nc_put_var(ncid, varid, obsdata)) ERR;
|
|
|
|
/* Write the file. */
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Check it out. */
|
|
|
|
/* Reopen the file. */
|
|
if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
|
|
|
|
if (nc_inq_typeids(ncid, &ntypes, &typeid)) ERR;
|
|
if (ntypes != 1) ERR;
|
|
|
|
/* Get info with the generic inquire for user-defined types */
|
|
if (nc_inq_user_type(ncid, typeid, name_in, NULL, NULL,
|
|
NULL, &class_in)) ERR;
|
|
if (strcmp(name_in, TYPE6_NAME) ||
|
|
class_in != NC_COMPOUND) ERR;
|
|
|
|
/* Get the same info with the compound-specific inquire function */
|
|
if (nc_inq_compound(ncid, typeid, name_in, &size_in, &nfields_in)) ERR;
|
|
if (strcmp(name_in, TYPE6_NAME) ||
|
|
size_in != sizeof(obs_t) ||
|
|
nfields_in != 5) ERR;
|
|
|
|
if (nc_inq_varid(ncid, VAR6_NAME, &varid)) ERR;
|
|
|
|
/* Read in attribute value and check it */
|
|
if (nc_get_att(ncid, varid, ATT6_NAME, &val_in)) ERR;
|
|
if (val_in.day != missing_val.day ||
|
|
val_in.elev != missing_val.elev ||
|
|
val_in.count != missing_val.count ||
|
|
val_in.relhum != missing_val.relhum) ERR;
|
|
|
|
/* Read in each value and check */
|
|
for (i = 0; i < DIM6_LEN; i++) {
|
|
size_t index[VAR6_RANK];
|
|
index[0] = i;
|
|
if (nc_get_var1(ncid, varid, index, (void *) &val_in)) ERR;
|
|
/* TODO: check values */
|
|
if (val_in.day != obsdata[i].day) ERR;
|
|
if (val_in.elev != obsdata[i].elev) ERR;
|
|
if (val_in.count != obsdata[i].count) ERR;
|
|
if (val_in.relhum != obsdata[i].relhum) ERR;
|
|
if (val_in.time != obsdata[i].time) ERR;
|
|
}
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
}
|
|
|
|
SUMMARIZE_ERR;
|
|
printf("*** Now opening the ref file for this...");
|
|
{
|
|
#define REF_FILE_NAME "ref_tst_compounds.nc"
|
|
int ncid;
|
|
int varid;
|
|
nc_type typeid;
|
|
char name_in[NC_MAX_NAME+1];
|
|
int i;
|
|
|
|
typedef struct obs_t {
|
|
char day ;
|
|
short elev;
|
|
int count;
|
|
float relhum;
|
|
double time;
|
|
} obs_t ;
|
|
|
|
obs_t obsdata[DIM6_LEN] = {
|
|
{15, 2, 1, 0.5, 3600.01},
|
|
{-99, -99, -99, -99.0f, -99.0},
|
|
{20, 6, 3, 0.75, 5000.01}
|
|
};
|
|
obs_t missing_val = {-99, -99, -99, -99, -99};
|
|
obs_t val_in;
|
|
size_t size_in;
|
|
size_t nfields_in;
|
|
nc_type class_in;
|
|
int ntypes;
|
|
char file_in[NC_MAX_NAME * 2];
|
|
|
|
if (getenv("srcdir"))
|
|
{
|
|
strcpy(file_in, getenv("srcdir"));
|
|
strcat(file_in, "/");
|
|
strcat(file_in, REF_FILE_NAME);
|
|
}
|
|
else
|
|
strcpy(file_in, REF_FILE_NAME);
|
|
|
|
/* Reopen the file. */
|
|
if (nc_open(file_in, NC_NOWRITE, &ncid)) ERR;
|
|
|
|
if (nc_inq_typeids(ncid, &ntypes, &typeid)) ERR;
|
|
if (ntypes != 1) ERR;
|
|
|
|
/* Get info with the generic inquire for user-defined types */
|
|
if (nc_inq_user_type(ncid, typeid, name_in, NULL, NULL,
|
|
NULL, &class_in)) ERR;
|
|
if (strcmp(name_in, TYPE6_NAME) ||
|
|
class_in != NC_COMPOUND) ERR;
|
|
|
|
/* Get the same info with the compound-specific inquire function */
|
|
if (nc_inq_compound(ncid, typeid, name_in, &size_in, &nfields_in)) ERR;
|
|
if (strcmp(name_in, TYPE6_NAME) || size_in != sizeof(obs_t) ||
|
|
nfields_in != 5) ERR;
|
|
|
|
if (nc_inq_varid(ncid, VAR6_NAME, &varid)) ERR;
|
|
|
|
/* Read in attribute value and check it */
|
|
if (nc_get_att(ncid, varid, ATT6_NAME, &val_in)) ERR;
|
|
if (val_in.day != missing_val.day ||
|
|
val_in.elev != missing_val.elev ||
|
|
val_in.count != missing_val.count ||
|
|
val_in.relhum != missing_val.relhum) ERR;
|
|
|
|
/* Read in each value and check */
|
|
for (i = 0; i < DIM6_LEN; i++) {
|
|
size_t index[VAR6_RANK];
|
|
index[0] = i;
|
|
if (nc_get_var1(ncid, varid, index, (void *) &val_in)) ERR;
|
|
/* TODO: check values */
|
|
if (val_in.day != obsdata[i].day) ERR;
|
|
if (val_in.elev != obsdata[i].elev) ERR;
|
|
if (val_in.count != obsdata[i].count) ERR;
|
|
if (val_in.relhum != obsdata[i].relhum) ERR;
|
|
if (val_in.time != obsdata[i].time) ERR;
|
|
}
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing compound var containing char array...");
|
|
{
|
|
#define DIM1_LEN 1
|
|
int ncid;
|
|
size_t len;
|
|
nc_type xtype;
|
|
nc_type hr_recid;
|
|
int dim_sizes[] = {NC_MAX_NAME + 1};
|
|
int i;
|
|
|
|
/* StarFleet Human Resources Department has data records for all
|
|
* employees. */
|
|
struct hr_rec
|
|
{
|
|
char name[NC_MAX_NAME + 1];
|
|
float max_temp;
|
|
};
|
|
struct hr_rec hr_data_out[DIM1_LEN], hr_data_in[DIM1_LEN];
|
|
char *dummy;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct hr_rec), DIM1_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)hr_data_out, (void *)dummy, sizeof(struct hr_rec) * DIM1_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
{
|
|
if (sprintf(hr_data_out[i].name, "alien_%d", i) < 0) ERR;
|
|
hr_data_out[i].max_temp = 99.99;
|
|
}
|
|
|
|
/* Create a file with a nested compound type attribute and variable. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
|
|
/* Now define the compound type. */
|
|
/*printf("sizeof(struct hr_rec)=%d\n", sizeof(struct hr_rec));*/
|
|
if (nc_def_compound(ncid, sizeof(struct hr_rec), "SF_HR_Record", &hr_recid)) ERR;
|
|
if (nc_insert_array_compound(ncid, hr_recid, "Name",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, name), NC_CHAR, 1, dim_sizes)) ERR;
|
|
if (nc_insert_compound(ncid, hr_recid, "Max_Temp",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, max_temp), NC_FLOAT)) ERR;
|
|
|
|
/* Write it as an attribute. */
|
|
if (nc_put_att(ncid, NC_GLOBAL, "HR_Records", hr_recid, DIM1_LEN, hr_data_out)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Read the att and check values. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_get_att(ncid, NC_GLOBAL, "HR_Records", hr_data_in)) ERR;
|
|
for (i=0; i<DIM1_LEN; i++)
|
|
if (strcmp(hr_data_in[i].name, hr_data_out[i].name) ||
|
|
hr_data_in[i].max_temp != hr_data_out[i].max_temp) ERR;
|
|
|
|
/* Use the inq functions to learn about the compound type. */
|
|
if (nc_inq_att(ncid, NC_GLOBAL, "HR_Records", &xtype, &len)) ERR;
|
|
if (len != DIM1_LEN) ERR;
|
|
|
|
/* Finish checking the containing compound type. */
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing compound var containing byte array...");
|
|
{
|
|
#define DIM1_LEN 1
|
|
#define ARRAY_LEN (NC_MAX_NAME + 1)
|
|
int ncid;
|
|
size_t len;
|
|
nc_type xtype;
|
|
nc_type hr_recid;
|
|
int dim_sizes[] = {ARRAY_LEN};
|
|
int i, j;
|
|
char *dummy;
|
|
/* StarFleet Human Resources Department has data records for all
|
|
* employees. */
|
|
struct hr_rec
|
|
{
|
|
char name[ARRAY_LEN];
|
|
float max_temp;
|
|
};
|
|
struct hr_rec hr_data_out[DIM1_LEN], hr_data_in[DIM1_LEN];
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct hr_rec), DIM1_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)hr_data_out, (void *)dummy, sizeof(struct hr_rec) * DIM1_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
{
|
|
hr_data_out[i].max_temp = 99.99;
|
|
for (j = 0; j < ARRAY_LEN; j++)
|
|
hr_data_out[i].name[j] = j;
|
|
}
|
|
|
|
/* Create a file with a nested compound type attribute and variable. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
|
|
/* Now define the compound type. */
|
|
/*printf("sizeof(struct hr_rec)=%d\n", sizeof(struct hr_rec));*/
|
|
if (nc_def_compound(ncid, sizeof(struct hr_rec), "SF_HR_Record", &hr_recid)) ERR;
|
|
if (nc_insert_array_compound(ncid, hr_recid, "Name",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, name), NC_UBYTE, 1, dim_sizes)) ERR;
|
|
if (nc_insert_compound(ncid, hr_recid, "Max_Temp",
|
|
NC_COMPOUND_OFFSET(struct hr_rec, max_temp), NC_FLOAT)) ERR;
|
|
|
|
/* Write it as an attribute. */
|
|
if (nc_put_att(ncid, NC_GLOBAL, "HR_Records", hr_recid, DIM1_LEN, hr_data_out)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Read the att and check values. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_get_att(ncid, NC_GLOBAL, "HR_Records", hr_data_in)) ERR;
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
{
|
|
if (hr_data_in[i].max_temp != hr_data_out[i].max_temp) ERR;
|
|
for (j = 0; j < ARRAY_LEN; j++)
|
|
if (hr_data_in[i].name[j] != hr_data_out[i].name[j]) ERR;
|
|
}
|
|
|
|
/* Use the inq functions to learn about the compound type. */
|
|
if (nc_inq_att(ncid, NC_GLOBAL, "HR_Records", &xtype, &len)) ERR;
|
|
if (len != DIM1_LEN) ERR;
|
|
|
|
/* Finish checking the containing compound type. */
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
SUMMARIZE_ERR;
|
|
printf("*** testing with user-contributed code...");
|
|
{
|
|
#define DATA_LEN 1
|
|
int ncid, typeid, varid, dimid;
|
|
int dimids[] = {0};
|
|
struct s1
|
|
{
|
|
short i;
|
|
long long j;
|
|
};
|
|
struct s1 data_out[DATA_LEN], data_in[DATA_LEN];
|
|
int idx;
|
|
char *dummy;
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
* is only needed to pass valgrind. */
|
|
if (!(dummy = calloc(sizeof(struct s1), DATA_LEN)))
|
|
return NC_ENOMEM;
|
|
memcpy((void *)data_out, (void *)dummy, sizeof(struct s1) * DATA_LEN);
|
|
free(dummy);
|
|
|
|
/* Create some phony data. */
|
|
for (idx = 0; idx < DATA_LEN; idx++)
|
|
{
|
|
data_out[idx].i = 20000;
|
|
data_out[idx].j = 300000;
|
|
}
|
|
|
|
/* Create a file with a compound type. Write a little data. */
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
if (nc_def_compound(ncid, sizeof(struct s1), "cmp1", &typeid)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "i",
|
|
NC_COMPOUND_OFFSET(struct s1, i), NC_SHORT)) ERR;
|
|
if (nc_insert_compound(ncid, typeid, "j",
|
|
NC_COMPOUND_OFFSET(struct s1, j), NC_INT64)) ERR;
|
|
if (nc_def_dim(ncid, "phony_dim", 1, &dimid)) ERR;
|
|
if (nc_def_var(ncid, "phony_var", typeid, 1, dimids, &varid)) ERR;
|
|
if (nc_put_var(ncid, varid, data_out)) ERR;
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
/* Reopen the file and check it. */
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
if (nc_get_var(ncid, 0, data_in)) ERR;
|
|
for (idx = 0; idx < DATA_LEN; idx++)
|
|
{
|
|
if (data_in[idx].i != data_out[idx].i ||
|
|
data_in[idx].j != data_out[idx].j) ERR;
|
|
}
|
|
if (nc_close(ncid)) ERR;
|
|
}
|
|
SUMMARIZE_ERR;
|
|
FINAL_RESULTS;
|
|
}
|