/src/netcdf-c/libdispatch/dinstance.c
Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata |
3 | | See COPYRIGHT for license information. |
4 | | */ |
5 | | |
6 | | /* |
7 | | This file contains various instance operations that operate |
8 | | on a deep level rather than the shallow level of e.g. nc_free_vlen_t. |
9 | | Currently two operations are defined: |
10 | | 1. reclaim a vector of instances |
11 | | 2. copy a vector of instances |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | #include <stddef.h> |
16 | | #include <stdint.h> |
17 | | #include <stdlib.h> |
18 | | #include <string.h> |
19 | | #include <assert.h> |
20 | | #include "netcdf.h" |
21 | | #include "netcdf_aux.h" |
22 | | #include "nc4internal.h" |
23 | | #include "nc4dispatch.h" |
24 | | #include "ncoffsets.h" |
25 | | #include "ncbytes.h" |
26 | | |
27 | | #undef REPORT |
28 | | #undef DEBUG |
29 | | |
30 | | /* DAP2 and DAP4 currently defer most of their API to a substrate NC |
31 | | that hold the true metadata. So there is a level of indirection |
32 | | necessary in order to get to the right NC* instance. |
33 | | */ |
34 | | |
35 | | #if defined(NETCDF_ENABLE_DAP4) || defined(NETCDF_ENABLE_DAP2) |
36 | | EXTERNL NC* NCD4_get_substrate(NC* nc); |
37 | | EXTERNL NC* NCD2_get_substrate(NC* nc); |
38 | | static NC* |
39 | | DAPSUBSTRATE(NC* nc) |
40 | | { |
41 | | if(USED2INFO(nc) != 0) |
42 | | return NCD2_get_substrate(nc); |
43 | | else if(USED4INFO(nc) != 0) |
44 | | return NCD4_get_substrate(nc); |
45 | | return nc; |
46 | | } |
47 | | #else |
48 | 0 | #define DAPSUBSTRATE(nc) (nc) |
49 | | #endif |
50 | | |
51 | | /* It is helpful to have a structure that contains memory and an offset */ |
52 | | typedef struct Position{char* memory; ptrdiff_t offset;} Position; |
53 | | |
54 | | /* Forward */ |
55 | | static int dump_datar(int ncid, nc_type xtype, Position*, NCbytes* buf); |
56 | | #ifdef USE_NETCDF4 |
57 | | static int dump_compound(int ncid, nc_type xtype, size_t size, size_t nfields, Position* offset, NCbytes* buf); |
58 | | static int dump_vlen(int ncid, nc_type xtype, nc_type basetype, Position* offset, NCbytes* buf); |
59 | | static int dump_enum(int ncid, nc_type xtype, nc_type basetype, Position* offset, NCbytes* buf); |
60 | | static int dump_opaque(int ncid, nc_type xtype, size_t size, Position* offset, NCbytes* buf); |
61 | | #endif |
62 | | |
63 | | /** |
64 | | \ingroup user_types |
65 | | Reclaim an array of instances of an arbitrary type. |
66 | | This function should be used when the other simpler functions |
67 | | such as *nc_free_vlens* or *nc_free_string* cannot be used. |
68 | | This recursively walks the top-level instances to reclaim |
69 | | any nested data such as vlen or strings or such. |
70 | | |
71 | | Assumes it is passed a pointer to count instances of xtype. |
72 | | Reclaims any nested data. |
73 | | |
74 | | WARNING: This needs access to the type metadata of the file, so |
75 | | a valid ncid and typeid must be available, which means the file |
76 | | must not have been closed or aborted. |
77 | | |
78 | | WARNING: DOES NOT RECLAIM THE TOP-LEVEL MEMORY (see the |
79 | | nc_reclaim_data_all function). The reason is that we do not |
80 | | know how it was allocated (e.g. static vs dynamic); only the |
81 | | caller can know that. But note that it assumes all memory |
82 | | blocks other than the top were dynamically allocated, so they |
83 | | will be free'd. |
84 | | |
85 | | Should work for any netcdf format. |
86 | | |
87 | | @param ncid root id |
88 | | @param xtype type id |
89 | | @param memory ptr to top-level memory to reclaim |
90 | | @param count number of instances of the type in memory block |
91 | | @return error code |
92 | | */ |
93 | | |
94 | | int |
95 | | nc_reclaim_data(int ncid, nc_type xtype, void* memory, size_t count) |
96 | 0 | { |
97 | 0 | int stat = NC_NOERR; |
98 | 0 | NC* nc = NULL; |
99 | | |
100 | 0 | if(ncid < 0 || xtype <= 0) |
101 | 0 | {stat = NC_EINVAL; goto done;} |
102 | 0 | if(memory == NULL && count > 0) |
103 | 0 | {stat = NC_EINVAL; goto done;} |
104 | 0 | if(memory == NULL || count == 0) |
105 | 0 | goto done; /* ok, do nothing */ |
106 | | #ifdef REPORT |
107 | | fprintf(stderr,">>> reclaim: memory=%p count=%lu ncid=%d xtype=%d\n",memory,(unsigned long)count,ncid,xtype); |
108 | | #endif |
109 | | |
110 | 0 | if((stat = NC_check_id(ncid,&nc))) goto done; |
111 | 0 | nc = DAPSUBSTRATE(nc); |
112 | | |
113 | | /* Call internal version */ |
114 | 0 | stat = NC_reclaim_data(nc,xtype,memory,count); |
115 | |
|
116 | | #if 0 |
117 | | #ifdef USE_NETCDF4 |
118 | | NC_FILE_INFO_T* file = NULL; |
119 | | /* Find info for this file and group and var, and set pointer to each. */ |
120 | | if ((stat = nc4_find_grp_h5(ncid, NULL, &file))) return stat; |
121 | | /* Call internal version */ |
122 | | stat = NC_reclaim_data(file,xtype,memory,count); |
123 | | #endif |
124 | | #endif |
125 | 0 | done: |
126 | 0 | return stat; |
127 | 0 | } |
128 | | |
129 | | /** |
130 | | \ingroup user_types |
131 | | Reclaim the memory allocated for an array of instances of an arbitrary type. |
132 | | This recursively walks the top-level instances to reclaim any nested data such as vlen or strings or such. |
133 | | This function differs from *nc_reclaim_data* in that it also reclaims the top-level memory. |
134 | | |
135 | | Assumes it is passed a count and a pointer to the top-level memory. |
136 | | Should work for any netcdf format. |
137 | | |
138 | | @param ncid root id |
139 | | @param xtype type id |
140 | | @param memory ptr to top-level memory to reclaim |
141 | | @param count number of instances of the type in memory block |
142 | | @return error code |
143 | | */ |
144 | | |
145 | | int |
146 | | nc_reclaim_data_all(int ncid, nc_type xtypeid, void* memory, size_t count) |
147 | 0 | { |
148 | 0 | int stat = NC_NOERR; |
149 | 0 | stat = nc_reclaim_data(ncid,xtypeid,memory,count); |
150 | 0 | if(stat == NC_NOERR && memory != NULL) |
151 | 0 | free(memory); |
152 | 0 | return stat; |
153 | 0 | } |
154 | | |
155 | | /**************************************************/ |
156 | | |
157 | | /** |
158 | | \ingroup user_types |
159 | | Copy an array of instances of an arbitrary type. This recursively walks |
160 | | the top-level instances to copy any nested data such as vlen or strings or such. |
161 | | |
162 | | Assumes it is passed a pointer to count instances of xtype and a |
163 | | space into which to copy the instance. Copys any nested data. |
164 | | |
165 | | WARNING: This needs access to the type metadata of the file, so |
166 | | a valid ncid and typeid must be available, which means the file |
167 | | must not have been closed or aborted. |
168 | | |
169 | | WARNING: DOES NOT ALLOCATE THE TOP-LEVEL MEMORY (see the |
170 | | nc_copy_data_all function). Note that all memory blocks other |
171 | | than the top are dynamically allocated. |
172 | | |
173 | | Should work for any netcdf format. |
174 | | |
175 | | @param ncid root id |
176 | | @param xtype type id |
177 | | @param memory ptr to top-level memory to copy |
178 | | @param count number of instances of the type in memory block |
179 | | @param copy top-level space into which to copy the instance |
180 | | @return error code |
181 | | */ |
182 | | |
183 | | int |
184 | | nc_copy_data(int ncid, nc_type xtype, const void* memory, size_t count, void* copy) |
185 | 0 | { |
186 | 0 | int stat = NC_NOERR; |
187 | 0 | NC* nc = NULL; |
188 | | |
189 | 0 | if(ncid < 0 || xtype <= 0) |
190 | 0 | {stat = NC_EINVAL; goto done;} |
191 | 0 | if(memory == NULL && count > 0) |
192 | 0 | {stat = NC_EINVAL; goto done;} |
193 | 0 | if(copy == NULL && count > 0) |
194 | 0 | {stat = NC_EINVAL; goto done;} |
195 | 0 | if(memory == NULL || count == 0) |
196 | 0 | goto done; /* ok, do nothing */ |
197 | | |
198 | | #ifdef REPORT |
199 | | fprintf(stderr,">>> copy : copy =%p memory=%p count=%lu ncid=%d xtype=%d\n",copy,memory,(unsigned long)count,ncid,xtype); |
200 | | #endif |
201 | | |
202 | 0 | if((stat = NC_check_id(ncid,&nc))) goto done; |
203 | 0 | nc = DAPSUBSTRATE(nc); |
204 | | |
205 | | /* Call internal version */ |
206 | 0 | stat = NC_copy_data(nc,xtype,memory,count,copy); |
207 | 0 | done: |
208 | 0 | return stat; |
209 | 0 | } |
210 | | |
211 | | /** |
212 | | \ingroup user_types |
213 | | Copy an array of instances of an arbitrary type. This recursively walks |
214 | | the top-level instances to copy any nested data such as vlen or strings or such. |
215 | | This function differs from *nc_copy_data* in that it also allocates |
216 | | the top-level memory. |
217 | | |
218 | | Assumes it is passed a pointer to count instances of xtype and a pointer |
219 | | into which the top-level allocated space is stored. |
220 | | |
221 | | @param ncid root id |
222 | | @param xtype type id |
223 | | @param memory ptr to top-level memory to copy |
224 | | @param count number of instances of the type in memory block |
225 | | @param copyp pointer into which the allocated top-level space is stored. |
226 | | @return error code |
227 | | */ |
228 | | int |
229 | | nc_copy_data_all(int ncid, nc_type xtype, const void* memory, size_t count, void** copyp) |
230 | 0 | { |
231 | 0 | int stat = NC_NOERR; |
232 | 0 | size_t xsize = 0; |
233 | 0 | void* copy = NULL; |
234 | | |
235 | | /* Get type size */ |
236 | 0 | if((stat = ncaux_inq_any_type(ncid,xtype,NULL,&xsize,NULL,NULL,NULL))) goto done; |
237 | | |
238 | | /* allocate the top-level */ |
239 | 0 | if(count > 0) { |
240 | 0 | if((copy = calloc(count,xsize))==NULL) |
241 | 0 | {stat = NC_ENOMEM; goto done;} |
242 | 0 | } |
243 | 0 | stat = nc_copy_data(ncid,xtype,memory,count,copy); |
244 | 0 | if(copyp) {*copyp = copy; copy = NULL;} |
245 | |
|
246 | 0 | done: |
247 | 0 | if(copy) |
248 | 0 | stat = nc_reclaim_data_all(ncid,xtype,copy,count); |
249 | |
|
250 | 0 | return stat; |
251 | 0 | } |
252 | | |
253 | | /**************************************************/ |
254 | | /* Alignment functions */ |
255 | | |
256 | | #ifdef USE_NETCDF4 |
257 | | |
258 | | /** |
259 | | @param ncid - only needed for a compound type |
260 | | @param xtype - type for which alignment is requested |
261 | | @return 0 if not found |
262 | | */ |
263 | | int |
264 | | NC_type_alignment(int ncid, nc_type xtype, size_t* alignp) |
265 | 0 | { |
266 | 0 | int stat = NC_NOERR; |
267 | 0 | NC* nc = NULL; |
268 | |
|
269 | 0 | if((stat = NC_check_id(ncid,&nc))) goto done; |
270 | 0 | nc = DAPSUBSTRATE(nc); |
271 | 0 | if(USENC3INFO(nc)) goto done; |
272 | | |
273 | | /* Call internal version */ |
274 | 0 | stat = NC_type_alignment_internal((NC_FILE_INFO_T*)nc->dispatchdata,xtype,NULL,alignp); |
275 | 0 | done: |
276 | 0 | return stat; |
277 | 0 | } |
278 | | #endif |
279 | | |
280 | | /**************************************************/ |
281 | | /* Dump an instance into a bytebuffer |
282 | | |
283 | | @param ncid root id |
284 | | @param xtype type id |
285 | | @param memory ptr to top-level memory to dump |
286 | | @param count number of instances of the type in memory block |
287 | | @param bufp return ptr to a buffer of dump'd data |
288 | | @return error code |
289 | | */ |
290 | | |
291 | | int |
292 | | nc_dump_data(int ncid, nc_type xtype, const void* memory, size_t count, char** bufp) |
293 | 0 | { |
294 | 0 | int stat = NC_NOERR; |
295 | 0 | size_t i; |
296 | 0 | Position offset; |
297 | 0 | NCbytes* buf = ncbytesnew(); |
298 | |
|
299 | 0 | if(ncid < 0 || xtype <= 0) |
300 | 0 | {stat = NC_EINVAL; goto done;} |
301 | 0 | if(memory == NULL && count > 0) |
302 | 0 | {stat = NC_EINVAL; goto done;} |
303 | 0 | if(memory == NULL || count == 0) |
304 | 0 | goto done; /* ok, do nothing */ |
305 | | #ifdef REPORT |
306 | | fprintf(stderr,">>> dump: memory=%p count=%lu ncid=%d xtype=%d\n",memory,(unsigned long)count,ncid,xtype); |
307 | | #endif |
308 | 0 | offset.memory = (char*)memory; /* use char* so we can do pointer arithmetic */ |
309 | 0 | offset.offset = 0; |
310 | 0 | for(i=0;i<count;i++) { |
311 | 0 | if(i > 0) ncbytescat(buf," "); |
312 | 0 | if((stat=dump_datar(ncid,xtype,&offset,buf))) /* dump one instance */ |
313 | 0 | break; |
314 | 0 | } |
315 | |
|
316 | 0 | if(bufp) *bufp = ncbytesextract(buf); |
317 | |
|
318 | 0 | done: |
319 | 0 | ncbytesfree(buf); |
320 | 0 | return stat; |
321 | 0 | } |
322 | | |
323 | | int |
324 | | nc_print_data(int ncid, nc_type xtype, const void* memory, size_t count) |
325 | 0 | { |
326 | 0 | char* s = NULL; |
327 | 0 | int stat = NC_NOERR; |
328 | 0 | if((stat=nc_dump_data(ncid,xtype,memory,count,&s))) return stat; |
329 | 0 | fprintf(stderr,"%s\n",s); |
330 | 0 | nullfree(s) |
331 | 0 | return stat; |
332 | 0 | } |
333 | | |
334 | | /* Recursive type walker: dump a single instance */ |
335 | | static int |
336 | | dump_datar(int ncid, nc_type xtype, Position* offset, NCbytes* buf) |
337 | 0 | { |
338 | 0 | int stat = NC_NOERR; |
339 | 0 | size_t xsize; |
340 | 0 | nc_type basetype; |
341 | 0 | size_t nfields; |
342 | 0 | int klass; |
343 | 0 | char s[128]; |
344 | | |
345 | | /* Get relevant type info */ |
346 | 0 | if((stat = ncaux_inq_any_type(ncid,xtype,NULL,&xsize,&basetype,&nfields,&klass))) goto done; |
347 | | |
348 | 0 | switch (xtype) { |
349 | 0 | case NC_CHAR: |
350 | 0 | snprintf(s,sizeof(s),"'%c'",*(char*)(offset->memory+offset->offset)); |
351 | 0 | ncbytescat(buf,s); |
352 | 0 | break; |
353 | 0 | case NC_BYTE: |
354 | 0 | snprintf(s,sizeof(s),"%d",*(char*)(offset->memory+offset->offset)); |
355 | 0 | ncbytescat(buf,s); |
356 | 0 | break; |
357 | 0 | case NC_UBYTE: |
358 | 0 | snprintf(s,sizeof(s),"%u",*(unsigned char*)(offset->memory+offset->offset)); |
359 | 0 | ncbytescat(buf,s); |
360 | 0 | break; |
361 | 0 | case NC_SHORT: |
362 | 0 | snprintf(s,sizeof(s),"%d",*(short*)(offset->memory+offset->offset)); |
363 | 0 | ncbytescat(buf,s); |
364 | 0 | break; |
365 | 0 | case NC_USHORT: |
366 | 0 | snprintf(s,sizeof(s),"%d",*(unsigned short*)(offset->memory+offset->offset)); |
367 | 0 | ncbytescat(buf,s); |
368 | 0 | break; |
369 | 0 | case NC_INT: |
370 | 0 | snprintf(s,sizeof(s),"%d",*(int*)(offset->memory+offset->offset)); |
371 | 0 | ncbytescat(buf,s); |
372 | 0 | break; |
373 | 0 | case NC_UINT: |
374 | 0 | snprintf(s,sizeof(s),"%d",*(unsigned int*)(offset->memory+offset->offset)); |
375 | 0 | ncbytescat(buf,s); |
376 | 0 | break; |
377 | 0 | case NC_FLOAT: |
378 | 0 | snprintf(s,sizeof(s),"%f",*(float*)(offset->memory+offset->offset)); |
379 | 0 | ncbytescat(buf,s); |
380 | 0 | break; |
381 | 0 | case NC_INT64: |
382 | 0 | snprintf(s,sizeof(s),"%lld",*(long long*)(offset->memory+offset->offset)); |
383 | 0 | ncbytescat(buf,s); |
384 | 0 | break; |
385 | 0 | case NC_UINT64: |
386 | 0 | snprintf(s,sizeof(s),"%llu",*(unsigned long long*)(offset->memory+offset->offset)); |
387 | 0 | ncbytescat(buf,s); |
388 | 0 | break; |
389 | 0 | case NC_DOUBLE: |
390 | 0 | snprintf(s,sizeof(s),"%lf",*(double*)(offset->memory+offset->offset)); |
391 | 0 | ncbytescat(buf,s); |
392 | 0 | break; |
393 | 0 | #ifdef USE_NETCDF4 |
394 | 0 | case NC_STRING: { |
395 | 0 | char* s = *(char**)(offset->memory + offset->offset); |
396 | 0 | ncbytescat(buf,"\""); |
397 | 0 | ncbytescat(buf,s); |
398 | 0 | ncbytescat(buf,"\""); |
399 | 0 | } break; |
400 | 0 | #endif |
401 | 0 | default: |
402 | 0 | #ifdef USE_NETCDF4 |
403 | | /* dump a user type */ |
404 | 0 | switch (klass) { |
405 | 0 | case NC_OPAQUE: stat = dump_opaque(ncid,xtype,xsize,offset,buf); break; |
406 | 0 | case NC_ENUM: stat = dump_enum(ncid,xtype,basetype,offset,buf); break; |
407 | 0 | case NC_COMPOUND: stat = dump_compound(ncid,xtype,xsize,nfields,offset,buf); break; |
408 | 0 | case NC_VLEN: stat = dump_vlen(ncid,xtype,basetype,offset,buf); break; |
409 | 0 | default: stat = NC_EBADTYPE; break; |
410 | 0 | } |
411 | | #else |
412 | | stat = NC_EBADTYPE; |
413 | | #endif |
414 | 0 | break; |
415 | 0 | } |
416 | 0 | if(xtype <= NC_MAX_ATOMIC_TYPE) |
417 | 0 | offset->offset += (ptrdiff_t)xsize; |
418 | |
|
419 | 0 | done: |
420 | 0 | return stat; |
421 | 0 | } |
422 | | |
423 | | #ifdef USE_NETCDF4 |
424 | | static int |
425 | | dump_vlen(int ncid, nc_type xtype, nc_type basetype, Position* offset, NCbytes* buf) |
426 | 0 | { |
427 | 0 | int stat = NC_NOERR; |
428 | 0 | size_t i; |
429 | 0 | nc_vlen_t* vl = (nc_vlen_t*)(offset->memory+offset->offset); |
430 | 0 | char s[128]; |
431 | |
|
432 | 0 | if(vl->len > 0 && vl->p == NULL) |
433 | 0 | {stat = NC_EINVAL; goto done;} |
434 | | |
435 | 0 | snprintf(s,sizeof(s),"{len=%u,p=(",(unsigned)vl->len); |
436 | 0 | ncbytescat(buf,s); |
437 | | /* dump each entry in the vlen list */ |
438 | 0 | if(vl->len > 0) { |
439 | 0 | Position voffset; |
440 | 0 | size_t alignment = 0; |
441 | 0 | if((stat = NC_type_alignment(ncid,basetype,&alignment))) goto done;; |
442 | 0 | voffset.memory = vl->p; |
443 | 0 | voffset.offset = 0; |
444 | 0 | for(i=0;i<vl->len;i++) { |
445 | 0 | if(i > 0) ncbytescat(buf," "); |
446 | 0 | voffset.offset = (ptrdiff_t)NC_read_align((uintptr_t)voffset.offset, alignment); |
447 | 0 | if((stat = dump_datar(ncid,basetype,&voffset,buf))) goto done; |
448 | 0 | } |
449 | 0 | } |
450 | 0 | ncbytescat(buf,")}"); |
451 | 0 | offset->offset += (ptrdiff_t)sizeof(nc_vlen_t); |
452 | | |
453 | 0 | done: |
454 | 0 | return stat; |
455 | 0 | } |
456 | | |
457 | | static int |
458 | | dump_enum(int ncid, nc_type xtype, nc_type basetype, Position* offset, NCbytes* buf) |
459 | 0 | { |
460 | 0 | int stat = NC_NOERR; |
461 | | |
462 | | /* basically same as an instance of the enum's integer basetype */ |
463 | 0 | stat = dump_datar(ncid,basetype,offset,buf); |
464 | 0 | return stat; |
465 | 0 | } |
466 | | |
467 | | static int |
468 | | dump_opaque(int ncid, nc_type xtype, size_t size, Position* offset, NCbytes* buf) |
469 | 0 | { |
470 | 0 | size_t i; |
471 | 0 | char sx[16]; |
472 | | /* basically a fixed size sequence of bytes */ |
473 | 0 | ncbytescat(buf,"|"); |
474 | 0 | for(i=0;i<size;i++) { |
475 | 0 | unsigned char x = (unsigned char)*(offset->memory+offset->offset+i); |
476 | 0 | snprintf(sx,sizeof(sx),"%2x",x); |
477 | 0 | ncbytescat(buf,sx); |
478 | 0 | } |
479 | 0 | ncbytescat(buf,"|"); |
480 | 0 | offset->offset += (ptrdiff_t)size; |
481 | 0 | return NC_NOERR; |
482 | 0 | } |
483 | | |
484 | | static int |
485 | | dump_compound(int ncid, nc_type xtype, size_t size, size_t nfields, Position* offset, NCbytes* buf) |
486 | 0 | { |
487 | 0 | int stat = NC_NOERR; |
488 | 0 | int i; |
489 | 0 | ptrdiff_t saveoffset; |
490 | 0 | int ndims; |
491 | 0 | int dimsizes[NC_MAX_VAR_DIMS]; |
492 | 0 | int fid; |
493 | |
|
494 | 0 | saveoffset = offset->offset; |
495 | |
|
496 | 0 | ncbytescat(buf,"<"); |
497 | | |
498 | | /* Get info about each field in turn and dump it */ |
499 | 0 | for(fid=0;fid<(int)nfields;fid++) { |
500 | 0 | size_t fieldalignment; |
501 | 0 | nc_type fieldtype; |
502 | 0 | char name[NC_MAX_NAME]; |
503 | 0 | char sd[128]; |
504 | | |
505 | | /* Get all relevant info about the field */ |
506 | 0 | if((stat = nc_inq_compound_field(ncid,xtype,fid,name,&fieldalignment,&fieldtype,&ndims,dimsizes))) goto done; |
507 | 0 | if(fid > 0) ncbytescat(buf,";"); |
508 | 0 | ncbytescat(buf,name); |
509 | 0 | ncbytescat(buf,"("); |
510 | 0 | if(ndims > 0) { |
511 | 0 | int j; |
512 | 0 | for(j=0;j<ndims;j++) { |
513 | 0 | snprintf(sd,sizeof(sd),"%s%d",(j==0?"":","),(int)dimsizes[j]); |
514 | 0 | ncbytescat(buf,sd); |
515 | 0 | } |
516 | 0 | } |
517 | 0 | ncbytescat(buf,")"); |
518 | 0 | if(ndims == 0) {ndims=1; dimsizes[0]=1;} /* fake the scalar case */ |
519 | | /* Align to this field */ |
520 | 0 | offset->offset = saveoffset + (ptrdiff_t)fieldalignment; |
521 | | /* compute the total number of elements in the field array */ |
522 | 0 | int arraycount = 1; |
523 | 0 | for(i=0;i<ndims;i++) arraycount *= dimsizes[i]; |
524 | 0 | for(i=0;i<arraycount;i++) { |
525 | 0 | if(i > 0) ncbytescat(buf," "); |
526 | 0 | if((stat = dump_datar(ncid, fieldtype, offset,buf))) goto done; |
527 | 0 | } |
528 | 0 | } |
529 | 0 | ncbytescat(buf,">"); |
530 | | /* Return to beginning of the compound and move |compound| */ |
531 | 0 | offset->offset = saveoffset; |
532 | 0 | offset->offset += (ptrdiff_t)size; |
533 | |
|
534 | 0 | done: |
535 | 0 | return stat; |
536 | 0 | } |
537 | | #endif |
538 | | |
539 | | /* Extended version that can handle atomic typeids */ |
540 | | int |
541 | | NC_inq_any_type(int ncid, nc_type typeid, char *name, size_t *size, |
542 | | nc_type *basetypep, size_t *nfieldsp, int *classp) |
543 | 0 | { |
544 | 0 | int stat = NC_NOERR; |
545 | 0 | #ifdef USE_NETCDF4 |
546 | 0 | if(typeid >= NC_FIRSTUSERTYPEID) { |
547 | 0 | stat = nc_inq_user_type(ncid,typeid,name,size,basetypep,nfieldsp,classp); |
548 | 0 | } else |
549 | 0 | #endif |
550 | 0 | if(typeid > NC_NAT && typeid <= NC_MAX_ATOMIC_TYPE) { |
551 | 0 | if(basetypep) *basetypep = NC_NAT; |
552 | 0 | if(nfieldsp) *nfieldsp = 0; |
553 | 0 | if(classp) *classp = typeid; |
554 | 0 | stat = NC4_inq_atomic_type(typeid,name,size); |
555 | 0 | } else |
556 | 0 | stat = NC_EBADTYPE; |
557 | 0 | return stat; |
558 | 0 | } |