netcdf-c/libsrc/var.c

864 lines
17 KiB
C
Raw Normal View History

2010-06-03 21:24:43 +08:00
/*
* Copyright 2018, University Corporation for Atmospheric Research
2010-06-03 21:24:43 +08:00
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*/
/* $Id: var.c,v 1.144 2010/05/30 00:50:35 russ Exp $ */
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "nc3internal.h"
2010-06-03 21:24:43 +08:00
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include "ncx.h"
#include "rnd.h"
#include "ncutf8.h"
2017-12-21 10:53:30 +08:00
#include "nc3dispatch.h"
2010-06-03 21:24:43 +08:00
#ifndef OFF_T_MAX
Primary change: add dap4 support Specific changes: 1. Add dap4 code: libdap4 and dap4_test. Note that until the d4ts server problem is solved, dap4 is turned off. 2. Modify various files to support dap4 flags: configure.ac, Makefile.am, CMakeLists.txt, etc. 3. Add nc_test/test_common.sh. This centralizes the handling of the locations of various things in the build tree: e.g. where is ncgen.exe located. See nc_test/test_common.sh for details. 4. Modify .sh files to use test_common.sh 5. Obsolete separate oc2 by moving it to be part of netcdf-c. This means replacing code with netcdf-c equivalents. 5. Add --with-testserver to configure.ac to allow override of the servers to be used for --enable-dap-remote-tests. 6. There were multiple versions of nctypealignment code. Try to centralize in libdispatch/doffset.c and include/ncoffsets.h 7. Add a unit test for the ncuri code because of its complexity. 8. Move the findserver code out of libdispatch and into a separate, self contained program in ncdap_test and dap4_test. 9. Move the dispatch header files (nc{3,4}dispatch.h) to .../include because they are now shared by modules. 10. Revamp the handling of TOPSRCDIR and TOPBUILDDIR for shell scripts. 11. Make use of MREMAP if available 12. Misc. minor changes e.g. - #include <config.h> -> #include "config.h" - Add some no-install headers to /include - extern -> EXTERNL and vice versa as needed - misc header cleanup - clean up checking for misc. unix vs microsoft functions 13. Change copyright decls in some files to point to LICENSE file. 14. Add notes to RELEASENOTES.md
2017-03-09 08:01:10 +08:00
#if 0
#define OFF_T_MAX (~ (off_t) 0 - (~ (off_t) 0 << (CHAR_BIT * sizeof (off_t) - 1)))
#endif
/* The behavior above is undefined, re: bitshifting a negative value, according
to warnings thrown by clang/gcc. An alternative OFF_T_MAX was written
based on info found at:
* http://stackoverflow.com/questions/4514572/c-question-off-t-and-other-signed-integer-types-minimum-and-maximum-values
*/
#define MAX_INT_VAL_STEP(t) \
((t) 1 << (CHAR_BIT * sizeof(t) - 1 - ((t) -1 < 1)))
#define MAX_INT_VAL(t) \
((MAX_INT_VAL_STEP(t) - 1) + MAX_INT_VAL_STEP(t))
#define MIN_INT_VAL(t) \
((t) -MAX_INT_VAL(t) - 1)
#define OFF_T_MAX MAX_INT_VAL(off_t)
2010-06-03 21:24:43 +08:00
#endif
/*
* Free var
* Formerly NC_free_var(var)
2010-06-03 21:24:43 +08:00
*/
void
free_NC_var(NC_var *varp)
{
if(varp == NULL)
return;
free_NC_attrarrayV(&varp->attrs);
free_NC_string(varp->name);
#ifndef MALLOCHACK
if(varp->dimids != NULL) free(varp->dimids);
if(varp->shape != NULL) free(varp->shape);
if(varp->dsizes != NULL) free(varp->dsizes);
#endif /*!MALLOCHACK*/
free(varp);
}
/*
* Common code for new_NC_var()
2010-06-03 21:24:43 +08:00
* and ncx_get_NC_var()
*/
NC_var *
new_x_NC_var(
NC_string *strp,
size_t ndims)
{
NC_var *varp;
const size_t o1 = M_RNDUP(ndims * sizeof(int));
const size_t o2 = M_RNDUP(ndims * sizeof(size_t));
#ifdef MALLOCHACK
const size_t sz = M_RNDUP(sizeof(NC_var)) +
o1 + o2 + ndims * sizeof(off_t);
#else /*!MALLOCHACK*/
const size_t o3 = ndims * sizeof(off_t);
const size_t sz = sizeof(NC_var);
#endif /*!MALLOCHACK*/
varp = (NC_var *) malloc(sz);
if(varp == NULL )
return NULL;
(void) memset(varp, 0, sz);
varp->name = strp;
varp->ndims = ndims;
if(ndims != 0)
{
#ifdef MALLOCHACK
/*
* NOTE: lint may complain about the next 3 lines:
* "pointer cast may result in improper alignment".
* We use the M_RNDUP() macro to get the proper alignment.
*/
varp->dimids = (int *)((char *)varp + M_RNDUP(sizeof(NC_var)));
varp->shape = (size_t *)((char *)varp->dimids + o1);
varp->dsizes = (off_t *)((char *)varp->shape + o2);
2010-06-03 21:24:43 +08:00
#else /*!MALLOCHACK*/
varp->dimids = (int*)malloc(o1);
varp->shape = (size_t*)malloc(o2);
varp->dsizes = (off_t*)malloc(o3);
2010-06-03 21:24:43 +08:00
#endif /*!MALLOCHACK*/
} else {
varp->dimids = NULL;
varp->shape = NULL;
varp->dsizes=NULL;
2010-06-03 21:24:43 +08:00
}
2010-06-03 21:24:43 +08:00
varp->xsz = 0;
varp->len = 0;
varp->begin = 0;
return varp;
2010-06-03 21:24:43 +08:00
}
/*
* Formerly
NC_new_var()
*/
static NC_var *
new_NC_var(const char *uname, nc_type type,
size_t ndims, const int *dimids)
{
NC_string *strp = NULL;
NC_var *varp = NULL;
int stat;
char* name;
stat = nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name);
if(stat != NC_NOERR)
2010-06-03 21:24:43 +08:00
return NULL;
strp = new_NC_string(strlen(name), name);
free(name);
if(strp == NULL)
return NULL;
2010-06-03 21:24:43 +08:00
varp = new_x_NC_var(strp, ndims);
if(varp == NULL )
{
free_NC_string(strp);
return NULL;
}
2010-06-03 21:24:43 +08:00
varp->type = type;
if( ndims != 0 && dimids != NULL)
(void) memcpy(varp->dimids, dimids, ndims * sizeof(int));
else
varp->dimids=NULL;
2010-06-03 21:24:43 +08:00
return(varp);
}
static NC_var *
dup_NC_var(const NC_var *rvarp)
{
NC_var *varp = new_NC_var(rvarp->name->cp, rvarp->type,
rvarp->ndims, rvarp->dimids);
if(varp == NULL)
return NULL;
2010-06-03 21:24:43 +08:00
if(dup_NC_attrarrayV(&varp->attrs, &rvarp->attrs) != NC_NOERR)
{
free_NC_var(varp);
return NULL;
}
if(rvarp->shape != NULL)
(void) memcpy(varp->shape, rvarp->shape,
rvarp->ndims * sizeof(size_t));
if(rvarp->dsizes != NULL)
(void) memcpy(varp->dsizes, rvarp->dsizes,
rvarp->ndims * sizeof(off_t));
2010-06-03 21:24:43 +08:00
varp->xsz = rvarp->xsz;
varp->len = rvarp->len;
varp->begin = rvarp->begin;
return varp;
}
/* vararray */
/*
* Free the stuff "in" (referred to by) an NC_vararray.
* Leaves the array itself allocated.
*/
void
free_NC_vararrayV0(NC_vararray *ncap)
{
assert(ncap != NULL);
if(ncap->nelems == 0)
return;
assert(ncap->value != NULL);
{
NC_var **vpp = ncap->value;
NC_var *const *const end = &vpp[ncap->nelems];
for( /*NADA*/; vpp < end; vpp++)
{
free_NC_var(*vpp);
*vpp = NULL;
}
}
ncap->nelems = 0;
}
/*
* Free NC_vararray values.
* formerly
NC_free_array()
*/
void
free_NC_vararrayV(NC_vararray *ncap)
{
assert(ncap != NULL);
2010-06-03 21:24:43 +08:00
if(ncap->nalloc == 0)
return;
NC_hashmapfree(ncap->hashmap);
2016-03-24 20:36:20 +08:00
ncap->hashmap = NULL;
2010-06-03 21:24:43 +08:00
assert(ncap->value != NULL);
free_NC_vararrayV0(ncap);
free(ncap->value);
ncap->value = NULL;
ncap->nalloc = 0;
}
int
dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref)
{
int status = NC_NOERR;
assert(ref != NULL);
assert(ncap != NULL);
if(ref->nelems != 0)
{
const size_t sz = ref->nelems * sizeof(NC_var *);
ncap->value = (NC_var **) malloc(sz);
if(ncap->value == NULL)
return NC_ENOMEM;
(void) memset(ncap->value, 0, sz);
ncap->nalloc = ref->nelems;
}
ncap->nelems = 0;
{
NC_var **vpp = ncap->value;
const NC_var **drpp = (const NC_var **)ref->value;
NC_var *const *const end = &vpp[ref->nelems];
for( /*NADA*/; vpp < end; drpp++, vpp++, ncap->nelems++)
{
*vpp = dup_NC_var(*drpp);
if(*vpp == NULL)
{
status = NC_ENOMEM;
break;
}
}
}
if(status != NC_NOERR)
{
free_NC_vararrayV(ncap);
return status;
}
assert(ncap->nelems == ref->nelems);
return NC_NOERR;
}
/*
* Add a new handle on the end of an array of handles
* Formerly
NC_incr_array(array, tail)
*/
static int
incr_NC_vararray(NC_vararray *ncap, NC_var *newelemp)
{
NC_var **vp;
assert(ncap != NULL);
if(ncap->nalloc == 0)
{
assert(ncap->nelems == 0);
vp = (NC_var **) malloc(NC_ARRAY_GROWBY * sizeof(NC_var *));
if(vp == NULL)
return NC_ENOMEM;
ncap->value = vp;
ncap->nalloc = NC_ARRAY_GROWBY;
ncap->hashmap = NC_hashmapnew(0);
2010-06-03 21:24:43 +08:00
}
else if(ncap->nelems +1 > ncap->nalloc)
{
vp = (NC_var **) realloc(ncap->value,
2016-03-24 20:44:41 +08:00
(ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_var *));
2010-06-03 21:24:43 +08:00
if(vp == NULL)
return NC_ENOMEM;
ncap->value = vp;
2016-03-24 20:44:41 +08:00
ncap->nalloc += NC_ARRAY_GROWBY;
2010-06-03 21:24:43 +08:00
}
if(newelemp != NULL)
{
NC_hashmapadd(ncap->hashmap, (uintptr_t)ncap->nelems, newelemp->name->cp, strlen(newelemp->name->cp));
2010-06-03 21:24:43 +08:00
ncap->value[ncap->nelems] = newelemp;
ncap->nelems++;
}
return NC_NOERR;
}
static NC_var *
elem_NC_vararray(const NC_vararray *ncap, size_t elem)
{
assert(ncap != NULL);
/* cast needed for braindead systems with signed size_t */
if(ncap->nelems == 0 || (unsigned long)elem >= ncap->nelems)
return NULL;
assert(ncap->value != NULL);
return ncap->value[elem];
}
/* End vararray per se */
/*
* Step thru NC_VARIABLE array, seeking match on name.
* Return varid or -1 on not found.
* *varpp is set to the appropriate NC_var.
2018-02-28 06:46:19 +08:00
* Formerly (sort of) NC_hvarid
2010-06-03 21:24:43 +08:00
*/
int
NC_findvar(const NC_vararray *ncap, const char *uname, NC_var **varpp)
{
2018-02-28 06:46:19 +08:00
int hash_var_id = -1;
uintptr_t data;
2018-02-28 06:46:19 +08:00
char *name = NULL;
2010-06-03 21:24:43 +08:00
assert(ncap != NULL);
if(ncap->nelems == 0)
2018-02-28 06:46:19 +08:00
goto done;
2010-06-03 21:24:43 +08:00
/* normalized version of uname */
2018-02-28 06:46:19 +08:00
if(nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name))
goto done;
2010-06-03 21:24:43 +08:00
if(NC_hashmapget(ncap->hashmap, name, strlen(name), &data) == 0)
2018-02-28 06:46:19 +08:00
goto done;
hash_var_id = (int)data;
2018-02-26 02:28:06 +08:00
if (varpp != NULL)
*varpp = ncap->value[hash_var_id];
2018-02-28 06:46:19 +08:00
done:
if(name != NULL) free(name);
2018-02-26 02:28:06 +08:00
return(hash_var_id); /* Normal return */
2010-06-03 21:24:43 +08:00
}
/*
2010-06-03 21:24:43 +08:00
* For a netcdf type
* return the size of one element in the external representation.
* Note that arrays get rounded up to X_ALIGN boundaries.
* Formerly
NC_xtypelen
* See also ncx_len()
*/
size_t
ncx_szof(nc_type type)
{
switch(type){
case NC_BYTE:
case NC_CHAR:
2015-08-16 06:26:35 +08:00
case NC_UBYTE:
2010-06-03 21:24:43 +08:00
return(1);
case NC_SHORT :
return(2);
case NC_INT:
return X_SIZEOF_INT;
case NC_FLOAT:
return X_SIZEOF_FLOAT;
case NC_DOUBLE :
2010-06-03 21:24:43 +08:00
return X_SIZEOF_DOUBLE;
case NC_USHORT :
2015-08-16 06:26:35 +08:00
return X_SIZEOF_USHORT;
case NC_UINT :
2015-08-16 06:26:35 +08:00
return X_SIZEOF_UINT;
case NC_INT64 :
2015-08-16 06:26:35 +08:00
return X_SIZEOF_INT64;
case NC_UINT64 :
2015-08-16 06:26:35 +08:00
return X_SIZEOF_UINT64;
2010-06-03 21:24:43 +08:00
default:
/* 37824 Ignore */
2010-06-03 21:24:43 +08:00
assert("ncx_szof invalid type" == 0);
return 0;
}
}
/*
* 'compile' the shape and len of a variable
* Formerly
NC_var_shape(var, dims)
*/
int
NC_var_shape(NC_var *varp, const NC_dimarray *dims)
{
size_t *shp, *op;
off_t *dsp;
int *ip = NULL;
2010-06-03 21:24:43 +08:00
const NC_dim *dimp;
off_t product = 1;
2010-06-03 21:24:43 +08:00
varp->xsz = ncx_szof(varp->type);
if(varp->ndims == 0 || varp->dimids == NULL)
2010-06-03 21:24:43 +08:00
{
goto out;
}
/*
* use the user supplied dimension indices
* to determine the shape
*/
for(ip = varp->dimids, op = varp->shape
; ip < &varp->dimids[varp->ndims]; ip++, op++)
2010-06-03 21:24:43 +08:00
{
if(*ip < 0 || (size_t) (*ip) >= ((dims != NULL) ? dims->nelems : 1) )
return NC_EBADDIM;
2010-06-03 21:24:43 +08:00
dimp = elem_NC_dimarray(dims, (size_t)*ip);
*op = dimp->size;
if(*op == NC_UNLIMITED && ip != varp->dimids)
return NC_EUNLIMPOS;
}
/*
2010-06-03 21:24:43 +08:00
* Compute the dsizes
*/
/* ndims is > 0 here */
for(shp = varp->shape + varp->ndims -1,
dsp = varp->dsizes + varp->ndims -1;
shp >= varp->shape;
shp--, dsp--)
{
/*if(!(shp == varp->shape && IS_RECVAR(varp)))*/
if( shp != NULL && (shp != varp->shape || !IS_RECVAR(varp)))
2010-06-03 21:24:43 +08:00
{
if( ((off_t)(*shp)) <= OFF_T_MAX / product )
2010-06-03 21:24:43 +08:00
{
product *= (*shp > 0 ? *shp : 1);
} else
2010-06-03 21:24:43 +08:00
{
product = OFF_T_MAX ;
2010-06-03 21:24:43 +08:00
}
}
*dsp = product;
2010-06-03 21:24:43 +08:00
}
out :
/*
* For CDF-1 and CDF-2 formats, the total number of array elements
* cannot exceed 2^32, unless this variable is the last fixed-size
* variable, there is no record variable, and the file starting
* offset of this variable is less than 2GiB.
* This will be checked in NC_check_vlens() during NC_endef()
*/
varp->len = product * varp->xsz;
if (varp->len % 4 > 0)
varp->len += 4 - varp->len % 4; /* round up */
2010-06-03 21:24:43 +08:00
#if 0
arrayp("\tshape", varp->ndims, varp->shape);
arrayp("\tdsizes", varp->ndims, varp->dsizes);
#endif
return NC_NOERR;
}
/*
* Check whether variable size is less than or equal to vlen_max,
* without overflowing in arithmetic calculations. If OK, return 1,
* else, return 0. For CDF1 format or for CDF2 format on non-LFS
* platforms, vlen_max should be 2^31 - 4, but for CDF2 format on
* systems with LFS it should be 2^32 - 4.
*/
int
NC_check_vlen(NC_var *varp, long long vlen_max) {
size_t ii;
long long prod=varp->xsz; /* product of xsz and dimensions so far */
2010-06-03 21:24:43 +08:00
assert(varp != NULL);
for(ii = IS_RECVAR(varp) ? 1 : 0; ii < varp->ndims; ii++) {
if(!varp->shape)
return 0; /* Shape is undefined/NULL. */
2018-06-18 02:16:09 +08:00
if ((long long)varp->shape[ii] > vlen_max / prod) {
return 0; /* size in bytes won't fit in a 32-bit int */
}
prod *= varp->shape[ii];
2010-06-03 21:24:43 +08:00
}
return 1; /* OK */
}
/*! Look up a variable by varid.
*
* Given a valid ncp structure and varid, return the var.
*
* Formerly NC_hlookupvar()
*
* @param[in] ncp NC3_INFO data structure.
* @param[in] varid The varid key for the var we are looking up.
* @param[out] varp Data structure to contain the varp pointer.
* @return Error code, if one exists, 0 otherwise.
2010-06-03 21:24:43 +08:00
*/
int NC_lookupvar(NC3_INFO* ncp, int varid, NC_var **varp)
{
if(varid == NC_GLOBAL)
2010-06-03 21:24:43 +08:00
{
/* Global is error in this context */
return NC_EGLOBAL;
2010-06-03 21:24:43 +08:00
}
if(varp)
*varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
else
return NC_ENOTVAR;
if(*varp == NULL)
return NC_ENOTVAR;
return NC_NOERR;
2010-06-03 21:24:43 +08:00
}
/* Public */
int
NC3_def_var( int ncid, const char *name, nc_type type,
int ndims, const int *dimids, int *varidp)
{
int status;
NC *nc;
NC3_INFO* ncp;
2010-06-03 21:24:43 +08:00
int varid;
NC_var *varp = NULL;
2010-06-03 21:24:43 +08:00
status = NC_check_id(ncid, &nc);
2010-06-03 21:24:43 +08:00
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
2010-06-03 21:24:43 +08:00
if(!NC_indef(ncp))
{
return NC_ENOTINDEFINE;
}
status = NC_check_name(name);
if(status != NC_NOERR)
return status;
2015-08-16 06:26:35 +08:00
status = nc3_cktype(nc->mode, type);
2010-06-03 21:24:43 +08:00
if(status != NC_NOERR)
return status;
if (ndims > NC_MAX_VAR_DIMS) return NC_EMAXDIMS;
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 */
{
return NC_EINVAL;
}
2010-06-03 21:24:43 +08:00
varid = NC_findvar(&ncp->vars, name, &varp);
if(varid != -1)
{
return NC_ENAMEINUSE;
}
2010-06-03 21:24:43 +08:00
varp = new_NC_var(name, type, ndims, dimids);
if(varp == NULL)
return NC_ENOMEM;
status = NC_var_shape(varp, &ncp->dims);
if(status != NC_NOERR)
{
free_NC_var(varp);
return status;
}
status = incr_NC_vararray(&ncp->vars, varp);
if(status != NC_NOERR)
{
free_NC_var(varp);
return status;
}
if(varidp != NULL)
*varidp = (int)ncp->vars.nelems -1; /* varid */
2017-12-21 10:53:30 +08:00
/* set the variable's fill mode */
if (NC_dofill(ncp))
varp->no_fill = 0;
else
varp->no_fill = 1;
2010-06-03 21:24:43 +08:00
return NC_NOERR;
}
int
NC3_inq_varid(int ncid, const char *name, int *varid_ptr)
{
int status;
NC *nc;
NC3_INFO* ncp;
2010-06-03 21:24:43 +08:00
NC_var *varp;
int varid;
status = NC_check_id(ncid, &nc);
2010-06-03 21:24:43 +08:00
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
2010-06-03 21:24:43 +08:00
varid = NC_findvar(&ncp->vars, name, &varp);
if(varid == -1)
{
return NC_ENOTVAR;
}
*varid_ptr = varid;
return NC_NOERR;
}
int
NC3_inq_var(int ncid,
int varid,
char *name,
nc_type *typep,
int *ndimsp,
int *dimids,
2017-12-21 10:53:30 +08:00
int *nattsp,
int *no_fillp,
void *fill_valuep)
2010-06-03 21:24:43 +08:00
{
int status;
NC *nc;
NC3_INFO* ncp;
2010-06-03 21:24:43 +08:00
NC_var *varp;
size_t ii;
status = NC_check_id(ncid, &nc);
2010-06-03 21:24:43 +08:00
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
2010-06-03 21:24:43 +08:00
varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
if(varp == NULL)
return NC_ENOTVAR;
if(name != NULL)
{
(void) strncpy(name, varp->name->cp, varp->name->nchars);
name[varp->name->nchars] = 0;
}
if(typep != 0)
*typep = varp->type;
if(ndimsp != 0)
{
*ndimsp = (int) varp->ndims;
}
if(dimids != 0)
{
for(ii = 0; ii < varp->ndims; ii++)
{
dimids[ii] = varp->dimids[ii];
}
}
if(nattsp != 0)
{
*nattsp = (int) varp->attrs.nelems;
}
2017-12-21 10:53:30 +08:00
if (no_fillp != NULL) *no_fillp = varp->no_fill;
if (fill_valuep != NULL) {
status = nc_get_att(ncid, varid, _FillValue, fill_valuep);
if (status != NC_NOERR && status != NC_ENOTATT)
return status;
if (status == NC_ENOTATT) {
status = NC3_inq_default_fill_value(varp->type, fill_valuep);
if (status != NC_NOERR) return status;
}
}
2010-06-03 21:24:43 +08:00
return NC_NOERR;
}
int
NC3_rename_var(int ncid, int varid, const char *unewname)
{
2018-02-28 06:46:19 +08:00
int status = NC_NOERR;
NC *nc;
NC3_INFO* ncp;
uintptr_t intdata;
2010-06-03 21:24:43 +08:00
NC_var *varp;
NC_string *old, *newStr;
int other;
2018-02-28 06:46:19 +08:00
char *newname = NULL; /* normalized */
2010-06-03 21:24:43 +08:00
status = NC_check_id(ncid, &nc);
2010-06-03 21:24:43 +08:00
if(status != NC_NOERR)
2018-02-28 06:46:19 +08:00
goto done;
ncp = NC3_DATA(nc);
2010-06-03 21:24:43 +08:00
if(NC_readonly(ncp))
2018-02-28 06:46:19 +08:00
{status = NC_EPERM; goto done;}
2010-06-03 21:24:43 +08:00
status = NC_check_name(unewname);
if(status != NC_NOERR)
2018-02-28 06:46:19 +08:00
goto done;
2010-06-03 21:24:43 +08:00
/* check for name in use */
other = NC_findvar(&ncp->vars, unewname, &varp);
if(other != -1)
2018-02-28 06:46:19 +08:00
{status = NC_ENAMEINUSE; goto done;}
status = NC_lookupvar(ncp, varid, &varp);
if(status != NC_NOERR)
2018-02-28 06:46:19 +08:00
goto done; /* invalid varid */
2010-06-03 21:24:43 +08:00
old = varp->name;
status = nc_utf8_normalize((const unsigned char *)unewname,(unsigned char **)&newname);
if(status != NC_NOERR)
2018-02-28 06:46:19 +08:00
goto done;
2010-06-03 21:24:43 +08:00
if(NC_indef(ncp))
{
/* Remove old name from hashmap; add new... */
/* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
NC_hashmapremove(ncp->vars.hashmap,old->cp,strlen(old->cp),NULL);
2010-06-03 21:24:43 +08:00
newStr = new_NC_string(strlen(newname),newname);
if(newStr == NULL)
2018-02-28 06:46:19 +08:00
{status = NC_ENOMEM; goto done;}
2010-06-03 21:24:43 +08:00
varp->name = newStr;
intdata = (uintptr_t)varid;
NC_hashmapadd(ncp->vars.hashmap, intdata, varp->name->cp, strlen(varp->name->cp));
free_NC_string(old);
2018-02-28 06:46:19 +08:00
goto done;
2010-06-03 21:24:43 +08:00
}
/* else, not in define mode */
/* If new name is longer than old, then complain,
but otherwise, no change (test is same as set_NC_string)*/
2018-02-28 06:46:19 +08:00
if(varp->name->nchars < strlen(newname))
{status = NC_ENOTINDEFINE; goto done;}
/* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
/* Remove old name from hashmap; add new... */
NC_hashmapremove(ncp->vars.hashmap,old->cp,strlen(old->cp),NULL);
/* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
2010-06-03 21:24:43 +08:00
status = set_NC_string(varp->name, newname);
if(status != NC_NOERR)
2018-02-28 06:46:19 +08:00
goto done;
2010-06-03 21:24:43 +08:00
intdata = (uintptr_t)varid;
NC_hashmapadd(ncp->vars.hashmap, intdata, varp->name->cp, strlen(varp->name->cp));
2010-06-03 21:24:43 +08:00
set_NC_hdirty(ncp);
if(NC_doHsync(ncp))
{
status = NC_sync(ncp);
if(status != NC_NOERR)
2018-02-28 06:46:19 +08:00
goto done;
2010-06-03 21:24:43 +08:00
}
2018-02-28 06:46:19 +08:00
done:
if(newname) free(newname);
return status;
2010-06-03 21:24:43 +08:00
}
2017-12-21 10:53:30 +08:00
int
NC3_def_var_fill(int ncid,
int varid,
int no_fill,
const void *fill_value)
{
int status;
NC *nc;
NC3_INFO* ncp;
NC_var *varp;
status = NC_check_id(ncid, &nc);
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
if(NC_readonly(ncp))
{
return NC_EPERM;
}
if(!NC_indef(ncp))
{
return NC_ENOTINDEFINE;
}
varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
if(varp == NULL)
return NC_ENOTVAR;
if (no_fill)
varp->no_fill = 1;
else
varp->no_fill = 0;
/* Are we setting a fill value? */
if (fill_value != NULL && !varp->no_fill) {
/* If there's a _FillValue attribute, delete it. */
status = NC3_del_att(ncid, varid, _FillValue);
if (status != NC_NOERR && status != NC_ENOTATT)
return status;
/* Create/overwrite attribute _FillValue */
status = NC3_put_att(ncid, varid, _FillValue, varp->type, 1, fill_value, varp->type);
if (status != NC_NOERR) return status;
}
return NC_NOERR;
}