2010-06-03 21:24:43 +08:00
|
|
|
/*
|
|
|
|
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 variable functions.
|
|
|
|
|
|
|
|
Copyright 2003-2006, University Corporation for Atmospheric
|
|
|
|
Research. See COPYRIGHT file for copying and redistribution
|
|
|
|
conditions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <nc4internal.h>
|
|
|
|
#include "nc4dispatch.h"
|
|
|
|
#include <math.h>
|
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2010-06-03 21:24:43 +08:00
|
|
|
#include <pnetcdf.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Min and max deflate levels tolerated by HDF5. */
|
|
|
|
#define MIN_DEFLATE_LEVEL 0
|
|
|
|
#define MAX_DEFLATE_LEVEL 9
|
|
|
|
|
|
|
|
/* This is to track opened HDF5 objects to make sure they are
|
|
|
|
* closed. */
|
|
|
|
#ifdef EXTRA_TESTS
|
|
|
|
extern int num_plists;
|
|
|
|
#endif /* EXTRA_TESTS */
|
|
|
|
|
|
|
|
/* One meg is the minimum buffer size. */
|
|
|
|
#define ONE_MEG 1048576
|
|
|
|
|
|
|
|
/* Szip options. */
|
|
|
|
#define NC_SZIP_EC_OPTION_MASK 4
|
|
|
|
#define NC_SZIP_NN_OPTION_MASK 32
|
|
|
|
#define NC_SZIP_MAX_PIXELS_PER_BLOCK 32
|
|
|
|
|
2013-07-11 04:09:31 +08:00
|
|
|
extern int nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, void *fill_value);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* If the HDF5 dataset for this variable is open, then close it and
|
|
|
|
* reopen it, with the perhaps new settings for chunk caching. */
|
|
|
|
int
|
|
|
|
nc4_reopen_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
|
|
|
|
{
|
|
|
|
hid_t access_pid;
|
|
|
|
|
|
|
|
if (var->hdf_datasetid)
|
|
|
|
{
|
|
|
|
if ((access_pid = H5Pcreate(H5P_DATASET_ACCESS)) < 0)
|
|
|
|
return NC_EHDFERR;
|
|
|
|
#ifdef EXTRA_TESTS
|
|
|
|
num_plists++;
|
|
|
|
#endif
|
|
|
|
if (H5Pset_chunk_cache(access_pid, var->chunk_cache_nelems,
|
|
|
|
var->chunk_cache_size,
|
|
|
|
var->chunk_cache_preemption) < 0)
|
|
|
|
return NC_EHDFERR;
|
|
|
|
if (H5Dclose(var->hdf_datasetid) < 0)
|
|
|
|
return NC_EHDFERR;
|
|
|
|
if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, var->name,
|
|
|
|
access_pid)) < 0)
|
|
|
|
return NC_EHDFERR;
|
|
|
|
if (H5Pclose(access_pid) < 0)
|
|
|
|
return NC_EHDFERR;
|
|
|
|
#ifdef EXTRA_TESTS
|
|
|
|
num_plists--;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set chunk cache size for a variable. */
|
|
|
|
int
|
2010-06-22 18:18:15 +08:00
|
|
|
NC4_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems,
|
|
|
|
float preemption)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
/* Check input for validity. */
|
|
|
|
if (preemption < 0 || preemption > 1)
|
|
|
|
return NC_EINVAL;
|
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* An attempt to do any of these things on a netCDF-3 file is
|
|
|
|
* ignored with no error. */
|
|
|
|
if (!h5)
|
|
|
|
return NC_NOERR;
|
|
|
|
|
|
|
|
assert(nc && grp && h5);
|
|
|
|
|
|
|
|
/* Find the var. */
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (var = grp->var; var; var = var->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
if (var->varid == varid)
|
|
|
|
break;
|
|
|
|
if (!var)
|
|
|
|
return NC_ENOTVAR;
|
|
|
|
|
|
|
|
/* Set the values. */
|
|
|
|
var->chunk_cache_size = size;
|
|
|
|
var->chunk_cache_nelems = nelems;
|
|
|
|
var->chunk_cache_preemption = preemption;
|
|
|
|
|
|
|
|
if ((retval = nc4_reopen_dataset(grp, var)))
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Need this version for fortran. Accept negative numbers to leave
|
|
|
|
* settings as they are. */
|
|
|
|
int
|
|
|
|
nc_set_var_chunk_cache_ints(int ncid, int varid, int size, int nelems,
|
|
|
|
int preemption)
|
|
|
|
{
|
|
|
|
size_t real_size = H5D_CHUNK_CACHE_NBYTES_DEFAULT;
|
|
|
|
size_t real_nelems = H5D_CHUNK_CACHE_NSLOTS_DEFAULT;
|
|
|
|
float real_preemption = H5D_CHUNK_CACHE_W0_DEFAULT;
|
|
|
|
|
|
|
|
if (size >= 0)
|
2012-08-17 02:31:48 +08:00
|
|
|
real_size = ((size_t) size) * MEGABYTE;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
if (nelems >= 0)
|
|
|
|
real_nelems = nelems;
|
|
|
|
|
|
|
|
if (preemption >= 0)
|
|
|
|
real_preemption = preemption / 100.;
|
|
|
|
|
2012-12-13 04:05:06 +08:00
|
|
|
return NC4_set_var_chunk_cache(ncid, varid, real_size, real_nelems,
|
2010-06-03 21:24:43 +08:00
|
|
|
real_preemption);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get chunk cache size for a variable. */
|
|
|
|
int
|
2010-06-22 18:18:15 +08:00
|
|
|
NC4_get_var_chunk_cache(int ncid, int varid, size_t *sizep,
|
|
|
|
size_t *nelemsp, float *preemptionp)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Attempting to do any of these things on a netCDF-3 file produces
|
|
|
|
* an error. */
|
|
|
|
if (!h5)
|
|
|
|
return NC_ENOTNC4;
|
|
|
|
|
|
|
|
assert(nc && grp && h5);
|
|
|
|
|
|
|
|
/* Find the var. */
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (var = grp->var; var; var = var->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
if (var->varid == varid)
|
|
|
|
break;
|
|
|
|
if (!var)
|
|
|
|
return NC_ENOTVAR;
|
|
|
|
|
|
|
|
/* Give the user what they want. */
|
|
|
|
if (sizep)
|
|
|
|
*sizep = var->chunk_cache_size;
|
|
|
|
if (nelemsp)
|
|
|
|
*nelemsp = var->chunk_cache_nelems;
|
|
|
|
if (preemptionp)
|
|
|
|
*preemptionp = var->chunk_cache_preemption;
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get chunk cache size for a variable. */
|
|
|
|
int
|
|
|
|
nc_get_var_chunk_cache_ints(int ncid, int varid, int *sizep,
|
|
|
|
int *nelemsp, int *preemptionp)
|
|
|
|
{
|
|
|
|
size_t real_size, real_nelems;
|
|
|
|
float real_preemption;
|
|
|
|
int ret;
|
|
|
|
|
2012-12-13 04:05:06 +08:00
|
|
|
if ((ret = NC4_get_var_chunk_cache(ncid, varid, &real_size,
|
2010-06-03 21:24:43 +08:00
|
|
|
&real_nelems, &real_preemption)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (sizep)
|
|
|
|
*sizep = real_size / MEGABYTE;
|
|
|
|
if (nelemsp)
|
|
|
|
*nelemsp = (int)real_nelems;
|
|
|
|
if(preemptionp)
|
|
|
|
*preemptionp = (int)(real_preemption * 100);
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
2013-10-18 04:25:39 +08:00
|
|
|
/* Check a set of chunksizes to see if they specify a chunk that is too big. */
|
2011-02-02 22:09:15 +08:00
|
|
|
static int
|
2011-02-04 00:50:51 +08:00
|
|
|
check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksizes)
|
2011-02-02 22:09:15 +08:00
|
|
|
{
|
2013-10-18 04:25:39 +08:00
|
|
|
double dprod;
|
2011-02-02 22:09:15 +08:00
|
|
|
size_t type_len;
|
|
|
|
int d;
|
|
|
|
int retval;
|
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
if ((retval = nc4_get_typelen_mem(grp->nc4_info, var->type_info->nc_typeid, 0, &type_len)))
|
2011-02-02 22:09:15 +08:00
|
|
|
return retval;
|
2014-02-12 07:12:08 +08:00
|
|
|
if (var->type_info->nc_type_class == NC_VLEN)
|
|
|
|
dprod = (double)sizeof(hvl_t);
|
2011-02-02 22:09:15 +08:00
|
|
|
else
|
2014-02-12 07:12:08 +08:00
|
|
|
dprod = (double)type_len;
|
2011-02-02 22:09:15 +08:00
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
{
|
|
|
|
if (chunksizes[d] < 1)
|
|
|
|
return NC_EINVAL;
|
2013-10-18 04:25:39 +08:00
|
|
|
dprod *= (double) chunksizes[d];
|
2011-02-02 22:09:15 +08:00
|
|
|
}
|
|
|
|
|
2013-10-18 04:25:39 +08:00
|
|
|
if (dprod > (double) NC_MAX_UINT)
|
2011-02-02 22:09:15 +08:00
|
|
|
return NC_EBADCHUNK;
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Find the default chunk nelems (i.e. length of chunk along each
|
|
|
|
* dimension). */
|
2010-07-01 05:05:11 +08:00
|
|
|
static int
|
2011-02-15 00:49:05 +08:00
|
|
|
nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
|
|
|
|
{
|
2012-01-30 02:56:29 +08:00
|
|
|
int d;
|
2014-02-28 03:19:14 +08:00
|
|
|
size_t type_size;
|
2014-03-27 23:58:53 +08:00
|
|
|
float num_values = 1, num_unlim = 0;
|
2011-02-15 00:49:05 +08:00
|
|
|
int retval;
|
2014-03-27 23:58:53 +08:00
|
|
|
size_t suggested_size;
|
2012-01-30 02:56:29 +08:00
|
|
|
#ifdef LOGGING
|
2013-10-18 04:25:39 +08:00
|
|
|
double total_chunk_size;
|
2012-01-30 02:56:29 +08:00
|
|
|
#endif
|
2011-02-15 00:49:05 +08:00
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
if (var->type_info->nc_type_class == NC_STRING)
|
2011-02-15 00:49:05 +08:00
|
|
|
type_size = sizeof(char *);
|
|
|
|
else
|
|
|
|
type_size = var->type_info->size;
|
|
|
|
|
2014-02-27 04:30:12 +08:00
|
|
|
#ifdef LOGGING
|
2011-02-15 00:49:05 +08:00
|
|
|
/* Later this will become the total number of bytes in the default
|
|
|
|
* chunk. */
|
2013-10-18 04:25:39 +08:00
|
|
|
total_chunk_size = (double) type_size;
|
2012-01-30 02:56:29 +08:00
|
|
|
#endif
|
2011-02-15 00:49:05 +08:00
|
|
|
|
|
|
|
/* How many values in the variable (or one record, if there are
|
2014-03-27 23:58:53 +08:00
|
|
|
* unlimited dimensions). */
|
2011-02-15 00:49:05 +08:00
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
{
|
|
|
|
assert(var->dim[d]);
|
2014-03-27 23:58:53 +08:00
|
|
|
if (! var->dim[d]->unlimited)
|
2011-02-15 00:49:05 +08:00
|
|
|
num_values *= (float)var->dim[d]->len;
|
2014-03-27 23:58:53 +08:00
|
|
|
else {
|
|
|
|
num_unlim++;
|
|
|
|
var->chunksizes[d] = 1; /* overwritten below, if all dims are unlimited */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (var->ndims > 0 && var->ndims == num_unlim) { /* all dims unlimited */
|
|
|
|
suggested_size = pow((double)DEFAULT_CHUNK_SIZE/type_size, 1.0/(double)(var->ndims));
|
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
{
|
|
|
|
var->chunksizes[d] = suggested_size ? suggested_size : 1;
|
|
|
|
LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
|
|
|
|
"chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d]));
|
|
|
|
}
|
2011-02-15 00:49:05 +08:00
|
|
|
}
|
2012-01-18 06:49:01 +08:00
|
|
|
|
2011-02-15 00:49:05 +08:00
|
|
|
/* Pick a chunk length for each dimension, if one has not already
|
|
|
|
* been picked above. */
|
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
if (!var->chunksizes[d])
|
|
|
|
{
|
|
|
|
suggested_size = (pow((double)DEFAULT_CHUNK_SIZE/(num_values * type_size),
|
2014-03-27 23:58:53 +08:00
|
|
|
1.0/(double)(var->ndims - num_unlim)) * var->dim[d]->len - .5);
|
2012-01-18 06:49:01 +08:00
|
|
|
if (suggested_size > var->dim[d]->len)
|
2011-02-15 00:49:05 +08:00
|
|
|
suggested_size = var->dim[d]->len;
|
|
|
|
var->chunksizes[d] = suggested_size ? suggested_size : 1;
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
|
|
|
|
"chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d]));
|
2011-02-15 00:49:05 +08:00
|
|
|
}
|
2011-02-15 23:47:10 +08:00
|
|
|
|
|
|
|
#ifdef LOGGING
|
2014-02-27 04:30:12 +08:00
|
|
|
/* Find total chunk size. */
|
2011-02-15 23:47:10 +08:00
|
|
|
for (d = 0; d < var->ndims; d++)
|
2013-10-18 04:25:39 +08:00
|
|
|
total_chunk_size *= (double) var->chunksizes[d];
|
2011-02-15 00:49:05 +08:00
|
|
|
LOG((4, "total_chunk_size %f", total_chunk_size));
|
2011-02-15 23:47:10 +08:00
|
|
|
#endif
|
2011-02-15 00:49:05 +08:00
|
|
|
|
2014-03-27 23:58:53 +08:00
|
|
|
/* But did this result in a chunk that is too big? */
|
2011-02-15 00:49:05 +08:00
|
|
|
retval = check_chunksizes(grp, var, var->chunksizes);
|
|
|
|
if (retval)
|
|
|
|
{
|
|
|
|
/* Other error? */
|
|
|
|
if (retval != NC_EBADCHUNK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Chunk is too big! Reduce each dimension by half and try again. */
|
|
|
|
for ( ; retval == NC_EBADCHUNK; retval = check_chunksizes(grp, var, var->chunksizes))
|
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
var->chunksizes[d] = var->chunksizes[d]/2 ? var->chunksizes[d]/2 : 1;
|
|
|
|
}
|
|
|
|
|
2011-02-15 03:15:36 +08:00
|
|
|
/* Do we have any big data overhangs? They can be dangerous to
|
|
|
|
* babies, the elderly, or confused campers who have had too much
|
|
|
|
* beer. */
|
|
|
|
for (d = 0; d < var->ndims; d++)
|
2011-06-24 01:15:01 +08:00
|
|
|
{
|
2014-03-28 01:11:06 +08:00
|
|
|
size_t num_chunks;
|
2011-06-24 01:15:01 +08:00
|
|
|
size_t overhang;
|
|
|
|
assert(var->chunksizes[d] > 0);
|
|
|
|
num_chunks = (var->dim[d]->len + var->chunksizes[d] - 1) / var->chunksizes[d];
|
|
|
|
if(num_chunks > 0) {
|
|
|
|
overhang = (num_chunks * var->chunksizes[d]) - var->dim[d]->len;
|
|
|
|
var->chunksizes[d] -= overhang / num_chunks;
|
|
|
|
}
|
|
|
|
}
|
2011-02-15 03:15:36 +08:00
|
|
|
|
2011-02-15 00:49:05 +08:00
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* This is called when a new netCDF-4 variable is defined. Break it
|
|
|
|
* down! */
|
|
|
|
static int
|
|
|
|
nc_def_var_nc4(int ncid, const char *name, nc_type xtype,
|
|
|
|
int ndims, const int *dimidsp, int *varidp)
|
|
|
|
{
|
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
NC_DIM_INFO_T *dim;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
2014-02-12 07:12:08 +08:00
|
|
|
NC_TYPE_INFO_T *type_info = NULL;
|
2010-06-03 21:24:43 +08:00
|
|
|
char norm_name[NC_MAX_NAME + 1];
|
|
|
|
int d;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
|
|
|
if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
assert(grp && h5);
|
|
|
|
|
|
|
|
/* If it's not in define mode, strict nc3 files error out,
|
|
|
|
* otherwise switch to define mode. */
|
|
|
|
if (!(h5->flags & NC_INDEF))
|
|
|
|
{
|
|
|
|
if (h5->cmode & NC_CLASSIC_MODEL)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_ENOTINDEFINE);
|
2010-06-03 21:24:43 +08:00
|
|
|
if ((retval = NC4_redef(ncid)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check and normalize the name. */
|
|
|
|
if ((retval = nc4_check_name(name, norm_name)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Not a Type is, well, not a type.*/
|
|
|
|
if (xtype == NC_NAT)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EBADTYPE);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* For classic files, only classic types are allowed. */
|
|
|
|
if (h5->cmode & NC_CLASSIC_MODEL && xtype > NC_DOUBLE)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_ESTRICTNC3);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* cast needed for braindead systems with signed size_t */
|
|
|
|
if((unsigned long) ndims > X_INT_MAX) /* Backward compat */
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EINVAL);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Classic model files have a limit on number of vars. */
|
|
|
|
if(h5->cmode & NC_CLASSIC_MODEL && h5->nvars >= NC_MAX_VARS)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EMAXVARS);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Check that this name is not in use as a var, grp, or type. */
|
|
|
|
if ((retval = nc4_check_dup_name(grp, norm_name)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* If the file is read-only, return an error. */
|
|
|
|
if (h5->no_write)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EPERM);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Check all the dimids to make sure they exist. */
|
|
|
|
for (d = 0; d < ndims; d++)
|
|
|
|
if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, NULL)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* These degrubbing messages sure are handy! */
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((3, "%s: name %s type %d ndims %d", __func__, norm_name, xtype, ndims));
|
2010-06-03 21:24:43 +08:00
|
|
|
#ifdef LOGGING
|
|
|
|
{
|
|
|
|
int dd;
|
|
|
|
for (dd = 0; dd < ndims; dd++)
|
|
|
|
LOG((4, "dimid[%d] %d", dd, dimidsp[dd]));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Add the var to the end of the list. */
|
|
|
|
if ((retval = nc4_var_list_add(&grp->var, &var)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Now fill in the values in the var info structure. */
|
2010-07-01 19:39:34 +08:00
|
|
|
if (!(var->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_ENOMEM);
|
2010-06-03 21:24:43 +08:00
|
|
|
strcpy(var->name, norm_name);
|
|
|
|
var->varid = grp->nvars++;
|
|
|
|
var->ndims = ndims;
|
2014-11-24 23:36:58 +08:00
|
|
|
var->is_new_var = NC_TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
/* If this is a user-defined type, there is a type_info struct with
|
2010-06-03 21:24:43 +08:00
|
|
|
* all the type information. For atomic types, fake up a type_info
|
|
|
|
* struct. */
|
2014-02-12 07:12:08 +08:00
|
|
|
if (xtype <= NC_STRING)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2014-02-12 07:12:08 +08:00
|
|
|
if (!(type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
|
|
|
|
BAIL(NC_ENOMEM);
|
|
|
|
type_info->nc_typeid = xtype;
|
|
|
|
type_info->endianness = NC_ENDIAN_NATIVE;
|
|
|
|
if ((retval = nc4_get_hdf_typeid(h5, xtype, &type_info->hdf_typeid,
|
|
|
|
type_info->endianness)))
|
|
|
|
BAIL(retval);
|
|
|
|
if ((type_info->native_hdf_typeid = H5Tget_native_type(type_info->hdf_typeid,
|
2010-06-03 21:24:43 +08:00
|
|
|
H5T_DIR_DEFAULT)) < 0)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EHDFERR);
|
|
|
|
if ((retval = nc4_get_typelen_mem(h5, type_info->nc_typeid, 0,
|
|
|
|
&type_info->size)))
|
|
|
|
BAIL(retval);
|
|
|
|
|
|
|
|
/* Set the "class" of the type */
|
2014-02-12 22:48:13 +08:00
|
|
|
if (xtype == NC_CHAR)
|
|
|
|
type_info->nc_type_class = NC_CHAR;
|
|
|
|
else
|
2014-02-12 07:12:08 +08:00
|
|
|
{
|
2014-02-12 22:48:13 +08:00
|
|
|
H5T_class_t class;
|
|
|
|
|
|
|
|
if ((class = H5Tget_class(type_info->hdf_typeid)) < 0)
|
|
|
|
BAIL(NC_EHDFERR);
|
|
|
|
switch(class)
|
|
|
|
{
|
|
|
|
case H5T_STRING:
|
|
|
|
type_info->nc_type_class = NC_STRING;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H5T_INTEGER:
|
|
|
|
type_info->nc_type_class = NC_INT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H5T_FLOAT:
|
|
|
|
type_info->nc_type_class = NC_FLOAT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BAIL(NC_EBADTYPID);
|
|
|
|
}
|
2014-02-12 07:12:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If this is a user defined type, find it. */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (nc4_find_type(grp->nc4_info, xtype, &type_info))
|
|
|
|
BAIL(NC_EBADTYPE);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
/* Point to the type, and increment its ref. count */
|
|
|
|
var->type_info = type_info;
|
|
|
|
var->type_info->rc++;
|
|
|
|
type_info = NULL;
|
|
|
|
|
2010-07-01 20:52:44 +08:00
|
|
|
/* Allocate space for dimension information. */
|
|
|
|
if (ndims)
|
|
|
|
{
|
2011-02-09 20:23:09 +08:00
|
|
|
if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *))))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_ENOMEM);
|
2011-02-09 20:23:09 +08:00
|
|
|
if (!(var->dimids = calloc(ndims, sizeof(int))))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_ENOMEM);
|
2010-07-01 20:52:44 +08:00
|
|
|
}
|
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
/* Assign dimensions to the variable */
|
2010-06-03 21:24:43 +08:00
|
|
|
/* At the same time, check to see if this is a coordinate
|
|
|
|
* variable. If so, it will have the same name as one of its
|
|
|
|
* dimensions. If it is a coordinate var, is it a coordinate var in
|
|
|
|
* the same group as the dim? */
|
2013-12-01 13:20:28 +08:00
|
|
|
/* Also, check whether we should use contiguous or chunked storage */
|
2014-02-12 07:12:08 +08:00
|
|
|
var->contiguous = NC_TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
for (d = 0; d < ndims; d++)
|
|
|
|
{
|
|
|
|
NC_GRP_INFO_T *dim_grp;
|
2013-12-01 13:20:28 +08:00
|
|
|
|
|
|
|
/* Look up each dimension */
|
2010-06-03 21:24:43 +08:00
|
|
|
if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, &dim_grp)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2013-12-01 13:20:28 +08:00
|
|
|
|
|
|
|
/* Check for dim index 0 having the same name, in the same group */
|
|
|
|
if (d == 0 && dim_grp == grp && strcmp(dim->name, norm_name) == 0)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2014-02-12 07:12:08 +08:00
|
|
|
var->dimscale = NC_TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
dim->coord_var = var;
|
2013-12-01 13:20:28 +08:00
|
|
|
|
|
|
|
/* Use variable's dataset ID for the dimscale ID */
|
|
|
|
if (dim->hdf_dimscaleid)
|
|
|
|
{
|
|
|
|
/* Detach dimscale from any variables using it */
|
|
|
|
if ((retval = rec_detach_scales(grp, dimidsp[d], dim->hdf_dimscaleid)) < 0)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2013-12-01 13:20:28 +08:00
|
|
|
|
|
|
|
if (H5Dclose(dim->hdf_dimscaleid) < 0)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EHDFERR);
|
2013-12-01 13:20:28 +08:00
|
|
|
dim->hdf_dimscaleid = 0;
|
|
|
|
|
|
|
|
/* Now delete the dataset (it will be recreated later, if necessary) */
|
|
|
|
if (H5Gunlink(grp->hdf_grpid, dim->name) < 0)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EDIMMETA);
|
2013-12-01 13:20:28 +08:00
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
2013-12-01 13:20:28 +08:00
|
|
|
|
|
|
|
/* Check for unlimited dimension and turn off contiguous storage */
|
2014-06-03 03:04:28 +08:00
|
|
|
/* (unless HDF4 file) */
|
|
|
|
#ifdef USE_HDF4
|
|
|
|
if (dim->unlimited && !h5->hdf4)
|
|
|
|
#else
|
2013-12-01 13:20:28 +08:00
|
|
|
if (dim->unlimited)
|
2014-06-03 03:04:28 +08:00
|
|
|
#endif
|
2014-02-12 07:12:08 +08:00
|
|
|
var->contiguous = NC_FALSE;
|
2013-12-01 13:20:28 +08:00
|
|
|
|
|
|
|
/* Track dimensions for variable */
|
2010-06-03 21:24:43 +08:00
|
|
|
var->dimids[d] = dimidsp[d];
|
|
|
|
var->dim[d] = dim;
|
|
|
|
}
|
|
|
|
|
2010-07-01 05:05:11 +08:00
|
|
|
/* Determine default chunksizes for this variable. (Even for
|
|
|
|
* variables which may be contiguous. */
|
|
|
|
LOG((4, "allocating array of %d size_t to hold chunksizes for var %s",
|
|
|
|
var->ndims, var->name));
|
2010-07-10 04:57:09 +08:00
|
|
|
if (var->ndims)
|
2011-02-04 00:50:51 +08:00
|
|
|
if (!(var->chunksizes = calloc(var->ndims, sizeof(size_t))))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_ENOMEM);
|
2010-07-01 05:05:11 +08:00
|
|
|
|
2011-02-15 00:49:05 +08:00
|
|
|
if ((retval = nc4_find_default_chunksizes2(grp, var)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Is this a variable with a chunksize greater than the current
|
|
|
|
* cache size? */
|
|
|
|
if ((retval = nc4_adjust_var_cache(grp, var)))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(retval);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* If the user names this variable the same as a dimension, but
|
2010-11-30 06:23:16 +08:00
|
|
|
* doesn't use that dimension first in its list of dimension ids,
|
|
|
|
* is not a coordinate variable. I need to change its HDF5 name,
|
|
|
|
* because the dimension will cause a HDF5 dataset to be created,
|
|
|
|
* and this var has the same name. */
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (dim = grp->dim; dim; dim = dim->l.next)
|
2011-02-24 01:33:11 +08:00
|
|
|
if (!strcmp(dim->name, norm_name) &&
|
|
|
|
(!var->ndims || dimidsp[0] != dim->dimid))
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2010-11-30 06:23:16 +08:00
|
|
|
/* Set a different hdf5 name for this variable to avoid name
|
|
|
|
* clash. */
|
|
|
|
if (strlen(norm_name) + strlen(NON_COORD_PREPEND) > NC_MAX_NAME)
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_EMAXNAME);
|
2010-11-30 06:23:16 +08:00
|
|
|
if (!(var->hdf5_name = malloc((strlen(NON_COORD_PREPEND) +
|
|
|
|
strlen(norm_name) + 1) * sizeof(char))))
|
2014-02-12 07:12:08 +08:00
|
|
|
BAIL(NC_ENOMEM);
|
2010-11-30 06:23:16 +08:00
|
|
|
|
|
|
|
sprintf(var->hdf5_name, "%s%s", NON_COORD_PREPEND, norm_name);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If this is a coordinate var, it is marked as a HDF5 dimension
|
|
|
|
* scale. (We found dim above.) Otherwise, allocate space to
|
|
|
|
* remember whether dimension scales have been attached to each
|
|
|
|
* dimension. */
|
|
|
|
if (!var->dimscale && ndims)
|
2014-02-12 07:12:08 +08:00
|
|
|
if (ndims && !(var->dimscale_attached = calloc(ndims, sizeof(nc_bool_t))))
|
|
|
|
BAIL(NC_ENOMEM);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Return the varid. */
|
|
|
|
if (varidp)
|
|
|
|
*varidp = var->varid;
|
|
|
|
LOG((4, "new varid %d", var->varid));
|
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
exit:
|
|
|
|
if (type_info)
|
|
|
|
if ((retval = nc4_type_free(type_info)))
|
|
|
|
BAIL2(retval);
|
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a new variable to hold user data. This is what it's all
|
|
|
|
* about baby! */
|
|
|
|
int
|
|
|
|
NC4_def_var(int ncid, const char *name, nc_type xtype, int ndims,
|
|
|
|
const int *dimidsp, int *varidp)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((2, "%s: ncid 0x%x name %s xtype %d ndims %d",
|
|
|
|
__func__, ncid, name, xtype, ndims));
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* If there are dimensions, I need their ids. */
|
|
|
|
if (ndims && !dimidsp)
|
|
|
|
return NC_EINVAL;
|
|
|
|
|
|
|
|
/* Find metadata for this file. */
|
2012-09-07 03:44:03 +08:00
|
|
|
if (!(nc = nc4_find_nc_file(ncid,&h5)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return NC_EBADID;
|
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Take care of files created/opened with parallel-netcdf library. */
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_file)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = ncmpi_def_var(nc->int_ncid, name, xtype, ndims,
|
|
|
|
dimidsp, varidp);
|
2013-01-18 10:25:12 +08:00
|
|
|
h5->pnetcdf_ndims[*varidp] = ndims;
|
2010-06-03 21:24:43 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif /* USE_PNETCDF */
|
|
|
|
|
|
|
|
/* Handle netcdf-4 cases. */
|
|
|
|
return nc_def_var_nc4(ncid, name, xtype, ndims, dimidsp, varidp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get all the information about a variable. Pass NULL for whatever
|
|
|
|
* you don't care about. This is an internal function, not exposed to
|
|
|
|
* the user. */
|
|
|
|
int
|
|
|
|
NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep,
|
|
|
|
int *ndimsp, int *dimidsp, int *nattsp,
|
|
|
|
int *shufflep, int *deflatep, int *deflate_levelp,
|
|
|
|
int *fletcher32p, int *contiguousp, size_t *chunksizesp,
|
|
|
|
int *no_fill, void *fill_valuep, int *endiannessp,
|
|
|
|
int *options_maskp, int *pixels_per_blockp)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
NC_ATT_INFO_T *att;
|
|
|
|
int natts=0;
|
|
|
|
int d;
|
|
|
|
int retval;
|
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((2, "%s: ncid 0x%x varid %d", __func__, ncid, varid));
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
|
|
|
return retval;
|
|
|
|
|
2013-01-15 11:46:46 +08:00
|
|
|
assert(nc);
|
2013-01-18 10:25:12 +08:00
|
|
|
assert(grp && h5);
|
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Take care of files created/opened with parallel-netcdf library. */
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_file)
|
2010-06-03 21:24:43 +08:00
|
|
|
return ncmpi_inq_var(nc->int_ncid, varid, name, xtypep, ndimsp,
|
|
|
|
dimidsp, nattsp);
|
|
|
|
#endif /* USE_PNETCDF */
|
|
|
|
|
|
|
|
/* Walk through the list of vars, and return the info about the one
|
|
|
|
with a matching varid. If the varid is -1, find the global
|
|
|
|
atts and call it a day. */
|
|
|
|
if (varid == NC_GLOBAL)
|
|
|
|
{
|
|
|
|
if (nattsp)
|
|
|
|
{
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (att = grp->att; att; att = att->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
natts++;
|
|
|
|
*nattsp = natts;
|
|
|
|
}
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the var. */
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (var = grp->var; var; var = var->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
if (var->varid == varid)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Oh no! Maybe we couldn't find it (*sob*)! */
|
|
|
|
if (!var)
|
|
|
|
return NC_ENOTVAR;
|
|
|
|
|
|
|
|
/* Copy the data to the user's data buffers. */
|
|
|
|
if (name)
|
|
|
|
strcpy(name, var->name);
|
|
|
|
if (xtypep)
|
2014-02-12 07:12:08 +08:00
|
|
|
*xtypep = var->type_info->nc_typeid;
|
2010-06-03 21:24:43 +08:00
|
|
|
if (ndimsp)
|
|
|
|
*ndimsp = var->ndims;
|
|
|
|
if (dimidsp)
|
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
dimidsp[d] = var->dimids[d];
|
|
|
|
if (nattsp)
|
|
|
|
{
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (att = var->att; att; att = att->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
natts++;
|
|
|
|
*nattsp = natts;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Chunking stuff. */
|
2010-07-01 05:05:11 +08:00
|
|
|
if (!var->contiguous && chunksizesp)
|
2010-06-03 21:24:43 +08:00
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
{
|
|
|
|
chunksizesp[d] = var->chunksizes[d];
|
|
|
|
LOG((4, "chunksizesp[%d]=%d", d, chunksizesp[d]));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contiguousp)
|
2010-07-01 19:39:34 +08:00
|
|
|
*contiguousp = var->contiguous ? NC_CONTIGUOUS : NC_CHUNKED;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Filter stuff. */
|
|
|
|
if (deflatep)
|
2014-02-12 07:12:08 +08:00
|
|
|
*deflatep = (int)var->deflate;
|
2010-06-03 21:24:43 +08:00
|
|
|
if (deflate_levelp)
|
|
|
|
*deflate_levelp = var->deflate_level;
|
|
|
|
if (shufflep)
|
2014-02-12 07:12:08 +08:00
|
|
|
*shufflep = (int)var->shuffle;
|
2010-06-03 21:24:43 +08:00
|
|
|
if (fletcher32p)
|
2014-02-12 07:12:08 +08:00
|
|
|
*fletcher32p = (int)var->fletcher32;
|
|
|
|
/* NOTE: No interface for returning szip flag currently (but it should never
|
|
|
|
* be set).
|
|
|
|
*/
|
2010-06-03 21:24:43 +08:00
|
|
|
if (options_maskp)
|
|
|
|
*options_maskp = var->options_mask;
|
|
|
|
if (pixels_per_blockp)
|
|
|
|
*pixels_per_blockp = var->pixels_per_block;
|
|
|
|
|
|
|
|
/* Fill value stuff. */
|
|
|
|
if (no_fill)
|
2014-02-12 07:12:08 +08:00
|
|
|
*no_fill = (int)var->no_fill;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Don't do a thing with fill_valuep if no_fill mode is set for
|
|
|
|
* this var, or if fill_valuep is NULL. */
|
|
|
|
if (!var->no_fill && fill_valuep)
|
|
|
|
{
|
|
|
|
/* Do we have a fill value for this var? */
|
|
|
|
if (var->fill_value)
|
|
|
|
{
|
2014-02-12 07:12:08 +08:00
|
|
|
if (var->type_info->nc_type_class == NC_STRING)
|
Corrected "BAIL" macros to avoid infinite loop when logging is disabled and an
error occurs after an "exit:" label.
Corrected a dozen Coverity errors (mainly allocation issues, along with a few
other things):
711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787,
1047274, 1130013, 1130014, 1139538
Refactored internal fill-value code to correctly handle string types, and
especially to allow NULL pointers and null strings (ie. "") to be
distinguished. The code now avoids partially aliasing the two together
(which only happened on the 'write' side of things and wasn't reflected on
the 'read' side, adding to the previous confusion).
Probably still weak on handling fill-values of variable-length and compound
datatypes.
Refactored the recursive metadata reads a bit more, to process HDF5 named
datatypes and datasets immediately, avoiding chewing up memory for those
types of objects, etc.
Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm
proceeding alphabetically through the nc_test4 code files).
2013-12-29 15:12:43 +08:00
|
|
|
{
|
|
|
|
if (!(fill_valuep = calloc(1, sizeof(char *))))
|
|
|
|
return NC_ENOMEM;
|
|
|
|
if (*(char **)var->fill_value)
|
|
|
|
if (!(*(char **)fill_valuep = strdup(*(char **)var->fill_value)))
|
2014-02-20 22:24:55 +08:00
|
|
|
{
|
|
|
|
free(fill_valuep);
|
Corrected "BAIL" macros to avoid infinite loop when logging is disabled and an
error occurs after an "exit:" label.
Corrected a dozen Coverity errors (mainly allocation issues, along with a few
other things):
711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787,
1047274, 1130013, 1130014, 1139538
Refactored internal fill-value code to correctly handle string types, and
especially to allow NULL pointers and null strings (ie. "") to be
distinguished. The code now avoids partially aliasing the two together
(which only happened on the 'write' side of things and wasn't reflected on
the 'read' side, adding to the previous confusion).
Probably still weak on handling fill-values of variable-length and compound
datatypes.
Refactored the recursive metadata reads a bit more, to process HDF5 named
datatypes and datasets immediately, avoiding chewing up memory for those
types of objects, etc.
Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm
proceeding alphabetically through the nc_test4 code files).
2013-12-29 15:12:43 +08:00
|
|
|
return NC_ENOMEM;
|
2014-02-20 22:24:55 +08:00
|
|
|
}
|
Corrected "BAIL" macros to avoid infinite loop when logging is disabled and an
error occurs after an "exit:" label.
Corrected a dozen Coverity errors (mainly allocation issues, along with a few
other things):
711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787,
1047274, 1130013, 1130014, 1139538
Refactored internal fill-value code to correctly handle string types, and
especially to allow NULL pointers and null strings (ie. "") to be
distinguished. The code now avoids partially aliasing the two together
(which only happened on the 'write' side of things and wasn't reflected on
the 'read' side, adding to the previous confusion).
Probably still weak on handling fill-values of variable-length and compound
datatypes.
Refactored the recursive metadata reads a bit more, to process HDF5 named
datatypes and datasets immediately, avoiding chewing up memory for those
types of objects, etc.
Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm
proceeding alphabetically through the nc_test4 code files).
2013-12-29 15:12:43 +08:00
|
|
|
}
|
|
|
|
else {
|
2014-02-12 07:12:08 +08:00
|
|
|
assert(var->type_info->size);
|
|
|
|
memcpy(fill_valuep, var->fill_value, var->type_info->size);
|
Corrected "BAIL" macros to avoid infinite loop when logging is disabled and an
error occurs after an "exit:" label.
Corrected a dozen Coverity errors (mainly allocation issues, along with a few
other things):
711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787,
1047274, 1130013, 1130014, 1139538
Refactored internal fill-value code to correctly handle string types, and
especially to allow NULL pointers and null strings (ie. "") to be
distinguished. The code now avoids partially aliasing the two together
(which only happened on the 'write' side of things and wasn't reflected on
the 'read' side, adding to the previous confusion).
Probably still weak on handling fill-values of variable-length and compound
datatypes.
Refactored the recursive metadata reads a bit more, to process HDF5 named
datatypes and datasets immediately, avoiding chewing up memory for those
types of objects, etc.
Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm
proceeding alphabetically through the nc_test4 code files).
2013-12-29 15:12:43 +08:00
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-12 07:12:08 +08:00
|
|
|
if (var->type_info->nc_type_class == NC_STRING)
|
Corrected "BAIL" macros to avoid infinite loop when logging is disabled and an
error occurs after an "exit:" label.
Corrected a dozen Coverity errors (mainly allocation issues, along with a few
other things):
711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787,
1047274, 1130013, 1130014, 1139538
Refactored internal fill-value code to correctly handle string types, and
especially to allow NULL pointers and null strings (ie. "") to be
distinguished. The code now avoids partially aliasing the two together
(which only happened on the 'write' side of things and wasn't reflected on
the 'read' side, adding to the previous confusion).
Probably still weak on handling fill-values of variable-length and compound
datatypes.
Refactored the recursive metadata reads a bit more, to process HDF5 named
datatypes and datasets immediately, avoiding chewing up memory for those
types of objects, etc.
Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm
proceeding alphabetically through the nc_test4 code files).
2013-12-29 15:12:43 +08:00
|
|
|
{
|
|
|
|
if (!(fill_valuep = calloc(1, sizeof(char *))))
|
|
|
|
return NC_ENOMEM;
|
2014-03-29 07:11:26 +08:00
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
if ((retval = nc4_get_default_fill_value(var->type_info, (char **)fill_valuep)))
|
2014-02-20 22:24:55 +08:00
|
|
|
{
|
|
|
|
free(fill_valuep);
|
Corrected "BAIL" macros to avoid infinite loop when logging is disabled and an
error occurs after an "exit:" label.
Corrected a dozen Coverity errors (mainly allocation issues, along with a few
other things):
711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787,
1047274, 1130013, 1130014, 1139538
Refactored internal fill-value code to correctly handle string types, and
especially to allow NULL pointers and null strings (ie. "") to be
distinguished. The code now avoids partially aliasing the two together
(which only happened on the 'write' side of things and wasn't reflected on
the 'read' side, adding to the previous confusion).
Probably still weak on handling fill-values of variable-length and compound
datatypes.
Refactored the recursive metadata reads a bit more, to process HDF5 named
datatypes and datasets immediately, avoiding chewing up memory for those
types of objects, etc.
Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm
proceeding alphabetically through the nc_test4 code files).
2013-12-29 15:12:43 +08:00
|
|
|
return retval;
|
2014-03-29 07:11:26 +08:00
|
|
|
} else {
|
|
|
|
free(fill_valuep);
|
|
|
|
}
|
Corrected "BAIL" macros to avoid infinite loop when logging is disabled and an
error occurs after an "exit:" label.
Corrected a dozen Coverity errors (mainly allocation issues, along with a few
other things):
711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787,
1047274, 1130013, 1130014, 1139538
Refactored internal fill-value code to correctly handle string types, and
especially to allow NULL pointers and null strings (ie. "") to be
distinguished. The code now avoids partially aliasing the two together
(which only happened on the 'write' side of things and wasn't reflected on
the 'read' side, adding to the previous confusion).
Probably still weak on handling fill-values of variable-length and compound
datatypes.
Refactored the recursive metadata reads a bit more, to process HDF5 named
datatypes and datasets immediately, avoiding chewing up memory for those
types of objects, etc.
Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm
proceeding alphabetically through the nc_test4 code files).
2013-12-29 15:12:43 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((retval = nc4_get_default_fill_value(var->type_info, fill_valuep)))
|
|
|
|
return retval;
|
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Does the user want the endianness of this variable? */
|
|
|
|
if (endiannessp)
|
|
|
|
*endiannessp = var->type_info->endianness;
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This functions sets extra stuff about a netCDF-4 variable which
|
|
|
|
must be set before the enddef but after the def_var. This is an
|
|
|
|
internal function, deliberately hidden from the user so that we can
|
|
|
|
change the prototype of this functions without changing the API. */
|
|
|
|
static int
|
|
|
|
nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate,
|
2011-02-01 05:30:39 +08:00
|
|
|
int *deflate_level, int *fletcher32, int *contiguous,
|
2010-06-03 21:24:43 +08:00
|
|
|
const size_t *chunksizes, int *no_fill,
|
2014-02-12 07:12:08 +08:00
|
|
|
const void *fill_value, int *endianness)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
NC_DIM_INFO_T *dim;
|
|
|
|
int d;
|
|
|
|
int retval;
|
2014-06-03 04:02:34 +08:00
|
|
|
nc_bool_t ishdf4 = NC_FALSE; /* Use this to avoid so many ifdefs */
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((2, "%s: ncid 0x%x varid %d", __func__, ncid, varid));
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
|
|
|
return retval;
|
|
|
|
|
2014-06-03 03:04:28 +08:00
|
|
|
#ifdef USE_HDF4
|
|
|
|
ishdf4 = h5->hdf4;
|
2014-06-03 03:25:53 +08:00
|
|
|
#endif
|
2014-06-03 03:04:28 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Attempting to do any of these things on a netCDF-3 file produces
|
|
|
|
* an error. */
|
|
|
|
if (!h5)
|
|
|
|
return NC_ENOTNC4;
|
|
|
|
|
|
|
|
assert(nc && grp && h5);
|
|
|
|
|
|
|
|
/* Find the var. */
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (var = grp->var; var; var = var->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
if (var->varid == varid)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Oh no! Maybe we couldn't find it (*sob*)! */
|
|
|
|
if (!var)
|
|
|
|
return NC_ENOTVAR;
|
|
|
|
|
|
|
|
/* Can't turn on contiguous and deflate/fletcher32/szip. */
|
2011-02-01 05:30:39 +08:00
|
|
|
if (contiguous)
|
|
|
|
if ((*contiguous != NC_CHUNKED && deflate) ||
|
2014-02-12 07:12:08 +08:00
|
|
|
(*contiguous != NC_CHUNKED && fletcher32))
|
2011-02-01 05:30:39 +08:00
|
|
|
return NC_EINVAL;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* If the HDF5 dataset has already been created, then it is too
|
|
|
|
* late to set all the extra stuff. */
|
|
|
|
if (var->created)
|
|
|
|
return NC_ELATEDEF;
|
|
|
|
|
|
|
|
/* Check compression options. */
|
2014-02-12 07:12:08 +08:00
|
|
|
if (deflate && !deflate_level)
|
2010-06-03 21:24:43 +08:00
|
|
|
return NC_EINVAL;
|
|
|
|
|
|
|
|
/* Valid deflate level? */
|
|
|
|
if (deflate && deflate_level)
|
|
|
|
{
|
|
|
|
if (*deflate)
|
|
|
|
if (*deflate_level < MIN_DEFLATE_LEVEL ||
|
|
|
|
*deflate_level > MAX_DEFLATE_LEVEL)
|
|
|
|
return NC_EINVAL;
|
|
|
|
|
2010-08-29 23:08:12 +08:00
|
|
|
/* For scalars, just ignore attempt to deflate. */
|
2010-06-03 21:24:43 +08:00
|
|
|
if (!var->ndims)
|
2010-08-29 23:08:12 +08:00
|
|
|
return NC_NOERR;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Well, if we couldn't find any errors, I guess we have to take
|
|
|
|
* the users settings. Darn! */
|
2014-02-12 07:12:08 +08:00
|
|
|
var->contiguous = NC_FALSE;
|
2010-06-03 21:24:43 +08:00
|
|
|
var->deflate = *deflate;
|
|
|
|
if (*deflate)
|
|
|
|
var->deflate_level = *deflate_level;
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((3, "%s: *deflate_level %d", __func__, *deflate_level));
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Shuffle filter? */
|
|
|
|
if (shuffle)
|
|
|
|
{
|
|
|
|
var->shuffle = *shuffle;
|
2014-02-12 07:12:08 +08:00
|
|
|
var->contiguous = NC_FALSE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Fltcher32 checksum error protection? */
|
|
|
|
if (fletcher32)
|
|
|
|
{
|
|
|
|
var->fletcher32 = *fletcher32;
|
2014-02-12 07:12:08 +08:00
|
|
|
var->contiguous = NC_FALSE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Does the user want a contiguous dataset? Not so fast! Make sure
|
|
|
|
* that there are no unlimited dimensions, and no filters in use
|
|
|
|
* for this data. */
|
2011-02-01 05:30:39 +08:00
|
|
|
if (contiguous && *contiguous)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2014-02-12 07:12:08 +08:00
|
|
|
if (var->deflate || var->fletcher32 || var->shuffle)
|
2010-06-03 21:24:43 +08:00
|
|
|
return NC_EINVAL;
|
|
|
|
|
2014-06-03 03:04:28 +08:00
|
|
|
if (!ishdf4) {
|
2010-06-03 21:24:43 +08:00
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
{
|
|
|
|
if ((retval = nc4_find_dim(grp, var->dimids[d], &dim, NULL)))
|
|
|
|
return retval;
|
|
|
|
if (dim->unlimited)
|
|
|
|
return NC_EINVAL;
|
|
|
|
}
|
2014-02-12 07:12:08 +08:00
|
|
|
var->contiguous = NC_TRUE;
|
2014-06-03 03:04:28 +08:00
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Chunksizes anyone? */
|
2014-06-03 03:04:28 +08:00
|
|
|
if (!ishdf4 && contiguous && *contiguous == NC_CHUNKED)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2014-02-12 07:12:08 +08:00
|
|
|
var->contiguous = NC_FALSE;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2011-02-01 05:30:39 +08:00
|
|
|
/* If the user provided chunksizes, check that they are not too
|
|
|
|
* big, and that their total size of chunk is less than 4 GB. */
|
|
|
|
if (chunksizes)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2011-02-02 22:09:15 +08:00
|
|
|
|
|
|
|
if ((retval = check_chunksizes(grp, var, chunksizes)))
|
2011-02-01 05:30:39 +08:00
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Set the chunksizes for this variable. */
|
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
var->chunksizes[d] = chunksizes[d];
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is this a variable with a chunksize greater than the current
|
|
|
|
* cache size? */
|
2014-02-12 07:12:08 +08:00
|
|
|
if (!var->contiguous && (chunksizes || deflate || contiguous))
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
/* Determine default chunksizes for this variable. */
|
|
|
|
if (!var->chunksizes[0])
|
2011-02-15 00:49:05 +08:00
|
|
|
if ((retval = nc4_find_default_chunksizes2(grp, var)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Adjust the cache. */
|
|
|
|
if ((retval = nc4_adjust_var_cache(grp, var)))
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Are we setting a fill modes? */
|
|
|
|
if (no_fill)
|
|
|
|
{
|
|
|
|
if (*no_fill)
|
2014-02-12 07:12:08 +08:00
|
|
|
var->no_fill = NC_TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
else
|
2014-02-12 07:12:08 +08:00
|
|
|
var->no_fill = NC_FALSE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Are we setting a fill value? */
|
|
|
|
if (fill_value && !var->no_fill)
|
|
|
|
{
|
|
|
|
/* Copy the fill_value. */
|
|
|
|
LOG((4, "Copying fill value into metadata for variable %s",
|
|
|
|
var->name));
|
|
|
|
|
|
|
|
/* If there's a _FillValue attribute, delete it. */
|
2012-12-13 04:05:06 +08:00
|
|
|
retval = NC4_del_att(ncid, varid, _FillValue);
|
2010-06-03 21:24:43 +08:00
|
|
|
if (retval && retval != NC_ENOTATT)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Create a _FillValue attribute. */
|
2014-02-12 07:12:08 +08:00
|
|
|
if ((retval = nc_put_att(ncid, varid, _FillValue, var->type_info->nc_typeid, 1, fill_value)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is the user setting the endianness? */
|
|
|
|
if (endianness)
|
|
|
|
var->type_info->endianness = *endianness;
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the deflate level for a var, lower is faster, higher is
|
|
|
|
* better. Must be called after nc_def_var and before nc_enddef or any
|
|
|
|
* functions which writes data to the file. */
|
|
|
|
int
|
|
|
|
NC4_def_var_deflate(int ncid, int varid, int shuffle, int deflate,
|
|
|
|
int deflate_level)
|
|
|
|
{
|
|
|
|
return nc_def_var_extra(ncid, varid, &shuffle, &deflate,
|
2014-02-12 07:12:08 +08:00
|
|
|
&deflate_level, NULL, NULL, NULL, NULL, NULL, NULL);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set checksum for a var. This must be called after the nc_def_var
|
|
|
|
* but before the nc_enddef. */
|
|
|
|
int
|
|
|
|
NC4_def_var_fletcher32(int ncid, int varid, int fletcher32)
|
|
|
|
{
|
|
|
|
return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, &fletcher32,
|
2014-02-12 07:12:08 +08:00
|
|
|
NULL, NULL, NULL, NULL, NULL);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Define chunking stuff for a var. This must be done after nc_def_var
|
|
|
|
and before nc_enddef.
|
|
|
|
|
|
|
|
Chunking is required in any dataset with one or more unlimited
|
|
|
|
dimension in HDF5, or any dataset using a filter.
|
|
|
|
|
|
|
|
Where chunksize is a pointer to an array of size ndims, with the
|
|
|
|
chunksize in each dimension.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
NC4_def_var_chunking(int ncid, int varid, int contiguous, const size_t *chunksizesp)
|
|
|
|
{
|
|
|
|
return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL,
|
2014-02-12 07:12:08 +08:00
|
|
|
&contiguous, chunksizesp, NULL, NULL, NULL);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Inquire about chunking stuff for a var. This is a private,
|
|
|
|
* undocumented function, used by the f77 API to avoid size_t
|
|
|
|
* problems. */
|
|
|
|
int
|
|
|
|
nc_inq_var_chunking_ints(int ncid, int varid, int *contiguousp, int *chunksizesp)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_VAR_INFO_T *var;
|
2014-06-03 04:02:34 +08:00
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
2014-06-03 03:04:28 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
size_t *cs = NULL;
|
|
|
|
int i, retval;
|
|
|
|
|
|
|
|
/* Find this ncid's file info. */
|
2014-06-03 03:04:28 +08:00
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return retval;
|
|
|
|
assert(nc);
|
|
|
|
|
|
|
|
/* Find var cause I need the number of dims. */
|
|
|
|
if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Allocate space for the size_t copy of the chunksizes array. */
|
|
|
|
if (var->ndims)
|
|
|
|
if (!(cs = malloc(var->ndims * sizeof(size_t))))
|
|
|
|
return NC_ENOMEM;
|
|
|
|
|
|
|
|
retval = NC4_inq_var_all(ncid, varid, NULL, NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL, contiguousp, cs, NULL,
|
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
|
2014-03-28 01:11:06 +08:00
|
|
|
/* Copy from size_t array. */
|
2010-09-22 22:25:42 +08:00
|
|
|
if (*contiguousp == NC_CHUNKED)
|
|
|
|
for (i = 0; i < var->ndims; i++)
|
|
|
|
{
|
2014-03-28 01:11:06 +08:00
|
|
|
chunksizesp[i] = (int)cs[i];
|
2010-09-22 22:25:42 +08:00
|
|
|
if (cs[i] > NC_MAX_INT)
|
|
|
|
retval = NC_ERANGE;
|
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
if (var->ndims)
|
|
|
|
free(cs);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function defines the chunking with ints, which works better
|
|
|
|
* with F77 portability. It is a secret function, which has been
|
|
|
|
* rendered unmappable, and it is impossible to apparate anywhere in
|
|
|
|
* this function. */
|
|
|
|
int
|
|
|
|
nc_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_VAR_INFO_T *var;
|
2014-06-03 03:04:28 +08:00
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
2010-06-03 21:24:43 +08:00
|
|
|
size_t *cs = NULL;
|
|
|
|
int i, retval;
|
|
|
|
|
|
|
|
/* Find this ncid's file info. */
|
2014-06-03 03:04:28 +08:00
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return retval;
|
|
|
|
assert(nc);
|
|
|
|
|
2014-06-03 03:04:28 +08:00
|
|
|
#ifdef USE_HDF4
|
|
|
|
if(h5->hdf4)
|
|
|
|
return NC_NOERR;
|
|
|
|
#endif
|
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Find var cause I need the number of dims. */
|
|
|
|
if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Allocate space for the size_t copy of the chunksizes array. */
|
|
|
|
if (var->ndims)
|
|
|
|
if (!(cs = malloc(var->ndims * sizeof(size_t))))
|
|
|
|
return NC_ENOMEM;
|
|
|
|
|
|
|
|
/* Copy to size_t array. */
|
|
|
|
for (i = 0; i < var->ndims; i++)
|
|
|
|
cs[i] = chunksizesp[i];
|
|
|
|
|
|
|
|
retval = nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL,
|
2014-02-12 07:12:08 +08:00
|
|
|
&contiguous, cs, NULL, NULL, NULL);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
if (var->ndims)
|
|
|
|
free(cs);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Define fill value behavior for a variable. This must be done after
|
|
|
|
nc_def_var and before nc_enddef. */
|
|
|
|
int
|
|
|
|
NC4_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value)
|
|
|
|
{
|
2011-02-01 05:30:39 +08:00
|
|
|
return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL,
|
2014-02-12 07:12:08 +08:00
|
|
|
NULL, &no_fill, fill_value, NULL);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Define the endianness of a variable. */
|
|
|
|
int
|
|
|
|
NC4_def_var_endian(int ncid, int varid, int endianness)
|
|
|
|
{
|
2011-02-01 05:30:39 +08:00
|
|
|
return nc_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL,
|
2014-02-12 07:12:08 +08:00
|
|
|
NULL, NULL, NULL, &endianness);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get var id from name. */
|
|
|
|
int
|
|
|
|
NC4_inq_varid(int ncid, const char *name, int *varidp)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
char norm_name[NC_MAX_NAME + 1];
|
|
|
|
int retval;
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2013-01-18 10:25:12 +08:00
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
#endif
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
if (!name)
|
|
|
|
return NC_EINVAL;
|
|
|
|
if (!varidp)
|
|
|
|
return NC_NOERR;
|
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((2, "%s: ncid 0x%x name %s", __func__, ncid, name));
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
2012-09-07 03:44:03 +08:00
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, NULL)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return retval;
|
2013-01-15 11:46:46 +08:00
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2013-01-18 10:25:12 +08:00
|
|
|
h5 = NC4_DATA(nc);
|
|
|
|
assert(h5);
|
2013-01-15 11:46:46 +08:00
|
|
|
/* Take care of files created/opened with parallel-netcdf library. */
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_file)
|
2013-01-15 11:46:46 +08:00
|
|
|
{
|
|
|
|
return ncmpi_inq_varid(nc->int_ncid, name, varidp);
|
|
|
|
}
|
|
|
|
#endif /* USE_PNETCDF */
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Normalize name. */
|
|
|
|
if ((retval = nc4_normalize_name(name, norm_name)))
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/* Find var of this name. */
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (var = grp->var; var; var = var->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
if (!(strcmp(var->name, norm_name)))
|
|
|
|
{
|
|
|
|
*varidp = var->varid;
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NC_ENOTVAR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Rename a var to "bubba," for example.
|
|
|
|
|
|
|
|
According to the netcdf-3.5 docs: If the new name is longer than
|
|
|
|
the old name, the netCDF dataset must be in define mode. */
|
|
|
|
int
|
|
|
|
NC4_rename_var(int ncid, int varid, const char *name)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
2014-11-24 23:36:58 +08:00
|
|
|
NC_VAR_INFO_T *var, *tmp_var;
|
2010-06-03 21:24:43 +08:00
|
|
|
int retval = NC_NOERR;
|
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((2, "%s: ncid 0x%x varid %d name %s",
|
|
|
|
__func__, ncid, varid, name));
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
|
|
|
return retval;
|
|
|
|
|
2013-01-18 10:25:12 +08:00
|
|
|
assert(h5);
|
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Take care of files created/opened with parallel-netcdf library. */
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_file)
|
2010-06-03 21:24:43 +08:00
|
|
|
return ncmpi_rename_var(nc->int_ncid, varid, name);
|
|
|
|
#endif /* USE_PNETCDF */
|
|
|
|
|
|
|
|
/* Is the new name too long? */
|
|
|
|
if (strlen(name) > NC_MAX_NAME)
|
|
|
|
return NC_EMAXNAME;
|
|
|
|
|
|
|
|
/* Trying to write to a read-only file? No way, Jose! */
|
|
|
|
if (h5->no_write)
|
|
|
|
return NC_EPERM;
|
|
|
|
|
|
|
|
/* Check name validity, if strict nc3 rules are in effect for this
|
|
|
|
* file. */
|
|
|
|
if ((retval = NC_check_name(name)))
|
|
|
|
return retval;
|
|
|
|
|
2014-11-24 23:36:58 +08:00
|
|
|
/* Check if name is in use, and retain a pointer to the correct variable */
|
|
|
|
tmp_var = NULL;
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (var = grp->var; var; var = var->l.next)
|
2014-11-24 23:36:58 +08:00
|
|
|
{
|
2010-06-03 21:24:43 +08:00
|
|
|
if (!strncmp(var->name, name, NC_MAX_NAME))
|
|
|
|
return NC_ENAMEINUSE;
|
|
|
|
if (var->varid == varid)
|
2014-11-24 23:36:58 +08:00
|
|
|
tmp_var = var;
|
|
|
|
}
|
|
|
|
if (!tmp_var)
|
2010-06-03 21:24:43 +08:00
|
|
|
return NC_ENOTVAR;
|
2014-11-24 23:36:58 +08:00
|
|
|
var = tmp_var;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* If we're not in define mode, new name must be of equal or
|
|
|
|
less size, if strict nc3 rules are in effect for this . */
|
|
|
|
if (!(h5->flags & NC_INDEF) && strlen(name) > strlen(var->name) &&
|
|
|
|
(h5->cmode & NC_CLASSIC_MODEL))
|
|
|
|
return NC_ENOTINDEFINE;
|
|
|
|
|
|
|
|
/* Change the HDF5 file, if this var has already been created
|
|
|
|
there. */
|
|
|
|
if (var->created)
|
|
|
|
{
|
|
|
|
if (H5Gmove(grp->hdf_grpid, var->name, name) < 0)
|
|
|
|
BAIL(NC_EHDFERR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now change the name in our metadata. */
|
2010-07-01 19:39:34 +08:00
|
|
|
free(var->name);
|
|
|
|
if (!(var->name = malloc((strlen(name) + 1) * sizeof(char))))
|
|
|
|
return NC_ENOMEM;
|
2010-06-03 21:24:43 +08:00
|
|
|
strcpy(var->name, name);
|
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
/* Check if this was a coordinate variable previously, but names are different now */
|
|
|
|
if (var->dimscale && strcmp(var->name, var->dim[0]->name))
|
|
|
|
{
|
|
|
|
/* Break up the coordinate variable */
|
|
|
|
if ((retval = nc4_break_coord_var(grp, var, var->dim[0])))
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if this should become a coordinate variable */
|
|
|
|
if (!var->dimscale)
|
|
|
|
{
|
|
|
|
/* Only variables with >0 dimensions can become coordinate variables */
|
|
|
|
if (var->ndims)
|
|
|
|
{
|
|
|
|
NC_GRP_INFO_T *dim_grp;
|
|
|
|
NC_DIM_INFO_T *dim;
|
|
|
|
|
|
|
|
/* Check to see if this is became a coordinate variable. If so, it
|
|
|
|
* will have the same name as dimension index 0. If it is a
|
|
|
|
* coordinate var, is it a coordinate var in the same group as the dim?
|
|
|
|
*/
|
|
|
|
if ((retval = nc4_find_dim(grp, var->dimids[0], &dim, &dim_grp)))
|
|
|
|
return retval;
|
|
|
|
if (strcmp(dim->name, name) == 0 && dim_grp == grp)
|
|
|
|
{
|
|
|
|
/* Reform the coordinate variable */
|
|
|
|
if ((retval = nc4_reform_coord_var(grp, var, dim)))
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
exit:
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
NC4_var_par_access(int ncid, int varid, int par_access)
|
|
|
|
{
|
|
|
|
#ifndef USE_PARALLEL
|
|
|
|
return NC_ENOPAR;
|
|
|
|
#else
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
int retval;
|
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((1, "%s: ncid 0x%x varid %d par_access %d", __func__, ncid,
|
2010-06-03 21:24:43 +08:00
|
|
|
varid, par_access));
|
|
|
|
|
|
|
|
if (par_access != NC_INDEPENDENT && par_access != NC_COLLECTIVE)
|
|
|
|
return NC_EINVAL;
|
|
|
|
|
|
|
|
/* Find info for this file and group, and set pointer to each. */
|
|
|
|
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
|
|
|
|
return retval;
|
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Handle files opened/created with parallel-netcdf library. */
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_file)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2013-01-18 10:25:12 +08:00
|
|
|
if (par_access == h5->pnetcdf_access_mode)
|
2010-06-03 21:24:43 +08:00
|
|
|
return NC_NOERR;
|
|
|
|
|
2013-01-18 10:25:12 +08:00
|
|
|
h5->pnetcdf_access_mode = par_access;
|
2010-06-03 21:24:43 +08:00
|
|
|
if (par_access == NC_INDEPENDENT)
|
|
|
|
return ncmpi_begin_indep_data(nc->int_ncid);
|
|
|
|
else
|
|
|
|
return ncmpi_end_indep_data(nc->int_ncid);
|
|
|
|
}
|
|
|
|
#endif /* USE_PNETCDF */
|
|
|
|
|
|
|
|
/* This function only for files opened with nc_open_par or nc_create_par. */
|
|
|
|
if (!h5->parallel)
|
|
|
|
return NC_ENOPAR;
|
|
|
|
|
|
|
|
/* Find the var, and set its preference. */
|
Refactored read_scale(), memio_new(), var_create_dataset() and makespecial()
to clean up resources properly on failure.
Refactored doubly-linked list code for objects in the libsrc4 directory,
cleaning up the add/del routines, breaking out the common next/prev
pointers into a struct and extracting the add/del operations on them,
changed the list of dims to add new dims in the same order as the other
types, made all add routines able to optionally return a pointer to the
newly created object.
Removed some dead code (pg_var(), nc4_pg_var1(), nc4_pg_varm(), misc. small
routines, etc)
Fixed fill value handling for string types in nc4_get_vara().
Changed many malloc()+strcpy() pairs into calls to strdup().
Cleaned up misc. other minor Coverity issues.
2013-12-08 17:29:26 +08:00
|
|
|
for (var = grp->var; var; var = var->l.next)
|
2010-06-03 21:24:43 +08:00
|
|
|
if (var->varid == varid)
|
|
|
|
break;
|
|
|
|
if (!var)
|
|
|
|
return NC_ENOTVAR;
|
|
|
|
|
|
|
|
if (par_access)
|
|
|
|
var->parallel_access = NC_COLLECTIVE;
|
|
|
|
else
|
|
|
|
var->parallel_access = NC_INDEPENDENT;
|
|
|
|
return NC_NOERR;
|
|
|
|
#endif /* USE_PARALLEL */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
nc4_put_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long,
|
|
|
|
const size_t *startp, const size_t *countp, const void *op)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
2013-01-29 03:58:06 +08:00
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2013-01-18 10:25:12 +08:00
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
#endif
|
2013-02-13 05:27:52 +08:00
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((2, "%s: ncid 0x%x varid %d mem_type %d mem_type_is_long %d",
|
|
|
|
__func__, ncid, varid, mem_type, mem_type_is_long));
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2012-09-07 03:44:03 +08:00
|
|
|
if (!(nc = nc4_find_nc_file(ncid,NULL)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return NC_EBADID;
|
2012-09-07 03:44:03 +08:00
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2013-01-18 10:25:12 +08:00
|
|
|
h5 = NC4_DATA(nc);
|
|
|
|
assert(h5);
|
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Handle files opened/created with the parallel-netcdf library. */
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_file)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2013-01-29 02:31:02 +08:00
|
|
|
MPI_Offset *mpi_start;
|
|
|
|
MPI_Offset *mpi_count;
|
|
|
|
int d;
|
|
|
|
|
2013-02-13 05:27:52 +08:00
|
|
|
mpi_start = (MPI_Offset*)alloca(sizeof(MPI_Offset)*h5->pnetcdf_ndims[varid]);
|
|
|
|
mpi_count = (MPI_Offset*)alloca(sizeof(MPI_Offset)*h5->pnetcdf_ndims[varid]);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* No NC_LONGs for parallel-netcdf library! */
|
|
|
|
if (mem_type_is_long)
|
|
|
|
return NC_EINVAL;
|
|
|
|
|
|
|
|
/* We must convert the start, count, and stride arrays to
|
|
|
|
* MPI_Offset type. */
|
2013-01-18 10:25:12 +08:00
|
|
|
for (d = 0; d < h5->pnetcdf_ndims[varid]; d++)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
mpi_start[d] = startp[d];
|
|
|
|
mpi_count[d] = countp[d];
|
|
|
|
}
|
|
|
|
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_access_mode == NC_INDEPENDENT)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
switch(mem_type)
|
|
|
|
{
|
|
|
|
case NC_BYTE:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_schar(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_UBYTE:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_uchar(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_CHAR:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_text(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_SHORT:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_short(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_INT:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_int(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_FLOAT:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_float(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_DOUBLE:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_double(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_NAT:
|
|
|
|
default:
|
2013-02-13 05:27:52 +08:00
|
|
|
return NC_EBADTYPE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
2013-01-29 02:31:02 +08:00
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
switch(mem_type)
|
|
|
|
{
|
|
|
|
case NC_BYTE:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_schar_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_UBYTE:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_uchar_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_CHAR:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_text_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_SHORT:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_short_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_INT:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_int_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_FLOAT:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_float_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_DOUBLE:
|
2013-02-13 05:27:52 +08:00
|
|
|
return ncmpi_put_vara_double_all(nc->int_ncid, varid, mpi_start, mpi_count, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
case NC_NAT:
|
|
|
|
default:
|
2013-02-13 05:27:52 +08:00
|
|
|
return NC_EBADTYPE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
}
|
2013-02-13 05:27:52 +08:00
|
|
|
|
|
|
|
return NC_EBADTYPE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
2013-01-29 02:31:02 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
#endif /* USE_PNETCDF */
|
|
|
|
|
|
|
|
return nc4_put_vara(nc, ncid, varid, startp, countp, mem_type,
|
|
|
|
mem_type_is_long, (void *)op);
|
|
|
|
}
|
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
#ifdef USE_HDF4
|
|
|
|
static int
|
2012-09-07 03:44:03 +08:00
|
|
|
nc4_get_hdf4_vara(NC *nc, int ncid, int varid, const size_t *startp,
|
2010-06-03 21:24:43 +08:00
|
|
|
const size_t *countp, nc_type mem_nc_type, int is_long, void *data)
|
|
|
|
{
|
2012-12-14 02:22:11 +08:00
|
|
|
NC_GRP_INFO_T *grp;
|
2010-06-03 21:24:43 +08:00
|
|
|
NC_HDF5_FILE_INFO_T *h5;
|
|
|
|
NC_VAR_INFO_T *var;
|
|
|
|
int32 start32[NC_MAX_VAR_DIMS], edge32[NC_MAX_VAR_DIMS];
|
|
|
|
int retval, d;
|
2012-12-14 02:22:11 +08:00
|
|
|
#if 0
|
|
|
|
NC_GRP_INFO_T *g;
|
|
|
|
NC_DIM_INFO_T *dim;
|
|
|
|
#endif
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Find our metadata for this file, group, and var. */
|
|
|
|
assert(nc);
|
|
|
|
if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
|
|
|
|
return retval;
|
2012-12-14 02:22:11 +08:00
|
|
|
h5 = NC4_DATA(nc);
|
2010-06-03 21:24:43 +08:00
|
|
|
assert(grp && h5 && var && var->name);
|
|
|
|
|
|
|
|
for (d = 0; d < var->ndims; d++)
|
|
|
|
{
|
|
|
|
start32[d] = startp[d];
|
|
|
|
edge32[d] = countp[d];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SDreaddata(var->sdsid, start32, NULL, edge32, data))
|
|
|
|
return NC_EHDFERR;
|
|
|
|
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
2014-02-12 07:12:08 +08:00
|
|
|
#endif /* USE_HDF4 */
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Get an array. */
|
|
|
|
static int
|
|
|
|
nc4_get_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long,
|
|
|
|
const size_t *startp, const size_t *countp, void *ip)
|
|
|
|
{
|
2012-09-07 03:44:03 +08:00
|
|
|
NC *nc;
|
|
|
|
NC_HDF5_FILE_INFO_T* h5;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2013-12-01 13:20:28 +08:00
|
|
|
LOG((2, "%s: ncid 0x%x varid %d mem_type %d mem_type_is_long %d",
|
|
|
|
__func__, ncid, varid, mem_type, mem_type_is_long));
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2012-09-07 03:44:03 +08:00
|
|
|
if (!(nc = nc4_find_nc_file(ncid,&h5)))
|
2010-06-03 21:24:43 +08:00
|
|
|
return NC_EBADID;
|
|
|
|
|
2013-03-16 04:31:07 +08:00
|
|
|
#if 0 /*def USE_PNETCDF*/
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Handle files opened/created with the parallel-netcdf library. */
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_file)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
MPI_Offset mpi_start[NC_MAX_VAR_DIMS], mpi_count[NC_MAX_VAR_DIMS];
|
|
|
|
int d;
|
|
|
|
|
|
|
|
/* No NC_LONGs for parallel-netcdf library! */
|
|
|
|
if (mem_type_is_long)
|
|
|
|
return NC_EINVAL;
|
|
|
|
|
|
|
|
/* We must convert the start, count, and stride arrays to
|
|
|
|
* MPI_Offset type. */
|
2013-01-18 10:25:12 +08:00
|
|
|
for (d = 0; d < h5->pnetcdf_ndims[varid]; d++)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
mpi_start[d] = startp[d];
|
|
|
|
mpi_count[d] = countp[d];
|
|
|
|
}
|
|
|
|
|
2013-01-18 10:25:12 +08:00
|
|
|
if (h5->pnetcdf_access_mode == NC_INDEPENDENT)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
switch(mem_type)
|
|
|
|
{
|
|
|
|
case NC_BYTE:
|
|
|
|
return ncmpi_get_vara_schar(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_UBYTE:
|
|
|
|
return ncmpi_get_vara_uchar(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_CHAR:
|
|
|
|
return ncmpi_get_vara_text(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_SHORT:
|
|
|
|
return ncmpi_get_vara_short(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_INT:
|
|
|
|
return ncmpi_get_vara_int(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_FLOAT:
|
|
|
|
return ncmpi_get_vara_float(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_DOUBLE:
|
|
|
|
return ncmpi_get_vara_double(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_NAT:
|
|
|
|
default:
|
|
|
|
return NC_EBADTYPE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch(mem_type)
|
|
|
|
{
|
|
|
|
case NC_BYTE:
|
|
|
|
return ncmpi_get_vara_schar_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_UBYTE:
|
|
|
|
return ncmpi_get_vara_uchar_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_CHAR:
|
|
|
|
return ncmpi_get_vara_text_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_SHORT:
|
|
|
|
return ncmpi_get_vara_short_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_INT:
|
|
|
|
return ncmpi_get_vara_int_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_FLOAT:
|
|
|
|
return ncmpi_get_vara_float_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_DOUBLE:
|
|
|
|
return ncmpi_get_vara_double_all(nc->int_ncid, varid, mpi_start, mpi_count, ip);
|
|
|
|
case NC_NAT:
|
|
|
|
default:
|
|
|
|
return NC_EBADTYPE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* USE_PNETCDF */
|
|
|
|
|
2014-02-12 07:12:08 +08:00
|
|
|
#ifdef USE_HDF4
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Handle HDF4 cases. */
|
2012-09-07 03:44:03 +08:00
|
|
|
if (h5->hdf4)
|
2010-06-03 21:24:43 +08:00
|
|
|
return nc4_get_hdf4_vara(nc, ncid, varid, startp, countp, mem_type,
|
|
|
|
mem_type_is_long, (void *)ip);
|
2014-02-12 07:12:08 +08:00
|
|
|
#endif /* USE_HDF4 */
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Handle HDF5 cases. */
|
|
|
|
return nc4_get_vara(nc, ncid, varid, startp, countp, mem_type,
|
|
|
|
mem_type_is_long, (void *)ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
NC4_put_vara(int ncid, int varid, const size_t *startp,
|
|
|
|
const size_t *countp, const void *op, int memtype)
|
|
|
|
{
|
2010-06-23 01:12:29 +08:00
|
|
|
return nc4_put_vara_tc(ncid, varid, memtype, 0, startp, countp, op);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Read an array of values. */
|
|
|
|
int
|
|
|
|
NC4_get_vara(int ncid, int varid, const size_t *startp,
|
|
|
|
const size_t *countp, void *ip, int memtype)
|
|
|
|
{
|
2010-06-23 01:12:29 +08:00
|
|
|
return nc4_get_vara_tc(ncid, varid, memtype, 0, startp, countp, ip);
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|