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