/src/netcdf-c/libsrc4/nc4dim.c
Line | Count | Source |
1 | | /* Copyright 2003-2018, University Corporation for Atmospheric |
2 | | * Research. See the COPYRIGHT file for copying and redistribution |
3 | | * conditions. */ |
4 | | /** |
5 | | * @file |
6 | | * @internal This file is part of netcdf-4, a netCDF-like interface |
7 | | * for HDF5, or a HDF5 backend for netCDF, depending on your point of |
8 | | * view. |
9 | | * |
10 | | * This file handles the nc4 dimension functions. |
11 | | * |
12 | | * @author Ed Hartnett |
13 | | */ |
14 | | |
15 | | #include "nc4internal.h" |
16 | | #include "nc4dispatch.h" |
17 | | |
18 | | /** |
19 | | * @internal Netcdf-4 files might have more than one unlimited |
20 | | * dimension, but return the first one anyway. |
21 | | * |
22 | | * @note that this code is inconsistent with nc_inq |
23 | | * |
24 | | * @param ncid File and group ID. |
25 | | * @param unlimdimidp Pointer that gets ID of first unlimited |
26 | | * dimension, or -1. |
27 | | * |
28 | | * @return ::NC_NOERR No error. |
29 | | * @return ::NC_EBADID Bad ncid. |
30 | | * @author Ed Hartnett |
31 | | */ |
32 | | int |
33 | | NC4_inq_unlimdim(int ncid, int *unlimdimidp) |
34 | 0 | { |
35 | 0 | NC_GRP_INFO_T *grp, *g; |
36 | 0 | NC_FILE_INFO_T *h5; |
37 | 0 | NC_DIM_INFO_T *dim; |
38 | 0 | int found = 0; |
39 | 0 | int retval; |
40 | |
|
41 | 0 | LOG((2, "%s: called", __func__)); |
42 | |
|
43 | 0 | if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) |
44 | 0 | return retval; |
45 | 0 | assert(h5 && grp); |
46 | |
|
47 | 0 | if (unlimdimidp) |
48 | 0 | { |
49 | | /* According to netcdf-3 manual, return -1 if there is no unlimited |
50 | | dimension. */ |
51 | 0 | *unlimdimidp = -1; |
52 | 0 | for (g = grp; g && !found; g = g->parent) |
53 | 0 | { |
54 | 0 | for(size_t i=0;i<ncindexsize(grp->dim);i++) |
55 | 0 | { |
56 | 0 | dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,i); |
57 | 0 | if(dim == NULL) continue; |
58 | 0 | if (dim->unlimited) |
59 | 0 | { |
60 | 0 | *unlimdimidp = dim->hdr.id; |
61 | 0 | found++; |
62 | 0 | break; |
63 | 0 | } |
64 | 0 | } |
65 | 0 | } |
66 | 0 | } |
67 | |
|
68 | 0 | return NC_NOERR; |
69 | 0 | } |
70 | | |
71 | | /** |
72 | | * @internal Given dim name, find its id. |
73 | | * Fully qualified names are legal |
74 | | * @param ncid File and group ID. |
75 | | * @param name Name of the dimension to find. |
76 | | * @param idp Pointer that gets dimension ID. |
77 | | * |
78 | | * @return ::NC_NOERR No error. |
79 | | * @return ::NC_EBADID Bad ncid. |
80 | | * @return ::NC_EBADDIM Dimension not found. |
81 | | * @return ::NC_EINVAL Invalid input. Name must be provided. |
82 | | * @author Ed Hartnett |
83 | | */ |
84 | | int |
85 | | NC4_inq_dimid(int ncid, const char *name, int *idp) |
86 | 0 | { |
87 | 0 | NC *nc = NULL; |
88 | 0 | NC_GRP_INFO_T *grp = NULL; |
89 | 0 | NC_GRP_INFO_T *g = NULL; |
90 | 0 | NC_FILE_INFO_T *h5 = NULL; |
91 | 0 | NC_DIM_INFO_T *dim = NULL; |
92 | 0 | char norm_name[NC_MAX_NAME + 1]; |
93 | 0 | int retval = NC_NOERR;; |
94 | 0 | int found = 0; |
95 | |
|
96 | 0 | LOG((2, "%s: ncid 0x%x name %s", __func__, ncid, name)); |
97 | | |
98 | | /* Check input. */ |
99 | 0 | if (!name) |
100 | 0 | {retval = NC_EINVAL; goto done;} |
101 | | |
102 | | /* If the first char is a /, this is a fully-qualified |
103 | | * name. Otherwise, this had better be a local name (i.e. no / in |
104 | | * the middle). */ |
105 | 0 | if (name[0] != '/' && strstr(name, "/")) |
106 | 0 | {retval = NC_EINVAL; goto done;} |
107 | | |
108 | | /* Find metadata for this file. */ |
109 | 0 | if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) |
110 | 0 | goto done; |
111 | 0 | assert(h5 && nc && grp); |
112 | | |
113 | | /* Normalize name. */ |
114 | 0 | if ((retval = nc4_normalize_name(name, norm_name))) |
115 | 0 | goto done;; |
116 | | |
117 | | /* If this is a fqn, then walk the sequence of parent groups to the last group |
118 | | and see if that group has a dimension of the right name */ |
119 | 0 | if(name[0] == '/') { /* FQN */ |
120 | 0 | int rootncid = (grp->nc4_info->root_grp->hdr.id | grp->nc4_info->controller->ext_ncid); |
121 | 0 | int parent = 0; |
122 | 0 | char* lastname = strrchr(norm_name,'/'); /* break off the last segment: the type name */ |
123 | 0 | if(lastname == norm_name) |
124 | 0 | {retval = NC_EINVAL; goto done;} |
125 | 0 | *lastname++ = '\0'; /* break off the lastsegment */ |
126 | 0 | if((retval = NC4_inq_grp_full_ncid(rootncid,norm_name,&parent))) |
127 | 0 | goto done; |
128 | | /* Get parent info */ |
129 | 0 | if((retval=nc4_find_nc4_grp(parent,&grp))) |
130 | 0 | goto done; |
131 | | /* See if dim exists in this group */ |
132 | 0 | dim = (NC_DIM_INFO_T*)ncindexlookup(grp->dim,lastname); |
133 | 0 | if(dim == NULL) |
134 | 0 | {retval = NC_EBADTYPE; goto done;} |
135 | 0 | goto done; |
136 | 0 | } |
137 | | |
138 | | /* check for a name match in this group and its parents */ |
139 | 0 | found = 0; |
140 | 0 | for (g = grp; g ; g = g->parent) { |
141 | 0 | dim = (NC_DIM_INFO_T*)ncindexlookup(g->dim,norm_name); |
142 | 0 | if(dim != NULL) {found = 1; break;} |
143 | 0 | } |
144 | 0 | if(!found) |
145 | 0 | {retval = NC_EBADDIM; goto done;} |
146 | | |
147 | 0 | done: |
148 | 0 | if(retval == NC_NOERR) { |
149 | 0 | assert(dim != NULL); |
150 | 0 | if (idp) |
151 | 0 | *idp = dim->hdr.id; |
152 | 0 | } |
153 | 0 | return retval; |
154 | 0 | } |
155 | | |
156 | | /** |
157 | | * @internal Inquire about a dimension, returning its name and length |
158 | | * from the in-memory metadata model. |
159 | | * |
160 | | * This is the generic netcdf-4 implementation that works purely from |
161 | | * the in-memory NC_DIM_INFO_T structures. It returns dim->len |
162 | | * directly for all dimensions, including unlimited ones. |
163 | | * |
164 | | * The HDF5 layer provides its own HDF5_inq_dim() (in |
165 | | * libhdf5/hdf5dim.c) which overrides this for HDF5-backed files. |
166 | | * HDF5_inq_dim queries the actual HDF5 datasets via nc4_find_dim_len() |
167 | | * to determine the current extent of unlimited dimensions, since data |
168 | | * may have been written since the dimension was created. That function |
169 | | * requires HDF5-specific format_grp_info and cannot be used by UDF |
170 | | * handlers or other non-HDF5 dispatch layers. |
171 | | * |
172 | | * UDF handlers and other non-HDF5 dispatch layers should use this |
173 | | * function in their dispatch tables. |
174 | | * |
175 | | * @param ncid File and group ID. |
176 | | * @param dimid Dimension ID. |
177 | | * @param name Pointer that gets dimension name. Ignored if NULL. |
178 | | * @param lenp Pointer that gets dimension length. Ignored if NULL. |
179 | | * |
180 | | * @return ::NC_NOERR No error. |
181 | | * @return ::NC_EBADID Bad ncid. |
182 | | * @return ::NC_EBADDIM Dimension not found. |
183 | | * @author Edward Hartnett @date 5/7/2023 |
184 | | */ |
185 | | int |
186 | | NC4_inq_dim(int ncid, int dimid, char *name, size_t *lenp) |
187 | 0 | { |
188 | 0 | NC_GRP_INFO_T *grp; |
189 | 0 | NC_FILE_INFO_T *h5; |
190 | 0 | NC_DIM_INFO_T *dim; |
191 | 0 | int retval; |
192 | |
|
193 | 0 | LOG((2, "%s: ncid 0x%x dimid %d", __func__, ncid, dimid)); |
194 | | |
195 | | /* Find our global metadata structure. */ |
196 | 0 | if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) |
197 | 0 | return retval; |
198 | 0 | assert(h5 && grp); |
199 | | |
200 | | /* Find the dimension. */ |
201 | 0 | if ((retval = nc4_find_dim(grp, dimid, &dim, NULL))) |
202 | 0 | return retval; |
203 | 0 | assert(dim); |
204 | | |
205 | | /* Return the dimension name, if the caller wants it. */ |
206 | 0 | if (name && dim->hdr.name) |
207 | 0 | strcpy(name, dim->hdr.name); |
208 | | |
209 | | /* Return the dimension length, if the caller wants it. */ |
210 | 0 | if (lenp) |
211 | 0 | *lenp = dim->len; |
212 | |
|
213 | 0 | return NC_NOERR; |
214 | 0 | } |
215 | | |
216 | | /** |
217 | | * @internal Returns an array of unlimited dimension ids.The user can |
218 | | * get the number of unlimited dimensions by first calling this with |
219 | | * NULL for the second pointer. |
220 | | * |
221 | | * @param ncid File and group ID. |
222 | | * @param nunlimdimsp Pointer that gets the number of unlimited |
223 | | * dimensions. Ignored if NULL. |
224 | | * @param unlimdimidsp Pointer that gets array of unlimited dimension |
225 | | * ID. Ignored if NULL. |
226 | | * |
227 | | * @return ::NC_NOERR No error. |
228 | | * @return ::NC_EBADID Bad ncid. |
229 | | * @author Ed Hartnett, Dennis Heimbigner |
230 | | */ |
231 | | int |
232 | | NC4_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp) |
233 | 0 | { |
234 | 0 | NC_DIM_INFO_T *dim; |
235 | 0 | NC_GRP_INFO_T *grp; |
236 | 0 | NC *nc; |
237 | 0 | NC_FILE_INFO_T *h5; |
238 | 0 | int num_unlim = 0; |
239 | 0 | int retval; |
240 | |
|
241 | 0 | LOG((2, "%s: ncid 0x%x", __func__, ncid)); |
242 | | |
243 | | /* Find info for this file and group, and set pointer to each. */ |
244 | 0 | if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) |
245 | 0 | return retval; |
246 | 0 | assert(h5 && nc && grp); |
247 | | |
248 | | /* Get our dim info. */ |
249 | 0 | assert(h5); |
250 | 0 | { |
251 | 0 | for(size_t i=0;i<ncindexsize(grp->dim);i++) |
252 | 0 | { |
253 | 0 | dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,i); |
254 | 0 | if(dim == NULL) continue; |
255 | 0 | if (dim->unlimited) |
256 | 0 | { |
257 | 0 | if (unlimdimidsp) |
258 | 0 | unlimdimidsp[num_unlim] = dim->hdr.id; |
259 | 0 | num_unlim++; |
260 | 0 | } |
261 | 0 | } |
262 | 0 | } |
263 | | |
264 | | /* Give the number if the user wants it. */ |
265 | 0 | if (nunlimdimsp) |
266 | 0 | *nunlimdimsp = num_unlim; |
267 | |
|
268 | 0 | return NC_NOERR; |
269 | 0 | } |