mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-21 08:39:46 +08:00
0b040e8cd7
* main: (39 commits) Define USE_SZIP variable for nc-config.cmake.in matching cmake variables in autotools configuration moving the version into the project command in cmake Updated doxygen files for older, less-forgiving versions of doxygen (1.9.1, at least) Clean up doxygen warnings that were being treated as failures. Correcting a weird doxygen issue that has appeared. cmake: Fix Szip link using correct cmake var cmake: Improve FindSzip logic to provide a Szip_LIBRARY var Changed link to netCDF-Fortran documentation. Replaced ancient K&R function declarations to be C23 compatible Rebased PR by hand against main. count argument in H5Sselect_hyperslab Add H5FD_http_finalize function and call on hdf5 finalize Catching up on PRs, this is 2431 on the current 'main' Fix cmake syntax typo. Typo fix in support of gh2824.wif Fix typo in nc-config.cmake.in Removed a use of sprintf that required changing a function signature Replaced some sprintf with snprintf with aid of new variable containing size Replaced trivial uses of sprintf with snprintf ...
479 lines
11 KiB
C
479 lines
11 KiB
C
/*
|
|
* Copyright 2018, University Corporation for Atmospheric Research
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
*/
|
|
|
|
#include "ut_includes.h"
|
|
#include <stddef.h>
|
|
|
|
#undef DEBUG
|
|
|
|
#define OPEN "[{("
|
|
#define CLOSE "]})"
|
|
|
|
#define LPAREN '('
|
|
#define RPAREN ')'
|
|
#define BLANK ' '
|
|
|
|
NCbytes* buf = NULL;
|
|
|
|
static Dimdef* finddim(const char* name, NClist* defs);
|
|
|
|
#if 0
|
|
static void
|
|
ranktest(int rank, char c, int count)
|
|
{
|
|
if(rank != count) {
|
|
fprintf(stderr,"Option '%c': rank mismatch: rank=%d count=%d\n",
|
|
c,rank,count);
|
|
exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int
|
|
parseslices(const char* s0, int* nslicesp, NCZSlice* slices)
|
|
{
|
|
int count,nchars,nslices,i;
|
|
const char* s = NULL;
|
|
unsigned long start,stop,stride;
|
|
|
|
/* First, compute number of slices */
|
|
for(s=s0,nslices=0;*s;s++) {
|
|
if(*s == '[') nslices++;
|
|
}
|
|
|
|
if(nslices > NC_MAX_VAR_DIMS) return THROW(NC_EINVAL); /* too many */
|
|
if(nslicesp) *nslicesp = nslices;
|
|
|
|
/* Extract the slices */
|
|
for(i=0,s=s0;*s;s+=nchars,i++) {
|
|
NCZSlice* sl = &slices[i];
|
|
/* Try 3-element slice first */
|
|
stride = 1; /* default */
|
|
nchars = -1;
|
|
count = sscanf(s,"[%lu:%lu]%n",&start,&stop,&nchars);
|
|
if(nchars == -1) {
|
|
nchars = -1;
|
|
count = sscanf(s,"[%lu:%lu:%lu]%n",&start,&stop,&stride,&nchars);
|
|
if(count != 3) return THROW(NC_EINVAL);
|
|
}
|
|
sl->start = start;
|
|
sl->stop = stop;
|
|
sl->stride = stride;
|
|
}
|
|
return NC_NOERR;
|
|
}
|
|
|
|
int
|
|
parsedimdef(const char* s0, Dimdef** defp)
|
|
{
|
|
int nchars;
|
|
const char* s = NULL;
|
|
Dimdef* def = NULL;
|
|
unsigned l;
|
|
const char* p;
|
|
ptrdiff_t count;
|
|
|
|
if((def = calloc(1,sizeof(struct Dimdef)))==NULL)
|
|
return THROW(NC_ENOMEM);
|
|
|
|
/* Extract */
|
|
s = s0;
|
|
if((p = strchr(s,'=')) == NULL) abort();
|
|
if((count = (p - s)) == 0) return THROW(NC_EINVAL);
|
|
def->name = malloc((size_t)count+1);
|
|
memcpy(def->name,s,(size_t)count);
|
|
def->name[count] = '\0';
|
|
s = p+1;
|
|
sscanf(s,"%u%n",&l,&nchars);
|
|
if(nchars == -1) return NC_EINVAL;
|
|
def->size = (size_t)l;
|
|
if(def->size == 0) def->isunlimited = 1;
|
|
s += nchars;
|
|
if(*s != '\0') return NC_EINVAL;
|
|
if(defp) *defp = def;
|
|
return NC_NOERR;
|
|
}
|
|
|
|
int
|
|
parsevardef(const char* s0, NClist* dimdefs, Vardef** varp)
|
|
{
|
|
int count;
|
|
const char* s = NULL;
|
|
Vardef* vd = NULL;
|
|
const char* p;
|
|
ptrdiff_t len;
|
|
char name[NC_MAX_NAME];
|
|
|
|
if((vd = calloc(1,sizeof(Vardef)))==NULL)
|
|
return THROW(NC_ENOMEM);
|
|
|
|
s=s0;
|
|
|
|
/* Scan for the end of type name */
|
|
p = strchr(s,BLANK);
|
|
if(p == NULL) return THROW(NC_EINVAL);
|
|
len = (p - s);
|
|
if(len == 0) return THROW(NC_EINVAL);
|
|
memcpy(name,s,(size_t)len);
|
|
name[len] = '\0';
|
|
vd->typeid = ut_typeforname(name);
|
|
vd->typesize = ut_typesize(vd->typeid);
|
|
while(*p == BLANK) p++;
|
|
s = p;
|
|
|
|
/* Scan for the end of var name */
|
|
p = strchr(s,LPAREN);
|
|
if(p == NULL) return THROW(NC_EINVAL);
|
|
len = (p - s);
|
|
if(len == 0) return THROW(NC_EINVAL);
|
|
memcpy(name,s,(size_t)len);
|
|
name[len] = '\0';
|
|
vd->name = strdup(name);
|
|
/* parse a vector of dimnames and chunksizes and convert */
|
|
s = p;
|
|
if(*s == LPAREN) {
|
|
char** names = NULL;
|
|
char* p;
|
|
s++;
|
|
count = parsestringvector(s,RPAREN,&names);
|
|
if(count >= NC_MAX_VAR_DIMS) return THROW(NC_EINVAL);
|
|
vd->rank = count;
|
|
if(vd->rank > 0) {
|
|
int j;
|
|
for(j=0;j<vd->rank;j++) {
|
|
Dimdef* dimref = NULL;
|
|
/* Split on / to get chunksize */
|
|
p = strchr(names[j],'/');
|
|
if(p) *p++ = '\0';
|
|
if((dimref = finddim(names[j],dimdefs)) == NULL)
|
|
return THROW(NC_EINVAL);
|
|
vd->dimrefs[j] = dimref;
|
|
vd->dimsizes[j] = dimref->size;
|
|
if(p == NULL)
|
|
vd->chunksizes[j] = dimref->size;
|
|
else {
|
|
unsigned long l;
|
|
sscanf(p,"%lu",&l);
|
|
vd->chunksizes[j] = (size_t)l;
|
|
}
|
|
}
|
|
/* Skip past the trailing rparen */
|
|
if((p = strchr(s,RPAREN)) == NULL) abort();
|
|
p++;
|
|
}
|
|
freestringvec(names);
|
|
}
|
|
if(varp) *varp = vd;
|
|
return NC_NOERR;
|
|
}
|
|
|
|
int
|
|
parsestringvector(const char* s0, int stopchar, char*** namesp)
|
|
{
|
|
int nelems,i;
|
|
const char* s;
|
|
char** names = NULL;
|
|
|
|
/* First, compute number of elements */
|
|
for(s=s0,nelems=1;*s;s++) {if(*s == ',') nelems++; if(*s == stopchar) break;}
|
|
if(nelems == 0) return THROW(NC_EINVAL);
|
|
names = calloc((size_t)nelems+1,sizeof(char*));
|
|
for(s=s0,i=0;i<nelems;i++) {
|
|
ptrdiff_t len;
|
|
const char* p = strchr(s,',');
|
|
if(p == NULL) p = strchr(s,stopchar);
|
|
if(p == NULL) p = s + strlen(s);
|
|
if(names[i] == NULL) {
|
|
char* q;
|
|
len = (p - s);
|
|
q = malloc(1+(size_t)len);
|
|
memcpy(q,s,(size_t)len);
|
|
q[len] = '\0';
|
|
names[i] = q;
|
|
}
|
|
if(*p == '\0' || *p == stopchar) s = p; else s = p+1;
|
|
}
|
|
names[nelems] = NULL;
|
|
if(namesp) *namesp = names;
|
|
return nelems;
|
|
}
|
|
|
|
void
|
|
freedimdefs(NClist* defs)
|
|
{
|
|
size_t i;
|
|
for(i=0;i<nclistlength(defs);i++) {
|
|
Dimdef* dd = nclistget(defs,i);
|
|
nullfree(dd->name);
|
|
nullfree(dd);
|
|
}
|
|
}
|
|
|
|
void
|
|
freevardefs(NClist* defs)
|
|
{
|
|
size_t i;
|
|
for(i=0;i<nclistlength(defs);i++) {
|
|
Vardef* vd = nclistget(defs,i);
|
|
nullfree(vd->name);
|
|
nullfree(vd);
|
|
}
|
|
}
|
|
|
|
void
|
|
freeranges(NCZChunkRange* ranges)
|
|
{
|
|
}
|
|
|
|
void
|
|
freeslices(NCZSlice* slices)
|
|
{
|
|
}
|
|
|
|
void
|
|
freestringvec(char** vec)
|
|
{
|
|
if(vec != NULL) {
|
|
char** p;
|
|
for(p=vec;*p;p++) free(*p);
|
|
}
|
|
nullfree(vec);
|
|
}
|
|
|
|
void
|
|
freeprojvector(int rank, NCZProjection** vec)
|
|
{
|
|
if(vec != NULL) {
|
|
int r;
|
|
for(r=0;r<rank;r++) free(vec[r]);
|
|
}
|
|
nullfree(vec);
|
|
}
|
|
|
|
/**************************************************/
|
|
|
|
#if 0
|
|
char*
|
|
printvec(int len, size64_t* vec)
|
|
{
|
|
char* result = NULL;
|
|
int i;
|
|
char value[128];
|
|
NCbytes* buf = ncbytesnew();
|
|
|
|
ncbytescat(buf,"(");
|
|
for(i=0;i<len;i++) {
|
|
if(i > 0) ncbytescat(buf,",");
|
|
snprintf(value,sizeof(value),"%lu",(unsigned long)vec[i]);
|
|
ncbytescat(buf,value);
|
|
}
|
|
ncbytescat(buf,")");
|
|
result = ncbytesextract(buf);
|
|
ncbytesfree(buf);
|
|
return result;
|
|
}
|
|
#endif /*0*/
|
|
|
|
/**************************************************/
|
|
size_t
|
|
ut_typesize(nc_type t)
|
|
{
|
|
switch (t) {
|
|
case NC_BYTE: case NC_UBYTE: return 1;
|
|
case NC_SHORT: case NC_USHORT: return 2;
|
|
case NC_INT: case NC_UINT: return 4;
|
|
case NC_INT64: case NC_UINT64: return 8;
|
|
case NC_FLOAT: return 4;
|
|
case NC_DOUBLE: return 8;
|
|
default: usage(THROW(NC_EINVAL));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
nc_type
|
|
ut_typeforname(const char* tname)
|
|
{
|
|
if(strcasecmp("byte",tname)==0) return NC_BYTE;
|
|
if(strcasecmp("ubyte",tname)==0) return NC_UBYTE;
|
|
if(strcasecmp("short",tname)==0) return NC_SHORT;
|
|
if(strcasecmp("ushort",tname)==0) return NC_USHORT;
|
|
if(strcasecmp("int",tname)==0) return NC_INT;
|
|
if(strcasecmp("uint",tname)==0) return NC_UINT;
|
|
if(strcasecmp("int64",tname)==0) return NC_INT64;
|
|
if(strcasecmp("uint64",tname)==0) return NC_UINT64;
|
|
if(strcasecmp("float",tname)==0) return NC_FLOAT;
|
|
if(strcasecmp("double",tname)==0) return NC_DOUBLE;
|
|
usage(THROW(NC_EINVAL));
|
|
return NC_NAT;
|
|
}
|
|
|
|
static Dimdef*
|
|
finddim(const char* name, NClist* defs)
|
|
{
|
|
size_t i;
|
|
for(i=0;i<nclistlength(defs);i++) {
|
|
Dimdef* dd = nclistget(defs,i);
|
|
if(strcmp(dd->name,name) == 0)
|
|
return dd;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
NCZM_IMPL
|
|
kind2impl(const char* kind)
|
|
{
|
|
if(strcasecmp("s3",kind)==0) return NCZM_S3;
|
|
else if(strcasecmp("file",kind)==0) return NCZM_FILE;
|
|
else if(strcasecmp("zip",kind)==0) return NCZM_ZIP;
|
|
else return NCZM_UNDEF;
|
|
}
|
|
|
|
const char*
|
|
impl2kind(NCZM_IMPL impl)
|
|
{
|
|
switch (impl) {
|
|
case NCZM_S3: return "s3";
|
|
case NCZM_FILE: return "file";
|
|
case NCZM_ZIP: return "zip";
|
|
case NCZM_UNDEF: break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Goal: Given a set of per-dimension indices,
|
|
compute the corresponding linear position.
|
|
*/
|
|
size64_t
|
|
computelinearoffset(int R, const size64_t* indices, const size64_t* max, size64_t* productp)
|
|
{
|
|
size64_t offset, product;
|
|
int i;
|
|
|
|
offset = 0; product = 1;
|
|
for(i=0;i<R;i++) {
|
|
offset *= max[i];
|
|
offset += indices[i];
|
|
product *= max[i];
|
|
}
|
|
if(productp) *productp = product;
|
|
return offset;
|
|
}
|
|
|
|
void
|
|
slices2vector(int rank, NCZSlice* slices, size64_t** startp, size64_t** stopp, size64_t** stridep, size64_t** maxp)
|
|
{
|
|
static size64_t start[NC_MAX_VAR_DIMS];
|
|
static size64_t stop[NC_MAX_VAR_DIMS];
|
|
static size64_t stride[NC_MAX_VAR_DIMS];
|
|
static size64_t max[NC_MAX_VAR_DIMS];
|
|
int i;
|
|
for(i=0;i<rank;i++) {
|
|
start[i] = slices[i].start;
|
|
stop[i] = slices[i].stop;
|
|
stride[i] = slices[i].stride;
|
|
max[i] = slices[i].len;
|
|
}
|
|
if(startp) *startp = start;
|
|
if(stopp) *stopp = stop;
|
|
if(stridep) *stridep = stride;
|
|
if(maxp) *maxp = max;
|
|
}
|
|
|
|
void
|
|
printoptions(struct UTOptions* opts)
|
|
{
|
|
char** p;
|
|
size_t i;
|
|
printf("Options:");
|
|
#if 0
|
|
printf(" debug=%d",opts->debug);
|
|
printf(" file=|%s|",opts->file);
|
|
printf(" output=|%s|",opts->output);
|
|
#endif
|
|
if(opts->kind)
|
|
printf(" kind=%s",opts->kind);
|
|
if(opts->cmds) {
|
|
printf(" cmds=");
|
|
for(i=0,p=opts->cmds;*p;p++,i++)
|
|
printf("%s%s",(i==0?"(":","),*p);
|
|
printf(")");
|
|
}
|
|
|
|
for(i=0;i<nclistlength(opts->dimdefs);i++) {
|
|
struct Dimdef* dd = (struct Dimdef*)nclistget(opts->dimdefs,i);
|
|
printf(" -d%s=%llu",dd->name,dd->size);
|
|
}
|
|
|
|
for(i=0;i<nclistlength(opts->vardefs);i++) {
|
|
int j;
|
|
struct Vardef* vd = (struct Vardef*)nclistget(opts->vardefs,i);
|
|
printf(" -v '%d %s[",vd->typeid,vd->name);
|
|
for(j=0;j<vd->rank;j++) {
|
|
Dimdef* vdd = vd->dimrefs[j];
|
|
if(j > 0) printf(",");
|
|
printf("%s/%llu",vdd->name,vd->chunksizes[j]);
|
|
}
|
|
printf("]'");
|
|
}
|
|
|
|
printf(" -s ");
|
|
for(i=0;i<(size_t)opts->nslices;i++) {
|
|
NCZSlice* sl = &opts->slices[i];
|
|
printf("%s",nczprint_slicex(*sl,1));
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
int
|
|
hasdriveletter(const char* f)
|
|
{
|
|
if(f == NULL || *f == '\0' || strlen(f) < 3) return 0;
|
|
if(f[1] != ':') return 0;
|
|
if(f[2] != '/' && f[2] != '\\') return 0;
|
|
if((f[0] < 'z' && f[0] >= 'a') || (f[0] < 'Z' && f[0] >= 'A'))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/* bubble sort a list of strings */
|
|
void
|
|
ut_sortlist(NClist* l)
|
|
{
|
|
int switched;
|
|
size_t i;
|
|
|
|
if(nclistlength(l) <= 1) return;
|
|
do {
|
|
switched = 0;
|
|
for(i=0;i<nclistlength(l)-1;i++) {
|
|
char* ith = nclistget(l,i);
|
|
char* ith1 = nclistget(l,i+1);
|
|
if(strcmp(ith,ith1) > 0) {
|
|
nclistset(l,i,ith1);
|
|
nclistset(l,i+1,ith);
|
|
switched = 1;
|
|
}
|
|
}
|
|
} while(switched);
|
|
#ifdef DEBUG
|
|
for(i=0;i<nclistlength(l);i++)
|
|
fprintf(stderr,"sorted: [%d] %s\n",i,(const char*)nclistget(l,i));
|
|
#endif
|
|
}
|
|
|
|
/* Fill in parts of common */
|
|
void
|
|
fillcommon(struct Common* common, Vardef* var)
|
|
{
|
|
memset(common,0,sizeof(struct Common));
|
|
common->typesize = sizeof(int);
|
|
if(var != NULL) {
|
|
common->rank = var->rank;
|
|
memcpy(common->dimlens,var->dimsizes,sizeof(size64_t)*(size_t)common->rank);
|
|
memcpy(common->chunklens,var->chunksizes,sizeof(size64_t)*(size_t)common->rank);
|
|
memcpy(common->memshape,common->dimlens,sizeof(size64_t)*(size_t)common->rank); /* fake it */
|
|
}
|
|
}
|