/src/netcdf-c/libsrc/dim.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2018, University Corporation for Atmospheric Research |
3 | | * See netcdf/COPYRIGHT file for copying and redistribution conditions. |
4 | | */ |
5 | | /* $Id: dim.c,v 1.83 2010/05/25 17:54:15 dmh Exp $ */ |
6 | | |
7 | | #if HAVE_CONFIG_H |
8 | | #include <config.h> |
9 | | #endif |
10 | | |
11 | | #include "nc3internal.h" |
12 | | #include <stdlib.h> |
13 | | #include <string.h> |
14 | | #include <assert.h> |
15 | | #include "ncx.h" |
16 | | #include "fbits.h" |
17 | | #include "ncutf8.h" |
18 | | |
19 | | /* |
20 | | * Free dim |
21 | | * Formerly |
22 | | NC_free_dim(dim) |
23 | | */ |
24 | | void |
25 | | free_NC_dim(NC_dim *dimp) |
26 | 318k | { |
27 | 318k | if(dimp == NULL) |
28 | 0 | return; |
29 | 318k | free_NC_string(dimp->name); |
30 | 318k | free(dimp); |
31 | 318k | } |
32 | | |
33 | | |
34 | | NC_dim * |
35 | | new_x_NC_dim(NC_string *name) |
36 | 318k | { |
37 | 318k | NC_dim *dimp; |
38 | | |
39 | 318k | dimp = (NC_dim *) malloc(sizeof(NC_dim)); |
40 | 318k | if(dimp == NULL) |
41 | 0 | return NULL; |
42 | | |
43 | 318k | dimp->name = name; |
44 | 318k | dimp->size = 0; |
45 | | |
46 | 318k | return(dimp); |
47 | 318k | } |
48 | | |
49 | | |
50 | | /* |
51 | | * Formerly |
52 | | NC_new_dim(const char *uname, long size) |
53 | | */ |
54 | | static NC_dim * |
55 | | new_NC_dim(const char *uname, size_t size) |
56 | 0 | { |
57 | 0 | NC_string *strp; |
58 | 0 | NC_dim *dimp = NULL; |
59 | 0 | int stat = NC_NOERR; |
60 | 0 | char* name = NULL; |
61 | |
|
62 | 0 | stat = nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name); |
63 | 0 | if(stat != NC_NOERR) |
64 | 0 | goto done; |
65 | 0 | strp = new_NC_string(strlen(name), name); |
66 | 0 | if(strp == NULL) |
67 | 0 | {stat = NC_ENOMEM; goto done;} |
68 | | |
69 | 0 | dimp = new_x_NC_dim(strp); |
70 | 0 | if(dimp == NULL) |
71 | 0 | { |
72 | 0 | free_NC_string(strp); |
73 | 0 | goto done; |
74 | 0 | } |
75 | | |
76 | 0 | dimp->size = size; |
77 | |
|
78 | 0 | done: |
79 | 0 | if(name) free(name); |
80 | 0 | return (dimp); |
81 | 0 | } |
82 | | |
83 | | |
84 | | static NC_dim * |
85 | | dup_NC_dim(const NC_dim *dimp) |
86 | 0 | { |
87 | 0 | return new_NC_dim(dimp->name->cp, dimp->size); |
88 | 0 | } |
89 | | |
90 | | /* |
91 | | * Step thru NC_DIMENSION array, seeking the UNLIMITED dimension. |
92 | | * Return dimid or -1 on not found. |
93 | | * *dimpp is set to the appropriate NC_dim. |
94 | | * The loop structure is odd. In order to parallelize, |
95 | | * we moved a clearer 'break' inside the loop body to the loop test. |
96 | | */ |
97 | | int |
98 | | find_NC_Udim(const NC_dimarray *ncap, NC_dim **dimpp) |
99 | 0 | { |
100 | 0 | assert(ncap != NULL); |
101 | |
|
102 | 0 | if(ncap->nelems == 0) |
103 | 0 | return -1; |
104 | | |
105 | 0 | { |
106 | 0 | int dimid = 0; |
107 | 0 | NC_dim **loc = ncap->value; |
108 | |
|
109 | 0 | for(; (size_t) dimid < ncap->nelems |
110 | 0 | && (*loc)->size != NC_UNLIMITED; dimid++, loc++) |
111 | 0 | { |
112 | | /*EMPTY*/ |
113 | 0 | } |
114 | 0 | if(dimid >= ncap->nelems) |
115 | 0 | return(-1); /* not found */ |
116 | | /* else, normal return */ |
117 | 0 | if(dimpp != NULL) |
118 | 0 | *dimpp = *loc; |
119 | 0 | return dimid; |
120 | 0 | } |
121 | 0 | } |
122 | | |
123 | | /* |
124 | | * Step thru NC_DIMENSION array, seeking match on uname. |
125 | | * Return dimid or -1 on not found. |
126 | | * *dimpp is set to the appropriate NC_dim. |
127 | | * The loop structure is odd. In order to parallelize, |
128 | | * we moved a clearer 'break' inside the loop body to the loop test. |
129 | | */ |
130 | | static int |
131 | | NC_finddim(const NC_dimarray *ncap, const char *uname, NC_dim **dimpp) |
132 | 0 | { |
133 | 0 | int dimid = -1; |
134 | 0 | char *name = NULL; |
135 | 0 | uintptr_t data; |
136 | |
|
137 | 0 | assert(ncap != NULL); |
138 | 0 | if(ncap->nelems == 0) |
139 | 0 | goto done; |
140 | | /* normalized version of uname */ |
141 | 0 | if(nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name)) |
142 | 0 | goto done; |
143 | 0 | if(NC_hashmapget(ncap->hashmap, name, strlen(name), &data) == 0) |
144 | 0 | goto done; |
145 | 0 | dimid = (int)data; |
146 | 0 | if(dimpp) *dimpp = ncap->value[dimid]; |
147 | |
|
148 | 0 | done: |
149 | 0 | if(name) free(name); |
150 | 0 | return dimid; |
151 | 0 | } |
152 | | |
153 | | |
154 | | /* dimarray */ |
155 | | |
156 | | |
157 | | /* |
158 | | * Free the stuff "in" (referred to by) an NC_dimarray. |
159 | | * Leaves the array itself allocated. |
160 | | */ |
161 | | void |
162 | | free_NC_dimarrayV0(NC_dimarray *ncap) |
163 | 73 | { |
164 | 73 | assert(ncap != NULL); |
165 | | |
166 | 73 | if(ncap->nelems == 0) |
167 | 0 | return; |
168 | | |
169 | 73 | assert(ncap->value != NULL); |
170 | | |
171 | 73 | { |
172 | 73 | NC_dim **dpp = ncap->value; |
173 | 73 | NC_dim *const *const end = &dpp[ncap->nelems]; |
174 | 318k | for( /*NADA*/; dpp < end; dpp++) |
175 | 318k | { |
176 | 318k | free_NC_dim(*dpp); |
177 | 318k | *dpp = NULL; |
178 | 318k | } |
179 | 73 | } |
180 | 73 | ncap->nelems = 0; |
181 | 73 | } |
182 | | |
183 | | |
184 | | /* |
185 | | * Free NC_dimarray values. |
186 | | * formerly |
187 | | NC_free_array() |
188 | | */ |
189 | | void |
190 | | free_NC_dimarrayV(NC_dimarray *ncap) |
191 | 355 | { |
192 | 355 | assert(ncap != NULL); |
193 | | |
194 | 355 | if(ncap->nalloc == 0) |
195 | 282 | return; |
196 | | |
197 | 73 | NC_hashmapfree(ncap->hashmap); |
198 | 73 | ncap->hashmap = NULL; |
199 | | |
200 | 73 | assert(ncap->value != NULL); |
201 | | |
202 | 73 | free_NC_dimarrayV0(ncap); |
203 | | |
204 | 73 | free(ncap->value); |
205 | 73 | ncap->value = NULL; |
206 | 73 | ncap->nalloc = 0; |
207 | 73 | } |
208 | | |
209 | | |
210 | | int |
211 | | dup_NC_dimarrayV(NC_dimarray *ncap, const NC_dimarray *ref) |
212 | 0 | { |
213 | 0 | int status = NC_NOERR; |
214 | |
|
215 | 0 | assert(ref != NULL); |
216 | 0 | assert(ncap != NULL); |
217 | |
|
218 | 0 | if(ref->nelems != 0) |
219 | 0 | { |
220 | 0 | const size_t sz = ref->nelems * sizeof(NC_dim *); |
221 | 0 | ncap->value = (NC_dim **) malloc(sz); |
222 | 0 | if(ncap->value == NULL) |
223 | 0 | return NC_ENOMEM; |
224 | 0 | (void) memset(ncap->value, 0, sz); |
225 | 0 | ncap->nalloc = ref->nelems; |
226 | 0 | } |
227 | | |
228 | 0 | ncap->nelems = 0; |
229 | 0 | { |
230 | 0 | NC_dim **dpp = ncap->value; |
231 | 0 | if(dpp != NULL) |
232 | 0 | { |
233 | 0 | const NC_dim **drpp = (const NC_dim **)ref->value; |
234 | 0 | NC_dim *const *const end = &dpp[ref->nelems]; |
235 | 0 | for( /*NADA*/; dpp < end; drpp++, dpp++, ncap->nelems++) |
236 | 0 | { |
237 | 0 | *dpp = dup_NC_dim(*drpp); |
238 | 0 | if(*dpp == NULL) |
239 | 0 | { |
240 | 0 | status = NC_ENOMEM; |
241 | 0 | break; |
242 | 0 | } |
243 | 0 | } |
244 | 0 | } |
245 | 0 | } |
246 | |
|
247 | 0 | if(status != NC_NOERR) |
248 | 0 | { |
249 | 0 | free_NC_dimarrayV(ncap); |
250 | 0 | return status; |
251 | 0 | } |
252 | | |
253 | 0 | assert(ncap->nelems == ref->nelems); |
254 | |
|
255 | 0 | return NC_NOERR; |
256 | 0 | } |
257 | | |
258 | | |
259 | | /* |
260 | | * Add a new handle on the end of an array of handles |
261 | | * Formerly |
262 | | NC_incr_array(array, tail) |
263 | | */ |
264 | | static int |
265 | | incr_NC_dimarray(NC_dimarray *ncap, NC_dim *newelemp) |
266 | 0 | { |
267 | 0 | NC_dim **vp; |
268 | |
|
269 | 0 | assert(ncap != NULL); |
270 | |
|
271 | 0 | if(ncap->nalloc == 0) |
272 | 0 | { |
273 | 0 | assert(ncap->nelems == 0); |
274 | 0 | vp = (NC_dim **) malloc(NC_ARRAY_GROWBY * sizeof(NC_dim *)); |
275 | 0 | if(vp == NULL) |
276 | 0 | return NC_ENOMEM; |
277 | 0 | ncap->value = vp; |
278 | 0 | ncap->nalloc = NC_ARRAY_GROWBY; |
279 | 0 | ncap->hashmap = NC_hashmapnew(0); |
280 | 0 | } |
281 | 0 | else if(ncap->nelems +1 > ncap->nalloc) |
282 | 0 | { |
283 | 0 | vp = (NC_dim **) realloc(ncap->value, |
284 | 0 | (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_dim *)); |
285 | 0 | if(vp == NULL) |
286 | 0 | return NC_ENOMEM; |
287 | 0 | ncap->value = vp; |
288 | 0 | ncap->nalloc += NC_ARRAY_GROWBY; |
289 | 0 | } |
290 | | |
291 | 0 | if(newelemp != NULL) |
292 | 0 | { |
293 | 0 | uintptr_t intdata = ncap->nelems; |
294 | 0 | NC_hashmapadd(ncap->hashmap, intdata, newelemp->name->cp, strlen(newelemp->name->cp)); |
295 | 0 | ncap->value[ncap->nelems] = newelemp; |
296 | 0 | ncap->nelems++; |
297 | 0 | } |
298 | 0 | return NC_NOERR; |
299 | 0 | } |
300 | | |
301 | | |
302 | | NC_dim * |
303 | | elem_NC_dimarray(const NC_dimarray *ncap, size_t elem) |
304 | 0 | { |
305 | 0 | assert(ncap != NULL); |
306 | | /* cast needed for braindead systems with signed size_t */ |
307 | 0 | if(ncap->nelems == 0 || (unsigned long) elem >= ncap->nelems) |
308 | 0 | return NULL; |
309 | | |
310 | 0 | assert(ncap->value != NULL); |
311 | |
|
312 | 0 | return ncap->value[elem]; |
313 | 0 | } |
314 | | |
315 | | |
316 | | /* Public */ |
317 | | |
318 | | int |
319 | | NC3_def_dim(int ncid, const char *name, size_t size, int *dimidp) |
320 | 0 | { |
321 | 0 | int status; |
322 | 0 | NC *nc; |
323 | 0 | NC3_INFO* ncp; |
324 | 0 | int dimid; |
325 | 0 | NC_dim *dimp; |
326 | |
|
327 | 0 | status = NC_check_id(ncid, &nc); |
328 | 0 | if(status != NC_NOERR) |
329 | 0 | return status; |
330 | 0 | ncp = NC3_DATA(nc); |
331 | |
|
332 | 0 | if(!NC_indef(ncp)) |
333 | 0 | return NC_ENOTINDEFINE; |
334 | | |
335 | 0 | status = NC_check_name(name); |
336 | 0 | if(status != NC_NOERR) |
337 | 0 | return status; |
338 | | |
339 | 0 | if(ncp->flags & NC_64BIT_DATA) {/*CDF-5*/ |
340 | 0 | if((sizeof(size_t) > 4) && (size > X_UINT64_MAX - 3)) /* "- 3" handles rounded-up size */ |
341 | 0 | return NC_EDIMSIZE; |
342 | 0 | } else if(ncp->flags & NC_64BIT_OFFSET) {/* CDF2 format and LFS */ |
343 | 0 | if((sizeof(size_t) > 4) && (size > X_UINT_MAX - 3)) /* "- 3" handles rounded-up size */ |
344 | 0 | return NC_EDIMSIZE; |
345 | 0 | } else {/*CDF-1*/ |
346 | 0 | if(size > X_INT_MAX - 3) |
347 | 0 | return NC_EDIMSIZE; |
348 | 0 | } |
349 | | |
350 | 0 | if(size == NC_UNLIMITED) |
351 | 0 | { |
352 | 0 | dimid = find_NC_Udim(&ncp->dims, &dimp); |
353 | 0 | if(dimid != -1) |
354 | 0 | { |
355 | 0 | assert(dimid != -1); |
356 | 0 | return NC_EUNLIMIT; |
357 | 0 | } |
358 | 0 | } |
359 | | |
360 | 0 | dimid = NC_finddim(&ncp->dims, name, &dimp); |
361 | 0 | if(dimid != -1) |
362 | 0 | return NC_ENAMEINUSE; |
363 | | |
364 | 0 | dimp = new_NC_dim(name, size); |
365 | 0 | if(dimp == NULL) |
366 | 0 | return NC_ENOMEM; |
367 | 0 | status = incr_NC_dimarray(&ncp->dims, dimp); |
368 | 0 | if(status != NC_NOERR) |
369 | 0 | { |
370 | 0 | free_NC_dim(dimp); |
371 | 0 | return status; |
372 | 0 | } |
373 | | |
374 | 0 | if(dimidp != NULL) |
375 | 0 | *dimidp = (int)ncp->dims.nelems -1; |
376 | 0 | return NC_NOERR; |
377 | 0 | } |
378 | | |
379 | | |
380 | | int |
381 | | NC3_inq_dimid(int ncid, const char *name, int *dimid_ptr) |
382 | 0 | { |
383 | 0 | int status; |
384 | 0 | NC *nc; |
385 | 0 | NC3_INFO* ncp; |
386 | 0 | int dimid; |
387 | |
|
388 | 0 | status = NC_check_id(ncid, &nc); |
389 | 0 | if(status != NC_NOERR) |
390 | 0 | return status; |
391 | 0 | ncp = NC3_DATA(nc); |
392 | |
|
393 | 0 | dimid = NC_finddim(&ncp->dims, name, NULL); |
394 | |
|
395 | 0 | if(dimid == -1) |
396 | 0 | return NC_EBADDIM; |
397 | | |
398 | 0 | if (dimid_ptr) |
399 | 0 | *dimid_ptr = dimid; |
400 | 0 | return NC_NOERR; |
401 | 0 | } |
402 | | |
403 | | int |
404 | | NC3_inq_dim(int ncid, int dimid, char *name, size_t *sizep) |
405 | 0 | { |
406 | 0 | int status; |
407 | 0 | NC *nc; |
408 | 0 | NC3_INFO* ncp; |
409 | 0 | NC_dim *dimp; |
410 | |
|
411 | 0 | status = NC_check_id(ncid, &nc); |
412 | 0 | if(status != NC_NOERR) |
413 | 0 | return status; |
414 | 0 | ncp = NC3_DATA(nc); |
415 | |
|
416 | 0 | dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid); |
417 | 0 | if(dimp == NULL) |
418 | 0 | return NC_EBADDIM; |
419 | | |
420 | 0 | if(name != NULL) |
421 | 0 | { |
422 | 0 | (void)strncpy(name, dimp->name->cp, |
423 | 0 | dimp->name->nchars); |
424 | 0 | name[dimp->name->nchars] = 0; |
425 | 0 | } |
426 | 0 | if(sizep != NULL) |
427 | 0 | { |
428 | 0 | if(dimp->size == NC_UNLIMITED) |
429 | 0 | *sizep = NC_get_numrecs(ncp); |
430 | 0 | else |
431 | 0 | *sizep = dimp->size; |
432 | 0 | } |
433 | 0 | return NC_NOERR; |
434 | 0 | } |
435 | | |
436 | | int |
437 | | NC3_rename_dim( int ncid, int dimid, const char *unewname) |
438 | 0 | { |
439 | 0 | int status = NC_NOERR; |
440 | 0 | NC *nc; |
441 | 0 | NC3_INFO* ncp; |
442 | 0 | int existid; |
443 | 0 | NC_dim *dimp; |
444 | 0 | char *newname = NULL; /* normalized */ |
445 | 0 | NC_string *old = NULL; |
446 | 0 | uintptr_t intdata; |
447 | | |
448 | |
|
449 | 0 | status = NC_check_id(ncid, &nc); |
450 | 0 | if(status != NC_NOERR) |
451 | 0 | goto done; |
452 | 0 | ncp = NC3_DATA(nc); |
453 | |
|
454 | 0 | if(NC_readonly(ncp)) |
455 | 0 | {status = NC_EPERM; goto done;} |
456 | | |
457 | 0 | status = NC_check_name(unewname); |
458 | 0 | if(status != NC_NOERR) |
459 | 0 | goto done; |
460 | | |
461 | 0 | existid = NC_finddim(&ncp->dims, unewname, &dimp); |
462 | 0 | if(existid != -1) |
463 | 0 | {status = NC_ENAMEINUSE; goto done;} |
464 | | |
465 | 0 | dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid); |
466 | 0 | if(dimp == NULL) |
467 | 0 | {status = NC_EBADDIM; goto done;} |
468 | | |
469 | 0 | old = dimp->name; |
470 | 0 | status = nc_utf8_normalize((const unsigned char *)unewname,(unsigned char **)&newname); |
471 | 0 | if(status != NC_NOERR) |
472 | 0 | goto done; |
473 | 0 | if(NC_indef(ncp)) |
474 | 0 | { |
475 | 0 | NC_string *newStr = new_NC_string(strlen(newname), newname); |
476 | 0 | if(newStr == NULL) |
477 | 0 | {status = NC_ENOMEM; goto done;} |
478 | | |
479 | | /* Remove old name from hashmap; add new... */ |
480 | 0 | NC_hashmapremove(ncp->dims.hashmap, old->cp, strlen(old->cp), NULL); |
481 | 0 | dimp->name = newStr; |
482 | |
|
483 | 0 | intdata = (uintptr_t)dimid; |
484 | 0 | NC_hashmapadd(ncp->dims.hashmap, intdata, newStr->cp, strlen(newStr->cp)); |
485 | 0 | free_NC_string(old); |
486 | 0 | goto done; |
487 | 0 | } |
488 | | |
489 | | /* else, not in define mode */ |
490 | | |
491 | | /* If new name is longer than old, then complain, |
492 | | but otherwise, no change (test is same as set_NC_string)*/ |
493 | 0 | if(dimp->name->nchars < strlen(newname)) { |
494 | 0 | {status = NC_ENOTINDEFINE; goto done;} |
495 | 0 | } |
496 | | |
497 | | /* Remove old name from hashmap; add new... */ |
498 | | /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */ |
499 | 0 | NC_hashmapremove(ncp->dims.hashmap, old->cp, strlen(old->cp), NULL); |
500 | | |
501 | | /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */ |
502 | 0 | status = set_NC_string(dimp->name, newname); |
503 | 0 | if(status != NC_NOERR) |
504 | 0 | goto done; |
505 | | |
506 | 0 | intdata = (uintptr_t)dimid; |
507 | 0 | NC_hashmapadd(ncp->dims.hashmap, intdata, dimp->name->cp, strlen(dimp->name->cp)); |
508 | |
|
509 | 0 | set_NC_hdirty(ncp); |
510 | |
|
511 | 0 | if(NC_doHsync(ncp)) |
512 | 0 | { |
513 | 0 | status = NC_sync(ncp); |
514 | 0 | if(status != NC_NOERR) |
515 | 0 | goto done; |
516 | 0 | } |
517 | | |
518 | 0 | done: |
519 | 0 | if(newname) free(newname); |
520 | 0 | return status; |
521 | 0 | } |