/* * Parse chunkspec string and convert into chunkspec_t structure. * ncid: location ID of open netCDF file or group in an open file * spec: string of form * dim1/n1,dim2/n2,...,dimk/nk * * specifying chunk size (ni) to be used for dimension named * dimi. Dimension names may be absolute, * e.g. "/grp_a/grp_a1/dim". The "ni" part of the spec may be * omitted, in which case it is assumed to be the entire * dimension size. That is also the default for dimensions * not mentioned in the string. * * Returns NC_NOERR if no error, NC_EINVAL if spec has consecutive * unescaped commas or no chunksize specified for dimension. */ int chunkspec_parse(int ncid, const char *spec) { const char *cp; /* character cursor */ const char *pp = spec; /* previous char cursor for detecting escapes */ const char *np; /* beginning of current dimension name */ size_t ndims = 0; int idim; int ret; chunkspecs.ndims = 0; if (!spec || *spec == '\0') return NC_NOERR; /* Count unescaped commas, handle consecutive unescaped commas as error */ for(cp = spec; *cp; cp++) { int comma_seen = 0; if(*cp == ',' && *pp != '\\') { if(comma_seen) { /* consecutive commas detected */ return(NC_EINVAL); } comma_seen = 1; ndims++; } else { comma_seen = 0; } pp = cp; } ndims++; chunkspecs.ndims = ndims; chunkspecs.dimids = (int *) emalloc(ndims * sizeof(int)); chunkspecs.chunksizes = (size_t *) emalloc(ndims * sizeof(size_t)); /* Look up dimension ids and assign chunksizes */ cp = spec; pp = spec; np = spec; idim = 0; for(cp = spec; ; cp++) { if(*cp == '\0' || (*cp == ',' && *pp != '\\')) { /* found end of "dim/nn" part */ char* dimname = 0; char *dp; int dimid; size_t chunksize; for(; pp > np && *pp != '/'; pp--) { /* look backwards for "/" */ continue; } if(*pp != '/') { /* no '/' found, no chunksize specified for dimension */ return(NC_EINVAL); } /* extract dimension name */ dimname = (char *) emalloc(pp - np + 1); dp = dimname; while(np < pp) { *dp++ = *np++; } *dp = '\0'; /* look up dimension id from dimension pathname */ ret = nc_inq_dimid2(ncid, dimname, &dimid); if(ret != NC_NOERR) break; chunkspecs.dimids[idim] = dimid; /* parse and assign corresponding chunksize */ pp++; /* now points to first digit of chunksize, ',', or '\0' */ if(*pp == ',' || *pp == '\0') { /* no size specified, use dim len */ size_t dimlen; ret = nc_inq_dimlen(ncid, dimid, &dimlen); if(ret != NC_NOERR) return(ret); chunksize = dimlen; } else { /* convert nnn string to long integer */ char *ep; long val = strtol(pp, &ep, 0); if(ep == pp || errno == ERANGE || val < 1) /* allow chunksize bigger than dimlen */ return (NC_EINVAL); chunksize = val; } chunkspecs.chunksizes[idim] = chunksize; idim++; if(dimname) free(dimname); if(*cp == '\0') break; /* set np to point to first char after comma */ np = cp + 1; } pp = cp; }; return NC_NOERR; }
/* * Parse chunkspec string and convert into dimchunkspec structure. * ncid: location ID of open netCDF file or group in an open file * spec: string of form * dim1/n1,dim2/n2,...,dimk/nk * specifying chunk size (ni) to be used for dimension named * dimi. Dimension names may be absolute, * e.g. "/grp_a/grp_a1/dim". The "ni" part of the spec may be * omitted, in which case it is assumed to be the entire * dimension size. That is also the default for dimensions * not mentioned in the string. However, for unlimited dimensions, * the default is a default size: 4 megabytes or the * existing unlimited size if smaller. * If the chunkspec string is "/", specifying no dimensions or * chunk sizes, it indicates chunking to be turned off on output. * * Returns NC_NOERR if no error, NC_EINVAL if spec has consecutive * unescaped commas or no chunksize specified for dimension. */ static int dimchunkspec_parse(int igrp, const char *spec) { const char *cp; /* character cursor */ const char *pp = spec; /* previous char cursor for detecting escapes */ const char *np; /* beginning of current dimension name */ size_t ndims = 0; int idim; int ret = NC_NOERR; int comma_seen = 0; dimchunkspecs.ndims = 0; dimchunkspecs.omit = false; if (!spec || *spec == '\0') /* default chunking */ goto done; /* Special rule: // is treated as equivalent to / */ if ((spec[0] == '/' && spec[1] == '\0') || (spec[0] == '/' && spec[1] == '/' && spec[2] == '\0')) { /* no chunking */ dimchunkspecs.omit = true; goto done; } /* Count unescaped commas, handle consecutive unescaped commas as error */ for(cp = spec; *cp; cp++) { if(*cp == ',' && *pp != '\\') { if(comma_seen) { /* consecutive commas detected */ {ret = NC_EINVAL; goto done;} } comma_seen = 1; ndims++; } else { comma_seen = 0; } pp = cp; } ndims++; dimchunkspecs.ndims = ndims; dimchunkspecs.idimids = (int *) emalloc(ndims * sizeof(int)); dimchunkspecs.chunksizes = (size_t *) emalloc(ndims * sizeof(size_t)); /* Look up dimension ids and assign chunksizes */ pp = spec; np = spec; idim = 0; for(cp = spec; ; cp++) { if(*cp == '\0' || (*cp == ',' && *pp != '\\')) { /* found end of "dim/nn" part */ char* dimname = 0; char *dp; int dimid; size_t chunksize; for(; pp > np && *pp != '/'; pp--) { /* look backwards for "/" */ continue; } if(*pp != '/') { /* no '/' found, no chunksize specified for dimension */ ret = NC_EINVAL; goto done; } /* extract dimension name */ dimname = (char *) emalloc(pp - np + 1); dp = dimname; while(np < pp) { *dp++ = *np++; } *dp = '\0'; /* look up dimension id from dimension pathname */ ret = nc_inq_dimid2(igrp, dimname, &dimid); if(ret != NC_NOERR) {if(dimname) free(dimname); goto done;} dimchunkspecs.idimids[idim] = dimid; /* parse and assign corresponding chunksize */ pp++; /* now points to first digit of chunksize, ',', or '\0' */ if(*pp == ',' || *pp == '\0') { /* no size specified, use dim len */ size_t dimlen; ret = nc_inq_dimlen(igrp, dimid, &dimlen); if(ret != NC_NOERR) {if(dimname) free(dimname); goto done;} chunksize = dimlen; } else { /* convert nnn string to long long integer */ char *ep; #ifdef HAVE_STRTOLL long long val = strtoll(pp, &ep, 0); #else long long val = strtol(pp, &ep, 0); #endif if(ep == pp || errno == ERANGE || val < 1) /* allow chunksize bigger than dimlen */ {if(dimname) free(dimname); ret = NC_EINVAL; goto done;} chunksize = (size_t)val; } dimchunkspecs.chunksizes[idim] = chunksize; idim++; if(dimname) free(dimname); dimname = NULL; if(*cp == '\0') break; /* set np to point to first char after comma */ np = cp + 1; } pp = cp; }; done: return ret; }