source: XIOS/trunk/extern/src_netcdf4/nc4grp.c @ 409

Last change on this file since 409 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 10.8 KB
Line 
1/*
2This file is part of netcdf-4, a netCDF-like interface for HDF5, or a
3HDF5 backend for netCDF, depending on your point of view.
4
5This file handles the nc4 groups.
6
7Copyright 2005, University Corporation for Atmospheric Research. See
8netcdf-4/docs/COPYRIGHT file for copying and redistribution
9conditions.
10
11$Id: nc4grp.c,v 1.44 2010/05/25 17:54:23 dmh Exp $
12*/
13
14#include "nc4internal.h"
15#include "nc4dispatch.h"
16
17/* Create a group. It's ncid is returned in the new_ncid pointer. */
18int
19NC4_def_grp(int parent_ncid, const char *name, int *new_ncid)
20{
21   NC_GRP_INFO_T *grp, *g;
22   NC_HDF5_FILE_INFO_T *h5;
23   char norm_name[NC_MAX_NAME + 1];
24   int retval;
25
26   LOG((2, "nc_def_grp: parent_ncid 0x%x name %s", parent_ncid, name));
27
28   /* Find info for this file and group, and set pointer to each. */
29   if ((retval = nc4_find_grp_h5(parent_ncid, &grp, &h5)))
30      return retval;
31   if (!h5)
32      return NC_ENOTNC4;
33
34   /* Check and normalize the name. */
35   if ((retval = nc4_check_name(name, norm_name)))
36      return retval;
37
38   /* Check that this name is not in use as a var, grp, or type. */
39   if ((retval = nc4_check_dup_name(grp, norm_name)))
40      return retval;
41
42   /* No groups in netcdf-3! */
43   if (h5->cmode & NC_CLASSIC_MODEL)
44      return NC_ESTRICTNC3;
45
46   /* If it's not in define mode, switch to define mode. */
47   if (!(h5->flags & NC_INDEF))
48      if ((retval = NC4_redef(parent_ncid)))
49         return retval;
50
51   /* Update internal lists to reflect new group. The actual HDF5
52    * group creation will be done when metadata is written by a
53    * sync. */
54   if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid, 
55                                  grp, grp->file, norm_name, &g)))
56      return retval;
57   if (new_ncid)
58      *new_ncid = grp->file->ext_ncid | h5->next_nc_grpid;
59   h5->next_nc_grpid++;
60   
61   return NC_NOERR;
62}
63
64/* Given an ncid and group name (NULL gets root group), return
65 * the ncid of that group. */
66int
67NC4_inq_ncid(int ncid, const char *name, int *grp_ncid)
68{
69   NC_GRP_INFO_T *grp, *g;
70   NC_HDF5_FILE_INFO_T *h5;
71   char norm_name[NC_MAX_NAME + 1];
72   int retval;
73
74   LOG((2, "nc_inq_ncid: ncid 0x%x name %s", ncid, name));
75   
76   /* Find info for this file and group, and set pointer to each. */
77   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
78      return retval;
79
80   /* Groups only work with netCDF-4/HDF5 files... */
81   if (!h5)
82      return NC_ENOTNC4;
83
84   /* Normalize name. */
85   if ((retval = nc4_normalize_name(name, norm_name)))
86      return retval;
87
88   /* Look through groups for one of this name. */
89   for (g = grp->children; g; g = g->next)
90      if (!strcmp(norm_name, g->name)) /* found it! */
91      {
92         if (grp_ncid)
93            *grp_ncid = grp->file->ext_ncid | g->nc_grpid;
94         return NC_NOERR;
95      }
96   
97   /* If we got here, we didn't find the named group. */
98   return NC_ENOGRP;
99}
100
101/* Given a location id, return the number of groups it contains, and
102 * an array of their locids. */
103int
104NC4_inq_grps(int ncid, int *numgrps, int *ncids)
105{
106   NC_GRP_INFO_T *grp, *g;
107   NC_HDF5_FILE_INFO_T *h5;
108   int num = 0;
109   int retval;
110
111   LOG((2, "nc_inq_grps: ncid 0x%x", ncid));
112
113   /* Find info for this file and group, and set pointer to each. */
114   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
115      return retval;
116
117   /* For netCDF-3 files, just report zero groups. */
118   if (!h5)
119   {
120      if (numgrps)
121         *numgrps = 0;
122      return NC_NOERR;
123   }
124
125   /* Count the number of groups in this group. */
126   for (g = grp->children; g; g = g->next)
127   {
128      if (ncids)
129      {
130         /* Combine the nc_grpid in a bitwise or with the ext_ncid,
131          * which allows the returned ncid to carry both file and
132          * group information. */
133         *ncids = g->nc_grpid | g->file->ext_ncid;
134         ncids++;
135      }
136      num++;
137   }
138   
139   if (numgrps)
140      *numgrps = num;
141
142   return NC_NOERR;
143}
144
145/* Given locid, find name of group. (Root group is named "/".) */
146int
147NC4_inq_grpname(int ncid, char *name)
148{
149   NC_GRP_INFO_T *grp;
150   NC_HDF5_FILE_INFO_T *h5;
151   int retval;
152
153   LOG((2, "nc_inq_grpname: ncid 0x%x", ncid));
154
155   /* Find info for this file and group, and set pointer to each. */
156   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
157      return retval;
158   if (name)
159   {
160      if (!h5)
161         strcpy(name, "/");
162      else
163         strcpy(name, grp->name);
164   }
165
166   return NC_NOERR;
167}
168
169/* Find the full path name to the group represented by ncid. Either
170 * pointer argument may be NULL; pass a NULL for the third parameter
171 * to get the length of the full path name. The length will not
172 * include room for a null pointer. */
173int
174NC4_inq_grpname_full(int ncid, size_t *lenp, char *full_name)
175{
176   char *name, grp_name[NC_MAX_NAME + 1];
177   int g, id = ncid, parent_id, *gid;
178   int i, ret = NC_NOERR;
179
180   /* How many generations? */
181   for (g = 0; !nc_inq_grp_parent(id, &parent_id); g++, id = parent_id)
182      ;
183
184   /* Allocate storage. */
185   if (!(name = malloc((g + 1) * (NC_MAX_NAME + 1) + 1)))
186      return NC_ENOMEM;
187   if (!(gid = malloc((g + 1) * sizeof(int))))
188   {
189      free(name);
190      return NC_ENOMEM;
191   }
192   assert(name && gid);
193
194   /* Always start with a "/" for the root group. */
195   strcpy(name, "/");
196
197   /* Get the ncids for all generations. */
198   gid[0] = ncid;
199   for (i = 1; i < g && !ret; i++)
200      ret = nc_inq_grp_parent(gid[i - 1], &gid[i]);
201
202   /* Assemble the full name. */
203   for (i = g - 1; !ret && i >= 0 && !ret; i--)
204   {
205      if ((ret = nc_inq_grpname(gid[i], grp_name)))
206         break;
207      strcat(name, grp_name);
208      if (i)
209         strcat(name, "/");
210   }
211
212   /* Give the user the length of the name, if he wants it. */
213   if (!ret && lenp)
214      *lenp = strlen(name);
215
216   /* Give the user the name, if he wants it. */
217   if (!ret && full_name)
218      strcpy(full_name, name);
219
220   free(gid);
221   free(name);
222
223   return ret;
224}
225
226/* Find the parent ncid of a group. For the root group, return
227 * NC_ENOGRP error.  *Now* I know what kind of tinfoil hat wearing nut
228 * job would call this function with a NULL pointer for parent_ncid -
229 * Russ Rew!! */
230int
231NC4_inq_grp_parent(int ncid, int *parent_ncid)
232{
233   NC_GRP_INFO_T *grp;
234   NC_HDF5_FILE_INFO_T *h5;
235   int retval;
236
237   LOG((2, "nc_inq_grp_parent: ncid 0x%x", ncid));
238
239   /* Find info for this file and group. */
240   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
241      return retval;
242
243   /* Groups only work with netCDF-4/HDF5 files... */
244   if (!h5)
245      return NC_ENOGRP;
246
247   /* Set the parent ncid, if there is one. */
248   if (grp->parent)
249   {
250      if (parent_ncid)
251         *parent_ncid = grp->file->ext_ncid | grp->parent->nc_grpid;
252   }
253   else
254      return NC_ENOGRP;
255   
256   return NC_NOERR;
257}
258
259/* Given a full name and ncid, find group ncid. */
260int
261NC4_inq_grp_full_ncid(int ncid, const char *full_name, int *grp_ncid)
262{
263   NC_GRP_INFO_T *grp;
264   NC_HDF5_FILE_INFO_T *h5;
265   int id1 = ncid, id2;
266   char *cp, *full_name_cpy;
267   int ret;
268
269   if (!full_name)
270      return NC_EINVAL;
271
272   /* Find info for this file and group, and set pointer to each. */
273   if ((ret = nc4_find_grp_h5(ncid, &grp, &h5)))
274      return ret;
275
276   /* Copy full_name because strtok messes with the value it works
277    * with, and we don't want to mess up full_name. */
278   if (!(full_name_cpy = malloc(strlen(full_name) + 1)))
279      return NC_ENOMEM;
280   strcpy(full_name_cpy, full_name);
281
282   /* Get the first part of the name. */
283   if (!(cp = strtok(full_name_cpy, "/")))
284   {
285      /* If "/" is passed, and this is the root group, return the root
286       * group id. */
287      if (!grp->parent)
288         id2 = ncid;
289      else
290      {
291         free(full_name_cpy);
292         return NC_ENOGRP;
293      }
294   }
295   else
296   {
297      /* Keep parsing the string. */
298      for (; cp; id1 = id2)
299      {
300         if ((ret = nc_inq_grp_ncid(id1, cp, &id2)))
301         {
302            free(full_name_cpy);
303            return ret;
304         }
305         cp = strtok(NULL, "/");
306      }
307   }
308
309   /* Give the user the requested value. */
310   if (grp_ncid)
311      *grp_ncid = id2;
312
313   free(full_name_cpy);
314
315   return NC_NOERR;
316}
317
318/* Get a list of ids for all the variables in a group. */
319int
320NC4_inq_varids(int ncid, int *nvars, int *varids)
321{
322   NC_GRP_INFO_T *grp;
323   NC_HDF5_FILE_INFO_T *h5;
324   NC_VAR_INFO_T *var;
325   int v, num_vars = 0;
326   int retval;
327
328   LOG((2, "nc_inq_varids: ncid 0x%x", ncid));
329
330   /* Find info for this file and group, and set pointer to each. */
331   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
332      return retval;
333
334   if (!h5)
335   {
336      /* If this is a netcdf-3 file, there is only one group, the root
337       * group, and its vars have ids 0 thru nvars - 1. */
338      if ((retval = nc_inq(ncid, NULL, &num_vars, NULL, NULL)))
339         return retval;
340      if (varids)
341         for (v = 0; v < num_vars; v++)
342            varids[v] = v;
343   }
344   else
345   {
346      /* This is a netCDF-4 group. Round up them doggies and count
347       * 'em. The list is in correct (i.e. creation) order. */
348      if (grp->var)
349      {
350         for (var = grp->var; var; var = var->next)
351         {
352            if (varids)
353               varids[num_vars] = var->varid;
354            num_vars++;
355         }
356      }
357   }
358
359   /* If the user wants to know how many vars in the group, tell
360    * him. */
361   if (nvars)
362      *nvars = num_vars;
363
364   return NC_NOERR;
365}
366
367/* This is the comparison function used for sorting dim ids. Integer
368   comparison: returns negative if b > a and positive if a > b. */
369int int_cmp(const void *a, const void *b)
370{
371   const int *ia = (const int *)a; 
372   const int *ib = (const int *)b;
373   return *ia  - *ib; 
374}
375
376/* Find all dimids for a location. This finds all dimensions in a
377 * group, with or without any of its parents, depending on last
378 * parameter. */
379int 
380NC4_inq_dimids(int ncid, int *ndims, int *dimids, int include_parents)
381{
382   NC_GRP_INFO_T *grp, *g;
383   NC_HDF5_FILE_INFO_T *h5;
384   NC_DIM_INFO_T *dim;
385   int d, num = 0;
386   int retval;
387
388   LOG((2, "nc_inq_dimids: ncid 0x%x include_parents: %d", ncid, 
389        include_parents));
390
391   /* Find info for this file and group, and set pointer to each. */
392   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
393      return retval;
394
395   if (!h5)
396   {
397      /* If this is a netcdf-3 file, then the dimids are going to be 0
398       * thru ndims-1, so just provide them. */
399      if ((retval = nc_inq(ncid, &num, NULL, NULL, NULL)))
400         return retval;
401      if (dimids)
402         for (d = 0; d < num; d++)
403            dimids[d] = d;
404   }
405   else
406   {
407      /* First count them. */
408      for (dim = grp->dim; dim; dim = dim->next)
409         num++;
410      if (include_parents)
411         for (g = grp->parent; g; g = g->parent)
412            for (dim = g->dim; dim; dim = dim->next)
413               num++;
414     
415      /* If the user wants the dimension ids, get them. */
416      if (dimids)
417      {
418         int n = 0;
419
420         /* Get dimension ids from this group. */
421         for (dim = grp->dim; dim; dim = dim->next)
422            dimids[n++] = dim->dimid;
423
424         /* Get dimension ids from parent groups. */
425         if (include_parents)
426            for (g = grp->parent; g; g = g->parent)
427               for (dim = g->dim; dim; dim = dim->next)
428                  dimids[n++] = dim->dimid;
429         
430         qsort(dimids, num, sizeof(int), int_cmp);
431      }
432   }
433
434   /* If the user wants the number of dims, give it. */
435   if (ndims)
436      *ndims = num;
437
438   return NC_NOERR;
439}
440
Note: See TracBrowser for help on using the repository browser.