Пример #1
0
/*
 * 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;
}
Пример #2
0
/*
 * 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;
}