1 /** \file
2 Attribute functions
3 
4 These functions read and write attributes.
5 
6 Copyright 2010 University Corporation for Atmospheric
7 Research/Unidata. See \ref copyright file for more info.  */
8 
9 #include "ncdispatch.h"
10 
11 /** \name Getting Attributes
12 
13 Functions to get the values of attributes.
14  */
15 /*! \{ */
16 
17 /*!
18 \ingroup attributes
19 Get an attribute of any type.
20 
21 The nc_get_att() functions works for any type of attribute, and must
22 be used to get attributes of user-defined type. We recommend that they
23 type safe versions of this function be used for atomic data types.
24 
25 \param ncid NetCDF or group ID, from a previous call to nc_open(),
26 nc_create(), nc_def_grp(), or associated inquiry functions such as
27 nc_inq_ncid().
28 
29 \param varid Variable ID of the attribute's variable, or ::NC_GLOBAL
30 for a global attribute.
31 
32 \param name Attribute name.
33 
34 \param value Pointer to location for returned attribute value(s). All
35 elements of the vector of attribute values are returned, so you must
36 allocate enough space to hold them. Before using the value as a C
37 string, make sure it is null-terminated. Call nc_inq_attlen() first to
38 find out the length of the attribute.
39 
40 \note See documentation for nc_get_att_string() regarding a special
41 case where memory must be explicitly released.
42 
43 \returns ::NC_NOERR for success.
44 \returns ::NC_EBADID Bad ncid.
45 \returns ::NC_ENOTVAR Bad varid.
46 \returns ::NC_EBADNAME Bad name. See \ref object_name.
47 \returns ::NC_EINVAL Invalid parameters.
48 \returns ::NC_ENOTATT Can't find attribute.
49 \returns ::NC_ECHAR Can't convert to or from NC_CHAR.
50 \returns ::NC_ENOMEM Out of memory.
51 \returns ::NC_ERANGE Data conversion went out of range.
52 
53 <h1>Example</h1>
54 
55 Here is an example using nc_get_att() from nc_test4/tst_vl.c creates a
56 VLEN attribute, then uses nc_get_att() to read it.
57 
58 @code
59 #define FILE_NAME "tst_vl.nc"
60 #define VLEN_NAME "vlen_name"
61 #define ATT_NAME "att_name"
62 
63       int ncid, typeid;
64       nc_vlen_t data[DIM_LEN], data_in[DIM_LEN];
65       ...
66 
67       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
68       if (nc_def_vlen(ncid, VLEN_NAME, NC_INT, &typeid)) ERR;
69       ...
70       if (nc_put_att(ncid, NC_GLOBAL, ATT_NAME, typeid, DIM_LEN, data)) ERR;
71       if (nc_close(ncid)) ERR;
72 
73       ...
74       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
75       if (nc_get_att(ncid, NC_GLOBAL, ATT_NAME, data_in)) ERR;
76       ...
77       if (nc_close(ncid)) ERR;
78 @endcode
79 
80 \author Glenn Davis, Ed Hartnett, Dennis Heimbigner
81 */
82 int
nc_get_att(int ncid,int varid,const char * name,void * value)83 nc_get_att(int ncid, int varid, const char *name, void *value)
84 {
85    NC* ncp;
86    int stat = NC_NOERR;
87    nc_type xtype;
88 
89    if ((stat = NC_check_id(ncid, &ncp)))
90       return stat;
91 
92    /* Need to get the type */
93    if ((stat = nc_inq_atttype(ncid, varid, name, &xtype)))
94       return stat;
95 
96    TRACE(nc_get_att);
97    return ncp->dispatch->get_att(ncid, varid, name, value, xtype);
98 }
99 /*! \} */
100 
101 /*!
102 \ingroup attributes
103 Get an attribute.
104 
105 This function gets an attribute from the netCDF file. The nc_get_att()
106 function works with any type of data, including user defined types.
107 
108 \note The netCDF library reads all attributes into memory when the
109 file is opened with nc_open(). Getting an attribute copies the value
110 from the in-memory store, and does not incur any file I/O penalties.
111 
112 \param ncid NetCDF or group ID, from a previous call to nc_open(),
113 nc_create(), nc_def_grp(), or associated inquiry functions such as
114 nc_inq_ncid().
115 
116 \param varid Variable ID of the attribute's variable, or ::NC_GLOBAL
117 for a global attribute.
118 
119 \param name Attribute name.
120 
121 \param value Pointer to location for returned attribute value(s). All
122 elements of the vector of attribute values are returned, so you must
123 allocate enough space to hold them. If you don't know how much
124 space to reserve, call nc_inq_attlen() first to find out the length of
125 the attribute.
126 
127 \returns ::NC_NOERR for success.
128 \returns ::NC_EBADID Bad ncid.
129 \returns ::NC_ENOTVAR Bad varid.
130 \returns ::NC_EBADNAME Bad name. See \ref object_name.
131 \returns ::NC_EINVAL Invalid parameters.
132 \returns ::NC_ENOTATT Can't find attribute.
133 \returns ::NC_ECHAR Can't convert to or from NC_CHAR.
134 \returns ::NC_ENOMEM Out of memory.
135 \returns ::NC_ERANGE Data conversion went out of range.
136 
137 <h1>Example</h1>
138 
139 Here is an example using nc_get_att_double() to determine the values
140 of a variable attribute named valid_range for a netCDF variable named
141 rh and using nc_get_att_text() to read a global attribute named title
142 in an existing netCDF dataset named foo.nc.
143 
144 In this example, it is assumed that we don't know how many values will
145 be returned, but that we do know the types of the attributes. Hence,
146 to allocate enough space to store them, we must first inquire about
147 the length of the attributes.
148 
149 \code
150      #include <netcdf.h>
151         ...
152      int  status;
153      int  ncid;
154      int  rh_id;
155      int  vr_len, t_len;
156      double *vr_val;
157      char *title;
158      extern char *malloc()
159 
160         ...
161      status = nc_open("foo.nc", NC_NOWRITE, &ncid);
162      if (status != NC_NOERR) handle_error(status);
163         ...
164      status = nc_inq_varid (ncid, "rh", &rh_id);
165      if (status != NC_NOERR) handle_error(status);
166         ...
167      status = nc_inq_attlen (ncid, rh_id, "valid_range", &vr_len);
168      if (status != NC_NOERR) handle_error(status);
169      status = nc_inq_attlen (ncid, NC_GLOBAL, "title", &t_len);
170      if (status != NC_NOERR) handle_error(status);
171 
172      vr_val = (double *) malloc(vr_len * sizeof(double));
173      title = (char *) malloc(t_len + 1);
174 
175      status = nc_get_att_double(ncid, rh_id, "valid_range", vr_val);
176      if (status != NC_NOERR) handle_error(status);
177      status = nc_get_att_text(ncid, NC_GLOBAL, "title", title);
178      if (status != NC_NOERR) handle_error(status);
179      title[t_len] = '\0';
180         ...
181 \endcode
182 \author Glenn Davis, Ed Hartnett, Dennis Heimbigner
183 */
184 /*! \{ */
185 
186 int
nc_get_att_text(int ncid,int varid,const char * name,char * value)187 nc_get_att_text(int ncid, int varid, const char *name, char *value)
188 {
189    NC* ncp;
190    int stat = NC_check_id(ncid, &ncp);
191    if(stat != NC_NOERR) return stat;
192    TRACE(nc_get_att_text);
193    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_CHAR);
194 }
195 
196 int
nc_get_att_schar(int ncid,int varid,const char * name,signed char * value)197 nc_get_att_schar(int ncid, int varid, const char *name, signed char *value)
198 {
199    NC* ncp;
200    int stat = NC_check_id(ncid, &ncp);
201    if(stat != NC_NOERR) return stat;
202    TRACE(nc_get_att_schar);
203    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_BYTE);
204 }
205 
206 int
nc_get_att_uchar(int ncid,int varid,const char * name,unsigned char * value)207 nc_get_att_uchar(int ncid, int varid, const char *name, unsigned char *value)
208 {
209    NC* ncp;
210    int stat = NC_check_id(ncid, &ncp);
211    if(stat != NC_NOERR) return stat;
212    TRACE(nc_get_att_uchar);
213    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_UBYTE);
214 }
215 
216 int
nc_get_att_short(int ncid,int varid,const char * name,short * value)217 nc_get_att_short(int ncid, int varid, const char *name, short *value)
218 {
219    NC* ncp;
220    int stat = NC_check_id(ncid, &ncp);
221    if(stat != NC_NOERR) return stat;
222    TRACE(nc_get_att_short);
223    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_SHORT);
224 }
225 
226 int
nc_get_att_int(int ncid,int varid,const char * name,int * value)227 nc_get_att_int(int ncid, int varid, const char *name, int *value)
228 {
229    NC* ncp;
230    int stat = NC_check_id(ncid, &ncp);
231    if(stat != NC_NOERR) return stat;
232    TRACE(nc_get_att_int);
233    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_INT);
234 }
235 
236 int
nc_get_att_long(int ncid,int varid,const char * name,long * value)237 nc_get_att_long(int ncid, int varid, const char *name, long *value)
238 {
239    NC* ncp;
240    int stat = NC_check_id(ncid, &ncp);
241    if(stat != NC_NOERR) return stat;
242    TRACE(nc_get_att_long);
243    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, longtype);
244 }
245 
246 int
nc_get_att_float(int ncid,int varid,const char * name,float * value)247 nc_get_att_float(int ncid, int varid, const char *name, float *value)
248 {
249    NC* ncp;
250    int stat = NC_check_id(ncid, &ncp);
251    if(stat != NC_NOERR) return stat;
252    TRACE(nc_get_att_float);
253    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_FLOAT);
254 }
255 
256 int
nc_get_att_double(int ncid,int varid,const char * name,double * value)257 nc_get_att_double(int ncid, int varid, const char *name, double *value)
258 {
259    NC* ncp;
260    int stat = NC_check_id(ncid, &ncp);
261    if(stat != NC_NOERR) return stat;
262    TRACE(nc_get_att_double);
263    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_DOUBLE);
264 }
265 
266 int
nc_get_att_ubyte(int ncid,int varid,const char * name,unsigned char * value)267 nc_get_att_ubyte(int ncid, int varid, const char *name, unsigned char *value)
268 {
269    NC* ncp;
270    int stat = NC_check_id(ncid, &ncp);
271    if(stat != NC_NOERR) return stat;
272    TRACE(nc_get_att_ubyte);
273    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_UBYTE);
274 }
275 
276 int
nc_get_att_ushort(int ncid,int varid,const char * name,unsigned short * value)277 nc_get_att_ushort(int ncid, int varid, const char *name, unsigned short *value)
278 {
279    NC* ncp;
280    int stat = NC_check_id(ncid, &ncp);
281    if(stat != NC_NOERR) return stat;
282    TRACE(nc_get_att_ushort);
283    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_USHORT);
284 }
285 
286 int
nc_get_att_uint(int ncid,int varid,const char * name,unsigned int * value)287 nc_get_att_uint(int ncid, int varid, const char *name, unsigned int *value)
288 {
289    NC* ncp;
290    int stat = NC_check_id(ncid, &ncp);
291    if(stat != NC_NOERR) return stat;
292    TRACE(nc_get_att_uint);
293    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_UINT);
294 }
295 
296 int
nc_get_att_longlong(int ncid,int varid,const char * name,long long * value)297 nc_get_att_longlong(int ncid, int varid, const char *name, long long *value)
298 {
299    NC* ncp;
300    int stat = NC_check_id(ncid, &ncp);
301    if(stat != NC_NOERR) return stat;
302    TRACE(nc_get_att_longlong);
303    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_INT64);
304 }
305 
306 int
nc_get_att_ulonglong(int ncid,int varid,const char * name,unsigned long long * value)307 nc_get_att_ulonglong(int ncid, int varid, const char *name, unsigned long long *value)
308 {
309    NC *ncp;
310    int stat = NC_check_id(ncid, &ncp);
311    if(stat != NC_NOERR) return stat;
312    TRACE(nc_get_att_ulonglong);
313    return ncp->dispatch->get_att(ncid, varid, name, (void *)value, NC_UINT64);
314 }
315 /*! \} */
316 
317 /*!
318 \ingroup attributes
319 Get a variable-length string attribute.
320 
321 This function gets an attribute from netCDF file. The nc_get_att()
322 function works with any type of data including user defined types, but
323 this function will retrieve attributes which are of type
324 variable-length string.
325 
326 \note Note that unlike most other nc_get_att functions,
327 nc_get_att_string() allocates a chunk of memory which is returned to
328 the calling function.  This chunk of memory must be specifically
329 deallocated with nc_free_string() to avoid any memory leaks.  Also
330 note that you must still preallocate the memory needed for the array
331 of pointers passed to nc_get_att_string().
332 
333 \param ncid NetCDF or group ID, from a previous call to nc_open(),
334 nc_create(), nc_def_grp(), or associated inquiry functions such as
335 nc_inq_ncid().
336 
337 \param varid Variable ID of the attribute's variable, or ::NC_GLOBAL
338 for a global attribute.
339 
340 \param name Attribute name.
341 
342 \param value Pointer to location for returned attribute value(s). All
343 elements of the vector of attribute values are returned, so you must
344 allocate enough space to hold them. If you don't know how much
345 space to reserve, call nc_inq_attlen() first to find out the length of
346 the attribute.
347 
348 \returns ::NC_NOERR for success.
349 \returns ::NC_EBADID Bad ncid.
350 \returns ::NC_ENOTVAR Bad varid.
351 \returns ::NC_EBADNAME Bad name. See \ref object_name.
352 \returns ::NC_EINVAL Invalid parameters.
353 \returns ::NC_ENOTATT Can't find attribute.
354 \returns ::NC_ECHAR Can't convert to or from NC_CHAR.
355 \returns ::NC_ENOMEM Out of memory.
356 \returns ::NC_ERANGE Data conversion went out of range.
357 
358 \section nc_get_att_string_example Example
359 
360 \code{.c}
361 #include <stdlib.h>
362 #include <stdio.h>
363 #include <string.h>
364 
365 #include <netcdf.h>
366 
367 void check(int stat) {
368   if (stat != NC_NOERR) {
369     printf("NetCDF error: %s\n", nc_strerror(stat));
370     exit(1);
371   }
372 }
373 
374 int main(int argc, char ** argv) {
375   int stat = 0;
376 
377   int ncid = 0;
378   stat = nc_open("test.nc", NC_NOWRITE, &ncid); check(stat);
379 
380   int varid = 0;
381   stat = nc_inq_varid(ncid, "variable", &varid); check(stat);
382 
383   size_t attlen = 0;
384   stat = nc_inq_attlen(ncid, varid, "attribute", &attlen); check(stat);
385 
386   char **string_attr = (char**)malloc(attlen * sizeof(char*));
387   memset(string_attr, 0, attlen * sizeof(char*));
388 
389   stat = nc_get_att_string(ncid, varid, "attribute", string_attr); check(stat);
390 
391   for (size_t k = 0; k < attlen; ++k) {
392     printf("variable:attribute[%d] = %s\n", k, string_attr[k]);
393   }
394 
395   stat = nc_free_string(attlen, string_attr); check(stat);
396 
397   free(string_attr);
398 
399   stat = nc_close(ncid); check(stat);
400 
401   return 0;
402 }
403 \endcode
404 \author Glenn Davis, Ed Hartnett, Dennis Heimbigner
405 */
406 
407 int
nc_get_att_string(int ncid,int varid,const char * name,char ** value)408 nc_get_att_string(int ncid, int varid, const char *name, char **value)
409 {
410     NC *ncp;
411     int stat = NC_check_id(ncid, &ncp);
412     if(stat != NC_NOERR) return stat;
413     TRACE(nc_get_att_string);
414     return ncp->dispatch->get_att(ncid,varid,name,(void*)value, NC_STRING);
415 }
416 /*! \} */
417