NetCDF 4.9.3
Loading...
Searching...
No Matches
nc4internal.c
Go to the documentation of this file.
1/* Copyright 2003-2018, University Corporation for Atmospheric
2 * Research. See the COPYRIGHT file for copying and redistribution
3 * conditions.
4 */
18#include "config.h"
19#include "netcdf.h"
20#include "netcdf_filter.h"
21#include "netcdf_meta.h"
22#include "nc4internal.h"
23#include "nc.h" /* from libsrc */
24#include "ncdispatch.h" /* from libdispatch */
25#include "ncutf8.h"
26#include <stdarg.h>
27#include <stddef.h>
28#include "ncrc.h"
29
37
42static NC_reservedatt NC_reserved[] = {
43 {NC_ATT_CLASS, READONLYFLAG|HIDDENATTRFLAG}, /*CLASS*/
44 {NC_ATT_DIMENSION_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*DIMENSION_LIST*/
45 {NC_ATT_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*NAME*/
46 {NC_ATT_REFERENCE_LIST, READONLYFLAG|HIDDENATTRFLAG}, /*REFERENCE_LIST*/
47 {NC_XARRAY_DIMS, READONLYFLAG|HIDDENATTRFLAG}, /*_ARRAY_DIMENSIONS*/
48 {NC_ATT_CODECS, VARFLAG|READONLYFLAG|NAMEONLYFLAG}, /*_Codecs*/
49 {NC_ATT_FORMAT, READONLYFLAG}, /*_Format*/
50 {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG|VIRTUALFLAG}, /*_IsNetcdf4*/
51 {NCPROPS,READONLYFLAG|NAMEONLYFLAG|HIDDENATTRFLAG}, /*_NCProperties*/
52 {NC_ATT_COORDINATES, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Coordinates*/
53 {NC_ATT_DIMID_NAME, READONLYFLAG|HIDDENATTRFLAG}, /*_Netcdf4Dimid*/
54 {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG|VIRTUALFLAG}, /*_SuperblockVersion*/
55 {NC_ATT_NC3_STRICT_NAME, READONLYFLAG}, /*_nc3_strict*/
56 {NC_ATT_NC3_STRICT_NAME, READONLYFLAG}, /*_nc3_strict*/
57 {NC_NCZARR_ATTR, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_attr */
58 {NC_NCZARR_GROUP, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_group */
59 {NC_NCZARR_ARRAY, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_array */
60 {NC_NCZARR_SUPERBLOCK, READONLYFLAG|HIDDENATTRFLAG}, /*_nczarr_superblock */
61};
62#define NRESERVED (sizeof(NC_reserved) / sizeof(NC_reservedatt)) /*|NC_reservedatt*/
63
64/*Forward */
65static int NC4_move_in_NCList(NC* nc, int new_id);
66static int bincmp(const void* arg1, const void* arg2);
67static int sortcmp(const void* arg1, const void* arg2);
68
69#if LOGGING
70/* This is the severity level of messages which will be logged. Use
71 severity 0 for errors, 1 for important log messages, 2 for less
72 important, etc. */
73int nc_log_level = NC_TURN_OFF_LOGGING;
74#if NC_HAS_PARALLEL4
75/* File pointer for the parallel I/O log file. */
76FILE *LOG_FILE = NULL;
77#endif /* NC_HAS_PARALLEL4 */
78
79/* This function prints out a message, if the severity of
80 * the message is lower than the global nc_log_level. To use it, do
81 * something like this:
82 *
83 * nc_log(0, "this computer will explode in %d seconds", i);
84 *
85 * After the first arg (the severity), use the rest like a normal
86 * printf statement. Output will appear on stderr for sequential
87 * builds, and in a file nc4_log_R.log for each process for a parallel
88 * build, where R is the rank of the process.
89 *
90 * Ed Hartnett
91 */
92void
93nc_log(int severity, const char *fmt, ...)
94{
95 va_list argp;
96 int t;
97 FILE *f = stderr;
98
99 /* If the severity is greater than the log level, we don't print
100 * this message. */
101 if (severity > nc_log_level)
102 return;
103
104#if NC_HAS_PARALLEL4
105 /* For parallel I/O build, if MPI has been initialized, instead of
106 * printing logging output to stderr, it goes to a file for each
107 * process. */
108 {
109 int mpi_initialized;
110 int mpierr;
111
112 /* Check to see if MPI has been initialized. */
113 if ((mpierr = MPI_Initialized(&mpi_initialized)))
114 return;
115
116 /* If MPI has been initialized use a log file. */
117 assert(LOG_FILE);
118 if (mpi_initialized)
119 f = LOG_FILE;
120 }
121#endif /* NC_HAS_PARALLEL4 */
122
123 /* If the severity is zero, this is an error. Otherwise insert that
124 many tabs before the message. */
125 if (!severity)
126 fprintf(f, "ERROR: ");
127 for (t = 0; t < severity; t++)
128 fprintf(f, "\t");
129
130 /* Print out the variable list of args with vprintf. */
131 va_start(argp, fmt);
132 vfprintf(f, fmt, argp);
133 va_end(argp);
134
135 /* Put on a final linefeed. */
136 fprintf(f, "\n");
137 fflush(f);
138}
139#endif /* LOGGING */
140
153int
154nc4_check_name(const char *name, char *norm_name)
155{
156 char *temp;
157 int retval;
158
159 assert(norm_name);
160
161 /* Check for NULL. */
162 if (!name)
163 return NC_EINVAL;
164
165 /* Make sure this is a valid netcdf name. This should be done
166 * before the name is normalized, because it gives better error
167 * codes for bad utf8 strings. */
168 if ((retval = NC_check_name(name)))
169 return retval;
170
171 /* Normalize the name. */
172 if ((retval = nc_utf8_normalize((const unsigned char *)name,
173 (unsigned char **)&temp)))
174 return retval;
175
176 /* Check length of normalized name. */
177 if (strlen(temp) > NC_MAX_NAME)
178 {
179 free(temp);
180 return NC_EMAXNAME;
181 }
182
183 /* Copy the normalized name. */
184 strcpy(norm_name, temp);
185 free(temp);
186
187 return NC_NOERR;
188}
189
210int
211nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata)
212{
213 NC *nc;
214 int ret;
215
216 /* Find NC pointer for this file. */
217 if ((ret = NC_check_id(ncid, &nc)))
218 return ret;
219
220 /* Add necessary structs to hold netcdf-4 file data. This is where
221 * the NC_FILE_INFO_T struct is allocated for the file. */
222 if ((ret = nc4_nc4f_list_add(nc, path, mode)))
223 return ret;
224
225 /* If the user wants a pointer to the NC_FILE_INFO_T, then provide
226 * it. */
227 if (dispatchdata)
228 *dispatchdata = nc->dispatchdata;
229
230 return NC_NOERR;
231}
232
246int
247nc4_file_change_ncid(int ncid, unsigned short new_ncid_index)
248{
249 NC *nc;
250 int ret;
251
252 LOG((2, "%s: ncid %d new_ncid_index %d", __func__, ncid, new_ncid_index));
253
254 /* Find NC pointer for this file. */
255 if ((ret = NC_check_id(ncid, &nc)))
256 return ret;
257
258 /* Move it in the list. It will faile if list spot is already
259 * occupied. */
260 LOG((3, "moving nc->ext_ncid %d nc->ext_ncid >> ID_SHIFT %d",
261 nc->ext_ncid, nc->ext_ncid >> ID_SHIFT));
262 if (NC4_move_in_NCList(nc, new_ncid_index))
263 return NC_EIO;
264 LOG((3, "moved to new_ncid_index %d new nc->ext_ncid %d", new_ncid_index,
265 nc->ext_ncid));
266
267 return NC_NOERR;
268}
269
289int
290nc4_file_list_get(int ncid, char **path, int *mode, void **dispatchdata)
291{
292 NC *nc;
293 int ret;
294
295 /* Find NC pointer for this file. */
296 if ((ret = NC_check_id(ncid, &nc)))
297 return ret;
298
299 /* If the user wants path, give it. */
300 if (path)
301 strncpy(*path, nc->path, NC_MAX_NAME);
302
303 /* If the user wants mode, give it. */
304 if (mode)
305 *mode = nc->mode;
306
307 /* If the user wants dispatchdata, give it. */
308 if (dispatchdata)
309 *dispatchdata = nc->dispatchdata;
310
311 return NC_NOERR;
312}
313
328int
329nc4_nc4f_list_add(NC *nc, const char *path, int mode)
330{
331 NC_FILE_INFO_T *h5;
332 int retval;
333
334 assert(nc && !NC4_DATA(nc) && path);
335
336 /* We need to malloc and initialize the substructure
337 NC_FILE_INFO_T. */
338 if (!(h5 = calloc(1, sizeof(NC_FILE_INFO_T))))
339 return NC_ENOMEM;
340 nc->dispatchdata = h5;
341 h5->controller = nc;
342
343 h5->hdr.sort = NCFIL;
344 h5->hdr.name = strdup(path);
345 h5->hdr.id = nc->ext_ncid;
346
347 /* Hang on to cmode, and note that we're in define mode. */
348 h5->cmode = mode | NC_INDEF;
349
350 /* The next_typeid needs to be set beyond the end of our atomic
351 * types. */
352 h5->next_typeid = NC_FIRSTUSERTYPEID;
353
354 /* Initialize lists for dimensions, types, and groups. */
355 h5->alldims = nclistnew();
356 h5->alltypes = nclistnew();
357 h5->allgroups = nclistnew();
358
359 /* There's always at least one open group - the root
360 * group. Allocate space for one group's worth of information. Set
361 * its grp id, name, and allocate associated empty lists. */
362 if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp)))
363 return retval;
364
365 return NC_NOERR;
366}
367
380int
381nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp)
382{
383 return nc4_find_nc_grp_h5(ncid, NULL, grp, NULL);
384}
385
401int
402nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
403{
404 return nc4_find_nc_grp_h5(ncid, NULL, grp, h5);
405}
406
421int
422nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grp, NC_FILE_INFO_T **h5)
423{
424 NC_GRP_INFO_T *my_grp = NULL;
425 NC_FILE_INFO_T *my_h5 = NULL;
426 NC *my_nc;
427 int retval;
428 size_t index;
429
430 /* Look up file metadata. */
431 if ((retval = NC_check_id(ncid, &my_nc)))
432 return retval;
433 my_h5 = my_nc->dispatchdata;
434 assert(my_h5 && my_h5->root_grp);
435
436 /* If we can't find it, the grp id part of ncid is bad. */
437 index = (ncid & GRP_ID_MASK);
438 if (!(my_grp = nclistget(my_h5->allgroups,index)))
439 return NC_EBADID;
440
441 /* Return pointers to caller, if desired. */
442 if (nc)
443 *nc = my_nc;
444 if (h5)
445 *h5 = my_h5;
446 if (grp)
447 *grp = my_grp;
448
449 return NC_NOERR;
450}
451
467int
468nc4_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, NC_GRP_INFO_T **grp,
469 NC_VAR_INFO_T **var)
470{
471 NC_FILE_INFO_T *my_h5;
472 NC_GRP_INFO_T *my_grp;
473 NC_VAR_INFO_T *my_var;
474 int retval;
475
476 /* Look up file and group metadata. */
477 if ((retval = nc4_find_grp_h5(ncid, &my_grp, &my_h5)))
478 return retval;
479 assert(my_grp && my_h5);
480
481 /* Find the var. */
482 if (!(my_var = (NC_VAR_INFO_T *)ncindexith(my_grp->vars, (size_t)varid)))
483 return NC_ENOTVAR;
484 assert(my_var && my_var->hdr.id == varid);
485
486 /* Return pointers that caller wants. */
487 if (h5)
488 *h5 = my_h5;
489 if (grp)
490 *grp = my_grp;
491 if (var)
492 *var = my_var;
493
494 return NC_NOERR;
495}
496
510int
511nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim,
512 NC_GRP_INFO_T **dim_grp)
513{
514 assert(grp && grp->nc4_info && dim);
515 LOG((4, "%s: dimid %d", __func__, dimid));
516
517 /* Find the dim info. */
518 if (!((*dim) = nclistget(grp->nc4_info->alldims, (size_t)dimid)))
519 return NC_EBADDIM;
520
521 /* Give the caller the group the dimension is in. */
522 if (dim_grp)
523 *dim_grp = (*dim)->container;
524
525 return NC_NOERR;
526}
527
538int
539nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
540{
541 assert(grp && var && name);
542
543 /* Find the var info. */
544 *var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
545 return NC_NOERR;
546}
547
557NC_TYPE_INFO_T *
558nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name)
559{
560 NC_GRP_INFO_T *g;
561 NC_TYPE_INFO_T *type, *res;
562
563 assert(start_grp);
564
565 /* Does this group have the type we are searching for? */
566 type = (NC_TYPE_INFO_T*)ncindexlookup(start_grp->type,name);
567 if(type != NULL)
568 return type;
569
570 /* Search subgroups. */
571 for(size_t i=0;i<ncindexsize(start_grp->children);i++) {
572 g = (NC_GRP_INFO_T*)ncindexith(start_grp->children,i);
573 if(g == NULL) continue;
574 if ((res = nc4_rec_find_named_type(g, name)))
575 return res;
576 }
577 /* Can't find it. Oh, woe is me! */
578 return NULL;
579}
580
592int
593nc4_find_type(const NC_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type)
594{
595 /* Check inputs. */
596 assert(h5);
597 if (typeid < 0 || !type)
598 return NC_EINVAL;
599 *type = NULL;
600
601 /* Atomic types don't have associated NC_TYPE_INFO_T struct, just
602 * return NOERR. */
603 if (typeid <= NC_STRING)
604 return NC_NOERR;
605
606 /* Find the type. */
607 if (!(*type = nclistget(h5->alltypes, (size_t)typeid)))
608 return NC_EBADTYPID;
609
610 return NC_NOERR;
611}
612
628int
629nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum,
630 NC_ATT_INFO_T **att)
631{
632 NC_VAR_INFO_T *var;
633 NC_ATT_INFO_T *my_att;
634 NCindex *attlist = NULL;
635
636 assert(grp && grp->hdr.name && att);
637
638 LOG((4, "%s: grp->name %s varid %d attnum %d", __func__, grp->hdr.name,
639 varid, attnum));
640
641 /* Get either the global or a variable attribute list. */
642 if (varid == NC_GLOBAL)
643 {
644 attlist = grp->att;
645 }
646 else
647 {
648 var = (NC_VAR_INFO_T*)ncindexith(grp->vars,(size_t)varid);
649 if (!var) return NC_ENOTVAR;
650
651 attlist = var->att;
652 }
653 assert(attlist);
654
655 /* Now find the attribute by name or number. If a name is provided,
656 * ignore the attnum. */
657 if (name)
658 my_att = (NC_ATT_INFO_T *)ncindexlookup(attlist, name);
659 else
660 my_att = (NC_ATT_INFO_T *)ncindexith(attlist, (size_t)attnum);
661
662 if (!my_att)
663 return NC_ENOTATT;
664
665 *att = my_att;
666 return NC_NOERR;
667}
668
685int
686nc4_find_nc_att(int ncid, int varid, const char *name, int attnum,
687 NC_ATT_INFO_T **att)
688{
689 NC_GRP_INFO_T *grp;
690 int retval;
691
692 LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d",
693 ncid, varid, name, attnum));
694
695 /* Find info for this file and group, and set pointer to each. */
696 if ((retval = nc4_find_grp_h5(ncid, &grp, NULL)))
697 return retval;
698 assert(grp);
699
700 return nc4_find_grp_att(grp, varid, name, attnum, att);
701}
702
711static void
712obj_track(NC_FILE_INFO_T* file, NC_OBJ* obj)
713{
714 NClist* list = NULL;
715 /* record the object in the file */
716 switch (obj->sort) {
717 case NCDIM: list = file->alldims; break;
718 case NCTYP: list = file->alltypes; break;
719 case NCGRP: list = file->allgroups; break;
720 default:
721 assert(NC_FALSE);
722 }
723 /* Insert at the appropriate point in the list */
724 nclistset(list,(size_t)obj->id,obj);
725}
726
739int
740nc4_var_list_add2(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var)
741{
742 NC_VAR_INFO_T *new_var = NULL;
743 NCglobalstate* gs = NC_getglobalstate();
744
745 /* Allocate storage for new variable. */
746 if (!(new_var = calloc(1, sizeof(NC_VAR_INFO_T))))
747 return NC_ENOMEM;
748 new_var->hdr.sort = NCVAR;
749 new_var->container = grp;
750
751 /* These are the HDF5-1.8.4 defaults. */
752 new_var->chunkcache.size = gs->chunkcache.size;
753 new_var->chunkcache.nelems = gs->chunkcache.nelems;
754 new_var->chunkcache.preemption = gs->chunkcache.preemption;
755
756 /* Now fill in the values in the var info structure. */
757 new_var->hdr.id = (int)ncindexsize(grp->vars);
758 if (!(new_var->hdr.name = strdup(name))) {
759 if(new_var)
760 free(new_var);
761 return NC_ENOMEM;
762 }
763
764 /* Create an indexed list for the attributes. */
765 new_var->att = ncindexnew(0);
766
767 /* Officially track it */
768 ncindexadd(grp->vars, (NC_OBJ *)new_var);
769
770 /* Set the var pointer, if one was given */
771 if (var)
772 *var = new_var;
773
774 return NC_NOERR;
775}
776
787int
788nc4_var_set_ndims(NC_VAR_INFO_T *var, int ndims)
789{
790 assert(var);
791
792 /* Remember the number of dimensions. */
793 var->ndims = (size_t)ndims;
794
795 /* Allocate space for dimension information. */
796 if (ndims)
797 {
798 if (!(var->dim = calloc((size_t)ndims, sizeof(NC_DIM_INFO_T *))))
799 return NC_ENOMEM;
800 if (!(var->dimids = calloc((size_t)ndims, sizeof(int))))
801 return NC_ENOMEM;
802
803 /* Initialize dimids to illegal values (-1). See the comment
804 in nc4_rec_match_dimscales(). */
805 memset(var->dimids, -1, (size_t)ndims * sizeof(int));
806 }
807
808 return NC_NOERR;
809}
810
823int
824nc4_var_list_add(NC_GRP_INFO_T* grp, const char* name, int ndims,
825 NC_VAR_INFO_T **var)
826{
827 int retval;
828
829 if ((retval = nc4_var_list_add2(grp, name, var)))
830 return retval;
831 if ((retval = nc4_var_set_ndims(*var, ndims)))
832 return retval;
833
834 return NC_NOERR;
835}
836
850int
851nc4_dim_list_add(NC_GRP_INFO_T *grp, const char *name, size_t len,
852 int assignedid, NC_DIM_INFO_T **dim)
853{
854 NC_DIM_INFO_T *new_dim = NULL;
855
856 assert(grp && name);
857
858 /* Allocate memory for dim metadata. */
859 if (!(new_dim = calloc(1, sizeof(NC_DIM_INFO_T))))
860 return NC_ENOMEM;
861
862 new_dim->hdr.sort = NCDIM;
863
864 /* Assign the dimension ID. */
865 if (assignedid >= 0)
866 new_dim->hdr.id = assignedid;
867 else
868 new_dim->hdr.id = grp->nc4_info->next_dimid++;
869
870 /* Remember the name and create a hash. */
871 if (!(new_dim->hdr.name = strdup(name))) {
872 if(new_dim)
873 free(new_dim);
874
875 return NC_ENOMEM;
876 }
877
878 /* Is dimension unlimited? */
879 new_dim->len = len;
880 if (len == NC_UNLIMITED)
881 new_dim->unlimited = NC_TRUE;
882
883 /* Remember the containing group. */
884 new_dim->container = grp;
885
886 /* Add object to dimension list for this group. */
887 ncindexadd(grp->dim, (NC_OBJ *)new_dim);
888 obj_track(grp->nc4_info, (NC_OBJ *)new_dim);
889
890 /* Set the dim pointer, if one was given */
891 if (dim)
892 *dim = new_dim;
893
894 return NC_NOERR;
895}
896
909int
910nc4_att_list_add(NCindex *list, const char *name, NC_ATT_INFO_T **att)
911{
912 NC_ATT_INFO_T *new_att = NULL;
913
914 LOG((3, "%s: name %s ", __func__, name));
915
916 if (!(new_att = calloc(1, sizeof(NC_ATT_INFO_T))))
917 return NC_ENOMEM;
918 new_att->hdr.sort = NCATT;
919
920 /* Fill in the information we know. */
921 new_att->hdr.id = (int)ncindexsize(list);
922 if (!(new_att->hdr.name = strdup(name))) {
923 if(new_att)
924 free(new_att);
925 return NC_ENOMEM;
926 }
927
928 /* Add object to list as specified by its number */
929 ncindexadd(list, (NC_OBJ *)new_att);
930
931 /* Set the attribute pointer, if one was given */
932 if (att)
933 *att = new_att;
934
935 return NC_NOERR;
936}
937
952int
953nc4_grp_list_add(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *parent, char *name,
954 NC_GRP_INFO_T **grp)
955{
956 NC_GRP_INFO_T *new_grp;
957
958 /* Check inputs. */
959 assert(h5 && name);
960 LOG((3, "%s: name %s ", __func__, name));
961
962 /* Get the memory to store this groups info. */
963 if (!(new_grp = calloc(1, sizeof(NC_GRP_INFO_T))))
964 return NC_ENOMEM;
965
966 /* Fill in this group's information. */
967 new_grp->hdr.sort = NCGRP;
968 new_grp->nc4_info = h5;
969 new_grp->parent = parent;
970
971 /* Assign the group ID. The root group will get id 0. */
972 new_grp->hdr.id = h5->next_nc_grpid++;
973 assert(parent || !new_grp->hdr.id);
974
975 /* Handle the group name. */
976 if (!(new_grp->hdr.name = strdup(name)))
977 {
978 free(new_grp);
979 return NC_ENOMEM;
980 }
981
982 /* Set up new indexed lists for stuff this group can contain. */
983 new_grp->children = ncindexnew(0);
984 new_grp->dim = ncindexnew(0);
985 new_grp->att = ncindexnew(0);
986 new_grp->type = ncindexnew(0);
987 new_grp->vars = ncindexnew(0);
988
989 /* Add object to lists */
990 if (parent)
991 ncindexadd(parent->children, (NC_OBJ *)new_grp);
992 obj_track(h5, (NC_OBJ *)new_grp);
993
994 /* Set the group pointer, if one was given */
995 if (grp)
996 *grp = new_grp;
997
998 return NC_NOERR;
999}
1000
1014int
1015nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name)
1016{
1017 NC_TYPE_INFO_T *type;
1018 NC_GRP_INFO_T *g;
1019 NC_VAR_INFO_T *var;
1020
1021 /* Any types of this name? */
1022 type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,name);
1023 if(type != NULL)
1024 return NC_ENAMEINUSE;
1025
1026 /* Any child groups of this name? */
1027 g = (NC_GRP_INFO_T*)ncindexlookup(grp->children,name);
1028 if(g != NULL)
1029 return NC_ENAMEINUSE;
1030
1031 /* Any variables of this name? */
1032 var = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,name);
1033 if(var != NULL)
1034 return NC_ENAMEINUSE;
1035
1036 return NC_NOERR;
1037}
1038
1052int
1053nc4_type_new(size_t size, const char *name, int assignedid,
1054 NC_TYPE_INFO_T **type)
1055{
1056 NC_TYPE_INFO_T *new_type;
1057
1058 LOG((4, "%s: size %d name %s assignedid %d", __func__, size, name, assignedid));
1059
1060 /* Check inputs. */
1061 assert(type);
1062
1063 /* Allocate memory for the type */
1064 if (!(new_type = calloc(1, sizeof(NC_TYPE_INFO_T))))
1065 return NC_ENOMEM;
1066 new_type->hdr.sort = NCTYP;
1067 new_type->hdr.id = assignedid;
1068
1069 /* Remember info about this type. */
1070 new_type->size = size;
1071 if (!(new_type->hdr.name = strdup(name))) {
1072 free(new_type);
1073 return NC_ENOMEM;
1074 }
1075
1076 /* Return a pointer to the new type. */
1077 *type = new_type;
1078
1079 return NC_NOERR;
1080}
1081
1095int
1096nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name,
1097 NC_TYPE_INFO_T **type)
1098{
1099 NC_TYPE_INFO_T *new_type;
1100 int retval;
1101
1102 /* Check inputs. */
1103 assert(grp && name && type);
1104 LOG((4, "%s: size %d name %s", __func__, size, name));
1105
1106 /* Create the new TYPE_INFO struct. */
1107 if ((retval = nc4_type_new(size, name, grp->nc4_info->next_typeid,
1108 &new_type)))
1109 return retval;
1110 grp->nc4_info->next_typeid++;
1111
1112 /* Increment the ref. count on the type */
1113 new_type->rc++;
1114
1115 /* Add object to lists */
1116 ncindexadd(grp->type, (NC_OBJ *)new_type);
1117 obj_track(grp->nc4_info,(NC_OBJ*)new_type);
1118
1119 /* back link */
1120 new_type->container = grp;
1121
1122 /* Return a pointer to the new type. */
1123 *type = new_type;
1124
1125 return NC_NOERR;
1126}
1127
1141int
1142nc4_field_list_add(NC_TYPE_INFO_T *parent, const char *name,
1143 size_t offset, nc_type xtype, int ndims,
1144 const int *dim_sizesp)
1145{
1146 NC_FIELD_INFO_T *field;
1147
1148 /* Name has already been checked and UTF8 normalized. */
1149 if (!name)
1150 return NC_EINVAL;
1151
1152 /* Allocate storage for this field information. */
1153 if (!(field = calloc(1, sizeof(NC_FIELD_INFO_T))))
1154 return NC_ENOMEM;
1155 field->hdr.sort = NCFLD;
1156
1157 /* Store the information about this field. */
1158 if (!(field->hdr.name = strdup(name)))
1159 {
1160 free(field);
1161 return NC_ENOMEM;
1162 }
1163 field->nc_typeid = xtype;
1164 field->offset = offset;
1165 field->ndims = ndims;
1166 if (ndims)
1167 {
1168 int i;
1169 if (!(field->dim_size = malloc((size_t)ndims * sizeof(int))))
1170 {
1171 free(field->hdr.name);
1172 free(field);
1173 return NC_ENOMEM;
1174 }
1175 for (i = 0; i < ndims; i++)
1176 field->dim_size[i] = dim_sizesp[i];
1177 }
1178
1179 /* Add object to lists */
1180 field->hdr.id = (int)nclistlength(parent->u.c.field);
1181 nclistpush(parent->u.c.field,field);
1182
1183 return NC_NOERR;
1184}
1185
1198int
1199nc4_enum_member_add(NC_TYPE_INFO_T *parent, size_t size,
1200 const char *name, const void *value)
1201{
1202 NC_ENUM_MEMBER_INFO_T *member;
1203
1204 /* Name has already been checked. */
1205 assert(name && size > 0 && value);
1206 LOG((4, "%s: size %d name %s", __func__, size, name));
1207
1208 /* Allocate storage for this field information. */
1209 if (!(member = calloc(1, sizeof(NC_ENUM_MEMBER_INFO_T))))
1210 return NC_ENOMEM;
1211 if (!(member->value = malloc(size))) {
1212 free(member);
1213 return NC_ENOMEM;
1214 }
1215 if (!(member->name = strdup(name))) {
1216 free(member->value);
1217 free(member);
1218 return NC_ENOMEM;
1219 }
1220
1221 /* Store the value for this member. */
1222 memcpy(member->value, value, size);
1223
1224 /* Add object to list */
1225 nclistpush(parent->u.e.enum_member,member);
1226
1227 return NC_NOERR;
1228}
1229
1237static void
1238field_free(NC_FIELD_INFO_T *field)
1239{
1240 /* Free some stuff. */
1241 if (field->hdr.name)
1242 free(field->hdr.name);
1243 if (field->dim_size)
1244 free(field->dim_size);
1245
1246 /* Nc_Free the memory. */
1247 free(field);
1248}
1249
1259int
1260nc4_type_free(NC_TYPE_INFO_T *type)
1261{
1262 size_t i;
1263
1264 assert(type && type->rc && type->hdr.name);
1265
1266 /* Decrement the ref. count on the type */
1267 type->rc--;
1268
1269 /* Release the type, if the ref. count drops to zero */
1270 if (type->rc == 0)
1271 {
1272 LOG((4, "%s: deleting type %s", __func__, type->hdr.name));
1273
1274 /* Free the name. */
1275 free(type->hdr.name);
1276
1277 /* Enums and compound types have lists of fields to clean up. */
1278 switch (type->nc_type_class)
1279 {
1280 case NC_COMPOUND:
1281 {
1282 NC_FIELD_INFO_T *field;
1283
1284 /* Delete all the fields in this type (there will be some if its a
1285 * compound). */
1286 for(i=0;i<nclistlength(type->u.c.field);i++) {
1287 field = nclistget(type->u.c.field,i);
1288 field_free(field);
1289 }
1290 nclistfree(type->u.c.field);
1291 }
1292 break;
1293
1294 case NC_ENUM:
1295 {
1296 NC_ENUM_MEMBER_INFO_T *enum_member;
1297
1298 /* Delete all the enum_members, if any. */
1299 for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1300 enum_member = nclistget(type->u.e.enum_member,i);
1301 free(enum_member->value);
1302 free(enum_member->name);
1303 free(enum_member);
1304 }
1305 nclistfree(type->u.e.enum_member);
1306 }
1307 break;
1308
1309 default:
1310 break;
1311 }
1312
1313 /* Release the memory. */
1314 free(type);
1315 }
1316
1317 return NC_NOERR;
1318}
1319
1328int
1329nc4_att_free(NC_ATT_INFO_T *att)
1330{
1331 int stat = NC_NOERR;
1332
1333 assert(att);
1334 LOG((3, "%s: name %s ", __func__, att->hdr.name));
1335
1336 /* Free the name. */
1337 if (att->hdr.name)
1338 free(att->hdr.name);
1339
1340 if (att->data) {
1341 NC_OBJ* parent;
1342 NC_FILE_INFO_T* h5 = NULL;
1343
1344 /* Locate relevant objects */
1345 parent = att->container;
1346 if(parent->sort == NCVAR) parent = (NC_OBJ*)(((NC_VAR_INFO_T*)parent)->container);
1347 assert(parent->sort == NCGRP);
1348 h5 = ((NC_GRP_INFO_T*)parent)->nc4_info;
1349 /* Reclaim the attribute data */
1350 if((stat = NC_reclaim_data(h5->controller,att->nc_typeid,att->data,att->len))) goto done;
1351 free(att->data); /* reclaim top level */
1352 att->data = NULL;
1353 }
1354
1355done:
1356 free(att);
1357 return stat;
1358}
1359
1369static int
1370var_free(NC_VAR_INFO_T *var)
1371{
1372 int retval;
1373
1374 assert(var);
1375 LOG((4, "%s: deleting var %s", __func__, var->hdr.name));
1376
1377 /* First delete all the attributes attached to this var. */
1378 for (size_t i = 0; i < ncindexsize(var->att); i++)
1379 if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(var->att, i))))
1380 return retval;
1381 ncindexfree(var->att);
1382
1383 /* Free some things that may be allocated. */
1384 if (var->chunksizes)
1385 free(var->chunksizes);
1386
1387 if (var->alt_name)
1388 free(var->alt_name);
1389
1390 if (var->dimids)
1391 free(var->dimids);
1392
1393 if (var->dim)
1394 free(var->dim);
1395
1396 /* Delete any fill value allocation. */
1397 if (var->fill_value) {
1398 int tid = var->type_info->hdr.id;
1399 if((retval = NC_reclaim_data_all(var->container->nc4_info->controller, tid, var->fill_value, 1))) return retval;
1400 var->fill_value = NULL;
1401 }
1402
1403 /* Release type information */
1404 if (var->type_info)
1405 if ((retval = nc4_type_free(var->type_info)))
1406 return retval;
1407
1408 /* Do this last because debugging may need it */
1409 if (var->hdr.name)
1410 free(var->hdr.name);
1411
1412 /* Delete the var. */
1413 free(var);
1414
1415 return NC_NOERR;
1416}
1417
1427int
1428nc4_var_list_del(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1429{
1430 int i;
1431
1432 assert(var && grp);
1433
1434 /* Remove from lists */
1435 i = ncindexfind(grp->vars, (NC_OBJ *)var);
1436 if (i >= 0)
1437 ncindexidel(grp->vars, (size_t)i);
1438
1439 return var_free(var);
1440}
1441
1450static int
1451dim_free(NC_DIM_INFO_T *dim)
1452{
1453 assert(dim);
1454 LOG((4, "%s: deleting dim %s", __func__, dim->hdr.name));
1455
1456 /* Free memory allocated for names. */
1457 if (dim->hdr.name)
1458 free(dim->hdr.name);
1459
1460 free(dim);
1461 return NC_NOERR;
1462}
1463
1473int
1474nc4_dim_list_del(NC_GRP_INFO_T *grp, NC_DIM_INFO_T *dim)
1475{
1476 if (grp && dim)
1477 {
1478 int pos = ncindexfind(grp->dim, (NC_OBJ *)dim);
1479 if(pos >= 0)
1480 ncindexidel(grp->dim, (size_t)pos);
1481 }
1482
1483 return dim_free(dim);
1484}
1485
1495int
1496nc4_rec_grp_del(NC_GRP_INFO_T *grp)
1497{
1498 int retval;
1499
1500 assert(grp);
1501 LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1502
1503 /* Recursively call this function for each child, if any, stopping
1504 * if there is an error. */
1505 for (size_t i = 0; i < ncindexsize(grp->children); i++)
1506 if ((retval = nc4_rec_grp_del((NC_GRP_INFO_T *)ncindexith(grp->children,
1507 i))))
1508 return retval;
1509 ncindexfree(grp->children);
1510
1511 /* Free attributes */
1512 for (size_t i = 0; i < ncindexsize(grp->att); i++)
1513 if ((retval = nc4_att_free((NC_ATT_INFO_T *)ncindexith(grp->att, i))))
1514 return retval;
1515 ncindexfree(grp->att);
1516
1517 /* Delete all vars. */
1518 for (size_t i = 0; i < ncindexsize(grp->vars); i++) {
1519 NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1520 if ((retval = var_free(v)))
1521 return retval;
1522 }
1523 ncindexfree(grp->vars);
1524
1525 /* Delete all dims, and free the list of dims. */
1526 for (size_t i = 0; i < ncindexsize(grp->dim); i++)
1527 if ((retval = dim_free((NC_DIM_INFO_T *)ncindexith(grp->dim, i))))
1528 return retval;
1529 ncindexfree(grp->dim);
1530
1531 /* Delete all types. */
1532 for (size_t i = 0; i < ncindexsize(grp->type); i++)
1533 if ((retval = nc4_type_free((NC_TYPE_INFO_T *)ncindexith(grp->type, i))))
1534 return retval;
1535 ncindexfree(grp->type);
1536
1537 /* Free the name. */
1538 free(grp->hdr.name);
1539
1540 /* Free up this group */
1541 free(grp);
1542
1543 return NC_NOERR;
1544}
1545
1555int
1556nc4_rec_grp_del_att_data(NC_GRP_INFO_T *grp)
1557{
1558 int retval;
1559
1560 assert(grp);
1561 LOG((3, "%s: grp->name %s", __func__, grp->hdr.name));
1562
1563 /* Recursively call this function for each child, if any, stopping
1564 * if there is an error. */
1565 for (size_t i = 0; i < ncindexsize(grp->children); i++)
1566 if ((retval = nc4_rec_grp_del_att_data((NC_GRP_INFO_T *)ncindexith(grp->children, i))))
1567 return retval;
1568
1569 /* Free attribute data in this group */
1570 for (size_t i = 0; i < ncindexsize(grp->att); i++) {
1571 NC_ATT_INFO_T * att = (NC_ATT_INFO_T*)ncindexith(grp->att, i);
1572 if((retval = NC_reclaim_data_all(grp->nc4_info->controller,att->nc_typeid,att->data,att->len)))
1573 return retval;
1574 att->data = NULL;
1575 att->len = 0;
1576 att->dirty = 0;
1577 }
1578
1579 /* Delete att data from all contained vars in this group */
1580 for (size_t i = 0; i < ncindexsize(grp->vars); i++) {
1581 NC_VAR_INFO_T* v = (NC_VAR_INFO_T *)ncindexith(grp->vars, i);
1582 for(size_t j=0;j<ncindexsize(v->att);j++) {
1583 NC_ATT_INFO_T* att = (NC_ATT_INFO_T*)ncindexith(v->att, j);
1584 if((retval = NC_reclaim_data_all(grp->nc4_info->controller,att->nc_typeid,att->data,att->len)))
1585 return retval;
1586 att->data = NULL;
1587 att->len = 0;
1588 att->dirty = 0;
1589 }
1590 }
1591
1592 return NC_NOERR;
1593}
1594
1605int
1606nc4_att_list_del(NCindex *list, NC_ATT_INFO_T *att)
1607{
1608 assert(att && list);
1609 ncindexidel(list, (size_t)((NC_OBJ *)att)->id);
1610 return nc4_att_free(att);
1611}
1612
1626int
1627nc4_file_list_del(int ncid)
1628{
1629 NC_FILE_INFO_T *h5;
1630 int retval;
1631
1632 /* Find our metadata for this file. */
1633 if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
1634 return retval;
1635 assert(h5);
1636
1637 /* Delete the file resources. */
1638 if ((retval = nc4_nc4f_list_del(h5)))
1639 return retval;
1640
1641 return NC_NOERR;
1642}
1643
1653int
1654nc4_nc4f_list_del(NC_FILE_INFO_T *h5)
1655{
1656 int retval;
1657
1658 assert(h5);
1659
1660 /* Order is important here. We must delete the attribute contents
1661 before deleteing any metadata because nc_reclaim_data depends
1662 on the existence of the type info.
1663 */
1664
1665 /* Delete all the attribute data contents in each group and variable. */
1666 if ((retval = nc4_rec_grp_del_att_data(h5->root_grp)))
1667 return retval;
1668
1669 /* Delete all the list contents for vars, dims, and atts, in each
1670 * group. */
1671 if ((retval = nc4_rec_grp_del(h5->root_grp)))
1672 return retval;
1673
1674 /* Cleanup these (extra) lists of all dims, groups, and types. */
1675 nclistfree(h5->alldims);
1676 nclistfree(h5->allgroups);
1677 nclistfree(h5->alltypes);
1678
1679 /* Free the NC_FILE_INFO_T struct. */
1680 nullfree(h5->hdr.name);
1681 free(h5);
1682
1683 return NC_NOERR;
1684}
1685
1699int
1700nc4_normalize_name(const char *name, char *norm_name)
1701{
1702 char *temp_name;
1703 int stat = nc_utf8_normalize((const unsigned char *)name,(unsigned char **)&temp_name);
1704 if(stat != NC_NOERR)
1705 return stat;
1706 if (strlen(temp_name) > NC_MAX_NAME)
1707 {
1708 free(temp_name);
1709 return NC_EMAXNAME;
1710 }
1711 strcpy(norm_name, temp_name);
1712 free(temp_name);
1713 return NC_NOERR;
1714}
1715
1716#ifdef NETCDF_ENABLE_SET_LOG_LEVEL
1717
1724int
1725nc4_init_logging(void)
1726{
1727 int ret = NC_NOERR;
1728
1729#if LOGGING
1730#if NC_HAS_PARALLEL4
1731 if (!LOG_FILE && nc_log_level >= 0)
1732 {
1733 char log_filename[NC_MAX_NAME];
1734 int my_rank = 0;
1735 int mpierr;
1736 int mpi_initialized;
1737
1738 /* If MPI has been initialized find the rank. */
1739 if ((mpierr = MPI_Initialized(&mpi_initialized)))
1740 return NC_EMPI;
1741 if (mpi_initialized)
1742 {
1743 if ((mpierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_rank)))
1744 return NC_EMPI;
1745 }
1746
1747 /* Create a filename with the rank in it. */
1748 snprintf(log_filename, sizeof(log_filename), "nc4_log_%d.log", my_rank);
1749
1750 /* Open a file for this rank to log messages. */
1751 if (!(LOG_FILE = fopen(log_filename, "w")))
1752 return NC_EINTERNAL;
1753 }
1754#endif /* NC_HAS_PARALLEL4 */
1755#endif /* LOGGING */
1756
1757 return ret;
1758}
1759
1766void
1767nc4_finalize_logging(void)
1768{
1769#if LOGGING
1770#if NC_HAS_PARALLEL4
1771 if (LOG_FILE)
1772 {
1773 fclose(LOG_FILE);
1774 LOG_FILE = NULL;
1775 }
1776#endif /* NC_HAS_PARALLEL4 */
1777#endif /* LOGGING */
1778}
1779
1793int
1794nc_set_log_level(int new_level)
1795{
1796#if LOGGING
1797 /* Remember the new level. */
1798 nc_log_level = new_level;
1799
1800#if NC_HAS_PARALLEL4
1801 /* For parallel I/O builds, call the log init/finalize functions
1802 * as needed, to open and close the log files. */
1803 if (new_level >= 0)
1804 {
1805 if (!LOG_FILE)
1806 nc4_init_logging();
1807 }
1808 else
1809 nc4_finalize_logging();
1810#endif /* NC_HAS_PARALLEL4 */
1811
1812 LOG((1, "log_level changed to %d", nc_log_level));
1813#endif /* LOGGING */
1814
1815 return NC_NOERR;
1816}
1817#endif /* NETCDF_ENABLE_SET_LOG_LEVEL */
1818
1819#if LOGGING
1820#define MAX_NESTS 10
1830static int
1831rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count)
1832{
1833 NC_ATT_INFO_T *att;
1834 NC_VAR_INFO_T *var;
1835 NC_DIM_INFO_T *dim;
1836 NC_TYPE_INFO_T *type;
1837 NC_FIELD_INFO_T *field;
1838 char tabs[MAX_NESTS+1] = "";
1839 char temp_string[10];
1840 int t, retval, d, i;
1841
1842 /* Come up with a number of tabs relative to the group. */
1843 for (t = 0; t < tab_count && t < MAX_NESTS; t++)
1844 tabs[t] = '\t';
1845 tabs[t] = '\0';
1846
1847 LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d",
1848 tabs, grp->hdr.name, grp->hdr.id, ncindexsize(grp->vars), ncindexsize(grp->att)));
1849
1850 for (i = 0; i < ncindexsize(grp->att); i++)
1851 {
1852 att = (NC_ATT_INFO_T *)ncindexith(grp->att, i);
1853 assert(att);
1854 LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1855 tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1856 }
1857
1858 for (i = 0; i < ncindexsize(grp->dim); i++)
1859 {
1860 dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1861 assert(dim);
1862 LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d",
1863 tabs, dim->hdr.id, dim->hdr.name, dim->len, dim->unlimited));
1864 }
1865
1866 for (i = 0; i < ncindexsize(grp->vars); i++)
1867 {
1868 int j;
1869 char storage_str[NC_MAX_NAME] = "";
1870 char *dims_string = NULL;
1871
1872 var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1873 assert(var);
1874 if (var->ndims > 0)
1875 {
1876 if (!(dims_string = malloc(sizeof(char) * var->ndims * 4)))
1877 return NC_ENOMEM;
1878 strcpy(dims_string, "");
1879 for (d = 0; d < var->ndims; d++)
1880 {
1881 snprintf(temp_string, sizeof(temp_string), " %d", var->dimids[d]);
1882 strcat(dims_string, temp_string);
1883 }
1884 }
1885 if (!var->meta_read)
1886 strcat(storage_str, "unknown");
1887 else if (var->storage == NC_CONTIGUOUS)
1888 strcat(storage_str, "contiguous");
1889 else if (var->storage == NC_COMPACT)
1890 strcat(storage_str, "compact");
1891 else if (var->storage == NC_CHUNKED)
1892 strcat(storage_str, "chunked");
1893 else if (var->storage == NC_VIRTUAL)
1894 strcat(storage_str, "virtual");
1895 else
1896 strcat(storage_str, "unknown");
1897 LOG((2, "%s VARIABLE - varid: %d name: %s ndims: %d "
1898 "dimids:%s storage: %s", tabs, var->hdr.id, var->hdr.name,
1899 var->ndims,
1900 (dims_string ? dims_string : " -"), storage_str));
1901 for (j = 0; j < ncindexsize(var->att); j++)
1902 {
1903 att = (NC_ATT_INFO_T *)ncindexith(var->att, j);
1904 assert(att);
1905 LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
1906 tabs, att->hdr.id, att->hdr.name, att->nc_typeid, att->len));
1907 }
1908 if (dims_string)
1909 free(dims_string);
1910 }
1911
1912 for (i = 0; i < ncindexsize(grp->type); i++)
1913 {
1914 type = (NC_TYPE_INFO_T*)ncindexith(grp->type, i);
1915 assert(type);
1916 LOG((2, "%s TYPE - nc_typeid: %d size: %d committed: %d name: %s",
1917 tabs, type->hdr.id, type->size, (int)type->committed, type->hdr.name));
1918 /* Is this a compound type? */
1919 if (type->nc_type_class == NC_COMPOUND)
1920 {
1921 int j;
1922 LOG((3, "compound type"));
1923 for (j = 0; j < nclistlength(type->u.c.field); j++)
1924 {
1925 field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, j);
1926 LOG((4, "field %s offset %d nctype %d ndims %d", field->hdr.name,
1927 field->offset, field->nc_typeid, field->ndims));
1928 }
1929 }
1930 else if (type->nc_type_class == NC_VLEN)
1931 {
1932 LOG((3, "VLEN type"));
1933 LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid));
1934 }
1935 else if (type->nc_type_class == NC_OPAQUE)
1936 LOG((3, "Opaque type"));
1937 else if (type->nc_type_class == NC_ENUM)
1938 {
1939 LOG((3, "Enum type"));
1940 LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid));
1941 }
1942 else
1943 {
1944 LOG((0, "Unknown class: %d", type->nc_type_class));
1945 return NC_EBADTYPE;
1946 }
1947 }
1948
1949 /* Call self for each child of this group. */
1950 for (i = 0; i < ncindexsize(grp->children); i++)
1951 if ((retval = rec_print_metadata((NC_GRP_INFO_T *)ncindexith(grp->children, i),
1952 tab_count + 1)))
1953 return retval;
1954
1955 return NC_NOERR;
1956}
1957
1968int
1969log_metadata_nc(NC_FILE_INFO_T *h5)
1970{
1971 LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x",
1972 h5->root_grp->nc4_info->controller->int_ncid,
1973 h5->root_grp->nc4_info->controller->ext_ncid));
1974 if (!h5)
1975 {
1976 LOG((2, "This is a netCDF-3 file."));
1977 return NC_NOERR;
1978 }
1979 LOG((2, "FILE - path: %s cmode: 0x%x parallel: %d redef: %d "
1980 "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->root_grp->nc4_info->controller->path,
1981 h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write,
1982 h5->next_nc_grpid));
1983 if(nc_log_level >= 2)
1984 return rec_print_metadata(h5->root_grp, 0);
1985 return NC_NOERR;
1986}
1987
1988#endif /*LOGGING */
1989
2001int
2002NC4_show_metadata(int ncid)
2003{
2004 int retval = NC_NOERR;
2005#if LOGGING
2006 NC_FILE_INFO_T *h5;
2007 int old_log_level = nc_log_level;
2008
2009 /* Find file metadata. */
2010 if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
2011 return retval;
2012
2013 /* Log level must be 2 to see metadata. */
2014 nc_log_level = 2;
2015 retval = log_metadata_nc(h5);
2016 nc_log_level = old_log_level;
2017#endif /*LOGGING*/
2018 return retval;
2019}
2020
2028const NC_reservedatt*
2029NC_findreserved(const char* name)
2030{
2031#if 0
2032 int n = NRESERVED;
2033 int L = 0;
2034 int R = (n - 1);
2035
2036 for(;;) {
2037 if(L > R) break;
2038 int m = (L + R) / 2;
2039 const NC_reservedatt* p = &NC_reserved[m];
2040 int cmp = strcmp(p->name,name);
2041 if(cmp == 0) return p;
2042 if(cmp < 0)
2043 L = (m + 1);
2044 else /*cmp > 0*/
2045 R = (m - 1);
2046 }
2047 return NULL;
2048#else
2049 return (const NC_reservedatt*)bsearch(name,NC_reserved,NRESERVED,sizeof(NC_reservedatt),bincmp);
2050#endif
2051}
2052
2053/* Ed Hartness requires this function */
2054static int
2055NC4_move_in_NCList(NC* nc, int new_id)
2056{
2057 int stat = move_in_NCList(nc,new_id);
2058 if(stat == NC_NOERR) {
2059 /* Synchronize header */
2060 if(nc->dispatchdata)
2061 ((NC_OBJ*)nc->dispatchdata)->id = nc->ext_ncid;
2062 }
2063 return stat;
2064}
2065
2066static int
2067sortcmp(const void* arg1, const void* arg2)
2068{
2069 NC_reservedatt* r1 = (NC_reservedatt*)arg1;
2070 NC_reservedatt* r2 = (NC_reservedatt*)arg2;
2071 return strcmp(r1->name,r2->name);
2072}
2073
2074static int
2075bincmp(const void* arg1, const void* arg2)
2076{
2077 const char* name = (const char*)arg1;
2078 NC_reservedatt* ra = (NC_reservedatt*)arg2;
2079 return strcmp(name,ra->name);
2080}
2081
2082void
2083NC_initialize_reserved(void)
2084{
2085 /* Guarantee the reserved attribute list is sorted */
2086 qsort((void*)NC_reserved,NRESERVED,sizeof(NC_reservedatt),sortcmp);
2087}
Main header file for the C API.
#define NC_UNLIMITED
Size argument to nc_def_dim() for an unlimited dimension.
Definition netcdf.h:261
#define NC_EBADTYPE
Not a netcdf data type.
Definition netcdf.h:420
#define NC_VIRTUAL
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:318
#define NC_VLEN
vlen (variable-length) types
Definition netcdf.h:53
#define NC_ENAMEINUSE
String match to name in use.
Definition netcdf.h:417
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition netcdf.h:458
#define NC_COMPOUND
compound types
Definition netcdf.h:56
#define NC_EINTERNAL
NetCDF Library Internal Error.
Definition netcdf.h:484
#define NC_CHUNKED
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:314
#define NC_ENUM
enum types
Definition netcdf.h:55
#define NC_CONTIGUOUS
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:315
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition netcdf.h:264
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition netcdf.h:436
#define NC_ENOTATT
Attribute not found.
Definition netcdf.h:418
#define NC_COMPACT
In HDF5 files you can set storage for each variable to be either contiguous or chunked,...
Definition netcdf.h:316
#define NC_ENOTVAR
Variable not found.
Definition netcdf.h:432
#define NC_EINVAL
Invalid Argument.
Definition netcdf.h:388
#define NC_MAX_NAME
Maximum for classic library.
Definition netcdf.h:291
#define NC_NOERR
No Error.
Definition netcdf.h:378
#define NC_EMPI
MPI operation failed.
Definition netcdf.h:521
#define NC_OPAQUE
opaque types
Definition netcdf.h:54
#define NC_EIO
Generic IO error.
Definition netcdf.h:467
#define NC_STRING
string
Definition netcdf.h:47
#define NC_EBADID
Not a netcdf id.
Definition netcdf.h:385
#define NC_EBADTYPID
Bad type ID.
Definition netcdf.h:507
#define NC_EBADDIM
Invalid dimension id or name.
Definition netcdf.h:421
int nc_type
The nc_type type is just an int.
Definition netcdf.h:25