1 /* Copyright 2018 University Corporation for Atmospheric
2 Research/Unidata. See \ref copyright file for more info.  */
3 /**
4  * @file
5  * Attribute inquiry functions
6  *
7  * These functions find out about attributes.
8  */
9 #include "ncdispatch.h"
10 
11 /**
12  * @name Learning about Attributes
13  *
14  * Functions to learn about the attributes in a file. */
15 /** \{ */ /* All these functions are part of this named group... */
16 
17 /**
18  * @ingroup attributes
19  * Return information about a netCDF attribute.
20  *
21  * The function nc_inq_att returns the attribute's type and length.
22  *
23  * @param ncid NetCDF or group ID, from a previous call to nc_open(),
24  * nc_create(), nc_def_grp(), or associated inquiry functions such as
25  * nc_inq_ncid().
26  *
27  * @param varid Variable ID of the attribute's variable, or
28  * ::NC_GLOBAL for a global attribute.
29  *
30  * @param name Pointer to the location for the returned attribute \ref
31  * object_name. \ref ignored_if_null.
32  *
33  * @param xtypep Pointer to location for returned attribute \ref
34  * data_type. \ref ignored_if_null.
35  *
36  * @param lenp Pointer to location for returned number of values
37  * currently stored in the attribute. For attributes of type
38  * ::NC_CHAR, you should not assume that this includes a trailing zero
39  * byte; it doesn't if the attribute was stored without a trailing
40  * zero byte, for example from a FORTRAN program. Before using the
41  * value as a C string, make sure it is null-terminated. \ref
42  * ignored_if_null.
43  *
44  * @section nc_inq_att_example Example
45  *
46  * Here is an example using nc_inq_att() to find out the type and
47  * length of a variable attribute named valid_range for a netCDF
48  * variable named rh and a global attribute named title in an existing
49  * netCDF dataset named foo.nc:
50  *
51 @code
52      #include <netcdf.h>
53         ...
54      int  status;
55      int  ncid;
56      int  rh_id;
57      nc_type vr_type, t_type;
58      size_t  vr_len, t_len;
59 
60         ...
61      status = nc_open("foo.nc", NC_NOWRITE, &ncid);
62      if (status != NC_NOERR) handle_error(status);
63         ...
64      status = nc_inq_varid (ncid, "rh", &rh_id);
65      if (status != NC_NOERR) handle_error(status);
66         ...
67      status = nc_inq_att (ncid, rh_id, "valid_range", &vr_type, &vr_len);
68      if (status != NC_NOERR) handle_error(status);
69      status = nc_inq_att (ncid, NC_GLOBAL, "title", &t_type, &t_len);
70      if (status != NC_NOERR) handle_error(status);
71 @endcode
72  *
73  * @return ::NC_NOERR no error.
74  * @return ::NC_EBADID bad ncid.
75  * @return ::NC_ENOTVAR bad varid.
76  * @return ::NC_EBADGRPID bad group ID.
77  * @return ::NC_EBADNAME bad name.
78  * @return ::NC_ENOTATT attribute not found.
79  * @return ::NC_ECHAR illegal conversion to or from NC_CHAR.
80  * @return ::NC_ENOMEM out of memory.
81  * @return ::NC_ERANGE range error when converting data.
82  * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
83 */
84 int
nc_inq_att(int ncid,int varid,const char * name,nc_type * xtypep,size_t * lenp)85 nc_inq_att(int ncid, int varid, const char *name, nc_type *xtypep,
86 	   size_t *lenp)
87 {
88    NC* ncp;
89    int stat = NC_check_id(ncid, &ncp);
90    if(stat != NC_NOERR) return stat;
91    return ncp->dispatch->inq_att(ncid, varid, name, xtypep, lenp);
92 }
93 
94 /**
95  * @ingroup attributes
96  * Find an attribute ID.
97  *
98  * @param ncid NetCDF or group ID, from a previous call to nc_open(),
99  * nc_create(), nc_def_grp(), or associated inquiry functions such as
100  * nc_inq_ncid().
101  *
102  * @param varid Variable ID of the attribute's variable, or
103  * ::NC_GLOBAL for a global attribute.
104  *
105  * @param name Attribute \ref object_name.
106  *
107  * @param idp Pointer to location for returned attribute number that
108  * specifies which attribute this is for this variable (or which
109  * global attribute). If you already know the attribute name, knowing
110  * its number is not very useful, because accessing information about
111  * an attribute requires its name.
112  *
113  * @section nc_inq_attid_example Example
114  *
115  * Here is an example using nc_inq_attid() from
116  * nc_test4/tst_vars2.c. In this example three attributes are created
117  * in a file. Then it is re-opened, and their IDs are checked. They
118  * will be 0, 1, and 2, in the order that the attributes were written
119  * to the file.
120  *
121 @code
122      #include <netcdf.h>
123      ...
124      printf("**** testing fill value with three other attributes...");
125      {
126 #define NUM_LEADERS 3
127          char leader[NUM_LEADERS][NC_MAX_NAME + 1] = {"hair_length_of_strategoi",
128                                                       "hair_length_of_Miltiades",
129                                                       "hair_length_of_Darius_I"};
130          short hair_length[NUM_LEADERS] = {3, 11, 4};
131          short short_in;
132          int a;
133 
134          if (nc_create(FILE_NAME, cmode, &ncid)) ERR;
135          if (nc_def_dim(ncid, DIM1_NAME, DIM1_LEN, &dimids[0])) ERR;
136          if (nc_def_var(ncid, VAR_NAME, NC_BYTE, NUM_DIMS, dimids, &varid)) ERR;
137          for (a = 0; a < NUM_LEADERS; a++)
138             if (nc_put_att_short(ncid, varid, leader[a], NC_SHORT, 1, &hair_length[a])) ERR;
139          if (nc_put_att_schar(ncid, varid, _FillValue, NC_BYTE, 1, &fill_value)) ERR;
140          if (nc_close(ncid)) ERR;
141 
142          if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
143          for (a = 0; a < NUM_LEADERS; a++)
144          {
145             ...
146             if (nc_inq_attid(ncid, 0, leader[a], &attnum_in)) ERR;
147             if (attnum_in != a) ERR;
148          }
149 
150          if (nc_close(ncid)) ERR;
151 @endcode
152  *
153  * @return ::NC_NOERR no error.
154  * @return ::NC_EBADID bad ncid.
155  * @return ::NC_ENOTVAR bad varid.
156  * @return ::NC_EBADGRPID bad group ID.
157  * @return ::NC_EBADNAME bad name.
158  * @return ::NC_ENOTATT attribute not found.
159  * @return ::NC_ENOMEM out of memory.
160  * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
161 */
162 int
nc_inq_attid(int ncid,int varid,const char * name,int * idp)163 nc_inq_attid(int ncid, int varid, const char *name, int *idp)
164 {
165    NC* ncp;
166    int stat = NC_check_id(ncid, &ncp);
167    if(stat != NC_NOERR) return stat;
168    return ncp->dispatch->inq_attid(ncid, varid, name, idp);
169 }
170 
171 /**
172  * @ingroup attributes
173  * Find the name of an attribute.
174  *
175  * @param ncid NetCDF or group ID, from a previous call to nc_open(),
176  * nc_create(), nc_def_grp(), or associated inquiry functions such as
177  * nc_inq_ncid().
178  *
179  * @param varid Variable ID of the attribute's variable, or
180  * ::NC_GLOBAL for a global attribute.
181  *
182  * @param attnum Attribute number. The attributes for each variable
183  * are numbered from 0 (the first attribute) to natts-1, where natts
184  * is the number of attributes for the variable, as returned from a
185  * call to nc_inq_varnatts().
186  *
187  * @param name Pointer to the location for the returned attribute \ref
188  * object_name.
189  *
190  * @section nc_inq_attname_example Example
191  *
192  * Here is an example from nc_test4/tst_atts3.c a variable of every
193  * type is added to a file, with names from the 'names' array. Then
194  * the file is re-opened, and the names of the attributes are checked
195  * in a for loop.
196  *
197 @code
198      #include <netcdf.h>
199      ...
200 #define NUM_ATTS 8
201 #define ATT_MAX_NAME 25
202 int
203 tst_att_ordering(int cmode)
204 {
205    int ncid;
206    char name[NUM_ATTS][ATT_MAX_NAME + 1] = {"Gc", "Gb", "Gs", "Gi", "Gf",
207 					    "Gd", "Gatt-name-dashes", "Gatt.name.dots"};
208    int len[NUM_ATTS] = {0, 2, 3, 3, 3, 3, 1, 1};
209    signed char b[2] = {-128, 127};
210    short s[3] = {-32768, 0, 32767};
211    int i[3] = {42, 0, -42};
212    float f[3] = {42.0, -42.0, 42.0};
213    double d[3] = {420.0, -420.0, 420.0};
214    int att_name_dashes = -1, att_name_dots = -2;
215    char name_in[NC_MAX_NAME];
216    int j;
217 
218    if (nc_create(FILE_NAME, cmode, &ncid)) ERR;
219    ...
220    if (nc_put_att_text(ncid, NC_GLOBAL, name[0], len[0], NULL)) ERR;
221    if (nc_put_att_schar(ncid, NC_GLOBAL, name[1], NC_BYTE, len[1], b)) ERR;
222    if (nc_put_att_short(ncid, NC_GLOBAL, name[2], NC_SHORT, len[2], s)) ERR;
223    if (nc_put_att_int(ncid, NC_GLOBAL, name[3], NC_INT, len[3], i)) ERR;
224    if (nc_put_att_float(ncid, NC_GLOBAL, name[4], NC_FLOAT, len[4], f)) ERR;
225    if (nc_put_att_double(ncid, NC_GLOBAL, name[5], NC_DOUBLE, len[5], d)) ERR;
226    if (nc_put_att_int(ncid, NC_GLOBAL, name[6], NC_INT, len[6], &att_name_dashes)) ERR;
227    if (nc_put_att_int(ncid, NC_GLOBAL, name[7], NC_INT, len[7], &att_name_dots)) ERR;
228    if (nc_close(ncid)) ERR;
229 
230    ...
231    if (nc_open(FILE_NAME, 0, &ncid)) ERR;
232    for (j = 0; j < NUM_ATTS; j++)
233    {
234       if (nc_inq_attname(ncid, NC_GLOBAL, j, name_in)) ERR;
235       if (strcmp(name_in, name[j])) ERR;
236    }
237 
238    if (nc_close(ncid)) ERR;
239 
240 @endcode
241  *
242  * @return ::NC_NOERR no error.
243  * @return ::NC_EBADID bad ncid.
244  * @return ::NC_ENOTVAR bad varid.
245  * @return ::NC_EBADGRPID bad group ID.
246  * @return ::NC_EBADNAME bad name.
247  * @return ::NC_ENOTATT attribute not found.
248  * @return ::NC_ECHAR illegal conversion to or from NC_CHAR.
249  * @return ::NC_ENOMEM out of memory.
250  * @return ::NC_ERANGE range error when converting data.
251  * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
252 */
253 int
nc_inq_attname(int ncid,int varid,int attnum,char * name)254 nc_inq_attname(int ncid, int varid, int attnum, char *name)
255 {
256    NC* ncp;
257    int stat = NC_check_id(ncid, &ncp);
258    if(stat != NC_NOERR) return stat;
259    return ncp->dispatch->inq_attname(ncid, varid, attnum, name);
260 }
261 
262 /**
263  * @ingroup attributes
264  * Find number of global or group attributes.
265  *
266  * @param ncid NetCDF or group ID, from a previous call to nc_open(),
267  * nc_create(), nc_def_grp(), or associated inquiry functions such as
268  * nc_inq_ncid().
269  *
270  * @param nattsp Pointer where number of global or group attributes
271  * will be written. \ref ignored_if_null.
272  *
273  * @section nc_inq_natts_example Example
274  *
275  * Here is an example from nc_test4/tst_vars.c:
276  *
277 @code
278      #include <netcdf.h>
279      ...
280 int
281 check_4D_example(char *file_name, int expected_format)
282 {
283    int ncid;
284    int format, ndims_in, nvars_in, natts_in;
285    ...
286 
287    if (nc_open(file_name, 0, &ncid)) ERR;
288    ...
289    if (nc_inq_natts(ncid, &natts_in)) ERR;
290    if (natts_in != 0) ERR;
291 @endcode
292 
293  * @return ::NC_NOERR no error.
294  * @return ::NC_EBADID bad ncid.
295  * @return ::NC_EBADGRPID bad group ID.
296  * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
297 */
298 int
nc_inq_natts(int ncid,int * nattsp)299 nc_inq_natts(int ncid, int *nattsp)
300 {
301    NC* ncp;
302    int stat = NC_check_id(ncid, &ncp);
303    if(stat != NC_NOERR) return stat;
304    if(nattsp == NULL) return NC_NOERR;
305    return ncp->dispatch->inq(ncid, NULL, NULL, nattsp, NULL);
306 }
307 
308 /**
309  * @ingroup attributes
310  * Find the type of an attribute.
311  *
312  * @param ncid NetCDF or group ID, from a previous call to nc_open(),
313  * nc_create(), nc_def_grp(), or associated inquiry functions such as
314  * nc_inq_ncid().
315  *
316  * @param varid Variable ID of the attribute's variable, or
317  * ::NC_GLOBAL for a global or group attribute.
318  *
319  * @param name Attribute \ref object_name.
320  *
321  * @param xtypep Pointer to location for returned attribute \ref
322  * data_type.
323  *
324  * @section nc_inq_atttype_example Example
325  *
326  * Here is an example from nc_test4/tst_h_refs.c. In this example, a
327  * file with an integer attribute is open. It's type is confirmed to
328  * be NC_INT.
329  *
330 @code
331      #include <netcdf.h>
332      ...
333     printf("*** Checking accessing file through netCDF-4 API...");
334     {
335 	int ncid, varid, attid;
336 	nc_type type;
337 
338 	if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
339         ...
340 	if (nc_inq_atttype(ncid, NC_GLOBAL, INT_ATT_NAME, &type)) ERR;
341 	if (type != NC_INT) ERR;
342 
343 @endcode
344  *
345  * @return ::NC_NOERR no error.
346  * @return ::NC_EBADID bad ncid.
347  * @return ::NC_ENOTVAR bad varid.
348  * @return ::NC_EBADGRPID bad group ID.
349  * @return ::NC_EBADNAME bad name.
350  * @return ::NC_ENOTATT attribute not found.
351  * @return ::NC_ECHAR illegal conversion to or from NC_CHAR.
352  * @return ::NC_ENOMEM out of memory.
353  * @return ::NC_ERANGE range error when converting data.
354  * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
355 */
356 int
nc_inq_atttype(int ncid,int varid,const char * name,nc_type * xtypep)357 nc_inq_atttype(int ncid, int varid, const char *name, nc_type *xtypep)
358 {
359    NC* ncp;
360    int stat = NC_check_id(ncid, &ncp);
361    if(stat != NC_NOERR) return stat;
362    return ncp->dispatch->inq_att(ncid, varid, name, xtypep, NULL);
363 }
364 
365 /**
366  * @ingroup attributes
367  * Find the length of an attribute.
368  *
369  * @param ncid NetCDF or group ID, from a previous call to nc_open(),
370  * nc_create(), nc_def_grp(), or associated inquiry functions such as
371  * nc_inq_ncid().
372  *
373  * @param varid Variable ID of the attribute's variable, or
374  * ::NC_GLOBAL for a global or group attribute.
375  *
376  * @param name Attribute \ref object_name.
377  *
378  * @param lenp Pointer to location for returned number of values
379  * currently stored in the attribute. Before using the value as a C
380  * string, make sure it is null-terminated. \ref ignored_if_null.
381  *
382  * @section nc_inq_attlen_example Example
383  *
384  * Here is an example from nc_test4/tst_h_scalar.c which checks the
385  * attributes of an already-open netCDF file. In this code, the length
386  * of two attributes are checked, and found to be 1.
387  *
388 @code
389      #include <netcdf.h>
390      ...
391 int
392 check_attrs(int ncid, int obj)
393 {
394     int attid;
395     int natts = 0;
396     size_t len;
397     nc_type type;
398     char *vlstr;
399     char fixstr[10];
400     int x;
401 
402     ...
403     if (nc_inq_attlen(ncid, obj, VSTR_ATT1_NAME, &len)) ERR_GOTO;
404     if (len != 1) ERR_GOTO;
405     ...
406     if (nc_inq_attlen(ncid, obj, VSTR_ATT2_NAME, &len)) ERR_GOTO;
407     if (len != 1) ERR_GOTO;
408 
409 @endcode
410 
411  * @return ::NC_NOERR no error.
412  * @return ::NC_EBADID bad ncid.
413  * @return ::NC_ENOTVAR bad varid.
414  * @return ::NC_EBADGRPID bad group ID.
415  * @return ::NC_EBADNAME bad name.
416  * @return ::NC_ENOTATT attribute not found.
417  * @return ::NC_ECHAR illegal conversion to or from NC_CHAR.
418  * @return ::NC_ENOMEM out of memory.
419  * @return ::NC_ERANGE range error when converting data.
420  * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
421 */
422 int
nc_inq_attlen(int ncid,int varid,const char * name,size_t * lenp)423 nc_inq_attlen(int ncid, int varid, const char *name, size_t *lenp)
424 {
425    NC* ncp;
426    int stat = NC_check_id(ncid, &ncp);
427    if(stat != NC_NOERR) return stat;
428    return ncp->dispatch->inq_att(ncid, varid, name, NULL, lenp);
429 }
430 
431 /*! \} */  /* End of named group ...*/
432