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