1/*********************************************************************
2 *   Copyright 2010, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *   $Id $
5 *********************************************************************/
6
7#include <stdlib.h>
8#include <string.h>
9#include <stdio.h>
10#include <netcdf.h>
11#include "utils.h"
12#include "chunkspec.h"
13
14/* Structure mapping dimension IDs to corresponding chunksizes. */
15static struct {
16    size_t ndims; /* number of dimensions in chunkspec string */
17    int *dimids; /* ids for dimensions in chunkspec string */
18    size_t *chunksizes; /* corresponding chunk sizes */
19    bool_t omit; /* true if chunking to be turned off */
20chunkspecs;
21
22/*
23 * Parse chunkspec string and convert into chunkspec_t structure.
24 *   ncid: location ID of open netCDF file or group in an open file
25 *   spec: string of form
26 *           dim1/n1,dim2/n2,...,dimk/nk
27 *
28 *         specifying chunk size (ni) to be used for dimension named
29 *         dimi.  Dimension names may be absolute,
30 *         e.g. "/grp_a/grp_a1/dim".  The "ni" part of the spec may be
31 *         omitted, in which case it is assumed to be the entire
32 *         dimension size.  That is also the default for dimensions
33 *         not mentioned in the string.
34 *         If the chunkspec string is "/", specifying no dimensions or
35 *         chunk sizes, it indicates chunking to be turned off on output.
36 *
37 * Returns NC_NOERR if no error, NC_EINVAL if spec has consecutive
38 * unescaped commas or no chunksize specified for dimension.
39 */
40int
41chunkspec_parse(int ncid, const char *spec) {
42    const char *cp;    /* character cursor */
43    const char *pp = spec; /* previous char cursor for detecting escapes */
44    const char *np;    /* beginning of current dimension name */
45    size_t ndims = 0;
46    int idim;
47    int ret;
48    int comma_seen = 0;
49
50    chunkspecs.ndims = 0;
51    chunkspecs.omit = false;
52    if (!spec || *spec == '\0') /* default chunking */
53 return NC_NOERR;
54    if (spec[0] == '/' && spec[1] == '\0') { /* no chunking */
55 chunkspecs.omit = true;
56 return NC_NOERR;
57    }
58    /* Count unescaped commas, handle consecutive unescaped commas as error */
59    for(cp = spec; *cpcp++) {
60 if(*cp == ',' && *pp != '\\') {
61     if(comma_seen) { /* consecutive commas detected */
62 return(NC_EINVAL);
63     }
64     comma_seen = 1;
65     ndims++;
66 } else {
67     comma_seen = 0;
68 }
69 pp = cp;
70    }
71    ndims++;
72    chunkspecs.ndims = ndims;
73    chunkspecs.dimids = (int *) emalloc(ndims * sizeof(int));
74    chunkspecs.chunksizes = (size_t *) emalloc(ndims * sizeof(size_t));
75    /* Look up dimension ids and assign chunksizes */
76    pp = spec;
77    np = spec;
78    idim = 0;
79    for(cp = spec; ; cp++) {
80 if(*cp == '\0' || (*cp == ',' && *pp != '\\')) { /* found end of "dim/nn" part */
81     char* dimname = 0;
82     char *dp;
83     int dimid;
84     size_t chunksize;
85
86     for(; pp > np && *pp != '/'; pp--) { /* look backwards for "/" */
87 continue;
88     }
89     if(*pp != '/') { /* no '/' found, no chunksize specified for dimension */
90 return(NC_EINVAL);
91     }
92     /* extract dimension name */
93     dimname = (char *) emalloc(pp - np + 1);
94     dp = dimname;
95     while(np < pp) {
96 *dp++ = *np++;
97     }
98     *dp = '\0';
99     /* look up dimension id from dimension pathname */
100     ret = nc_inq_dimid2(nciddimname, &dimid);
101     if(ret != NC_NOERR)
102 break;
103     chunkspecs.dimids[idim] = dimid;
104     /* parse and assign corresponding chunksize */
105     pp++; /* now points to first digit of chunksize, ',', or '\0' */
106     if(*pp == ',' || *pp == '\0') { /* no size specified, use dim len */
107 size_t dimlen;
108 ret = nc_inq_dimlen(nciddimid, &dimlen);
109 if(ret != NC_NOERR)
110     return(ret);
111 chunksize = dimlen;
112     } else {       /* convert nnn string to long long integer */
113 char *ep;
114#ifdef HAVE_STRTOLL
115 long long val = strtoll(pp, &ep, 0);
116#else
117 long long val = strtol(pp, &ep, 0);
118#endif
119 if(ep == pp || errno == ERANGE || val < 1) /* allow chunksize bigger than dimlen */
120     return (NC_EINVAL);
121 chunksize = (size_t)val;
122     }
123     chunkspecs.chunksizes[idim] = chunksize;
124     idim++;
125     free(dimname);
126     if(*cp == '\0')
127 break;
128     /* set np to point to first char after comma */
129     np = cp + 1;
130 }
131 pp = cp;
132    };
133    return NC_NOERR;
134}
135
136/* Return size in chunkspec string specified for dimension corresponding to dimid, 0 if not found */
137size_t
138chunkspec_size(int dimid) {
139    int idim;
140    for(idim = 0; idim < chunkspecs.ndimsidim++) {
141 if(dimid == chunkspecs.dimids[idim]) {
142     return chunkspecs.chunksizes[idim];
143 }
144    }
145    return 0;
146}
147
148/* Return number of dimensions for which chunking was specified in
149 * chunkspec string on command line, 0 if no chunkspec string was
150 * specified. */
151int
152chunkspec_ndims(void) {
153    return chunkspecs.ndims;
154}
155
156/* Return whether chunking should be omitted, due to explicit
157 * command-line specification. */
158bool_t
159chunkspec_omit(void) {
160    return chunkspecs.omit;
161}
162
163


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed