source: XIOS/dev/branch_openmp/extern/src_netcdf4/nc4attr.c @ 1501

Last change on this file since 1501 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: 24.4 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 attribute functions.
6
7Remember that with atts, type conversion can take place when writing
8them, and when reading them.
9
10Copyright 2003-2011, University Corporation for Atmospheric
11Research. See COPYRIGHT file for copying and redistribution
12conditions.
13*/
14
15#include "nc4internal.h"
16#include "nc.h"
17#include "nc4dispatch.h"
18#include "ncdispatch.h"
19
20#ifdef USE_PNETCDF
21#include <pnetcdf.h>
22#endif
23
24int nc4typelen(nc_type type);
25
26/* Get or put attribute metadata from our linked list of file
27   info. Always locate the attribute by name, never by attnum.
28   The mem_type is ignored if data=NULL. */
29int
30nc4_get_att(int ncid, NC_FILE_INFO_T *nc, int varid, const char *name, 
31            nc_type *xtype, nc_type mem_type, size_t *lenp, 
32            int *attnum, int is_long, void *data) 
33{
34   NC_GRP_INFO_T *grp;
35   NC_HDF5_FILE_INFO_T *h5;
36   NC_ATT_INFO_T *att;
37   int my_attnum = -1;
38   int need_to_convert = 0;
39   int range_error = NC_NOERR;
40   void *bufr = NULL;
41   size_t type_size;
42   char norm_name[NC_MAX_NAME + 1];
43   int i;
44   int retval = NC_NOERR;
45
46   if (attnum)
47      my_attnum = *attnum;
48   assert(nc && nc->nc4_info);
49
50   LOG((3, "nc4_get_att: ncid 0x%x varid %d name %s attnum %d mem_type %d", 
51        ncid, varid, name, my_attnum, mem_type));
52
53   /* Find info for this file and group, and set pointer to each. */
54   h5 = nc->nc4_info;
55   if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
56      return NC_EBADGRPID;     
57
58   /* Normalize name. */
59   if ((retval = nc4_normalize_name(name, norm_name)))
60      return retval;
61
62   /* Find the attribute, if it exists. If we don't find it, we are
63      major failures. */
64   if ((retval = nc4_find_grp_att(grp, varid, norm_name, my_attnum, &att)))
65      return retval;
66   
67   /* If mem_type is NC_NAT, it means we want to use the attribute's
68    * file type as the mem type as well. */
69   if (mem_type == NC_NAT)
70      mem_type = att->xtype;
71
72   /* If the attribute is NC_CHAR, and the mem_type isn't, or vice
73    * versa, that's a freakish attempt to convert text to
74    * numbers. Some pervert out there is trying to pull a fast one!
75    * Send him an NC_ECHAR error...*/
76   if (data && att->len &&
77       ((att->xtype == NC_CHAR && mem_type != NC_CHAR) ||
78        (att->xtype != NC_CHAR && mem_type == NC_CHAR)))
79      return NC_ECHAR; /* take that, you freak! */
80
81   /* Copy the info. */
82   if (lenp)
83      *lenp = att->len;
84   if (xtype)
85      *xtype = att->xtype;
86   if (attnum)
87      *attnum = att->attnum;
88
89   /* Zero len attributes are easy to read! */
90   if (!att->len)
91      return NC_NOERR;
92
93   /* Later on, we will need to know the size of this type. */
94   if ((retval = nc4_get_typelen_mem(h5, mem_type, is_long, &type_size)))
95      return retval;
96
97   /* We may have to convert data. Treat NC_CHAR the same as
98    * NC_UBYTE. If the mem_type is NAT, don't try any conversion - use
99    * the attribute's type. */
100   if (data && att->len && mem_type != att->xtype &&
101       mem_type != NC_NAT &&
102       !(mem_type == NC_CHAR && 
103         (att->xtype == NC_UBYTE || att->xtype == NC_BYTE)))
104   {
105      need_to_convert++;
106      if (!(bufr = malloc((size_t)(att->len * type_size))))
107         return NC_ENOMEM;
108      if ((retval = nc4_convert_type(att->data, bufr, att->xtype, 
109                                     mem_type, (size_t)att->len, &range_error, 
110                                     NULL, (h5->cmode & NC_CLASSIC_MODEL), 0, is_long)))
111         BAIL(retval);
112
113      /* For strict netcdf-3 rules, ignore erange errors between UBYTE
114       * and BYTE types. */
115      if ((h5->cmode & NC_CLASSIC_MODEL) &&
116          (att->xtype == NC_UBYTE || att->xtype == NC_BYTE) &&
117          (mem_type == NC_UBYTE || mem_type == NC_BYTE) &&
118          range_error)
119         range_error = 0;
120   }
121   else
122   {
123      bufr = att->data;
124   }
125
126   /* If the caller wants data, copy it for him. If he hasn't
127      allocated enough memory for it, he will burn in segmantation
128      fault hell, writhing with the agony of undiscovered memory
129      bugs! */
130   if (data)
131   {
132      if (att->vldata)
133      {
134         size_t base_typelen = type_size;
135         hvl_t *vldest = data;
136         NC_TYPE_INFO_T *type;
137         if ((retval = nc4_find_type(h5, att->xtype, &type)))
138            return retval;
139         for (i = 0; i < att->len; i++)
140         {
141            vldest[i].len = att->vldata[i].len;
142            if (!(vldest[i].p = malloc(vldest[i].len * base_typelen)))
143               BAIL(NC_ENOMEM);
144            memcpy(vldest[i].p, att->vldata[i].p, vldest[i].len * base_typelen);
145         }
146      }
147      else if (att->stdata)
148      {
149         for (i = 0; i < att->len; i++)
150         {
151            if (!(((char **)data)[i] = malloc(strlen(att->stdata[i]) + 1)))
152               BAIL(NC_ENOMEM);
153            strcpy(((char **)data)[i], att->stdata[i]);
154         }
155      }
156      else
157      {
158         /* For long types, we need to handle this special... */
159         if (is_long && att->xtype == NC_INT)
160         {
161            long *lp = data;
162            int *ip = bufr;
163            for (i = 0; i < att->len; i++)
164               *lp++ = *ip++;
165         }
166         else
167            memcpy(data, bufr, (size_t)(att->len * type_size));
168      }
169   }
170
171 exit:
172   if (need_to_convert) free(bufr);
173   if (retval)
174      return retval;
175   if (range_error)
176      return NC_ERANGE;
177   return NC_NOERR;
178}
179
180/* Put attribute metadata into our global metadata. */
181int
182nc4_put_att(int ncid, NC_FILE_INFO_T *nc, int varid, const char *name, 
183            nc_type file_type, nc_type mem_type, size_t len, int is_long, 
184            const void *data)
185{
186   NC_GRP_INFO_T *grp; 
187   NC_HDF5_FILE_INFO_T *h5;
188   NC_VAR_INFO_T *var = NULL;
189   NC_ATT_INFO_T *att, **attlist = NULL, *varatt;
190   NC_TYPE_INFO_T *type = NULL;
191   char norm_name[NC_MAX_NAME + 1];
192   int new_att = 0;
193   int retval = NC_NOERR, range_error = 0;
194   size_t type_size;
195   int i;
196   int res;
197
198   if (!name) 
199      return NC_EBADNAME;
200   assert(nc && nc->nc4_info);
201
202   LOG((1, "nc4_put_att: ncid 0x%x varid %d name %s "
203        "file_type %d mem_type %d len %d", ncid, varid,
204        name, file_type, mem_type, len));
205
206   /* If len is not zero, then there must be some data. */
207   if (len && !data)
208      return NC_EINVAL;
209
210   /* Find info for this file and group, and set pointer to each. */
211   h5 = nc->nc4_info;
212   if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
213      return NC_EBADGRPID;     
214
215   /* If the file is read-only, return an error. */
216   if (h5->no_write)
217     return NC_EPERM;
218
219   /* Check and normalize the name. */
220   if ((retval = nc4_check_name(name, norm_name)))
221      return retval;
222
223   /* Find att, if it exists. */
224   if (varid == NC_GLOBAL)
225      attlist = &grp->att;
226   else
227   {
228      for (var = grp->var; var; var = var->next)
229         if (var->varid == varid)
230         {
231            attlist = &var->att;
232            break;
233         }
234      if (!var)
235         return NC_ENOTVAR;
236   }
237   for (att = *attlist; att; att = att->next)
238      if (!strcmp(att->name, norm_name))
239         break;
240
241   if (!att)
242   {
243      /* If this is a new att, require define mode. */
244      if (!(h5->flags & NC_INDEF))
245      {
246         if (h5->cmode & NC_CLASSIC_MODEL)
247            return NC_EINDEFINE;
248         if ((retval = NC4_redef(ncid)))
249            BAIL(retval);
250      }
251      new_att++;
252   }
253   else
254   {
255      /* For an existing att, if we're not in define mode, the len
256         must not be greater than the existing len for classic model. */
257      if (!(h5->flags & NC_INDEF) && 
258          len * nc4typelen(file_type) > (size_t)att->len * nc4typelen(att->xtype))
259      {
260         if (h5->cmode & NC_CLASSIC_MODEL)
261            return NC_EINDEFINE;
262         if ((retval = NC4_redef(ncid)))
263            BAIL(retval);
264      }
265   }
266
267   /* We must have two valid types to continue. */
268   if (file_type == NC_NAT || mem_type == NC_NAT)
269      return NC_EBADTYPE;
270
271   /* Get information about this type. */
272   if ((retval = nc4_find_type(h5, file_type, &type)))
273      return retval;
274   if ((retval = nc4_get_typelen_mem(h5, file_type, is_long, &type_size)))
275      return retval;
276
277   /* No character conversions are allowed. */
278   if (file_type != mem_type && 
279       (file_type == NC_CHAR || mem_type == NC_CHAR || 
280        file_type == NC_STRING || mem_type == NC_STRING))
281      return NC_ECHAR;
282
283   /* For classic mode file, only allow atts with classic types to be
284    * created. */
285   if (h5->cmode & NC_CLASSIC_MODEL && file_type > NC_DOUBLE)
286      return NC_ESTRICTNC3;
287
288   /* Add to the end of the attribute list, if this att doesn't
289      already exist. */
290   if (new_att)
291   {
292      LOG((3, "adding attribute %s to the list...", norm_name));
293      if ((res = nc4_att_list_add(attlist)))
294         BAIL (res);
295      /* Find this att's entry in the list (the last one). */
296      for (att=*attlist; att->next; att=att->next)
297         ;
298   }
299
300   /* Now fill in the metadata. */
301   att->dirty++;
302   if (att->name)
303      free(att->name);
304   if (!(att->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
305      return NC_ENOMEM;
306   strcpy(att->name, norm_name);
307   att->xtype = file_type;
308   att->len = len;
309   if (att->prev)
310      att->attnum = att->prev->attnum + 1;
311   else
312      att->attnum = 0;
313   if (type)
314      att->class = type->class;
315
316   /* If this is the _FillValue attribute, then we will also have to
317    * copy the value to the fll_vlue pointer of the NC_VAR_INFO_T
318    * struct for this var. (But ignore a global _FillValue
319    * attribute). */
320   if (!strcmp(att->name, _FillValue) && varid != NC_GLOBAL)
321   {
322      NC_TYPE_INFO_T *type_info;
323      int size;
324
325      /* Fill value must be same type. */
326      if (att->xtype != var->xtype)
327         return NC_EINVAL;
328
329      /* If we already wrote to the dataset, then return an error. */
330      if (var->written_to)
331         return NC_ELATEFILL;
332
333      /* If fill value hasn't been set, allocate space. Of course,
334       * vlens have to be differnt... */
335      if ((retval = nc4_get_typelen_mem(grp->file->nc4_info, var->xtype, 0, 
336                                        &type_size)))
337         return retval;
338      if ((retval = nc4_find_type(grp->file->nc4_info, var->xtype, &type_info)))
339         BAIL(retval);
340     
341      /* Already set a fill value? Now I'll have to free the old
342       * one. Make up your damn mind, would you? */
343      if (var->fill_value)
344      {
345         if (type_info && type_info->class == NC_VLEN)
346            if ((retval = nc_free_vlen(var->fill_value)))
347               return retval;
348         free(var->fill_value);
349      }
350
351      /* Allocate space for the fill value. */
352      if (type_info && type_info->class == NC_VLEN)
353         size = sizeof(hvl_t);
354      else if (var->xtype == NC_STRING)
355         size = sizeof(char *);
356      else
357         size = type_size;
358
359      /*         size = strlen(*(char **)data) + 1; */
360      if (!(var->fill_value = malloc(size)))
361         return NC_ENOMEM;
362
363      /* Copy the fill_value. */
364      LOG((4, "Copying fill value into metadata for variable %s", var->name));
365      if (type_info && type_info->class == NC_VLEN)
366      {
367         nc_vlen_t *in_vlen = (nc_vlen_t *)data, *fv_vlen = (nc_vlen_t *)(var->fill_value);
368         fv_vlen->len = in_vlen->len;
369         if (!(fv_vlen->p = malloc(size * in_vlen->len)))
370            return NC_ENOMEM;
371         memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * size);
372      }
373      else if (var->xtype == NC_STRING)
374      {
375         if (!(*(char **)var->fill_value = malloc(strlen(*(char **)data) + 1)))
376            return NC_ENOMEM;
377         strcpy(*(char **)(var->fill_value), *(char **)data);
378      }
379      else
380         memcpy(var->fill_value, data, type_size);
381
382      /* Mark the var and all its atts as dirty, so they get
383       * rewritten. */
384      var->dirty++;
385      for (varatt = var->att; varatt; varatt = varatt->next)
386         varatt->dirty++;
387   }
388
389   /* Copy the attribute data, if there is any. VLENs and string
390    * arrays have to be handled specially. */
391   if (type && type->class == NC_VLEN && data && att->len)
392   {
393      const hvl_t *vldata1;
394
395      vldata1 = data;
396      if (!(att->vldata = malloc(att->len * sizeof(hvl_t))))
397         BAIL(NC_ENOMEM);       
398      for (i = 0; i < att->len; i++)
399      {
400         att->vldata[i].len = vldata1[i].len;
401         if (!(att->vldata[i].p = malloc(type_size * att->vldata[i].len)))
402            BAIL(NC_ENOMEM);
403         memcpy(att->vldata[i].p, vldata1[i].p, type_size * att->vldata[i].len);
404      }
405   }
406   else if (file_type == NC_STRING && data && att->len)
407   {
408      LOG((4, "copying array of NC_STRING"));
409      if (!(att->stdata = malloc(sizeof(char *) * att->len)))
410         BAIL(NC_ENOMEM);       
411      for (i = 0; i < att->len; i++)
412      {
413         LOG((5, "copying string %d of size %d", i, strlen(((char **)data)[i]) + 1));
414         if (!(att->stdata[i] = malloc(strlen(((char **)data)[i]) + 1)))
415            BAIL(NC_ENOMEM);
416         strcpy(att->stdata[i], ((char **)data)[i]);
417      }
418   }
419   else
420   {
421      /* Data types are like religions, in that one can convert.  */
422      if (att->len)
423      {
424         if (!new_att)
425            free (att->data);
426         if (!(att->data = malloc(att->len * type_size)))
427            BAIL(NC_ENOMEM);
428         if (type)
429         {
430            /* Just copy the data... */
431            if (type->class == NC_OPAQUE || type->class == NC_COMPOUND || type->class == NC_ENUM)
432               memcpy(att->data, data, len * type_size);
433            else
434               LOG((0, "nc4_put_att: unknown type."));
435         }
436         else
437         {
438            if ((retval = nc4_convert_type(data, att->data, mem_type, file_type, 
439                                           len, &range_error, NULL, 
440                                           (h5->cmode & NC_CLASSIC_MODEL), is_long, 0)))
441               BAIL(retval);
442         }
443      }
444   }
445   att->dirty = 1;
446   att->created = 0;
447
448 exit:
449   /* If there was an error return it, otherwise return any potential
450      range error value. If none, return NC_NOERR as usual.*/
451   if (retval)     
452      return retval;
453   if (range_error)
454      return NC_ERANGE;
455   return NC_NOERR;
456}
457
458/* Learn about an att. All the nc4 nc_inq_ functions just call
459 * add_meta_get to get the metadata on an attribute. */
460int
461NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp)
462{
463   NC_FILE_INFO_T *nc;
464
465   LOG((2, "nc_inq_att: ncid 0x%x varid %d name %s", ncid, varid, name));
466
467   /* Find metadata. */
468   if (!(nc = nc4_find_nc_file(ncid)))
469      return NC_EBADID;
470
471#ifdef USE_PNETCDF
472   /* Take care of files created/opened with parallel-netcdf library. */
473   if (nc->pnetcdf_file)
474   {
475      MPI_Offset mpi_len;
476      int ret;
477
478      if ((ret = ncmpi_inq_att(nc->int_ncid, varid, name, xtypep, &mpi_len)))
479         return ret;
480      if (lenp)
481         *lenp = mpi_len;
482   }
483#endif /* USE_PNETCDF */
484
485   /* Handle netcdf-3 files. */
486   assert(nc->nc4_info);
487
488   /* Handle netcdf-4 files. */
489   return nc4_get_att(ncid, nc, varid, name, xtypep, NC_UBYTE, lenp, NULL, 0, NULL);
490}
491
492/* Learn an attnum, given a name. */
493int 
494NC4_inq_attid(int ncid, int varid, const char *name, int *attnump)
495{
496   NC_FILE_INFO_T *nc;
497
498   LOG((2, "nc_inq_attid: ncid 0x%x varid %d name %s", ncid, varid, name));
499
500   /* Find metadata. */
501   if (!(nc = nc4_find_nc_file(ncid)))
502      return NC_EBADID;
503
504#ifdef USE_PNETCDF
505   /* Take care of files created/opened with parallel-netcdf library. */
506   if (nc->pnetcdf_file)
507      return ncmpi_inq_attid(nc->int_ncid, varid, name, attnump);
508#endif /* USE_PNETCDF */
509
510   /* Handle netcdf-3 files. */
511   assert(nc->nc4_info);
512
513   /* Handle netcdf-4 files. */
514   return nc4_get_att(ncid, nc, varid, name, NULL, NC_UBYTE, 
515                      NULL, attnump, 0, NULL);
516}
517
518
519/* Given an attnum, find the att's name. */
520int
521NC4_inq_attname(int ncid, int varid, int attnum, char *name)
522{
523   NC_FILE_INFO_T *nc;
524   NC_ATT_INFO_T *att;
525   int retval = NC_NOERR;
526
527   LOG((2, "nc_inq_attname: ncid 0x%x varid %d attnum %d", 
528        ncid, varid, attnum));
529
530   /* Find metadata. */
531   if (!(nc = nc4_find_nc_file(ncid)))
532      return NC_EBADID;
533
534#ifdef USE_PNETCDF
535   /* Take care of files created/opened with parallel-netcdf library. */
536   if (nc->pnetcdf_file)
537      return ncmpi_inq_attname(nc->int_ncid, varid, attnum, name);
538#endif /* USE_PNETCDF */
539
540   /* Handle netcdf-3 files. */
541   assert(nc->nc4_info);
542
543   /* Handle netcdf-4 files. */
544   if ((retval = nc4_find_nc_att(ncid, varid, NULL, attnum, &att)))
545      return retval;
546
547   /* Get the name. */
548   if (name)
549      strcpy(name, att->name);
550
551   return NC_NOERR;
552}
553
554/* I think all atts should be named the exact same thing, to avoid
555   confusion! */
556int
557NC4_rename_att(int ncid, int varid, const char *name, 
558              const char *newname)
559{
560   NC_FILE_INFO_T *nc;
561   NC_GRP_INFO_T *grp; 
562   NC_HDF5_FILE_INFO_T *h5;
563   NC_VAR_INFO_T *var;
564   NC_ATT_INFO_T *att, *list;
565   char norm_newname[NC_MAX_NAME + 1], norm_name[NC_MAX_NAME + 1];
566   hid_t datasetid = 0;
567   int retval = NC_NOERR;
568
569   if (!name || !newname)
570      return NC_EINVAL;
571
572   LOG((2, "nc_rename_att: ncid 0x%x varid %d name %s newname %s",
573        ncid, varid, name, newname));
574
575   /* If the new name is too long, that's an error. */
576   if (strlen(newname) > NC_MAX_NAME)
577      return NC_EMAXNAME;
578
579   /* Find metadata for this file. */
580   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
581      return retval;
582
583#ifdef USE_PNETCDF
584   /* Take care of files created/opened with parallel-netcdf library. */
585   if (nc->pnetcdf_file)
586      return ncmpi_rename_att(nc->int_ncid, varid, name, newname);
587#endif /* USE_PNETCDF */
588
589   /* Handle netcdf-3 files. */
590   assert(h5);
591
592   /* If the file is read-only, return an error. */
593   if (h5->no_write)
594     return NC_EPERM;
595
596   /* Check and normalize the name. */
597   if ((retval = nc4_check_name(newname, norm_newname)))
598      return retval;
599
600   /* Is norm_newname in use? */
601   if (varid == NC_GLOBAL)
602   {
603      list = grp->att;
604   }
605   else
606   {
607      for (var = grp->var; var; var = var->next)
608         if (var->varid == varid)
609         {
610            list = var->att;
611            break;
612         }
613      if (!var)
614         return NC_ENOTVAR;
615   }
616   for (att = list; att; att = att->next)
617      if (!strncmp(att->name, norm_newname, NC_MAX_NAME))
618         return NC_ENAMEINUSE;
619
620   /* Normalize name and find the attribute. */
621   if ((retval = nc4_normalize_name(name, norm_name)))
622      return retval;
623   for (att = list; att; att = att->next)
624      if (!strncmp(att->name, norm_name, NC_MAX_NAME))
625         break;
626   if (!att)
627      return NC_ENOTATT;
628
629   /* If we're not in define mode, new name must be of equal or
630      less size, if complying with strict NC3 rules. */
631   if (!(h5->flags & NC_INDEF) && strlen(norm_newname) > strlen(att->name) &&
632       (h5->cmode & NC_CLASSIC_MODEL))
633      return NC_ENOTINDEFINE;
634
635   /* Delete the original attribute, if it exists in the HDF5 file. */
636   if (att->created)
637   {
638      if (varid == NC_GLOBAL)
639      {
640         if (H5Adelete(grp->hdf_grpid, att->name) < 0)
641            return NC_EHDFERR;
642      }
643      else
644      {
645         if ((retval = nc4_open_var_grp2(grp, varid, &datasetid)))
646            return retval;
647         if (H5Adelete(datasetid, att->name) < 0)
648            return NC_EHDFERR;
649      }
650      att->created = 0;
651   }
652
653   /* Copy the new name into our metadata. */
654   free(att->name);
655   if (!(att->name = malloc((strlen(norm_newname) + 1) * sizeof(char))))
656      return NC_ENOMEM;
657   strcpy(att->name, norm_newname);
658   att->dirty = 1;
659
660   return retval;
661}
662
663/* Delete an att. Rub it out. Push the button on it. Liquidate
664   it. Bump it off. Take it for a one-way ride. Terminate it. Drop the
665   bomb on it. You get the idea.
666   Ed Hartnett, 10/1/3
667*/
668int
669NC4_del_att(int ncid, int varid, const char *name)
670{
671   NC_FILE_INFO_T *nc;
672   NC_GRP_INFO_T *grp; 
673   NC_HDF5_FILE_INFO_T *h5;
674   NC_ATT_INFO_T *att, *natt;
675   NC_VAR_INFO_T *var;
676   NC_ATT_INFO_T **attlist = NULL;
677   hid_t locid = 0, datasetid = 0;
678   int retval = NC_NOERR;
679
680   if (!name)
681      return NC_EINVAL;
682
683   LOG((2, "nc_del_att: ncid 0x%x varid %d name %s",
684        ncid, varid, name));
685   
686   /* Find metadata for this file. */
687   if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
688      return retval;
689
690#ifdef USE_PNETCDF
691   /* Take care of files created/opened with parallel-netcdf library. */
692   if (nc->pnetcdf_file)
693      return ncmpi_del_att(nc->int_ncid, varid, name);   
694#endif /* USE_PNETCDF */
695
696   /* Handle netcdf-3 files. */
697   assert(h5);
698
699   assert(h5 && grp);
700
701   /* If the file is read-only, return an error. */
702   if (h5->no_write)
703      return NC_EPERM;
704
705   /* If it's not in define mode, forget it. */
706   if (!(h5->flags & NC_INDEF))
707   {
708      if (h5->cmode & NC_CLASSIC_MODEL)
709         return NC_ENOTINDEFINE;
710      if ((retval = NC4_redef(ncid)))
711         BAIL(retval);
712   }
713
714   /* Get either the global or a variable attribute list. Also figure
715      out the HDF5 location it's attached to. */
716   if (varid == NC_GLOBAL)
717   {
718      attlist = &grp->att;
719      locid = grp->hdf_grpid;
720   }
721   else
722   {
723      for(var = grp->var; var; var = var->next)
724      {
725         if (var->varid == varid)
726         {
727            attlist = &var->att;
728            break;
729         }
730      }
731      if (!var)
732         return NC_ENOTVAR;
733      if (var->created)
734      {
735         locid = var->hdf_datasetid;
736      }
737   }
738
739   /* Now find the attribute by name or number. */
740   for (att = *attlist; att; att = att->next)
741      if (!strcmp(att->name, name))
742         break;
743
744   /* If att is NULL, we couldn't find the attribute. */
745   if (!att) 
746      BAIL_QUIET(NC_ENOTATT);
747   
748   /* Delete it from the HDF5 file, if it's been created. */
749   if (att->created)
750      if(H5Adelete(locid, att->name) < 0)
751         BAIL(NC_EATTMETA);
752
753   /* Renumber all following attributes. */
754   for (natt = att->next; natt; natt = natt->next)
755      natt->attnum--;
756
757   /* Delete this attribute from this list. */
758   if ((retval = nc4_att_list_del(attlist, att)))
759      BAIL(retval);
760   
761 exit:
762   if (datasetid > 0) H5Dclose(datasetid);
763   return retval;
764}
765
766/* Write an attribute with type conversion. */
767int
768nc4_put_att_tc(int ncid, int varid, const char *name, nc_type file_type, 
769               nc_type mem_type, int mem_type_is_long, size_t len, 
770               const void *op)
771{
772   NC_FILE_INFO_T *nc;
773
774   if (!name || strlen(name) > NC_MAX_NAME)
775      return NC_EBADNAME;
776
777   LOG((3, "nc4_put_att_tc: ncid 0x%x varid %d name %s file_type %d "
778        "mem_type %d len %d", ncid, varid, name, file_type, mem_type, len));
779
780   /* The length needs to be positive (cast needed for braindead
781      systems with signed size_t). */
782   if((unsigned long) len > X_INT_MAX) 
783      return NC_EINVAL;
784
785   /* Find metadata. */
786   if (!(nc = nc4_find_nc_file(ncid)))
787      return NC_EBADID;
788
789#ifdef USE_PNETCDF
790   /* Take care of files created/opened with parallel-netcdf library. */
791   if (nc->pnetcdf_file)
792   {
793      if (mem_type == NC_UBYTE)
794         mem_type = NC_BYTE;
795      switch(mem_type)
796      {
797         case NC_BYTE:
798            return ncmpi_put_att_schar(nc->int_ncid, varid, name, 
799                                     file_type, len, op);
800         case NC_CHAR:
801            return ncmpi_put_att_text(nc->int_ncid, varid, name, 
802                                    len, op);
803         case NC_SHORT:
804            return ncmpi_put_att_short(nc->int_ncid, varid, name, 
805                                     file_type, len, op);
806         case NC_INT:
807            if (mem_type_is_long)
808               return ncmpi_put_att_long(nc->int_ncid, varid, name, 
809                                       file_type, len, op);
810            else
811               return ncmpi_put_att_int(nc->int_ncid, varid, name, 
812                                      file_type, len, op);
813         case NC_FLOAT:
814            return ncmpi_put_att_float(nc->int_ncid, varid, name, 
815                                     file_type, len, op);
816         case NC_DOUBLE:
817            return ncmpi_put_att_double(nc->int_ncid, varid, name, 
818                                      file_type, len, op);
819         case NC_NAT:
820         default:
821            return NC_EBADTYPE;
822      }
823   }
824#endif /* USE_PNETCDF */
825
826   /* Handle netcdf-3 files. */
827   assert(nc->nc4_info);
828
829   /* Otherwise, handle things the netcdf-4 way. */
830   return nc4_put_att(ncid, nc, varid, name, file_type, mem_type, len, 
831                      mem_type_is_long, op);
832}
833
834/* Read an attribute of any type, with type conversion. This may be
835 * called by any of the nc_get_att_* functions. */
836int
837nc4_get_att_tc(int ncid, int varid, const char *name, nc_type mem_type, 
838               int mem_type_is_long, void *ip)
839{
840   NC_FILE_INFO_T *nc;
841
842   LOG((3, "nc4_get_att_tc: ncid 0x%x varid %d name %s mem_type %d", 
843        ncid, varid, name, mem_type));
844
845   /* Find metadata. */
846   if (!(nc = nc4_find_nc_file(ncid)))
847      return NC_EBADID;
848
849#ifdef USE_PNETCDF
850   /* Take care of files created/opened with parallel-netcdf library. */
851   if (nc->pnetcdf_file)
852   {
853      if (mem_type == NC_UBYTE)
854         mem_type = NC_BYTE;
855      switch(mem_type)
856      {
857         case NC_BYTE:
858            return ncmpi_get_att_schar(nc->int_ncid, varid, name, ip);
859         case NC_CHAR:
860            return ncmpi_get_att_text(nc->int_ncid, varid, name, ip);
861         case NC_SHORT:
862            return ncmpi_get_att_short(nc->int_ncid, varid, name, ip);
863         case NC_INT:
864            if (mem_type_is_long)
865               return ncmpi_get_att_long(nc->int_ncid, varid, name, ip);
866            else
867               return ncmpi_get_att_int(nc->int_ncid, varid, name, ip);
868         case NC_FLOAT:
869            return ncmpi_get_att_float(nc->int_ncid, varid, name, ip);
870         case NC_DOUBLE:
871            return ncmpi_get_att_double(nc->int_ncid, varid, name, ip);
872         case NC_NAT:
873         default:
874            return NC_EBADTYPE;
875      }
876   }
877#endif /* USE_PNETCDF */
878
879   /* Handle netcdf-3 files. */
880   assert(nc->nc4_info);
881
882   return nc4_get_att(ncid, nc, varid, name, NULL, mem_type, 
883                      NULL, NULL, mem_type_is_long, ip);
884}
885
886int
887NC4_put_att(int ncid, int varid, const char *name, nc_type xtype, 
888                   size_t nelems, const void *value, nc_type memtype)
889{
890   return nc4_put_att_tc(ncid, varid, name, xtype, memtype, 0, nelems, value);
891}
892
893int
894NC4_get_att(int ncid, int varid, const char *name, void *value, nc_type memtype)
895{
896   return nc4_get_att_tc(ncid, varid, name, memtype, 0, value);
897}
Note: See TracBrowser for help on using the repository browser.