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;
22   NC_HDF5_FILE_INFO_T *h5;
23   char norm_name[NC_MAX_NAME + 1];
24   int retval;
25
26   LOG((2, "%s: parent_ncid 0x%x name %s", __func__parent_ncidname));
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(namenorm_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(grpnorm_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   grpgrp->nc4_info->controllernorm_nameNULL)))
56      return retval;
57   if (new_ncid)
58      *new_ncid = grp->nc4_info->controller->ext_ncid | h5->next_nc_grpid;
59   h5->next_nc_grpid++;
60
61   return NC_NOERR;
62}
63
64/* Rename a group. */
65int
66NC4_rename_grp(int grpid, const char *name)
67{
68   NC_GRP_INFO_T *grp;
69   NC_HDF5_FILE_INFO_T *h5;
70   char norm_name[NC_MAX_NAME + 1];
71   int retval;
72
73   LOG((2, "nc_rename_grp: grpid 0x%x name %s", grpidname));
74
75   /* Find info for this file and group, and set pointer to each. */
76   if ((retval = nc4_find_grp_h5(grpid, &grp, &h5)))
77      return retval;
78   if (!h5)
79      return NC_ENOTNC4;
80
81   if (h5->no_write)
82      return NC_EPERM; /* attempt to write to a read-only file */
83
84   /* Do not allow renaming the root group */
85   if(grp->parent == NULL)
86 return NC_EBADGRPID;
87
88   /* Check and normalize the name. */
89   if ((retval = nc4_check_name(namenorm_name)))
90      return retval;
91
92   /* Check that this name is not in use as a var, grp, or type. */
93   if ((retval = nc4_check_dup_name(grpnorm_name)))
94      return retval;
95
96   /* If it's not in define mode, switch to define mode. */
97   if (!(h5->flags & NC_INDEF))
98      if ((retval = NC4_redef(grpid)))
99  return retval;
100
101   /* Rename the group, if it exists in the file */
102   if (grp->hdf_grpid)
103   {
104      /* Close the group */
105      if (H5Gclose(grp->hdf_grpid) < 0)
106         return NC_EHDFERR;
107      grp->hdf_grpid = 0;
108
109      /* Attempt to rename & re-open the group, if the parent group is open */
110      if (grp->parent->hdf_grpid)
111      {
112         /* Rename the group */
113         if (H5Gmove(grp->parent->hdf_grpidgrp->namename) < 0)
114            return NC_EHDFERR;
115
116         /* Reopen the group, with the new name */
117         if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpidnameH5P_DEFAULT)) < 0)
118            return NC_EHDFERR;
119      }
120   }
121
122   /* Give the group its new name in metadata. UTF8 normalization
123    * has been done. */
124   free(grp->name);
125   if (!(grp->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
126      return NC_ENOMEM;
127   strcpy(grp->namenorm_name);
128
129   return NC_NOERR;
130}
131
132/* Given an ncid and group name (NULL gets root group), return
133 * the ncid of that group. */
134int
135NC4_inq_ncid(int ncid, const char *name, int *grp_ncid)
136{
137   NC_GRP_INFO_T *grp, *g;
138   NC_HDF5_FILE_INFO_T *h5;
139   char norm_name[NC_MAX_NAME + 1];
140   int retval;
141
142   LOG((2, "nc_inq_ncid: ncid 0x%x name %s", ncidname));
143
144   /* Find info for this file and group, and set pointer to each. */
145   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
146      return retval;
147
148   /* Groups only work with netCDF-4/HDF5 files... */
149   if (!h5)
150      return NC_ENOTNC4;
151
152   /* Normalize name. */
153   if ((retval = nc4_normalize_name(namenorm_name)))
154      return retval;
155
156   /* Look through groups for one of this name. */
157   for (g = grp->childrengg = g->l.next)
158      if (!strcmp(norm_nameg->name)) /* found it! */
159      {
160  if (grp_ncid)
161     *grp_ncid = grp->nc4_info->controller->ext_ncid | g->nc_grpid;
162  return NC_NOERR;
163      }
164
165   /* If we got here, we didn't find the named group. */
166   return NC_ENOGRP;
167}
168
169/* Given a location id, return the number of groups it contains, and
170 * an array of their locids. */
171int
172NC4_inq_grps(int ncid, int *numgrps, int *ncids)
173{
174   NC_GRP_INFO_T *grp, *g;
175   NC_HDF5_FILE_INFO_T *h5;
176   int num = 0;
177   int retval;
178
179   LOG((2, "nc_inq_grps: ncid 0x%x", ncid));
180
181   /* Find info for this file and group, and set pointer to each. */
182   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
183      return retval;
184
185   /* For netCDF-3 files, just report zero groups. */
186   if (!h5)
187   {
188      if (numgrps)
189  *numgrps = 0;
190      return NC_NOERR;
191   }
192
193   /* Count the number of groups in this group. */
194   for (g = grp->childrengg = g->l.next)
195   {
196      if (ncids)
197      {
198  /* Combine the nc_grpid in a bitwise or with the ext_ncid,
199   * which allows the returned ncid to carry both file and
200   * group information. */
201  *ncids = g->nc_grpid | g->nc4_info->controller->ext_ncid;
202  ncids++;
203      }
204      num++;
205   }
206
207   if (numgrps)
208      *numgrps = num;
209
210   return NC_NOERR;
211}
212
213/* Given locid, find name of group. (Root group is named "/".) */
214int
215NC4_inq_grpname(int ncid, char *name)
216{
217   NC_GRP_INFO_T *grp;
218   NC_HDF5_FILE_INFO_T *h5;
219   int retval;
220
221   LOG((2, "nc_inq_grpname: ncid 0x%x", ncid));
222
223   /* Find info for this file and group, and set pointer to each. */
224   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
225      return retval;
226   if (name)
227   {
228      if (!h5)
229  strcpy(name, "/");
230      else
231  strcpy(namegrp->name);
232   }
233
234   return NC_NOERR;
235}
236
237/* Find the full path name to the group represented by ncid. Either
238 * pointer argument may be NULL; pass a NULL for the third parameter
239 * to get the length of the full path name. The length will not
240 * include room for a null pointer. */
241int
242NC4_inq_grpname_full(int ncid, size_t *lenp, char *full_name)
243{
244   char *namegrp_name[NC_MAX_NAME + 1];
245   int gid = ncidparent_id, *gid;
246   int iret = NC_NOERR;
247
248   /* How many generations? */
249   for (g = 0; !NC4_inq_grp_parent(id, &parent_id); g++, id = parent_id)
250      ;
251
252   /* Allocate storage. */
253   if (!(name = malloc((g + 1) * (NC_MAX_NAME + 1) + 1)))
254      return NC_ENOMEM;
255   if (!(gid = malloc((g + 1) * sizeof(int))))
256   {
257      free(name);
258      return NC_ENOMEM;
259   }
260   assert(name && gid);
261
262   /* Always start with a "/" for the root group. */
263   strcpy(name, "/");
264
265   /* Get the ncids for all generations. */
266   gid[0] = ncid;
267   for (i = 1; i < g && !reti++)
268      ret = NC4_inq_grp_parent(gid[i - 1], &gid[i]);
269
270   /* Assemble the full name. */
271   for (i = g - 1; !ret && i >= 0 && !reti--)
272   {
273      if ((ret = NC4_inq_grpname(gid[i], grp_name)))
274  break;
275      strcat(namegrp_name);
276      if (i)
277  strcat(name, "/");
278   }
279
280   /* Give the user the length of the name, if he wants it. */
281   if (!ret && lenp)
282      *lenp = strlen(name);
283
284   /* Give the user the name, if he wants it. */
285   if (!ret && full_name)
286      strcpy(full_namename);
287
288   free(gid);
289   free(name);
290
291   return ret;
292}
293
294/* Find the parent ncid of a group. For the root group, return
295 * NC_ENOGRP error.  *Now* I know what kind of tinfoil hat wearing nut
296 * job would call this function with a NULL pointer for parent_ncid -
297 * Russ Rew!! */
298int
299NC4_inq_grp_parent(int ncid, int *parent_ncid)
300{
301   NC_GRP_INFO_T *grp;
302   NC_HDF5_FILE_INFO_T *h5;
303   int retval;
304
305   LOG((2, "nc_inq_grp_parent: ncid 0x%x", ncid));
306
307   /* Find info for this file and group. */
308   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
309      return retval;
310
311   /* Groups only work with netCDF-4/HDF5 files... */
312   if (!h5)
313      return NC_ENOGRP;
314
315   /* Set the parent ncid, if there is one. */
316   if (grp->parent)
317   {
318      if (parent_ncid)
319  *parent_ncid = grp->nc4_info->controller->ext_ncid | grp->parent->nc_grpid;
320   }
321   else
322      return NC_ENOGRP;
323
324   return NC_NOERR;
325}
326
327/* Given a full name and ncid, find group ncid. */
328int
329NC4_inq_grp_full_ncid(int ncid, const char *full_name, int *grp_ncid)
330{
331   NC_GRP_INFO_T *grp;
332   NC_HDF5_FILE_INFO_T *h5;
333   int id1 = ncidid2;
334   char *cp, *full_name_cpy;
335   int ret;
336
337   if (!full_name)
338      return NC_EINVAL;
339
340   /* Find info for this file and group, and set pointer to each. */
341   if ((ret = nc4_find_grp_h5(ncid, &grp, &h5)))
342      return ret;
343
344   /* Copy full_name because strtok messes with the value it works
345    * with, and we don't want to mess up full_name. */
346   if (!(full_name_cpy = malloc(strlen(full_name) + 1)))
347      return NC_ENOMEM;
348   strcpy(full_name_cpyfull_name);
349
350   /* Get the first part of the name. */
351   if (!(cp = strtok(full_name_cpy, "/")))
352   {
353      /* If "/" is passed, and this is the root group, return the root
354       * group id. */
355      if (!grp->parent)
356  id2 = ncid;
357      else
358      {
359  free(full_name_cpy);
360  return NC_ENOGRP;
361      }
362   }
363   else
364   {
365      /* Keep parsing the string. */
366      for (; cpid1 = id2)
367      {
368  if ((ret = NC4_inq_ncid(id1cp, &id2)))
369  {
370     free(full_name_cpy);
371     return ret;
372  }
373  cp = strtok(NULL, "/");
374      }
375   }
376
377   /* Give the user the requested value. */
378   if (grp_ncid)
379      *grp_ncid = id2;
380
381   free(full_name_cpy);
382
383   return NC_NOERR;
384}
385
386/* Get a list of ids for all the variables in a group. */
387int
388NC4_inq_varids(int ncid, int *nvars, int *varids)
389{
390   NC_GRP_INFO_T *grp;
391   NC_HDF5_FILE_INFO_T *h5;
392   NC_VAR_INFO_T *var;
393   int vnum_vars = 0;
394   int retval;
395
396   LOG((2, "nc_inq_varids: ncid 0x%x", ncid));
397
398   /* Find info for this file and group, and set pointer to each. */
399   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
400      return retval;
401
402   if (!h5)
403   {
404      /* If this is a netcdf-3 file, there is only one group, the root
405       * group, and its vars have ids 0 thru nvars - 1. */
406      if ((retval = NC4_inq(ncidNULL, &num_varsNULLNULL)))
407  return retval;
408      if (varids)
409  for (v = 0; v < num_varsv++)
410     varids[v] = v;
411   }
412   else
413   {
414      /* This is a netCDF-4 group. Round up them doggies and count
415       * 'em. The list is in correct (i.e. creation) order. */
416      if (grp->var)
417      {
418  for (var = grp->varvarvar = var->l.next)
419  {
420     if (varids)
421        varids[num_vars] = var->varid;
422     num_vars++;
423  }
424      }
425   }
426
427   /* If the user wants to know how many vars in the group, tell
428    * him. */
429   if (nvars)
430      *nvars = num_vars;
431
432   return NC_NOERR;
433}
434
435/* This is the comparison function used for sorting dim ids. Integer
436   comparison: returns negative if b > a and positive if a > b. */
437int int_cmp(const void *a, const void *b)
438{
439   const int *ia = (const int *)a;
440   const int *ib = (const int *)b;
441   return *ia  - *ib;
442}
443
444/* Find all dimids for a location. This finds all dimensions in a
445 * group, with or without any of its parents, depending on last
446 * parameter. */
447int
448NC4_inq_dimids(int ncid, int *ndims, int *dimids, int include_parents)
449{
450   NC_GRP_INFO_T *grp, *g;
451   NC_HDF5_FILE_INFO_T *h5;
452   NC_DIM_INFO_T *dim;
453   int dnum = 0;
454   int retval;
455
456   LOG((2, "nc_inq_dimids: ncid 0x%x include_parents: %d", ncid,
457 include_parents));
458
459   /* Find info for this file and group, and set pointer to each. */
460   if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
461      return retval;
462
463   if (!h5)
464   {
465      /* If this is a netcdf-3 file, then the dimids are going to be 0
466       * thru ndims-1, so just provide them. */
467      if ((retval = NC4_inq(ncid, &numNULLNULLNULL)))
468  return retval;
469      if (dimids)
470  for (d = 0; d < numd++)
471     dimids[d] = d;
472   }
473   else
474   {
475      /* First count them. */
476      for (dim = grp->dimdimdim = dim->l.next)
477  num++;
478      if (include_parents)
479  for (g = grp->parentgg = g->parent)
480     for (dim = g->dimdimdim = dim->l.next)
481        num++;
482
483      /* If the user wants the dimension ids, get them. */
484      if (dimids)
485      {
486  int n = 0;
487
488  /* Get dimension ids from this group. */
489  for (dim = grp->dimdimdim = dim->l.next)
490     dimids[n++] = dim->dimid;
491
492  /* Get dimension ids from parent groups. */
493  if (include_parents)
494     for (g = grp->parentgg = g->parent)
495        for (dim = g->dimdimdim = dim->l.next)
496   dimids[n++] = dim->dimid;
497
498  qsort(dimidsnum, sizeof(int), int_cmp);
499      }
500   }
501
502   /* If the user wants the number of dims, give it. */
503   if (ndims)
504      *ndims = num;
505
506   return NC_NOERR;
507}
508


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed