netcdf-c/libsrc/dim.c
Dennis Heimbigner 5ca78309cc The effect of this change is to make the struct NC structure
contain as little file-type specific info as possible.  It
modifies especially libsrc so that all of the netcdf-3 data
that used to be in struct NC is now kept in a separate chunk
of data pointed to by the struct NC. This makes all of
current protocols consistent: netcdf-3, netcdf-4, and dap.
2012-09-06 19:44:03 +00:00

506 lines
9.0 KiB
C

/*
* Copyright 1996, University Corporation for Atmospheric Research
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*/
/* $Id: dim.c,v 1.83 2010/05/25 17:54:15 dmh Exp $ */
#include "nc3internal.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "ncx.h"
#include "fbits.h"
#include "utf8proc.h"
/*
* Free dim
* Formerly
NC_free_dim(dim)
*/
void
free_NC_dim(NC_dim *dimp)
{
if(dimp == NULL)
return;
free_NC_string(dimp->name);
free(dimp);
}
NC_dim *
new_x_NC_dim(NC_string *name)
{
NC_dim *dimp;
dimp = (NC_dim *) malloc(sizeof(NC_dim));
if(dimp == NULL)
return NULL;
dimp->name = name;
dimp->hash = hash_fast(name->cp, strlen(name->cp));
dimp->size = 0;
return(dimp);
}
/*
* Formerly
NC_new_dim(const char *uname, long size)
*/
static NC_dim *
new_NC_dim(const char *uname, size_t size)
{
NC_string *strp;
NC_dim *dimp;
char *name = (char *)utf8proc_NFC((const unsigned char *)uname);
if(name == NULL)
return NULL;
strp = new_NC_string(strlen(name), name);
free(name);
if(strp == NULL)
return NULL;
dimp = new_x_NC_dim(strp);
if(dimp == NULL)
{
free_NC_string(strp);
return NULL;
}
dimp->size = size;
return(dimp);
}
static NC_dim *
dup_NC_dim(const NC_dim *dimp)
{
return new_NC_dim(dimp->name->cp, dimp->size);
}
/*
* Step thru NC_DIMENSION array, seeking the UNLIMITED dimension.
* Return dimid or -1 on not found.
* *dimpp is set to the appropriate NC_dim.
* The loop structure is odd. In order to parallelize,
* we moved a clearer 'break' inside the loop body to the loop test.
*/
int
find_NC_Udim(const NC_dimarray *ncap, NC_dim **dimpp)
{
assert(ncap != NULL);
if(ncap->nelems == 0)
return -1;
{
int dimid = 0;
NC_dim **loc = ncap->value;
for(; (size_t) dimid < ncap->nelems
&& (*loc)->size != NC_UNLIMITED; dimid++, loc++)
{
/*EMPTY*/
}
if(dimid >= ncap->nelems)
return(-1); /* not found */
/* else, normal return */
if(dimpp != NULL)
*dimpp = *loc;
return dimid;
}
}
/*
* Step thru NC_DIMENSION array, seeking match on uname.
* Return dimid or -1 on not found.
* *dimpp is set to the appropriate NC_dim.
* The loop structure is odd. In order to parallelize,
* we moved a clearer 'break' inside the loop body to the loop test.
*/
static int
NC_finddim(const NC_dimarray *ncap, const char *uname, NC_dim **dimpp)
{
int dimid;
uint32_t shash;
NC_dim ** loc;
char *name;
assert(ncap != NULL);
if(ncap->nelems == 0)
return -1;
{
dimid = 0;
loc = (NC_dim **) ncap->value;
/* normalized version of uname */
name = (char *)utf8proc_NFC((const unsigned char *)uname);
if(name == NULL)
return NC_ENOMEM;
shash = hash_fast(name, strlen(name));
for(; (size_t) dimid < ncap->nelems
&& ((*loc)->hash != shash
|| strncmp((*loc)->name->cp, name, strlen(name)) != 0);
dimid++, loc++)
{
/*EMPTY*/
}
free(name);
if(dimid >= ncap->nelems)
return(-1); /* not found */
/* else, normal return */
if(dimpp != NULL)
*dimpp = *loc;
return(dimid);
}
}
/* dimarray */
/*
* Free the stuff "in" (referred to by) an NC_dimarray.
* Leaves the array itself allocated.
*/
void
free_NC_dimarrayV0(NC_dimarray *ncap)
{
assert(ncap != NULL);
if(ncap->nelems == 0)
return;
assert(ncap->value != NULL);
{
NC_dim **dpp = ncap->value;
NC_dim *const *const end = &dpp[ncap->nelems];
for( /*NADA*/; dpp < end; dpp++)
{
free_NC_dim(*dpp);
*dpp = NULL;
}
}
ncap->nelems = 0;
}
/*
* Free NC_dimarray values.
* formerly
NC_free_array()
*/
void
free_NC_dimarrayV(NC_dimarray *ncap)
{
assert(ncap != NULL);
if(ncap->nalloc == 0)
return;
assert(ncap->value != NULL);
free_NC_dimarrayV0(ncap);
free(ncap->value);
ncap->value = NULL;
ncap->nalloc = 0;
}
int
dup_NC_dimarrayV(NC_dimarray *ncap, const NC_dimarray *ref)
{
int status = NC_NOERR;
assert(ref != NULL);
assert(ncap != NULL);
if(ref->nelems != 0)
{
const size_t sz = ref->nelems * sizeof(NC_dim *);
ncap->value = (NC_dim **) malloc(sz);
if(ncap->value == NULL)
return NC_ENOMEM;
(void) memset(ncap->value, 0, sz);
ncap->nalloc = ref->nelems;
}
ncap->nelems = 0;
{
NC_dim **dpp = ncap->value;
const NC_dim **drpp = (const NC_dim **)ref->value;
NC_dim *const *const end = &dpp[ref->nelems];
for( /*NADA*/; dpp < end; drpp++, dpp++, ncap->nelems++)
{
*dpp = dup_NC_dim(*drpp);
if(*dpp == NULL)
{
status = NC_ENOMEM;
break;
}
}
}
if(status != NC_NOERR)
{
free_NC_dimarrayV(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_dimarray(NC_dimarray *ncap, NC_dim *newelemp)
{
NC_dim **vp;
assert(ncap != NULL);
if(ncap->nalloc == 0)
{
assert(ncap->nelems == 0);
vp = (NC_dim **) malloc(NC_ARRAY_GROWBY * sizeof(NC_dim *));
if(vp == NULL)
return NC_ENOMEM;
ncap->value = vp;
ncap->nalloc = NC_ARRAY_GROWBY;
}
else if(ncap->nelems +1 > ncap->nalloc)
{
vp = (NC_dim **) realloc(ncap->value,
(ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_dim *));
if(vp == NULL)
return NC_ENOMEM;
ncap->value = vp;
ncap->nalloc += NC_ARRAY_GROWBY;
}
if(newelemp != NULL)
{
ncap->value[ncap->nelems] = newelemp;
ncap->nelems++;
}
return NC_NOERR;
}
NC_dim *
elem_NC_dimarray(const NC_dimarray *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];
}
/* Public */
int
NC3_def_dim(int ncid, const char *name, size_t size, int *dimidp)
{
int status;
NC *nc;
NC3_INFO* ncp;
int dimid;
NC_dim *dimp;
status = NC_check_id(ncid, &nc);
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
if(!NC_indef(ncp))
return NC_ENOTINDEFINE;
status = NC_check_name(name);
if(status != NC_NOERR)
return status;
if ((ncp->flags & NC_64BIT_OFFSET) && sizeof(off_t) > 4) {
/* CDF2 format and LFS */
if(size > X_UINT_MAX - 3) /* "- 3" handles rounded-up size */
return NC_EDIMSIZE;
} else {
/* CDF1 format */
if(size > X_INT_MAX - 3)
return NC_EDIMSIZE;
}
if(size == NC_UNLIMITED)
{
dimid = find_NC_Udim(&ncp->dims, &dimp);
if(dimid != -1)
{
assert(dimid != -1);
return NC_EUNLIMIT;
}
}
if(ncp->dims.nelems >= NC_MAX_DIMS)
return NC_EMAXDIMS;
dimid = NC_finddim(&ncp->dims, name, &dimp);
if(dimid != -1)
return NC_ENAMEINUSE;
dimp = new_NC_dim(name, size);
if(dimp == NULL)
return NC_ENOMEM;
status = incr_NC_dimarray(&ncp->dims, dimp);
if(status != NC_NOERR)
{
free_NC_dim(dimp);
return status;
}
if(dimidp != NULL)
*dimidp = (int)ncp->dims.nelems -1;
return NC_NOERR;
}
int
NC3_inq_dimid(int ncid, const char *name, int *dimid_ptr)
{
int status;
NC *nc;
NC3_INFO* ncp;
int dimid;
status = NC_check_id(ncid, &nc);
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
dimid = NC_finddim(&ncp->dims, name, NULL);
if(dimid == -1)
return NC_EBADDIM;
if (dimid_ptr)
*dimid_ptr = dimid;
return NC_NOERR;
}
int
NC3_inq_dim(int ncid, int dimid, char *name, size_t *sizep)
{
int status;
NC *nc;
NC3_INFO* ncp;
NC_dim *dimp;
status = NC_check_id(ncid, &nc);
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
if(dimp == NULL)
return NC_EBADDIM;
if(name != NULL)
{
(void)strncpy(name, dimp->name->cp,
dimp->name->nchars);
name[dimp->name->nchars] = 0;
}
if(sizep != NULL)
{
if(dimp->size == NC_UNLIMITED)
*sizep = NC_get_numrecs(ncp);
else
*sizep = dimp->size;
}
return NC_NOERR;
}
int
NC3_rename_dim( int ncid, int dimid, const char *unewname)
{
int status;
NC *nc;
NC3_INFO* ncp;
int existid;
NC_dim *dimp;
char *newname; /* normalized */
status = NC_check_id(ncid, &nc);
if(status != NC_NOERR)
return status;
ncp = NC3_DATA(nc);
if(NC_readonly(ncp))
return NC_EPERM;
status = NC_check_name(unewname);
if(status != NC_NOERR)
return status;
existid = NC_finddim(&ncp->dims, unewname, &dimp);
if(existid != -1)
return NC_ENAMEINUSE;
dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
if(dimp == NULL)
return NC_EBADDIM;
newname = (char *)utf8proc_NFC((const unsigned char *)unewname);
if(newname == NULL)
return NC_ENOMEM;
if(NC_indef(ncp))
{
NC_string *old = dimp->name;
NC_string *newStr = new_NC_string(strlen(newname), newname);
free(newname);
if(newStr == NULL)
return NC_ENOMEM;
dimp->name = newStr;
dimp->hash = hash_fast(newStr->cp, strlen(newStr->cp));
free_NC_string(old);
return NC_NOERR;
}
/* else, not in define mode */
status = set_NC_string(dimp->name, newname);
dimp->hash = hash_fast(newname, strlen(newname));
free(newname);
if(status != NC_NOERR)
return status;
set_NC_hdirty(ncp);
if(NC_doHsync(ncp))
{
status = NC_sync(ncp);
if(status != NC_NOERR)
return status;
}
return NC_NOERR;
}