1 /* This is part of the netCDF package.
2    Copyright 2005 University Corporation for Atmospheric Research/Unidata
3    See COPYRIGHT file for conditions of use.
4 
5    Test netcdf-4 group code.
6 
7    Ed Hartnett
8 */
9 
10 #include <nc_tests.h>
11 #include "err_macros.h"
12 #include "netcdf.h"
13 
14 #define FILE_NAME "tst_grps.nc"
15 #define FILE_NAME_CLASSIC "tst_grps_classic.nc"
16 #define FILE_NAME_CLASSIC_MODEL "tst_grps_classic_model.nc"
17 #define DIM1_NAME "kingdom"
18 #define DIM1_LEN 3
19 #define DIM2_NAME "year"
20 #define DIM2_LEN 5
21 #define VAR1_NAME "Number_of_Beheadings_in_Family"
22 #define DYNASTY "Tudor"
23 #define HENRY_IV "Henry_IV"
24 #define HENRY_VII "Henry_VII"
25 #define HENRY_VIII "Henry_VIII"
26 #define MARGARET "Margaret"
27 #define JAMES_V_OF_SCOTLAND "James_V_of_Scotland"
28 #define MARY_I_OF_SCOTLAND "Mary_I_of_Scotland"
29 #define JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND "James_VI_of_Scotland_and_I_of_England"
30 #define MAX_SIBLING_GROUPS 10
31 #define NUM_CASTLES_NAME "Number_of_Castles"
32 
33 int
main(int argc,char ** argv)34 main(int argc, char **argv)
35 {
36    printf("\n*** Testing netcdf-4 group functions.\n");
37    printf("*** testing simple group create...");
38    {
39       int ncid, ncid2;
40       char name_in[NC_MAX_NAME + 1];
41       int henry_vii_id;
42       int henry_viii_id;
43       int grpid_in[MAX_SIBLING_GROUPS], varids_in[MAX_SIBLING_GROUPS];
44       int nvars_in, ncid_in;
45       int parent_ncid;
46       char name_out[NC_MAX_NAME + 1];
47       int num_grps;
48 
49       /* Create a netCDF classic file. Groups will not be allowed. */
50       if (nc_create(FILE_NAME_CLASSIC, 0, &ncid2)) ERR;
51       if (nc_def_grp(ncid2, name_out, &henry_vii_id) != NC_ENOTNC4) ERR;
52       if (nc_close(ncid2)) ERR;
53 
54       /* Create a file with one group, a group to contain data about
55        * Henry VII. */
56       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
57       if (nc_inq_grp_parent(ncid, &parent_ncid) != NC_ENOGRP) ERR;
58       /* This should also work as simple "is this the root group" test */
59       if (nc_inq_grp_parent(ncid, NULL) != NC_ENOGRP) ERR;
60       strcpy(name_out, HENRY_VII);
61 
62       /* These will not work. */
63       if (nc_def_grp(ncid + TEST_VAL_42, name_out, &henry_vii_id) != NC_EBADID) ERR;
64       if (nc_def_grp(ncid, NULL, &henry_vii_id) != NC_EINVAL) ERR;
65       if (nc_def_grp(ncid, BAD_NAME, &henry_vii_id) != NC_EBADNAME) ERR;
66 
67       /* Define the group. */
68       if (nc_def_grp(ncid, name_out, &henry_vii_id)) ERR;
69 
70       /* Check it out. */
71       if (nc_inq_grp_parent(henry_vii_id, &parent_ncid)) ERR;
72       if (parent_ncid != ncid) ERR;
73       if (nc_inq_ncid(ncid, HENRY_VII, &ncid_in)) ERR;
74       if (ncid_in != henry_vii_id) ERR;
75       if (nc_inq_ncid(ncid, MARGARET, &ncid_in) != NC_ENOGRP) ERR;
76       if (nc_close(ncid)) ERR;
77 
78       /* Check it out. */
79       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
80       if (nc_inq_grp_parent(ncid, &parent_ncid) != NC_ENOGRP) ERR;
81       if (nc_inq_grps(ncid, &num_grps, NULL)) ERR;
82       if (num_grps != 1) ERR;
83       if (nc_inq_grps(ncid, NULL, grpid_in)) ERR;
84       if (nc_inq_grpname(ncid, name_in)) ERR;
85       if (strcmp(name_in, "/")) ERR;
86       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
87       if (nc_inq_grp_parent(grpid_in[0], &parent_ncid)) ERR;
88       if (parent_ncid != ncid) ERR;
89       if (strcmp(name_in, HENRY_VII)) ERR;
90       if (nc_inq_varids(grpid_in[0], &nvars_in, varids_in)) ERR;
91       if (nvars_in != 0) ERR;
92       if (nc_inq_varids(grpid_in[0], NULL, varids_in)) ERR;
93       if (nc_inq_varids(grpid_in[0], &nvars_in, NULL)) ERR;
94       if (nc_inq_varids(grpid_in[0], NULL, NULL)) ERR;
95 
96       if (nc_inq_ncid(ncid, HENRY_VII, &ncid_in)) ERR;
97       if (ncid_in != grpid_in[0]) ERR;
98 
99       /* These should fail - file is read-only. */
100       if (nc_def_grp(ncid, HENRY_VIII, &henry_viii_id) != NC_EPERM) ERR;
101       if (nc_rename_grp(grpid_in[0], HENRY_VIII) != NC_EPERM) ERR;
102 
103       /* Close the file. */
104       if (nc_close(ncid)) ERR;
105    }
106    SUMMARIZE_ERR;
107    printf("*** testing simple group rename...");
108    {
109       int ncid, ncid2;
110       int grpid_in;
111       char name_in[NC_MAX_NAME + 1];
112       int henry_vii_id;
113 
114       /* Create a classic model file. No groups will be allowed. */
115       if (nc_create(FILE_NAME_CLASSIC_MODEL, NC_NETCDF4|NC_CLASSIC_MODEL, &ncid2)) ERR;
116       if (nc_def_grp(ncid2, HENRY_VII, &henry_vii_id) != NC_ESTRICTNC3) ERR;
117       if (nc_def_var(ncid2, HENRY_IV, NC_INT, 0, NULL, NULL)) ERR;
118       if (nc_close(ncid2)) ERR;
119 
120       /* Create a file with one group, a group to contain data about
121        * Henry VII. */
122       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
123       if (nc_def_var(ncid, HENRY_IV, NC_INT, 0, NULL, NULL)) ERR;
124 
125       /* Turn off define mode. It will automatically be turned back on
126        * when nc_def_grp is called. */
127       if (nc_enddef(ncid)) ERR;
128       if (nc_def_grp(ncid, HENRY_VII, &henry_vii_id)) ERR;
129 
130       /* Check it out. */
131       if (nc_inq_grpname(henry_vii_id, name_in)) ERR;
132       if (strcmp(name_in, HENRY_VII)) ERR;
133 
134       /* These will not work. */
135       if (nc_rename_grp(henry_vii_id, BAD_NAME) != NC_EBADNAME) ERR;
136       if (nc_rename_grp(henry_vii_id, HENRY_IV) != NC_ENAMEINUSE) ERR;
137       if (nc_rename_grp(ncid, HENRY_IV) != NC_EBADGRPID) ERR;
138 
139       /* Rename the group. */
140       if (nc_rename_grp(henry_vii_id, HENRY_VIII)) ERR;
141 
142       /* Check it out. */
143       if (nc_inq_grpname(henry_vii_id, name_in)) ERR;
144       if (strcmp(name_in, HENRY_VIII)) ERR;
145 
146       /* Close the file. */
147       if (nc_close(ncid)) ERR;
148 
149       /* Re-open the file. */
150       if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
151 
152       /* Check it out. */
153       if (nc_inq_grps(ncid, NULL, &grpid_in)) ERR;
154       if (nc_inq_grpname(grpid_in, name_in)) ERR;
155       if (strcmp(name_in, HENRY_VIII)) ERR;
156 
157       /* Rename it. */
158       if (nc_rename_grp(grpid_in, HENRY_VII)) ERR;
159       if (nc_inq_grpname(grpid_in, name_in)) ERR;
160       if (strcmp(name_in, HENRY_VII)) ERR;
161 
162       /* Close the file. */
163       if (nc_close(ncid)) ERR;
164    }
165    SUMMARIZE_ERR;
166 
167    printf("*** testing netcdf-3 and group functions...");
168    {
169       int ncid;
170       char name_in[NC_MAX_NAME + 1];
171       size_t len_in;
172 
173       /* Create a classic file. */
174       if (nc_create(FILE_NAME, NC_CLOBBER, &ncid)) ERR;
175       if (nc_inq_grpname(ncid, name_in)) ERR;
176       if (strcmp(name_in, "/")) ERR;
177       if (nc_inq_grpname_full(ncid, &len_in, name_in)) ERR;
178       if (strcmp(name_in, "/") || len_in != 1) ERR;
179       if (nc_close(ncid)) ERR;
180    }
181    SUMMARIZE_ERR;
182 
183    printf("*** testing use of unlimited dim in parent group...");
184    {
185 #define NDIMS_IN_VAR 1
186 #define NDIMS_IN_FILE 2
187 #define BABE_LIMIT 3
188 #define DIM_NAME1 "Influence"
189 #define DIM_NAME2 "Babe_Factor"
190 #define VAR_NAME1 "Court_of_Star_Chamber"
191 #define VAR_NAME2 "Justice_of_the_Peace"
192 #define VAR_NAME3 "Bosworth_Field"
193       int ncid, dimid1, dimid2, varid1, varid2, varid3, henry_vii_id;
194       int grpid_in, varid_in1, varid_in2, varid_in3;
195       nc_type xtype_in;
196       int ndims_in, dimids_in[NDIMS_IN_FILE], dimid1_in, natts;
197       char name_in[NC_MAX_NAME + 1];
198       size_t len_in, index[NDIMS_IN_VAR] = {0};
199       long long value = NC_FILL_INT64 + 1, value_in;
200 
201       /* Create a file with an unlimited dim and a limited, used by
202        * variables in child groups. */
203       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
204       if (nc_def_dim(ncid, DIM_NAME1, NC_UNLIMITED, &dimid1)) ERR;
205       if (nc_def_dim(ncid, DIM_NAME2, BABE_LIMIT, &dimid2)) ERR;
206       if (nc_def_grp(ncid, HENRY_VII, &henry_vii_id)) ERR;
207       if (nc_def_var(henry_vii_id, VAR_NAME1, NC_INT64, NDIMS_IN_VAR, &dimid1, &varid1)) ERR;
208       if (nc_def_var(henry_vii_id, VAR_NAME2, NC_INT64, NDIMS_IN_VAR, &dimid1, &varid2)) ERR;
209       if (nc_def_var(henry_vii_id, VAR_NAME3, NC_INT64, NDIMS_IN_VAR, &dimid2, &varid3)) ERR;
210 
211       /* These won't work. */
212       if (nc_inq_ncid(ncid + TEST_VAL_42, HENRY_VII, &grpid_in) != NC_EBADID) ERR;
213 
214       /* Check it out. Find the group by name. */
215       if (nc_inq_ncid(ncid, HENRY_VII, &grpid_in)) ERR;
216 
217       /* Ensure that dimensions in parent are visible and correct. */
218       memset(dimids_in,0,sizeof(dimids_in));
219       if (nc_inq_dimids(grpid_in, &ndims_in, dimids_in, 1)) ERR;
220       if (ndims_in != NDIMS_IN_FILE || dimids_in[0] != dimid1 || dimids_in[1] != dimid2) ERR;
221       if (nc_inq_dim(grpid_in, dimids_in[0], name_in, &len_in)) ERR;
222       if (strcmp(name_in, DIM_NAME1) || len_in != 0) ERR;
223       if (nc_inq_dim(grpid_in, dimids_in[1], name_in, &len_in)) ERR;
224       if (strcmp(name_in, DIM_NAME2) || len_in != BABE_LIMIT) ERR;
225 
226       /* Check the vars in the group. */
227       if (nc_inq_varid(grpid_in, VAR_NAME1, &varid_in1)) ERR;
228       if (nc_inq_varid(grpid_in, VAR_NAME2, &varid_in2)) ERR;
229       if (nc_inq_varid(grpid_in, VAR_NAME3, &varid_in3)) ERR;
230       if (varid_in1 != varid1 || varid_in2 != varid2 || varid_in3 != varid3) ERR;
231       if (nc_inq_var(grpid_in, varid1, name_in, &xtype_in, &ndims_in, &dimid1_in, &natts)) ERR;
232       if (strcmp(name_in, VAR_NAME1) || xtype_in != NC_INT64 || ndims_in != NDIMS_IN_VAR ||
233           dimid1_in != dimid1 || natts != 0) ERR;
234       if (nc_inq_var(grpid_in, varid2, name_in, &xtype_in, &ndims_in, &dimid1_in, &natts)) ERR;
235       if (strcmp(name_in, VAR_NAME2) || xtype_in != NC_INT64 || ndims_in != NDIMS_IN_VAR ||
236           dimid1_in != dimid1 || natts != 0) ERR;
237       if (nc_inq_var(grpid_in, varid3, name_in, &xtype_in, &ndims_in, &dimid1_in, &natts)) ERR;
238       if (strcmp(name_in, VAR_NAME3) || xtype_in != NC_INT64 || ndims_in != NDIMS_IN_VAR ||
239           dimid1_in != dimid2 || natts != 0) ERR;
240 
241       /* Write one value to one variable. */
242       if (nc_put_var1_longlong(grpid_in, varid_in1, index, &value)) ERR;
243 
244       /* Read one value from the second unlim dim variable. It should
245        * be the fill value. */
246       if (nc_get_var1_longlong(grpid_in, varid_in2, index, &value_in)) ERR;
247       if (value_in != NC_FILL_INT64) ERR;
248 
249       /* Read one value from the variable with limited dim. It should
250        * be the fill value. */
251       if (nc_get_var1_longlong(grpid_in, varid_in3, index, &value_in)) ERR;
252       if (value_in != NC_FILL_INT64) ERR;
253 
254       /* Attempt to read beyond end of dimensions to generate error. */
255       index[0] = BABE_LIMIT;
256       if (nc_get_var1_longlong(grpid_in, varid_in1, index, &value_in) != NC_EINVALCOORDS) ERR;
257       if (nc_get_var1_longlong(grpid_in, varid_in2, index, &value_in) != NC_EINVALCOORDS) ERR;
258       if (nc_get_var1_longlong(grpid_in, varid_in3, index, &value_in) != NC_EINVALCOORDS) ERR;
259 
260       if (nc_close(ncid)) ERR;
261 
262       /* Check it out again. */
263       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
264 
265       /* Find the group by name. */
266       if (nc_inq_ncid(ncid, HENRY_VII, &grpid_in)) ERR;
267 
268       /* Ensure that dimensions in parent are visible and correct. */
269       if (nc_inq_dimids(grpid_in, &ndims_in, dimids_in, 1)) ERR;
270       if (ndims_in != NDIMS_IN_FILE || dimids_in[0] != dimid1 || dimids_in[1] != dimid2) ERR;
271       if (nc_inq_dim(grpid_in, dimids_in[0], name_in, &len_in)) ERR;
272       if (strcmp(name_in, DIM_NAME1) || len_in != 1) ERR;
273       if (nc_inq_dim(grpid_in, dimids_in[1], name_in, &len_in)) ERR;
274       if (strcmp(name_in, DIM_NAME2) || len_in != BABE_LIMIT) ERR;
275 
276       /* Check the vars in the group. */
277       if (nc_inq_varid(grpid_in, VAR_NAME1, &varid_in1)) ERR;
278       if (nc_inq_varid(grpid_in, VAR_NAME2, &varid_in2)) ERR;
279       if (nc_inq_varid(grpid_in, VAR_NAME3, &varid_in3)) ERR;
280       if (varid_in1 != varid1 || varid_in2 != varid2 || varid_in3 != varid3) ERR;
281       if (nc_inq_var(grpid_in, varid1, name_in, &xtype_in, &ndims_in, &dimid1_in, &natts)) ERR;
282       if (strcmp(name_in, VAR_NAME1) || xtype_in != NC_INT64 || ndims_in != NDIMS_IN_VAR ||
283           dimid1_in != dimid1 || natts != 0) ERR;
284       if (nc_inq_var(grpid_in, varid2, name_in, &xtype_in, &ndims_in, &dimid1_in, &natts)) ERR;
285       if (strcmp(name_in, VAR_NAME2) || xtype_in != NC_INT64 || ndims_in != NDIMS_IN_VAR ||
286           dimid1_in != dimid1 || natts != 0) ERR;
287       if (nc_inq_var(grpid_in, varid3, name_in, &xtype_in, &ndims_in, &dimid1_in, &natts)) ERR;
288       if (strcmp(name_in, VAR_NAME3) || xtype_in != NC_INT64 || ndims_in != NDIMS_IN_VAR ||
289           dimid1_in != dimid2 || natts != 0) ERR;
290 
291       /* Read one value from the second unlim dim variable. It should
292        * be the fill value. */
293       index[0] = 0;
294       if (nc_get_var1_longlong(grpid_in, varid_in2, index, &value_in)) ERR;
295       if (value_in != NC_FILL_INT64) ERR;
296 
297       /* Read one value from the variable with limited dim. It should
298        * be the fill value. */
299       if (nc_get_var1_longlong(grpid_in, varid_in3, index, &value_in)) ERR;
300       if (value_in != NC_FILL_INT64) ERR;
301 
302       /* Attempt to read beyond end of dimensions to generate error. */
303       index[0] = BABE_LIMIT;
304       if (nc_get_var1_longlong(grpid_in, varid_in1, index, &value_in) != NC_EINVALCOORDS) ERR;
305       if (nc_get_var1_longlong(grpid_in, varid_in2, index, &value_in) != NC_EINVALCOORDS) ERR;
306       if (nc_get_var1_longlong(grpid_in, varid_in3, index, &value_in) != NC_EINVALCOORDS) ERR;
307 
308       if (nc_close(ncid)) ERR;
309    }
310    SUMMARIZE_ERR;
311 
312    printf("*** testing simple nested group creates...");
313    {
314       char root_name[] = "/";
315       int ncid, grp_ncid;
316       int henry_vii_id, margaret_id, james_v_of_scotland_id, mary_i_of_scotland_id;
317       char name_in[NC_MAX_NAME + 1];
318       char full_name[NC_MAX_NAME * 10], full_name_in[NC_MAX_NAME * 10];
319       char full_name_in1[NC_MAX_NAME * 10];
320       char wrong_name[NC_MAX_NAME * 10];
321       int grpid_in[MAX_SIBLING_GROUPS];
322       int grp_in;
323       int grp_in2;
324       int num_grps;
325       size_t len, len1;
326 
327       /* This name is wrong. */
328       strcpy(wrong_name, "/");
329       strcat(wrong_name, HENRY_VII);
330       strcpy(wrong_name, "/");
331       strcat(wrong_name, MARGARET);
332       strcpy(wrong_name, "/");
333       strcat(wrong_name, MARGARET);
334 
335       /* Create a file with some nested groups in it, suitable
336        * to storing information about the Tudor dynasty of England. */
337       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
338       if (nc_def_grp(ncid, HENRY_VII, &henry_vii_id)) ERR;
339       if (nc_def_grp(henry_vii_id, MARGARET, &margaret_id)) ERR;
340       if (nc_def_grp(margaret_id, JAMES_V_OF_SCOTLAND, &james_v_of_scotland_id)) ERR;
341       if (nc_def_grp(james_v_of_scotland_id, MARY_I_OF_SCOTLAND, &mary_i_of_scotland_id)) ERR;
342       /* nc_def_grp will accept NULL as ID pointer. Group will be
343        * created, but ID not returned. */
344       if (nc_def_grp(mary_i_of_scotland_id, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, NULL)) ERR;
345 
346       strcpy(full_name, "/");
347       if (nc_inq_grpname_full(ncid, &len, full_name_in)) ERR;
348       if (len != 1 || strcmp(full_name_in, full_name)) ERR;
349       if (nc_inq_grpname_len(ncid, &len)) ERR;
350       if (len != 1) ERR;
351 
352       /* These won't work. */
353       if (nc_inq_grp_full_ncid(ncid + TEST_VAL_42, full_name, &grp_in) != NC_EBADID) ERR;
354       if (nc_inq_grp_full_ncid(ncid, NULL, &grp_in) != NC_EINVAL) ERR;
355 
356       /* Get the ncid from the full name. */
357       if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR;
358       if (grp_in != ncid) ERR;
359 
360       /* Works (pretty pointlessly) with NULL for ID pointer. */
361       if (nc_inq_grp_full_ncid(ncid, full_name, NULL)) ERR;
362 
363       /* Get the root group ID from '/'. */
364       if (nc_inq_grp_full_ncid(ncid, root_name, &grp_in2)) ERR;
365       if (grp_in2 != ncid) ERR;
366 
367       /* But the root group does not exist within another group. */
368       if (nc_inq_grp_full_ncid(mary_i_of_scotland_id, root_name, &grp_in2) != NC_ENOGRP) ERR;
369 
370       /* This name is wrong. */
371       if (nc_inq_grp_full_ncid(ncid, wrong_name, &grp_in2) != NC_ENOGRP) ERR;
372 
373       if (nc_inq_grp_ncid(ncid, HENRY_VII, NULL)) ERR;
374       if (nc_inq_grp_ncid(ncid, HENRY_VII, &grp_ncid)) ERR;
375       if (nc_inq_grps(ncid, &num_grps, NULL)) ERR;
376       if (num_grps != 1) ERR;
377       if (nc_inq_grps(ncid, NULL, grpid_in)) ERR;
378       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
379       if (strcmp(name_in, HENRY_VII)) ERR;
380       if (nc_inq_grpname(grpid_in[0], NULL)) ERR;
381       if (grpid_in[0] != grp_ncid) ERR;
382       strcat(full_name, HENRY_VII);
383       if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in)) ERR;
384       if (len != strlen(HENRY_VII) + 1 || strcmp(full_name_in, full_name)) ERR;
385       if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR;
386       if (grp_in != grpid_in[0]) ERR;
387 
388       /* Also works with NULL last param. */
389       if (nc_inq_grp_full_ncid(ncid, full_name, NULL)) ERR;
390 
391       if (nc_inq_grp_ncid(grpid_in[0], MARGARET, &grp_ncid)) ERR;
392       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
393       if (num_grps != 1) ERR;
394       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
395       if (strcmp(name_in, MARGARET)) ERR;
396       if (grpid_in[0] != grp_ncid) ERR;
397       strcat(full_name, "/");
398       strcat(full_name, MARGARET);
399       if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in)) ERR;
400       if (len != strlen(full_name) || strcmp(full_name_in, full_name)) ERR;
401       if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR;
402       if (grp_in != grpid_in[0]) ERR;
403 
404       if (nc_inq_grp_ncid(grpid_in[0], JAMES_V_OF_SCOTLAND, &grp_ncid)) ERR;
405       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
406       if (num_grps != 1) ERR;
407       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
408       if (strcmp(name_in, JAMES_V_OF_SCOTLAND)) ERR;
409       if (grpid_in[0] != grp_ncid) ERR;
410       strcat(full_name, "/");
411       strcat(full_name, JAMES_V_OF_SCOTLAND);
412       if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in)) ERR;
413       if (len != strlen(full_name) || strcmp(full_name_in, full_name)) ERR;
414       if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR;
415       if (grp_in != grpid_in[0]) ERR;
416 
417       if (nc_inq_grp_ncid(grpid_in[0], MARY_I_OF_SCOTLAND, &grp_ncid)) ERR;
418       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
419       if (num_grps != 1) ERR;
420       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
421       if (strcmp(name_in, MARY_I_OF_SCOTLAND)) ERR;
422       if (grpid_in[0] != grp_ncid) ERR;
423       strcat(full_name, "/");
424       strcat(full_name, MARY_I_OF_SCOTLAND);
425       if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in)) ERR;
426       if (len != strlen(full_name) || strcmp(full_name_in, full_name)) ERR;
427       if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR;
428       if (grp_in != grpid_in[0]) ERR;
429 
430       if (nc_inq_grp_ncid(grpid_in[0], JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &grp_ncid)) ERR;
431       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
432       if (num_grps != 1) ERR;
433       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
434       if (strcmp(name_in, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND)) ERR;
435       if (grpid_in[0] != grp_ncid) ERR;
436       strcat(full_name, "/");
437       strcat(full_name, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND);
438       if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in)) ERR;
439       if (len != strlen(full_name) || strcmp(full_name_in, full_name)) ERR;
440       if (nc_inq_grp_full_ncid(ncid, full_name, &grp_in)) ERR;
441       if (grp_in != grpid_in[0]) ERR;
442       if (nc_inq_grpname_full(grpid_in[0], NULL, NULL)) ERR;
443       if (nc_inq_grpname_full(grpid_in[0], &len1, NULL)) ERR;
444       if (len1 != strlen(full_name)) ERR;
445       if (nc_inq_grpname_full(grpid_in[0], &len, full_name_in1)) ERR;
446       if (strcmp(full_name_in1, full_name)) ERR;
447 
448       if (nc_close(ncid)) ERR;
449 
450       /* Check it out. */
451       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
452       if (nc_inq_grp_ncid(ncid, HENRY_VII, &grp_ncid)) ERR;
453       if (nc_inq_grps(ncid, &num_grps, NULL)) ERR;
454       if (num_grps != 1) ERR;
455       if (nc_inq_grps(ncid, NULL, grpid_in)) ERR;
456       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
457       if (strcmp(name_in, HENRY_VII)) ERR;
458       if (grpid_in[0] != grp_ncid) ERR;
459 
460       if (nc_inq_grp_ncid(grpid_in[0], MARGARET, &grp_ncid)) ERR;
461       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
462       if (num_grps != 1) ERR;
463       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
464       if (strcmp(name_in, MARGARET)) ERR;
465       if (grpid_in[0] != grp_ncid) ERR;
466 
467       if (nc_inq_grp_ncid(grpid_in[0], JAMES_V_OF_SCOTLAND, &grp_ncid)) ERR;
468       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
469       if (num_grps != 1) ERR;
470       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
471       if (strcmp(name_in, JAMES_V_OF_SCOTLAND)) ERR;
472       if (grpid_in[0] != grp_ncid) ERR;
473 
474       if (nc_inq_grp_ncid(grpid_in[0], MARY_I_OF_SCOTLAND, &grp_ncid)) ERR;
475       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
476       if (num_grps != 1) ERR;
477       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
478       if (strcmp(name_in, MARY_I_OF_SCOTLAND)) ERR;
479       if (grpid_in[0] != grp_ncid) ERR;
480 
481       if (nc_inq_grp_ncid(grpid_in[0], JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &grp_ncid)) ERR;
482       if (nc_inq_grps(grpid_in[0], &num_grps, grpid_in)) ERR;
483       if (num_grps != 1) ERR;
484       if (nc_inq_grpname(grpid_in[0], name_in)) ERR;
485       if (strcmp(name_in, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND)) ERR;
486       if (grpid_in[0] != grp_ncid) ERR;
487 
488       /* Close up shop. */
489       if (nc_close(ncid)) ERR;
490    }
491    SUMMARIZE_ERR;
492 
493    printf("*** testing simple sibling group creates...");
494    {
495       int ncid;
496       int henry_vii_id, margaret_id, james_v_of_scotland_id, mary_i_of_scotland_id;
497       int james_i_of_england_id, tudor_id;
498       char name_in[NC_MAX_NAME + 1];
499       int grpid_in[MAX_SIBLING_GROUPS];
500       int ncid_in;
501       int num_grps;
502       int dynasty;
503 
504       /* Create a file with one group, and beneath it a group for each Tudor. */
505       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
506       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
507       if (nc_def_grp(tudor_id, HENRY_VII, &henry_vii_id)) ERR;
508       if (nc_def_grp(tudor_id, MARGARET, &margaret_id)) ERR;
509       if (nc_def_grp(tudor_id, JAMES_V_OF_SCOTLAND, &james_v_of_scotland_id)) ERR;
510       if (nc_def_grp(tudor_id, MARY_I_OF_SCOTLAND, &mary_i_of_scotland_id)) ERR;
511       if (nc_def_grp(tudor_id, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &james_i_of_england_id)) ERR;
512       if (nc_close(ncid)) ERR;
513 
514       /* Make sure we've got all the tudors where we want them. */
515       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
516       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
517       if (num_grps != 1) ERR;
518       if (nc_inq_grpname(dynasty, name_in)) ERR;
519       if (strcmp(name_in, DYNASTY)) ERR;
520       if (nc_inq_grps(dynasty, &num_grps, grpid_in)) ERR;
521       if (num_grps != 5) ERR;
522       if (nc_inq_ncid(dynasty, HENRY_VII, &ncid_in)) ERR;
523       if (nc_inq_grpname(ncid_in, name_in)) ERR;
524       if (strcmp(name_in, HENRY_VII)) ERR;
525       if (nc_inq_ncid(dynasty, MARGARET, &ncid_in)) ERR;
526       if (nc_inq_grpname(ncid_in, name_in)) ERR;
527       if (strcmp(name_in, MARGARET)) ERR;
528       if (nc_inq_ncid(dynasty, JAMES_V_OF_SCOTLAND, &ncid_in)) ERR;
529       if (nc_inq_grpname(ncid_in, name_in)) ERR;
530       if (strcmp(name_in, JAMES_V_OF_SCOTLAND)) ERR;
531       if (nc_inq_ncid(dynasty, MARY_I_OF_SCOTLAND, &ncid_in)) ERR;
532       if (nc_inq_grpname(ncid_in, name_in)) ERR;
533       if (strcmp(name_in, MARY_I_OF_SCOTLAND)) ERR;
534       if (nc_inq_ncid(dynasty, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &ncid_in)) ERR;
535       if (nc_inq_grpname(ncid_in, name_in)) ERR;
536       if (strcmp(name_in, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND)) ERR;
537       if (nc_close(ncid)) ERR;
538    }
539    SUMMARIZE_ERR;
540 
541    printf("*** testing more group attributes...");
542    {
543       int ncid, num_grps, dynasty, ncid_in;
544       int grpid_in[MAX_SIBLING_GROUPS];
545       int henry_vii_id, margaret_id, james_v_of_scotland_id, mary_i_of_scotland_id;
546       int james_i_of_england_id, tudor_id;
547       int num_castles_henry_vii = 1, num_castles_margaret = 0, num_castles_james_v = 2;
548       int num_castles_mary_i = 3, num_castles_james_vi = 4;
549       char name_in[NC_MAX_NAME + 1];
550 
551       /* Create a file with one group, and beneath it a group for each
552        * Tudor. We will have some attributes in the groups.*/
553       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
554       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
555       if (nc_def_grp(tudor_id, HENRY_VII, &henry_vii_id)) ERR;
556       if (nc_put_att_int(henry_vii_id, NC_GLOBAL, NUM_CASTLES_NAME, NC_INT,
557 			 1, &num_castles_henry_vii)) ERR;
558       if (nc_def_grp(tudor_id, MARGARET, &margaret_id)) ERR;
559       if (nc_put_att_int(margaret_id, NC_GLOBAL, NUM_CASTLES_NAME, NC_INT,
560 			 1, &num_castles_margaret)) ERR;
561       if (nc_def_grp(tudor_id, JAMES_V_OF_SCOTLAND, &james_v_of_scotland_id)) ERR;
562       if (nc_put_att_int(james_v_of_scotland_id, NC_GLOBAL, NUM_CASTLES_NAME, NC_INT,
563 			 1, &num_castles_james_v)) ERR;
564       if (nc_def_grp(tudor_id, MARY_I_OF_SCOTLAND, &mary_i_of_scotland_id)) ERR;
565       if (nc_put_att_int(mary_i_of_scotland_id, NC_GLOBAL, NUM_CASTLES_NAME, NC_INT,
566 			 1, &num_castles_mary_i)) ERR;
567       if (nc_def_grp(tudor_id, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND,
568 		     &james_i_of_england_id)) ERR;
569       if (nc_put_att_int(james_i_of_england_id, NC_GLOBAL, NUM_CASTLES_NAME,
570 			 NC_INT, 1, &num_castles_james_vi)) ERR;
571       if (nc_close(ncid)) ERR;
572 
573       /* Make sure we've got all the tudors where we want them. */
574       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
575       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
576       if (num_grps != 1) ERR;
577       if (nc_inq_grpname(dynasty, name_in)) ERR;
578       if (strcmp(name_in, DYNASTY)) ERR;
579       if (nc_inq_grps(dynasty, &num_grps, grpid_in)) ERR;
580       if (num_grps != 5) ERR;
581       if (nc_inq_ncid(dynasty, HENRY_VII, &ncid_in)) ERR;
582       if (nc_inq_grpname(ncid_in, name_in)) ERR;
583       if (strcmp(name_in, HENRY_VII)) ERR;
584       if (nc_inq_ncid(dynasty, MARGARET, &ncid_in)) ERR;
585       if (nc_inq_grpname(ncid_in, name_in)) ERR;
586       if (strcmp(name_in, MARGARET)) ERR;
587       if (nc_inq_ncid(dynasty, JAMES_V_OF_SCOTLAND, &ncid_in)) ERR;
588       if (nc_inq_grpname(ncid_in, name_in)) ERR;
589       if (strcmp(name_in, JAMES_V_OF_SCOTLAND)) ERR;
590       if (nc_inq_ncid(dynasty, MARY_I_OF_SCOTLAND, &ncid_in)) ERR;
591       if (nc_inq_grpname(ncid_in, name_in)) ERR;
592       if (strcmp(name_in, MARY_I_OF_SCOTLAND)) ERR;
593       if (nc_inq_ncid(dynasty, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &ncid_in)) ERR;
594       if (nc_inq_grpname(ncid_in, name_in)) ERR;
595       if (strcmp(name_in, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND)) ERR;
596       if (nc_close(ncid)) ERR;
597    }
598    SUMMARIZE_ERR;
599 
600    printf("*** testing groups and dimensions...");
601    {
602       int ncid;
603       int tudor_id;
604       int num_grps;
605       int dimid, dimid_in, dynasty;
606       size_t len_in;
607       char name_in[NC_MAX_NAME + 1];
608 
609       /* Create a file with one group, and within that group, a dimension.*/
610       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
611       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
612       if (nc_def_dim(tudor_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
613       if (nc_close(ncid)) ERR;
614 
615       /* Now check the file to see if the dimension is there. */
616       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
617       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
618       if (num_grps != 1) ERR;
619       if (nc_inq_grpname(dynasty, name_in)) ERR;
620       if (strcmp(name_in, DYNASTY)) ERR;
621       if (nc_inq_dimid(dynasty, DIM1_NAME, &dimid_in)) ERR;
622       if (dimid_in != 0) ERR;
623       if (nc_inq_dimname(dynasty, 0, name_in)) ERR;
624       if (strcmp(name_in, DIM1_NAME)) ERR;
625       if (nc_inq_dim(dynasty, 0, name_in, &len_in)) ERR;
626       if (strcmp(name_in, DIM1_NAME)) ERR;
627       if (len_in != DIM1_LEN) ERR;
628       if (nc_close(ncid)) ERR;
629    }
630    SUMMARIZE_ERR;
631 
632    printf("*** testing groups and vars...");
633    {
634       int ncid, ndims_in;
635       int tudor_id;
636       int num_grps;
637       int dimid, dynasty, varid;
638       size_t len_in;
639       int natts_in;
640       nc_type xtype_in;
641       char name_in[NC_MAX_NAME + 1];
642       int dimids_in[MAX_SIBLING_GROUPS];
643 
644       /* Create a file with one group, and within that group, a
645        * dimension, and a variable.*/
646       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
647       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
648       if (nc_def_dim(tudor_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
649       if (nc_def_var(tudor_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
650       if (nc_close(ncid)) ERR;
651 
652       /* Now check the file to see if the dimension and variable are
653        * there. */
654       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
655       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
656       if (num_grps != 1) ERR;
657       if (nc_inq_dim(dynasty, 0, name_in, &len_in)) ERR;
658       if (strcmp(name_in, DIM1_NAME) || len_in != DIM1_LEN) ERR;
659       if (nc_inq_var(dynasty, 0, name_in, &xtype_in, &ndims_in, dimids_in,
660 		     &natts_in)) ERR;
661       if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_INT || ndims_in != 1 ||
662 	  dimids_in[0] != 0 || natts_in != 0) ERR;
663       if (nc_close(ncid)) ERR;
664    }
665    SUMMARIZE_ERR;
666 
667    printf("*** testing group functions in netCDF classic file...");
668    {
669       int ncid;
670       int num_grps;
671 
672       /* Create a classic file.*/
673       if (nc_create(FILE_NAME, 0, &ncid)) ERR;
674       if (nc_inq_grps(ncid, &num_grps, NULL)) ERR;
675       if (num_grps) ERR;
676       if (nc_close(ncid)) ERR;
677 
678       /* Now check the file to see if the dimension and variable are
679        * there. */
680       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
681       if (nc_inq_grps(ncid, &num_grps, NULL)) ERR;
682       if (num_grps) ERR;
683       if (nc_close(ncid)) ERR;
684    }
685    SUMMARIZE_ERR;
686 
687    printf("*** testing groups and vars...");
688    {
689       int ncid, ndims_in;
690       int henry_vii_id, margaret_id, james_v_of_scotland_id, mary_i_of_scotland_id;
691       int james_i_of_england_id, tudor_id;
692       int dimids_in[MAX_SIBLING_GROUPS];
693       int num_grps;
694       int dimid, dynasty, varid;
695       size_t len_in;
696       int natts_in;
697       int grpids_in[10];
698       nc_type xtype_in;
699       char name_in[NC_MAX_NAME + 1];
700       int data_out[DIM1_LEN] = {-99, 0, 99}, data_in[DIM1_LEN];
701       int i, j;
702 
703       /* Create a file with a group, DYNASTY, containing 5 groups,
704        * each with a dimension and one int variable. */
705       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
706       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
707       /* Henry VII. */
708       if (nc_def_grp(tudor_id, HENRY_VII, &henry_vii_id)) ERR;
709       if (nc_def_dim(henry_vii_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
710       if (nc_def_var(henry_vii_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
711       if (nc_put_var_int(henry_vii_id, varid, data_out)) ERR;
712       /* Margaret. */
713       if (nc_def_grp(tudor_id, MARGARET, &margaret_id)) ERR;
714       if (nc_def_dim(margaret_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
715       if (nc_def_var(margaret_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
716       if (nc_put_var_int(margaret_id, varid, data_out)) ERR;
717       /* James V of Scotland. */
718       if (nc_def_grp(tudor_id, JAMES_V_OF_SCOTLAND, &james_v_of_scotland_id)) ERR;
719       if (nc_def_dim(james_v_of_scotland_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
720       if (nc_def_var(james_v_of_scotland_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
721       if (nc_put_var_int(james_v_of_scotland_id, varid, data_out)) ERR;
722       /* Mary I of Scotland. */
723       if (nc_def_grp(tudor_id, MARY_I_OF_SCOTLAND, &mary_i_of_scotland_id)) ERR;
724       if (nc_def_dim(mary_i_of_scotland_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
725       if (nc_def_var(mary_i_of_scotland_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
726       if (nc_put_var_int(mary_i_of_scotland_id, varid, data_out)) ERR;
727       /* James VI of Scotland and I of England. */
728       if (nc_def_grp(tudor_id, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &james_i_of_england_id)) ERR;
729       if (nc_def_dim(james_i_of_england_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
730       if (nc_def_var(james_i_of_england_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
731       if (nc_put_var_int(james_i_of_england_id, varid, data_out)) ERR;
732 
733       /*nc_show_metadata(ncid);*/
734 
735       /* Check it out. */
736       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
737       if (num_grps != 1) ERR;
738       if (nc_inq_grps(dynasty, &num_grps, grpids_in)) ERR;
739       if (num_grps != 5) ERR;
740       for (i = 0; i < 5; i++)
741       {
742 	 if (nc_inq_dim(grpids_in[i], i, name_in, &len_in)) ERR;
743 	 if (strcmp(name_in, DIM1_NAME) || len_in != DIM1_LEN) ERR;
744 	 if (nc_inq_var(grpids_in[i], 0, name_in, &xtype_in, &ndims_in, dimids_in,
745 			&natts_in)) ERR;
746 	 if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_INT || ndims_in != 1 ||
747 	     dimids_in[0] != i || natts_in != 0) ERR;
748 	 if (nc_get_var_int(grpids_in[i], 0, data_in)) ERR;
749 	 for (j=0; j<DIM1_LEN; j++)
750 	    if (data_in[j] != data_out[j]) ERR;
751       }
752 
753       if (nc_close(ncid)) ERR;
754 
755       /* Reopen. */
756       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
757 
758       /* Check it out. */
759       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
760       if (num_grps != 1) ERR;
761       if (nc_inq_grps(dynasty, &num_grps, grpids_in)) ERR;
762       if (num_grps != 5) ERR;
763       for (i = 0; i < 5; i++)
764       {
765 	 /* We actually get the groups in alphabetical order, so our
766 	  * dimid is not i. */
767 	 /*if (nc_inq_dim(grpids_in[i], i, name_in, &len_in)) ERR;
768 	   if (strcmp(name_in, DIM1_NAME) || len_in != DIM1_LEN) ERR;*/
769 	 if (nc_inq_var(grpids_in[i], 0, name_in, &xtype_in, &ndims_in, dimids_in,
770 			&natts_in)) ERR;
771 	 if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_INT || ndims_in != 1 ||
772 	     natts_in != 0) ERR;
773 	 if (nc_get_var_int(grpids_in[i], 0, data_in)) ERR;
774 	 for (j=0; j<DIM1_LEN; j++)
775 	    if (data_in[j] != data_out[j]) ERR;
776       }
777 
778       if (nc_close(ncid)) ERR;
779    }
780    SUMMARIZE_ERR;
781 
782    printf("*** testing very simple groups and dimension scoping...");
783    {
784       int ncid;
785       int dimids_in[MAX_SIBLING_GROUPS], nvars_in, ndims_in;
786       int henry_vii_id;
787       int num_grps;
788       int dimid, dimid2, varid;
789       size_t len_in;
790       int natts_in;
791       int unlimdimid_in;
792       int grpids_in[10];
793       nc_type xtype_in;
794       char name_in[NC_MAX_NAME + 1];
795       int data_out[DIM1_LEN] = {0, 2, 6}, data_in[DIM1_LEN];
796       int j;
797 
798       /* Create a netCDF-4 file. */
799       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
800 
801       /* Define two dimensions, "year" and "kingdom" in the root group. */
802       if (nc_def_dim(ncid, DIM2_NAME, DIM2_LEN, &dimid2)) ERR;
803       if (nc_def_dim(ncid, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
804 
805       /* Define a HENRY_VII group. It contains a var with dim "kingdom". */
806       if (nc_def_grp(ncid, HENRY_VII, &henry_vii_id)) ERR;
807       if (nc_def_var(henry_vii_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
808       if (nc_put_var_int(henry_vii_id, varid, data_out)) ERR;
809 
810       /* Done! */
811       if (nc_close(ncid)) ERR;
812 
813       /* Reopen the file. */
814       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
815 
816       /* Check the file. */
817       if (nc_inq_grps(ncid, &num_grps, &henry_vii_id)) ERR;
818       if (num_grps != 1) ERR;
819       if (nc_inq_grps(henry_vii_id, &num_grps, grpids_in)) ERR;
820       if (num_grps != 0) ERR;
821       if (nc_inq(henry_vii_id, &ndims_in, &nvars_in, &natts_in, &unlimdimid_in)) ERR;
822       if (ndims_in != 0 || nvars_in != 1 || natts_in != 0 || unlimdimid_in != -1) ERR;
823       if (nc_inq_var(henry_vii_id, 0, name_in, &xtype_in, &ndims_in, dimids_in,
824 		     &natts_in)) ERR;
825       if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_INT || ndims_in != 1 ||
826 	  dimids_in[0] != dimid || natts_in != 0) ERR;
827       if (nc_inq_dim(ncid, dimid, name_in, &len_in)) ERR;
828       if (strcmp(name_in, DIM1_NAME) || len_in != DIM1_LEN) ERR;
829       if (nc_get_var_int(henry_vii_id, 0, data_in)) ERR;
830       for (j=0; j<DIM1_LEN; j++)
831 	 if (data_in[j] != data_out[j]) ERR;
832 
833       /* Close the file. */
834       if (nc_close(ncid)) ERR;
835    }
836    SUMMARIZE_ERR;
837 
838    printf("*** testing groups and dimension scoping...");
839    {
840 #define NUM_GRPS 5
841       int ncid;
842       int henry_vii_id, margaret_id, james_v_of_scotland_id, mary_i_of_scotland_id;
843       int james_i_of_england_id, tudor_id;
844       int dimids_in[MAX_SIBLING_GROUPS], nvars_in, ndims_in;
845       int num_grps;
846       int dimid, dimid2, dynasty, varid;
847       size_t len_in;
848       int natts_in;
849       int unlimdimid_in;
850       int grpids_in[10];
851       nc_type xtype_in;
852       char name_in[NC_MAX_NAME + 1];
853       int data_out[DIM1_LEN] = {0, 2, 6}, data_in[DIM1_LEN];
854       int i, j;
855 
856       /* Create a netCDF-4 file. */
857       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
858 
859       /* Define a bunch of groups, define a variable in each, and
860        * write some data in it. The vars use a shared dimension from
861        * the parent group. */
862 
863       /* Create the parent group. */
864       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
865 
866       /* Define two dimensions, "year" and "kingdom" in the parent group. */
867       if (nc_def_dim(tudor_id, DIM2_NAME, DIM2_LEN, &dimid2)) ERR;
868       if (nc_def_dim(tudor_id, DIM1_NAME, DIM1_LEN, &dimid)) ERR;
869 
870       /* Define a HENRY_VII group. It contains a var with dim "kingdom". */
871       if (nc_def_grp(tudor_id, HENRY_VII, &henry_vii_id)) ERR;
872       if (nc_def_var(henry_vii_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
873       if (nc_put_var_int(henry_vii_id, varid, data_out)) ERR;
874 
875       /* Define a MARGARET group. */
876       if (nc_def_grp(tudor_id, MARGARET, &margaret_id)) ERR;
877       if (nc_def_var(margaret_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
878       if (nc_put_var_int(margaret_id, varid, data_out)) ERR;
879 
880       /* Define a JAMES_V_OF_SCOTLAND group. */
881       if (nc_def_grp(tudor_id, JAMES_V_OF_SCOTLAND, &james_v_of_scotland_id)) ERR;
882       if (nc_def_var(james_v_of_scotland_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
883       if (nc_put_var_int(james_v_of_scotland_id, varid, data_out)) ERR;
884 
885       /* Define a MARY_I_OF_SCOTLAND group. */
886       if (nc_def_grp(tudor_id, MARY_I_OF_SCOTLAND, &mary_i_of_scotland_id)) ERR;
887       if (nc_def_var(mary_i_of_scotland_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
888       if (nc_put_var_int(mary_i_of_scotland_id, varid, data_out)) ERR;
889 
890       /* Define a JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND group. */
891       if (nc_def_grp(tudor_id, JAMES_VI_OF_SCOTLAND_AND_I_OF_ENGLAND, &james_i_of_england_id)) ERR;
892       if (nc_def_var(james_i_of_england_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
893       if (nc_put_var_int(james_i_of_england_id, varid, data_out)) ERR;
894 
895       /* Done! */
896       if (nc_close(ncid)) ERR;
897 
898       /* Reopen the file. */
899       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
900 
901       /* Check the file. */
902       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
903       if (num_grps != 1) ERR;
904       if (nc_inq_grps(dynasty, &num_grps, grpids_in)) ERR;
905       if (num_grps != NUM_GRPS) ERR;
906       for (i = 0; i < NUM_GRPS; i++)
907       {
908 	 if (nc_inq(grpids_in[i], &ndims_in, &nvars_in, &natts_in, &unlimdimid_in)) ERR;
909 	 if (ndims_in != 0 || nvars_in != 1 || natts_in != 0 || unlimdimid_in != -1) ERR;
910 	 if (nc_inq_var(grpids_in[i], 0, name_in, &xtype_in, &ndims_in, dimids_in,
911 			&natts_in)) ERR;
912 	 if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_INT || ndims_in != 1 ||
913 	     dimids_in[0] != dimid || natts_in != 0) ERR;
914 	 if (nc_inq_dim(grpids_in[i], dimid, name_in, &len_in)) ERR;
915 	 if (strcmp(name_in, DIM1_NAME) || len_in != DIM1_LEN) ERR;
916 	 if (nc_get_var_int(grpids_in[i], 0, data_in)) ERR;
917 	 for (j=0; j<DIM1_LEN; j++)
918 	    if (data_in[j] != data_out[j]) ERR;
919       }
920 
921       /* Close the file. */
922       if (nc_close(ncid)) ERR;
923    }
924    SUMMARIZE_ERR;
925 
926    printf("*** testing more groups and dimension scoping...");
927    {
928       int ncid;
929       int henry_vii_id;
930       int tudor_id;
931       int dimids_in[MAX_SIBLING_GROUPS], ndims_in;
932       int year_did, kingdom_did, varid, dimids[2], parent_id;
933       int natts_in;
934       int numgrps;
935       int grpids_in[10];
936       nc_type xtype_in;
937       char name_in[NC_MAX_NAME + 1];
938 
939       /* Create a netCDF-4 file. */
940       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
941 
942       /* Create the parent group. */
943       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
944 
945       /* Define two dimensions, "year" and "kingdom" in the parent group. */
946       if (nc_def_dim(tudor_id, DIM1_NAME, DIM1_LEN, &kingdom_did)) ERR;
947       if (nc_def_dim(tudor_id, DIM2_NAME, DIM2_LEN, &year_did)) ERR;
948 
949       /* Define a HENRY_VII group. It contains a var using both dimensions. */
950       if (nc_def_grp(tudor_id, HENRY_VII, &henry_vii_id)) ERR;
951       dimids[0] = year_did;
952       dimids[1] = kingdom_did;
953       if (nc_def_var(henry_vii_id, VAR1_NAME, NC_UINT64, 2, dimids, &varid)) ERR;
954       if (nc_inq_var(henry_vii_id, varid, name_in, &xtype_in, &ndims_in,
955 		     dimids_in, &natts_in)) ERR;
956       if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_UINT64 || ndims_in != 2 ||
957 	  dimids_in[0] != year_did || dimids_in[1] != kingdom_did ||
958 	  natts_in != 0) ERR;
959 
960       /* Close the file. */
961       if (nc_close(ncid)) ERR;
962 
963       /* Reopen the file. */
964       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
965 
966       /* Find our group. */
967       if (nc_inq_grps(ncid, &numgrps, grpids_in)) ERR;
968       if (numgrps != 1) ERR;
969       parent_id = grpids_in[0];
970       if (nc_inq_grps(parent_id, &numgrps, grpids_in)) ERR;
971       if (numgrps != 1) ERR;
972       henry_vii_id = grpids_in[0];
973       if (nc_inq_var(henry_vii_id, varid, name_in, &xtype_in, &ndims_in,
974 		     dimids_in, &natts_in)) ERR;
975       if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_UINT64 || ndims_in != 2 ||
976 	  dimids_in[0] != year_did || dimids_in[1] != kingdom_did ||
977 	  natts_in != 0) ERR;
978       /* Close the file. */
979       if (nc_close(ncid)) ERR;
980 
981    }
982    SUMMARIZE_ERR;
983    printf("*** testing groups and unlimited dimensions...");
984    {
985       int ncid;
986       int henry_vii_id;
987       int tudor_id;
988       int dimids_in[MAX_SIBLING_GROUPS], ndims_in;
989       int num_grps;
990       int dimid, dynasty, varid;
991       size_t len_in;
992       int natts_in;
993       int grpids_in[10];
994       nc_type xtype_in;
995       char name_in[NC_MAX_NAME + 1];
996       int data_out[DIM1_LEN] = {0, 2, 6}, data_in[DIM1_LEN];
997       size_t start[1] = {0}, count[1] = {3};
998       int j;
999 
1000       /* Create one group, with one var, which has one dimension, which is unlimited. */
1001       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
1002       if (nc_def_grp(ncid, DYNASTY, &tudor_id)) ERR;
1003       if (nc_def_dim(tudor_id, DIM1_NAME, NC_UNLIMITED, &dimid)) ERR;
1004       if (nc_def_grp(tudor_id, HENRY_VII, &henry_vii_id)) ERR;
1005       if (nc_def_var(henry_vii_id, VAR1_NAME, NC_INT, 1, &dimid, &varid)) ERR;
1006       if (nc_put_vara_int(henry_vii_id, varid, start, count, data_out)) ERR;
1007       if (nc_close(ncid)) ERR;
1008 
1009       /* Now check the file to see if the dimension and variable are
1010        * there. */
1011       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
1012       if (nc_inq_grps(ncid, &num_grps, &dynasty)) ERR;
1013       if (num_grps != 1) ERR;
1014       if (nc_inq_grps(dynasty, &num_grps, grpids_in)) ERR;
1015       if (num_grps != 1) ERR;
1016       if (nc_inq_dim(grpids_in[0], 0, name_in, &len_in)) ERR;
1017       if (strcmp(name_in, DIM1_NAME) || len_in != DIM1_LEN) ERR;
1018       if (nc_inq_var(grpids_in[0], 0, name_in, &xtype_in, &ndims_in, dimids_in,
1019 		     &natts_in)) ERR;
1020       if (strcmp(name_in, VAR1_NAME) || xtype_in != NC_INT || ndims_in != 1 ||
1021 	  dimids_in[0] != 0 || natts_in != 0) ERR;
1022       if (nc_get_vara_int(grpids_in[0], 0, start, count, data_in)) ERR;
1023       for (j=0; j<DIM1_LEN; j++)
1024 	 if (data_in[j] != data_out[j]) ERR;
1025       if (nc_close(ncid)) ERR;
1026    }
1027    SUMMARIZE_ERR;
1028 
1029    printf("*** testing nested groups...");
1030    {
1031 #define DIM_NAME "dim"
1032 #define DIM_LEN 3
1033 #define VAR_NAME "var"
1034 #define VAR_RANK 1
1035 #define ATT_NAME "units"
1036 #define ATT_VAL "m/s"
1037 #define GATT_NAME "title"
1038 #define GATT_VAL "for testing groups"
1039 #define G1_NAME "the_in_crowd"
1040 #define G2_NAME "the_out_crowd"
1041 #define G3_NAME "the_confused_crowd"
1042       int ncid;
1043       int dimid, varid;
1044       int var_dims[VAR_RANK];
1045       int g1id, g2id, g3id;
1046 
1047       /* Create a file with nested groups. */
1048       if (nc_create(FILE_NAME, NC_CLOBBER | NC_NETCDF4, &ncid)) ERR;
1049       /* At root level define dim, var, atts */
1050       if (nc_def_dim(ncid, DIM_NAME, DIM_LEN, &dimid)) ERR;
1051       var_dims[0] = dimid;
1052       if (nc_def_var(ncid, VAR_NAME, NC_FLOAT, VAR_RANK, var_dims, &varid)) ERR;
1053       if (nc_put_att_text(ncid, varid, ATT_NAME, strlen(ATT_VAL), ATT_VAL)) ERR;
1054       if (nc_put_att_text(ncid, NC_GLOBAL, GATT_NAME, strlen(GATT_VAL),
1055 			  GATT_VAL)) ERR;
1056 
1057       /* put dim, var, atts with same names in a group */
1058       if (nc_def_grp(ncid, G1_NAME, &g1id)) ERR;
1059       if (nc_def_dim(g1id, DIM_NAME, DIM_LEN, &dimid)) ERR;
1060       var_dims[0] = dimid;
1061       if (nc_def_var(g1id, VAR_NAME, NC_FLOAT, VAR_RANK, var_dims, &varid)) ERR;
1062       if (nc_put_att_text(g1id, varid, ATT_NAME, strlen(ATT_VAL), ATT_VAL)) ERR;
1063       if (nc_put_att_text(g1id, NC_GLOBAL, GATT_NAME, strlen(GATT_VAL),
1064 			  GATT_VAL)) ERR;
1065       if (nc_enddef(g1id)) ERR;
1066 
1067       /* put dim, var, atts with same names in a second group */
1068       if (nc_def_grp(ncid, G2_NAME, &g2id)) ERR;
1069       if (nc_def_dim(g2id, DIM_NAME, DIM_LEN, &dimid)) ERR;
1070       var_dims[0] = dimid;
1071       if (nc_def_var(g2id, VAR_NAME, NC_FLOAT, VAR_RANK, var_dims, &varid)) ERR;
1072       if (nc_put_att_text(g2id, varid, ATT_NAME, strlen(ATT_VAL), ATT_VAL)) ERR;
1073       if (nc_put_att_text(g2id, NC_GLOBAL, GATT_NAME, strlen(GATT_VAL),
1074 			  GATT_VAL)) ERR;
1075       if (nc_enddef(g2id)) ERR;
1076 
1077       /* put dim, var, atts with same names in a subgroup of second group */
1078       if (nc_def_grp(g2id, G3_NAME, &g3id)) ERR;
1079       if (nc_def_dim(g3id, DIM_NAME, DIM_LEN, &dimid)) ERR;
1080       var_dims[0] = dimid;
1081       if (nc_def_var(g3id, VAR_NAME, NC_FLOAT, VAR_RANK, var_dims, &varid)) ERR;
1082       if (nc_put_att_text(g3id, varid, ATT_NAME, strlen(ATT_VAL), ATT_VAL)) ERR;
1083       if (nc_put_att_text(g3id, NC_GLOBAL, GATT_NAME, strlen(GATT_VAL),
1084 			  GATT_VAL)) ERR;
1085       if (nc_enddef(g3id)) ERR;
1086 
1087       if (nc_close(ncid)) ERR;
1088 
1089    }
1090    SUMMARIZE_ERR;
1091 
1092    printf("*** testing nested groups, user defined types, and enddef...");
1093    {
1094 #define SCI_FI "Science_Fiction"
1095 #define BASE_SIZE 2
1096 #define TYPE_NAME "The_Blob"
1097 #define DATE_MOVIE "data_movie"
1098       int ncid, xtype, g1id, class;
1099       char name_in[NC_MAX_NAME + 1];
1100       size_t len_in;
1101       unsigned char data[BASE_SIZE] = {42, 43}, data_in[BASE_SIZE];
1102 
1103       /* Create a file. */
1104       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
1105 
1106       /* define subgroup with a user defined type. */
1107       if (nc_def_grp(ncid, SCI_FI, &g1id)) ERR;
1108       if (nc_def_opaque(g1id, BASE_SIZE, TYPE_NAME, &xtype)) ERR;
1109       if (nc_put_att(g1id, NC_GLOBAL, DATE_MOVIE, xtype, 1, &data)) ERR;
1110 
1111       /* Check it. */
1112       if (nc_inq_user_type(g1id, xtype, name_in, &len_in, NULL, NULL, &class)) ERR;
1113       if (strcmp(name_in, TYPE_NAME) || len_in != BASE_SIZE || class != NC_OPAQUE) ERR;
1114       if (nc_get_att(g1id, NC_GLOBAL, DATE_MOVIE, data_in)) ERR;
1115       if (data[0] != data_in[0] || data[1] != data_in[1]) ERR;
1116 
1117       /* Call enddef and try again. */
1118       if (nc_enddef(g1id)) ERR;
1119 
1120       if (nc_inq_user_type(g1id, xtype, name_in, &len_in, NULL, NULL, &class)) ERR;
1121       if (strcmp(name_in, TYPE_NAME) || len_in != BASE_SIZE || class != NC_OPAQUE) ERR;
1122       if (nc_get_att(g1id, NC_GLOBAL, DATE_MOVIE, data_in)) ERR;
1123       if (data[0] != data_in[0] || data[1] != data_in[1]) ERR;
1124 
1125       if (nc_close(ncid)) ERR;
1126 
1127       /* Reopen and recheck. */
1128       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
1129       if (nc_inq_grp_ncid(ncid, SCI_FI, &g1id)) ERR;
1130 
1131       if (nc_inq_user_type(g1id, xtype, name_in, &len_in, NULL, NULL, &class)) ERR;
1132       if (strcmp(name_in, TYPE_NAME) || len_in != BASE_SIZE || class != NC_OPAQUE) ERR;
1133       if (nc_get_att(g1id, NC_GLOBAL, DATE_MOVIE, data_in)) ERR;
1134       if (data[0] != data_in[0] || data[1] != data_in[1]) ERR;
1135 
1136       if (nc_close(ncid)) ERR;
1137 
1138    }
1139    SUMMARIZE_ERR;
1140 
1141    printf("*** creating file with lots of user-defined types...");
1142    {
1143       int ncid, typeid;
1144       int g1id, g2id, g3id;
1145 
1146       /* Create a file with nested groups. */
1147       if (nc_create(FILE_NAME, NC_CLOBBER | NC_NETCDF4, &ncid)) ERR;
1148       if (nc_def_opaque(ncid, 10, "opaque-1", &typeid)) ERR;
1149       if (nc_def_vlen(ncid, "vlen-1", NC_INT, &typeid)) ERR;
1150       if (nc_enddef(ncid)) ERR;
1151 
1152       if (nc_def_grp(ncid, G1_NAME, &g1id)) ERR;
1153       if (nc_def_opaque(g1id, 7, "opaque-2", &typeid)) ERR;
1154       if (nc_def_vlen(g1id, "vlen-2", NC_BYTE, &typeid)) ERR;
1155       if (nc_enddef(g1id)) ERR;
1156 
1157       if (nc_def_grp(ncid, G2_NAME, &g2id)) ERR;
1158       if (nc_def_opaque(g2id, 4, "opaque-3", &typeid)) ERR;
1159       if (nc_def_vlen(g2id, "vlen-3", NC_BYTE, &typeid)) ERR;
1160       if (nc_enddef(g2id)) ERR;
1161 
1162       /* put dim, var, atts with same names in a subgroup of second group */
1163       if (nc_def_grp(g2id, G3_NAME, &g3id)) ERR;
1164       if (nc_def_opaque(g3id, 13, "opaque-4", &typeid)) ERR;
1165       if (nc_def_vlen(g3id, "vlen-4", NC_BYTE, &typeid)) ERR;
1166       if (nc_enddef(g3id)) ERR;
1167 
1168       if (nc_close(ncid)) ERR;
1169 
1170       /* Now count how many user-defined types there are */
1171       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
1172       if (nc_close(ncid)) ERR;
1173 
1174    }
1175    SUMMARIZE_ERR;
1176 
1177    printf("*** creating file with lots of groups...");
1178    {
1179 #define PARENT_NUM_GRPS 6
1180 #define SUB_NUM_GRPS 2
1181 
1182       int ncid, g1id, sub_grpid, num_grps, g, s;
1183       char grp_name[NC_MAX_NAME + 1];
1184 
1185       /* Create a file with lots of groups. */
1186       if (nc_create(FILE_NAME, NC_CLOBBER | NC_NETCDF4, &ncid)) ERR;
1187       for (g = 0; g < PARENT_NUM_GRPS; g++)
1188       {
1189 	 sprintf(grp_name, "grp_%d", g);
1190 	 if (nc_def_grp(ncid, grp_name, &g1id)) ERR;
1191 	 for (s = 0; s < SUB_NUM_GRPS; s++)
1192 	 {
1193 	    sprintf(grp_name, "sub_grp_%d", s);
1194 	    if (nc_def_grp(g1id, grp_name, &sub_grpid)) ERR;
1195 	 }
1196       }
1197 
1198       if (nc_close(ncid)) ERR;
1199 
1200       /* Now count how groups there are. */
1201       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
1202       if (nc_inq_grps(ncid, &num_grps, NULL)) ERR;
1203       if (num_grps != PARENT_NUM_GRPS) ERR;
1204       if (nc_close(ncid)) ERR;
1205 
1206    }
1207    SUMMARIZE_ERR;
1208 
1209    printf("*** creating file with type defined after group...");
1210    {
1211 #define GRP_NAME "phony_group"
1212 #define CMP1_NAME "cmp1"
1213 #define CMP2_NAME "cmp2"
1214 
1215       int ncid, varid, varid2, grpid, numvars, retval;
1216       int typeid, typeid2;
1217       size_t nfields;
1218       char name[NC_MAX_NAME + 1];
1219       size_t size;
1220       struct s1
1221       {
1222          int i1;
1223          int i2;
1224       };
1225       struct s2
1226       {
1227          int i3;
1228          double f1;
1229       };
1230       struct s1 data;
1231       struct s2 data2;
1232 
1233       /* Create some phony data. */
1234       data.i1 = 5;
1235       data.i2 = 10;
1236       data2.i3 = 50;
1237       data2.f1 = 100.0;
1238 
1239       /* Create file */
1240       if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
1241 
1242       /* Create compound datatype #1, in root group */
1243       if (nc_def_compound(ncid, sizeof(struct s1), CMP1_NAME, &typeid)) ERR;
1244       if (nc_inq_compound(ncid, typeid, name, &size, &nfields)) ERR;
1245       if (size != sizeof(struct s1) || strcmp(name, CMP1_NAME) || nfields) ERR;
1246       if (nc_insert_compound(ncid, typeid, "i1",
1247    			  NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR;
1248       if (nc_insert_compound(ncid, typeid, "i2",
1249    			  NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR;
1250 
1251       /* Create variable with compound datatype #1, in root group */
1252       if (nc_def_var(ncid, VAR_NAME, typeid, 0, NULL, &varid)) ERR;
1253       if (nc_put_var(ncid, varid, &data)) ERR;
1254 
1255       /* Create child group, in root group*/
1256       if (nc_def_grp(ncid, GRP_NAME, &grpid)) ERR;
1257 
1258       /* Close and re-open file, to guarantee the creation ordering is difficult
1259        *   for the library to deal with.
1260        */
1261       if (nc_close(ncid)) ERR;
1262       if ((retval = nc_open(FILE_NAME, NC_WRITE, &ncid))) ERR;
1263 
1264       /* Create compound datatype #2, in root group */
1265       if (nc_def_compound(ncid, sizeof(struct s2), CMP2_NAME, &typeid2)) ERR;
1266       if (nc_inq_compound(ncid, typeid2, name, &size, &nfields)) ERR;
1267       if (size != sizeof(struct s2) || strcmp(name, CMP2_NAME) || nfields) ERR;
1268       if (nc_insert_compound(ncid, typeid2, "i3",
1269    			  NC_COMPOUND_OFFSET(struct s2, i3), NC_INT)) ERR;
1270       if (nc_insert_compound(ncid, typeid2, "f1",
1271    			  NC_COMPOUND_OFFSET(struct s2, f1), NC_DOUBLE)) ERR;
1272 
1273       /* Create variable with compound datatype #2, in root group */
1274       if (nc_def_var(grpid, VAR_NAME, typeid2, 0, NULL, &varid2)) ERR;
1275       if (nc_put_var(ncid, varid2, &data2)) ERR;
1276 
1277       if (nc_close(ncid)) ERR;
1278 
1279 
1280       /* Verify that the variable in the child group was recognized by the library */
1281       if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
1282       if (nc_inq_grp_ncid(ncid, GRP_NAME, &grpid)) ERR;
1283       if (nc_inq_nvars(grpid, &numvars)) ERR;
1284       if (numvars != 1) ERR;
1285       if (nc_close(ncid)) ERR;
1286    }
1287    SUMMARIZE_ERR;
1288 
1289    FINAL_RESULTS;
1290 }
1291