/** \ingroup variables \internal */ static int NC_get_var(int ncid, int varid, void *value, nc_type memtype) { int ndims; size_t shape[NC_MAX_VAR_DIMS]; int stat = nc_inq_varndims(ncid,varid, &ndims); if(stat) return stat; stat = NC_getshape(ncid,varid, ndims, shape); if(stat) return stat; return NC_get_vara(ncid, varid, NC_coord_zero, shape, value, memtype); }
/** \internal \ingroup variables */ static int NC_put_vara(int ncid, int varid, const size_t *start, const size_t *edges, const void *value, nc_type memtype) { NC* ncp; int stat = NC_check_id(ncid, &ncp); if(stat != NC_NOERR) return stat; if(edges == NULL) { size_t shape[NC_MAX_VAR_DIMS]; int ndims; stat = nc_inq_varndims(ncid, varid, &ndims); if(stat != NC_NOERR) return stat; stat = NC_getshape(ncid, varid, ndims, shape); if(stat != NC_NOERR) return stat; return ncp->dispatch->put_vara(ncid, varid, start, shape, value, memtype); } else return ncp->dispatch->put_vara(ncid, varid, start, edges, value, memtype); }
/** * @internal Check the start, count, and stride parameters for gets * and puts, and handle NULLs. * * @param ncid The file ID. * @param varid The variable ID. * @param start Pointer to start array. If NULL NC_EINVALCOORDS will * be returned for non-scalar variable. * @param count Pointer to pointer to count array. If *count is NULL, * an array of the correct size will be allocated, and filled with * counts that represent the full extent of the variable. In this * case, the memory must be freed by the caller. * @param stride Pointer to pointer to stride array. If NULL, stide is * ignored. If *stride is NULL an array of the correct size will be * allocated, and filled with ones. In this case, the memory must be * freed by the caller. * * @return ::NC_NOERR No error. * @return ::NC_EBADID Bad ncid. * @return ::NC_ENOTVAR Variable not found. * @return ::NC_ENOMEM Out of memory. * @return ::NC_EINVALCOORDS Missing start array. * @author Ed Hartnett */ int NC_check_nulls(int ncid, int varid, const size_t *start, size_t **count, ptrdiff_t **stride) { int varndims; int stat; if ((stat = nc_inq_varndims(ncid, varid, &varndims))) return stat; /* For non-scalar vars, start is required. */ if (!start && varndims) return NC_EINVALCOORDS; /* If count is NULL, assume full extent of var. */ if (!*count) { if (!(*count = malloc(varndims * sizeof(size_t)))) return NC_ENOMEM; if ((stat = NC_getshape(ncid, varid, varndims, *count))) { free(*count); *count = NULL; return stat; } } /* If stride is NULL, do nothing, if *stride is NULL use all 1s. */ if (stride && !*stride) { int i; if (!(*stride = malloc(varndims * sizeof(ptrdiff_t)))) return NC_ENOMEM; for (i = 0; i < varndims; i++) (*stride)[i] = 1; } return NC_NOERR; }
/** \internal \ingroup variables */ int NC_get_vara(int ncid, int varid, const size_t *start, const size_t *edges, void *value, nc_type memtype) { NC* ncp; int stat = NC_check_id(ncid, &ncp); if(stat != NC_NOERR) return stat; #ifdef USE_NETCDF4 if(memtype >= NC_FIRSTUSERTYPEID) memtype = NC_NAT; #endif if(edges == NULL) { size_t shape[NC_MAX_VAR_DIMS]; int ndims; stat = nc_inq_varndims(ncid, varid, &ndims); if(stat != NC_NOERR) return stat; stat = NC_getshape(ncid,varid,ndims,shape); if(stat != NC_NOERR) return stat; stat = ncp->dispatch->get_vara(ncid,varid,start,shape,value,memtype); } else stat = ncp->dispatch->get_vara(ncid,varid,start,edges,value,memtype); return stat; }
/** \internal \ingroup variables */ int NCDEFAULT_get_varm(int ncid, int varid, const size_t *start, const size_t *edges, const ptrdiff_t *stride, const ptrdiff_t *imapp, void *value0, nc_type memtype) { int status = NC_NOERR; nc_type vartype = NC_NAT; int varndims,maxidim; NC* ncp; int memtypelen; char* value = (char*)value0; status = NC_check_id (ncid, &ncp); if(status != NC_NOERR) return status; /* if(NC_indef(ncp)) return NC_EINDEFINE; */ status = nc_inq_vartype(ncid, varid, &vartype); if(status != NC_NOERR) return status; /* Check that this is an atomic type */ if(vartype > NC_MAX_ATOMIC_TYPE) return NC_EMAPTYPE; status = nc_inq_varndims(ncid, varid, &varndims); if(status != NC_NOERR) return status; if(memtype == NC_NAT) { memtype = vartype; } if(memtype == NC_CHAR && vartype != NC_CHAR) return NC_ECHAR; else if(memtype != NC_CHAR && vartype == NC_CHAR) return NC_ECHAR; memtypelen = nctypelen(memtype); maxidim = (int) varndims - 1; if (maxidim < 0) { /* * The variable is a scalar; consequently, * there s only one thing to get and only one place to put it. * (Why was I called?) */ size_t edge1[1] = {1}; return NC_get_vara(ncid, varid, start, edge1, value, memtype); } /* * else * The variable is an array. */ { int idim; size_t *mystart = NULL; size_t *myedges; size_t *iocount; /* count vector */ size_t *stop; /* stop indexes */ size_t *length; /* edge lengths in bytes */ ptrdiff_t *mystride; ptrdiff_t *mymap; size_t varshape[NC_MAX_VAR_DIMS]; int isrecvar; size_t numrecs; /* Compute some dimension related values */ isrecvar = NC_is_recvar(ncid,varid,&numrecs); NC_getshape(ncid,varid,varndims,varshape); /* * Verify stride argument; also see if stride is all ones */ if(stride != NULL) { int stride1 = 1; for (idim = 0; idim <= maxidim; ++idim) { if (stride[idim] == 0 /* cast needed for braindead systems with signed size_t */ || ((unsigned long) stride[idim] >= X_INT_MAX)) { return NC_ESTRIDE; } if(stride[idim] != 1) stride1 = 0; } /* If stride1 is true, and there is no imap then call get_vara directly. */ if(stride1 && imapp == NULL) { return NC_get_vara(ncid, varid, start, edges, value, memtype); } } /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ /* Allocate space for mystart,mystride,mymap etc.all at once */ mystart = (size_t *)calloc((size_t)(varndims * 7), sizeof(ptrdiff_t)); if(mystart == NULL) return NC_ENOMEM; myedges = mystart + varndims; iocount = myedges + varndims; stop = iocount + varndims; length = stop + varndims; mystride = (ptrdiff_t *)(length + varndims); mymap = mystride + varndims; /* * Initialize I/O parameters. */ for (idim = maxidim; idim >= 0; --idim) { mystart[idim] = start != NULL ? start[idim] : 0; if (edges != NULL && edges[idim] == 0) { status = NC_NOERR; /* read/write no data */ goto done; } #ifdef COMPLEX myedges[idim] = edges != NULL ? edges[idim] : idim == 0 && isrecvar ? numrecs - mystart[idim] : varshape[idim] - mystart[idim]; #else if(edges != NULL) myedges[idim] = edges[idim]; else if (idim == 0 && isrecvar) myedges[idim] = numrecs - mystart[idim]; else myedges[idim] = varshape[idim] - mystart[idim]; #endif mystride[idim] = stride != NULL ? stride[idim] : 1; /* Remember: in netCDF-2 imapp is byte oriented, not index oriented * Starting from netCDF-3, imapp is index oriented */ #ifdef COMPLEX mymap[idim] = (imapp != NULL ? imapp[idim] : (idim == maxidim ? 1 : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1])); #else if(imapp != NULL) mymap[idim] = imapp[idim]; else if (idim == maxidim) mymap[idim] = 1; else mymap[idim] = mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; #endif iocount[idim] = 1; length[idim] = ((size_t)mymap[idim]) * myedges[idim]; stop[idim] = (mystart[idim] + myedges[idim] * (size_t)mystride[idim]); } /* * Check start, edges */ for (idim = maxidim; idim >= 0; --idim) { size_t dimlen = idim == 0 && isrecvar ? numrecs : varshape[idim]; if (mystart[idim] >= dimlen) { status = NC_EINVALCOORDS; goto done; } if (mystart[idim] + myedges[idim] > dimlen) { status = NC_EEDGE; goto done; } } /* Lower body */ /* * As an optimization, adjust I/O parameters when the fastest * dimension has unity stride both externally and internally. * In this case, the user could have called a simpler routine * (i.e. ncvar$1() */ if (mystride[maxidim] == 1 && mymap[maxidim] == 1) { iocount[maxidim] = myedges[maxidim]; mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; mymap[maxidim] = (ptrdiff_t) length[maxidim]; } /* * Perform I/O. Exit when done. */ for (;;) { /* TODO: */ int lstatus = NC_get_vara(ncid, varid, mystart, iocount, value, memtype); if (lstatus != NC_NOERR) { if(status == NC_NOERR || lstatus != NC_ERANGE) status = lstatus; } /* * The following code permutes through the variable s * external start-index space and it s internal address * space. At the UPC, this algorithm is commonly * called "odometer code". */ idim = maxidim; carry: value += (((int)mymap[idim]) * memtypelen); mystart[idim] += (size_t)mystride[idim]; if (mystart[idim] == stop[idim]) { size_t l = (length[idim] * (size_t)memtypelen); value -= l; mystart[idim] = start[idim]; if (--idim < 0) break; /* normal return */ goto carry; } } /* I/O loop */ done: free(mystart); } /* variable is array */ return status; }
/** \internal \ingroup variables Most dispatch tables will use the default procedures */ int NCDEFAULT_get_vars(int ncid, int varid, const size_t * start, const size_t * edges, const ptrdiff_t * stride, void *value0, nc_type memtype) { #ifdef VARS_USES_VARM NC* ncp; int stat = NC_check_id(ncid, &ncp); if(stat != NC_NOERR) return stat; return ncp->dispatch->get_varm(ncid,varid,start,edges,stride,NULL,value0,memtype); #else /* Rebuilt get_vars code to simplify and avoid use of get_varm */ int status = NC_NOERR; int i,simplestride,isrecvar; int rank; struct GETodometer odom; nc_type vartype = NC_NAT; NC* ncp; int memtypelen; size_t vartypelen; char* value = (char*)value0; size_t numrecs; size_t varshape[NC_MAX_VAR_DIMS]; size_t mystart[NC_MAX_VAR_DIMS]; size_t myedges[NC_MAX_VAR_DIMS]; ptrdiff_t mystride[NC_MAX_VAR_DIMS]; char *memptr = NULL; status = NC_check_id (ncid, &ncp); if(status != NC_NOERR) return status; status = nc_inq_vartype(ncid, varid, &vartype); if(status != NC_NOERR) return status; if(memtype == NC_NAT) memtype = vartype; /* compute the variable type size */ status = nc_inq_type(ncid,vartype,NULL,&vartypelen); if(status != NC_NOERR) return status; if(memtype > NC_MAX_ATOMIC_TYPE) memtypelen = (int)vartypelen; else memtypelen = nctypelen(memtype); /* Check gross internal/external type compatibility */ if(vartype != memtype) { /* If !atomic, the two types must be the same */ if(vartype > NC_MAX_ATOMIC_TYPE || memtype > NC_MAX_ATOMIC_TYPE) return NC_EBADTYPE; /* ok, the types differ but both are atomic */ if(memtype == NC_CHAR || vartype == NC_CHAR) return NC_ECHAR; } /* Get the variable rank */ status = nc_inq_varndims(ncid, varid, &rank); if(status != NC_NOERR) return status; /* Get variable dimension sizes */ isrecvar = NC_is_recvar(ncid,varid,&numrecs); NC_getshape(ncid,varid,rank,varshape); /* Optimize out using various checks */ if (rank == 0) { /* * The variable is a scalar; consequently, * there s only one thing to get and only one place to put it. * (Why was I called?) */ size_t edge1[1] = {1}; return NC_get_vara(ncid, varid, start, edge1, value, memtype); } /* Do various checks and fixups on start/edges/stride */ simplestride = 1; /* assume so */ for(i=0;i<rank;i++) { size_t dimlen; mystart[i] = (start == NULL ? 0 : start[i]); if(edges == NULL) { if(i == 0 && isrecvar) myedges[i] = numrecs - start[i]; else myedges[i] = varshape[i] - mystart[i]; } else myedges[i] = edges[i]; if(myedges[i] == 0) return NC_NOERR; /* cannot read anything */ mystride[i] = (stride == NULL ? 1 : stride[i]); if(mystride[i] <= 0 /* cast needed for braindead systems with signed size_t */ || ((unsigned long) mystride[i] >= X_INT_MAX)) return NC_ESTRIDE; if(mystride[i] != 1) simplestride = 0; /* illegal value checks */ dimlen = (i == 0 && isrecvar ? numrecs : varshape[i]); /* mystart is unsigned, never < 0 */ if(mystart[i] >= dimlen) return NC_EINVALCOORDS; /* myedges is unsigned, never < 0 */ if(mystart[i] + myedges[i] > dimlen) return NC_EEDGE; } if(simplestride) { return NC_get_vara(ncid, varid, mystart, myedges, value, memtype); } /* memptr indicates where to store the next value */ memptr = value; odom_init(&odom,rank,mystart,myedges,mystride); /* walk the odometer to extract values */ while(odom_more(&odom)) { int localstatus = NC_NOERR; /* Read a single value */ localstatus = NC_get_vara(ncid,varid,odom.index,nc_sizevector1,memptr,memtype); /* So it turns out that when get_varm is used, all errors are delayed and ERANGE will be overwritten by more serious errors. */ if(localstatus != NC_NOERR) { if(status == NC_NOERR || localstatus != NC_ERANGE) status = localstatus; } memptr += memtypelen; odom_next(&odom); } return status; #endif }