1/*
2
3This file is part of netcdf-4, a netCDF-like interface for HDF5, or a
4HDF5 backend for netCDF, depending on your point of view.
5
6This file handles the nc4 dimension functions.
7
8Copyright 2003-5, University Corporation for Atmospheric Research. See
9the COPYRIGHT file for copying and redistribution conditions.
10
11$Id: nc4dim.c,v 1.41 2010/05/25 17:54:23 dmh Exp $
12*/
13
14#include "nc4internal.h"
15#include "nc4dispatch.h"
16
17/* Netcdf-4 files might have more than one unlimited dimension, but
18   return the first one anyway. */
19/* Note that this code is inconsistent with nc_inq */
20int
21NC4_inq_unlimdim(int ncid, int *unlimdimidp)
22{
23   NC *nc;
24   NC_GRP_INFO_T *grp, *g;
25   NC_HDF5_FILE_INFO_T *h5;
26   NC_DIM_INFO_T *dim;
27   int found = 0;
28   int retval;
29
30   LOG((2, "%s: called", __func__));
31
32   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
33      return retval;
34   assert(h5);
35
36   /* According to netcdf-3 manual, return -1 if there is no unlimited
37      dimension. */
38   *unlimdimidp = -1;
39   for (g = grpg && !foundg = g->parent)
40   {
41      for (dim = g->dimdimdim = dim->l.next)
42      {
43  if (dim->unlimited)
44  {
45     *unlimdimidp = dim->dimid;
46     found++;
47     break;
48  }
49      }
50   }
51
52   return NC_NOERR;
53}
54
55/* Dimensions are defined in attributes attached to the appropriate
56   group in the data file. */
57int
58NC4_def_dim(int ncid, const char *name, size_t len, int *idp)
59{
60   NC *nc;
61   NC_GRP_INFO_T *grp;
62   NC_HDF5_FILE_INFO_T *h5;
63   NC_DIM_INFO_T *dim;
64   char norm_name[NC_MAX_NAME + 1];
65   int retval = NC_NOERR;
66   uint32_t nn_hash;
67
68   LOG((2, "%s: ncid 0x%x name %s len %d", __func__ncidname,
69 (int)len));
70
71   /* Find our global metadata structure. */
72   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
73      return retval;
74
75   assert(h5 && nc /*& grp*/);
76
77   /* If the file is read-only, return an error. */
78   if (h5->no_write)
79     return NC_EPERM;
80
81   /* Check some stuff if strict nc3 rules are in effect. */
82   if (h5->cmode & NC_CLASSIC_MODEL)
83   {
84      /* Only one limited dimenson for strict nc3. */
85      if (len == NC_UNLIMITED)
86  for (dim = grp->dimdimdim = dim->l.next)
87     if (dim->unlimited)
88        return NC_EUNLIMIT;
89
90      /* Must be in define mode for stict nc3. */
91      if (!(h5->flags & NC_INDEF))
92  return NC_ENOTINDEFINE;
93   }
94
95   /* If it's not in define mode, enter define mode. */
96   if (!(h5->flags & NC_INDEF))
97      if ((retval = NC4_redef(ncid)))
98  return retval;
99
100   /* Make sure this is a valid netcdf name. */
101   if ((retval = nc4_check_name(namenorm_name)))
102      return retval;
103
104   /* For classic model: dim length has to fit in a 32-bit unsigned
105    * int, as permitted for 64-bit offset format. */
106   if (h5->cmode & NC_CLASSIC_MODEL)
107      if(len > X_UINT_MAX) /* Backward compat */
108  return NC_EDIMSIZE;
109
110   nn_hash = hash_fast(norm_name, strlen(norm_name));
111
112   /* Make sure the name is not already in use. */
113   for (dim = grp->dimdimdim = dim->l.next)
114      if (nn_hash == dim->hash && !strncmp(dim->namenorm_nameNC_MAX_NAME))
115  return NC_ENAMEINUSE;
116
117   /* Add a dimension to the list. The ID must come from the file
118    * information, since dimids are visible in more than one group. */
119   nc4_dim_list_add(&grp->dim, &dim);
120   dim->dimid = grp->nc4_info->next_dimid++;
121
122   /* Initialize the metadata for this dimension. */
123   if (!(dim->name = strdup(norm_name)))
124      return NC_ENOMEM;
125   dim->len = len;
126   if (len == NC_UNLIMITED)
127      dim->unlimited = NC_TRUE;
128
129   dim->hash = nn_hash;
130
131   /* Pass back the dimid. */
132   if (idp)
133      *idp = dim->dimid;
134
135   return retval;
136}
137
138/* Given dim name, find its id. */
139int
140NC4_inq_dimid(int ncid, const char *name, int *idp)
141{
142   NC *nc;
143   NC_GRP_INFO_T *grp, *g;
144   NC_HDF5_FILE_INFO_T *h5;
145   NC_DIM_INFO_T *dim;
146   char norm_name[NC_MAX_NAME + 1];
147   int finished = 0;
148   int retval;
149   uint32_t shash;
150
151   LOG((2, "%s: ncid 0x%x name %s", __func__ncidname));
152
153   /* Find metadata for this file. */
154   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
155      return retval;
156
157   assert(h5);
158   assert(nc && grp);
159
160   /* Normalize name. */
161   if ((retval = nc4_normalize_name(namenorm_name)))
162      return retval;
163
164   shash = hash_fast(norm_name, strlen(norm_name));
165
166   /* Go through each dim and check for a name match. */
167   for (g = grpg && !finishedg = g->parent)
168      for (dim = g->dimdimdim = dim->l.next)
169  if (dim->hash == shash && !strncmp(dim->namenorm_nameNC_MAX_NAME))
170  {
171     if (idp)
172        *idp = dim->dimid;
173     return NC_NOERR;
174  }
175
176   return NC_EBADDIM;
177}
178
179/* Find out name and len of a dim. For an unlimited dimension, the
180   length is the largest length so far written. If the name of lenp
181   pointers are NULL, they will be ignored. */
182int
183NC4_inq_dim(int ncid, int dimid, char *name, size_t *lenp)
184{
185   NC *nc;
186   NC_HDF5_FILE_INFO_T *h5;
187   NC_GRP_INFO_T *grp, *dim_grp;
188   NC_DIM_INFO_T *dim;
189   int ret = NC_NOERR;
190
191   LOG((2, "%s: ncid 0x%x dimid %d", __func__nciddimid));
192
193   /* Find our global metadata structure. */
194   if ((ret = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
195      return ret;
196
197   assert(h5);
198   assert(nc && grp);
199
200   /* Find the dimension and its home group. */
201   if ((ret = nc4_find_dim(grpdimid, &dim, &dim_grp)))
202      return ret;
203   assert(dim);
204
205   /* Return the dimension name, if the caller wants it. */
206   if (name && dim->name)
207      strcpy(namedim->name);
208
209   /* Return the dimension length, if the caller wants it. */
210   if (lenp)
211   {
212      if (dim->unlimited)
213      {
214  /* Since this is an unlimited dimension, go to the file
215     and see how many records there are. Take the max number
216     of records from all the vars that share this
217     dimension. */
218  *lenp = 0;
219  if ((ret = nc4_find_dim_len(dim_grpdimid, &lenp)))
220     return ret;
221      }
222      else
223      {
224  if (dim->too_long)
225  {
226     ret = NC_EDIMSIZE;
227     *lenp = NC_MAX_UINT;
228  }
229  else
230     *lenp = dim->len;
231      }
232   }
233
234   return ret;
235}
236
237/* Rename a dimension, for those who like to prevaricate. */
238int
239NC4_rename_dim(int ncid, int dimid, const char *name)
240{
241   NC *nc;
242   NC_GRP_INFO_T *grp;
243   NC_HDF5_FILE_INFO_T *h5;
244   NC_DIM_INFO_T *dim, *tmp_dim;
245   char norm_name[NC_MAX_NAME + 1];
246   int retval;
247
248   if (!name)
249      return NC_EINVAL;
250
251   LOG((2, "%s: ncid 0x%x dimid %d name %s", __func__ncid,
252 dimidname));
253
254   /* Find info for this file and group, and set pointer to each. */
255   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
256      return retval;
257
258   assert(nc);
259   assert(h5 && grp);
260
261   /* Trying to write to a read-only file? No way, Jose! */
262   if (h5->no_write)
263      return NC_EPERM;
264
265   /* Make sure this is a valid netcdf name. */
266   if ((retval = nc4_check_name(namenorm_name)))
267      return retval;
268
269   /* Check if name is in use, and retain a pointer to the correct dim */
270   tmp_dim = NULL;
271   for (dim = grp->dimdimdim = dim->l.next)
272   {
273      if (!strncmp(dim->namenorm_nameNC_MAX_NAME))
274  return NC_ENAMEINUSE;
275      if (dim->dimid == dimid)
276  tmp_dim = dim;
277   }
278   if (!tmp_dim)
279      return NC_EBADDIM;
280   dim = tmp_dim;
281
282   /* Check for renaming dimension w/o variable */
283   if (dim->hdf_dimscaleid)
284   {
285      /* Sanity check */
286      assert(!dim->coord_var);
287
288      /* Close the HDF5 dataset */
289      if (H5Dclose(dim->hdf_dimscaleid) < 0)
290         return NC_EHDFERR;
291      dim->hdf_dimscaleid = 0;
292
293      /* Now delete the dataset (it will be recreated later, if necessary) */
294      if (H5Gunlink(grp->hdf_grpiddim->name) < 0)
295         return NC_EDIMMETA;
296   }
297
298   /* Give the dimension its new name in metadata. UTF8 normalization
299    * has been done. */
300   if(dim->name)
301      free(dim->name);
302   if (!(dim->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
303      return NC_ENOMEM;
304   strcpy(dim->namenorm_name);
305
306   dim->hash = hash_fast(norm_name, strlen(norm_name));
307
308   /* Check if dimension was a coordinate variable, but names are different now */
309   if (dim->coord_var && strcmp(dim->namedim->coord_var->name))
310   {
311      /* Break up the coordinate variable */
312      if ((retval = nc4_break_coord_var(grpdim->coord_vardim)))
313         return retval;
314   }
315
316   /* Check if dimension should become a coordinate variable */
317   if (!dim->coord_var)
318   {
319      NC_VAR_INFO_T *var;
320
321      /* Attempt to find a variable with the same name as the dimension in
322       * the current group. */
323      if ((retval = nc4_find_var(grpdim->name, &var)))
324         return retval;
325
326      /* Check if we found a variable and the variable has the dimension in
327       * index 0. */
328      if (var && var->dim[0] == dim)
329      {
330          /* Sanity check */
331          assert(var->dimids[0] == dim->dimid);
332
333          /* Reform the coordinate variable */
334          if ((retval = nc4_reform_coord_var(grpvardim)))
335             return retval;
336      }
337   }
338
339   return NC_NOERR;
340}
341
342/* Returns an array of unlimited dimension ids.The user can get the
343   number of unlimited dimensions by first calling this with NULL for
344   the second pointer.
345*/
346int
347NC4_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp)
348{
349  NC_DIM_INFO_T *dim;
350  NC_GRP_INFO_T *grp;
351  NC *nc;
352  NC_HDF5_FILE_INFO_T *h5;
353  int num_unlim = 0;
354  int retval;
355
356  LOG((2, "%s: ncid 0x%x", __func__ncid));
357
358  /* Find info for this file and group, and set pointer to each. */
359  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
360    return retval;
361
362   /* Get our dim info. */
363   assert(h5);
364   {
365      for (dim=grp->dimdimdim=dim->l.next)
366      {
367  if (dim->unlimited)
368  {
369     if (unlimdimidsp)
370        unlimdimidsp[num_unlim] = dim->dimid;
371     num_unlim++;
372  }
373      }
374   }
375
376   /* Give the number if the user wants it. */
377   if (nunlimdimsp)
378      *nunlimdimsp = num_unlim;
379
380   return NC_NOERR;
381}
382
383


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