1 /*********************************************************************
2  *   Copyright 1993, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *   $Id$
5  *********************************************************************/
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "h4config.h"
12 #ifdef H4_HAVE_NETCDF
13 #include "netcdf.h"
14 #else
15 #include "hdf4_netcdf.h"
16 #endif
17 #include "testcdf.h"		/* defines in-memory test netcdf structure */
18 #include "add.h"		/* functions to update in-memory netcdf */
19 #include "error.h"
20 #include "tests.h"
21 #include "alloc.h"
22 #include "emalloc.h"
23 #ifdef HDF
24 #include "hdf.h"
25 #endif
26 
27 #define LEN_OF(array) ((sizeof array) / (sizeof array[0]))
28 
29 
30 /*
31  * Test nccreate
32  *    create a netcdf with no data, close it, test that it can be opened
33  *    try again with NC_CLOBBER mode, check that no errors occurred
34  *    try again with NC_NOCLOBBER mode, check error return
35  * On exit, netcdf files are closed.
36  * Uses: nccreate, ncendef, ncclose, ncopen.
37  */
38 void
test_nccreate(path)39 test_nccreate(path)
40      char *path;		/* name of cdf file to create */
41 {
42     int nerrs = 0;
43     static char pname[] = "test_nccreate";
44     int cdfid;
45 
46     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
47 
48     if ((cdfid = nccreate(path, NC_CLOBBER)) == -1) {
49 	error("%s: nccreate failed to NC_CLOBBER", pname);
50 	return;
51     }
52     /* created OK */
53     if (ncendef (cdfid) == -1) {
54 	error("%s: ncendef failed", pname);
55 	nerrs++;
56     }
57     if (ncclose (cdfid) == -1) {
58 	error("%s: ncclose failed", pname);
59 	nerrs++;
60     }
61     if ((cdfid = ncopen(path, NC_NOWRITE)) == -1) {
62 	error("%s: ncopen of newly created netcdf failed", pname);
63 	return;
64     }
65     /* opened OK */
66     if (ncclose (cdfid) == -1) {
67 	error("%s: second ncclose failed", pname);
68 	nerrs++;
69     }
70     /* this call should fail, since we're using NC_NOCLOBBER mode */
71     if ((cdfid = nccreate(path, NC_NOCLOBBER)) != -1) {
72 	error("%s: nccreate failed to honor NC_NOCLOBBER mode", pname);
73 	nerrs++;
74     }
75 
76     /* Initialize in-memory netcdf to empty */
77     add_reset(&test);
78     if (nerrs > 0)
79       (void) fprintf(stderr,"FAILED! ***\n");
80     else
81       (void) fprintf(stderr,"ok ***\n");
82 }
83 
84 
85 /*
86  * Test ncopen
87  *    try to open a non-existent netCDF, check error return
88  *    open a netCDF with NC_WRITE mode, write something, close it
89  *    open a netCDF with NC_NOWRITE mode, write something and check error
90  *    try to open a netcdf twice, check whether returned cdf ids different
91  * On exit, netcdf files are closed.
92  * Uses: ncopen, ncredef, ncattput, ncendef, ncclose.
93  */
94 void
test_ncopen(path)95 test_ncopen(path)
96      char *path;		/* name of writable netcdf file to open */
97 {
98     int nerrs = 0;
99     static char pname[] = "test_ncopen";
100     int cdfid0, cdfid1;
101     static char title_val[] = "test netcdf";
102     static char xpath[] = "tooth-fairy.cdf"; /* must not exist */
103     static struct cdfatt title = /* attribute */
104       {NC_GLOBAL, "title", NC_CHAR, LEN_OF (title_val), (void *) title_val};
105 
106     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
107 
108     if((cdfid0 = ncopen(xpath, NC_NOWRITE)) != -1) {
109 	error("%s: ncopen should fail opening nonexistent file",
110 	      pname);
111 	return;
112     }
113     if((cdfid0 = ncopen(xpath, NC_WRITE)) != -1) {
114 	error("%s: ncopen should fail writing nonexistent file",
115 	      pname);
116 	return;
117     }
118     if ((cdfid0 = ncopen(path, NC_WRITE)) == -1) {
119 	error("%s: ncopen failed with NC_WRITE mode", pname);
120 	return;
121     }
122     /* opened */
123     if (ncredef(cdfid0) == -1) {
124 	error("%s: cdredef failed", pname);
125 	ncclose(cdfid0); return;
126     }
127     /* in define mode */
128     if (ncattput(cdfid0, NC_GLOBAL, "title", NC_CHAR, title.len, title.val)
129 	== -1) {
130 	error("%s: ncattput failed", pname);
131 	ncclose(cdfid0); return;
132     }
133     add_att(&test, NC_GLOBAL, &title); /* keep in-memory netcdf updated */
134     if (ncendef (cdfid0) == -1) {
135 	error("%s: ncendef failed after ncattput", pname);
136 	ncclose(cdfid0); return;
137     }
138     if (ncclose (cdfid0) == -1) {
139 	error("%s: ncclose failed in NC_WRITE mode", pname);
140 	return;
141     }
142 
143     if ((cdfid0 = ncopen(path, NC_NOWRITE)) == -1) {
144 	error("%s: ncopen failed with NC_NOWRITE mode", pname);
145 	return;
146     }
147     /* opened */
148     /* this should fail, since in NC_NOWRITE mode */
149     if (ncredef(cdfid0) != -1) {
150 	error("%s: cdredef should fail after NC_NOWRITE open", pname);
151 	ncclose(cdfid0); return;
152     }
153 
154     if ((cdfid1 = ncopen(path, NC_WRITE)) == -1) {
155 	error("%s: second ncopen failed", pname);
156 	nerrs++;
157     }
158     else
159     {
160 	    /* second open OK */
161 	    if (cdfid0 == cdfid1) {
162 		error("%s: ncopen should return new cdfid on second open",
163 		      pname);
164 		nerrs++;
165 	    }
166 	    if (ncclose (cdfid1) == -1) {
167 		error("%s: ncclose failed to close after second open", pname);
168 		nerrs++;
169 	    }
170     }
171 
172     if (ncclose (cdfid0) == -1) {
173 	error("%s: ncclose failed in NC_NOWRITE mode", pname);
174 	nerrs++;
175     }
176     if (nerrs > 0)
177       (void) fprintf(stderr,"FAILED! ***\n");
178     else
179       (void) fprintf(stderr,"ok ***\n");
180 }
181 
182 
183 /*
184  * Test ncredef
185  *    open a netCDF, enter define mode, add dimension, variable, attribute
186  *    try ncredef from within define mode, check error
187  *    leave define mode and close, releasing netcdf handle
188  *    try ncredef with old handle, check error
189  * On exit netcdf files are closed.
190  * Uses: ncopen, ncredef, ncdimdef, ncvardef, ncattput, ncclose
191  */
192 void
test_ncredef(path)193 test_ncredef(path)
194      char *path;		/* name of writable netcdf file to open */
195 {
196     int nerrs = 0;
197     static char pname[] = "test_ncredef";
198     int cdfid;			/* netcdf id */
199     int ii_dim;			/* dimension id */
200     static struct cdfdim ii =	/* dimension */
201       {"ii", 4};
202     int aa_id;			/* variable id */
203     static struct cdfvar aa =	/* variable */
204       {"aa", NC_LONG, 1, ___, 0};
205     static char units_val[] = "furlongs";
206     static struct cdfatt aa_units = /* attribute */
207       {___, "units", NC_CHAR, LEN_OF(units_val), (void *)units_val};
208 
209     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
210 
211     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
212 	error("%s: ncopen failed", pname);
213 	return;
214     }
215     /* opened OK, enter define mode */
216     if (ncredef(cdfid) == -1) {
217 	error("%s: cdredef failed", pname);
218 	ncclose(cdfid); return;
219     }
220     /* in define mode OK, add a dimension */
221     if ((ii_dim = ncdimdef(cdfid, ii.name, ii.size)) == -1) {
222 	error("%s: ncdimdef failed", pname);
223 	ncclose(cdfid); return;
224     }
225     add_dim(&test, &ii);	/* keep in-memory netcdf in sync */
226 
227     /* dimension added OK, add a variable */
228     aa.dims = (int *)emalloc(sizeof(int) * aa.ndims);
229     aa.dims[0] = ii_dim;
230     if ((aa_id = ncvardef(cdfid, aa.name, aa.type,
231 			   aa.ndims, aa.dims)) == -1) {
232 	error("%s: ncvardef failed", pname);
233 	ncclose(cdfid); return;
234     }
235     add_var(&test, &aa);	/* keep in-memory netcdf in sync */
236 
237     /* variable added OK, add a variable attribute */
238     aa_units.var = aa_id;
239     if (ncattput(cdfid, aa_units.var, aa_units.name,
240 		  aa_units.type, aa_units.len, (void *) aa_units.val) == -1) {
241 	error("%s: ncattput failed", pname);
242 	ncclose(cdfid); return;
243     }
244     add_att(&test, aa_id, &aa_units); /* keep in-memory netcdf in sync */
245 
246     if (ncredef(cdfid) != -1) {
247 	error("%s: cdredef in define mode should have failed", pname);
248 	ncclose(cdfid); return;
249     }
250     if (ncendef (cdfid) == -1) {
251 	error("%s: ncendef failed", pname);
252 	ncclose(cdfid); return;
253     }
254     if (ncclose (cdfid) == -1) {
255 	error("%s: ncclose failed", pname);
256 	return;
257     }
258     if (ncredef(cdfid) != -1) {
259 	error("%s: ncredef failed to report bad cdf handle", pname);
260 	nerrs++;
261     }
262     Free ((char *)aa.dims);
263     if (nerrs > 0)
264       (void) fprintf(stderr,"FAILED! ***\n");
265     else
266       (void) fprintf(stderr,"ok ***\n");
267 }
268 
269 
270 /*
271  * Test ncendef
272  *    check return from proper cdfendif after define mode
273  *    try ncendef when in data mode, check error
274  *    try ncendef with bad handle, check error
275  *  On exit netcdf files are closed.
276  * Uses: ncopen, ncredef, ncdimdef, ncvardef, ncattput, ncendef, ncclose
277  */
278 void
test_ncendef(path)279 test_ncendef(path)
280      char *path;		/* name of writable netcdf file to open */
281 {
282     int nerrs = 0;
283     static char pname[] = "test_ncendef";
284     int cdfid;			/* netcdf id */
285     int jj_dim, kk_dim;		/* dimension ids */
286     int bb_id;			/* variable id */
287     static struct cdfdim kk =	/* dimension */
288       {"kk", 3};
289     static struct cdfdim jj =	/* dimension */
290       {"jj", 3};
291     static struct cdfvar bb =	/* variable */
292       {"bb", NC_LONG, 2, ___, 0};
293     static float bb_rangev[2] = {0., 100.}; /* attribute vector */
294     static struct cdfatt bb_range = /* attribute */
295       {___, "valid_range", NC_FLOAT, LEN_OF(bb_rangev), (void *)bb_rangev};
296 
297     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
298 
299     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
300 	error("%s: ncopen failed", pname);
301 	return;
302     }
303     /* opened */
304     if (ncredef(cdfid) == -1) {
305 	error("%s: ncredef failed", pname);
306 	ncclose(cdfid); return;
307     }
308     /* in define mode, add dimensions */
309     if ((jj_dim = ncdimdef(cdfid, jj.name, jj.size)) == -1 ||
310 	(kk_dim = ncdimdef(cdfid, kk.name, kk.size)) == -1) {
311 	error("%s: ncdimdef failed", pname);
312 	ncclose(cdfid); return;
313     }
314     add_dim(&test, &jj);	/* keep in-memory netcdf in sync */
315     add_dim(&test, &kk);	/* keep in-memory netcdf in sync */
316 
317     /* dimensions added OK, add a variable */
318     bb.dims = (int *) emalloc(sizeof(int) * bb.ndims);
319     bb.dims[0] = kk_dim;
320     bb.dims[1] = jj_dim;
321     if ((bb_id = ncvardef(cdfid, bb.name, bb.type,
322 			   bb.ndims, bb.dims)) == -1) {
323 	error("%s: ncvardef failed", pname);
324 	ncclose(cdfid); return;
325     }
326     add_var(&test, &bb);	/* keep in-memory netcdf in sync */
327 
328     /* variable added OK, add a variable attribute */
329     if (ncattput(cdfid, bb_id, bb_range.name, bb_range.type, bb_range.len,
330 		  (void *) bb_range.val) == -1) {
331 	error("%s: ncattput failed", pname);
332 	ncclose(cdfid); return;
333     }
334     add_att(&test, bb_id, &bb_range); /* keep in-memory netcdf in sync */
335 
336     if (ncendef (cdfid) == -1) {
337 	error("%s: ncendef failed", pname);
338 	ncclose(cdfid); return;
339     }
340     /* in data mode */
341     if (ncendef (cdfid) != -1) { /* should fail in data mode */
342 	error("%s: ncendef in data mode should have failed", pname);
343 	ncclose(cdfid); return;
344     }
345     if (ncclose (cdfid) == -1) {
346 	error("%s: ncclose failed", pname);
347 	return;
348     }
349     /* should fail on a bad handle */
350     if (ncendef (cdfid) != -1) {
351 	error("ncendef failed to report bad netcdf handle");
352 	nerrs++;
353     }
354     if (nerrs > 0)
355       (void) fprintf(stderr,"FAILED! ***\n");
356     else
357       (void) fprintf(stderr,"ok ***\n");
358 }
359 
360 
361 /*
362  * Test ncclose
363  *    try on open netCDF
364  *    try in define mode and data mode
365  *    try with bad handle, check error
366  *  On exit netcdf files are closed.
367  */
368 void
test_ncclose(path)369 test_ncclose(path)
370      char *path;		/* name of writable netcdf file to open */
371 {
372     int nerrs = 0;
373     static char pname[] = "test_ncclose";
374     int cdfid;			/* netcdf id */
375 
376     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
377 
378     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
379 	error("%s: ncopen failed", pname);
380 	return;
381     }
382     /* opened */
383     if (ncredef(cdfid) == -1) {
384 	error("%s: ncredef failed", pname);
385 	ncclose(cdfid); return;
386     }
387     /* in define mode */
388     if (ncclose (cdfid) == -1) {
389 	error("%s: ncclose in define mode failed", pname);
390 	nerrs++;
391     }
392 
393     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
394 	error("%s: ncopen failed", pname);
395 	return;
396     }
397     /* in data mode */
398     if (ncclose (cdfid) == -1) {
399 	error("%s: ncclose failed", pname);
400 	nerrs++;
401     }
402     if (ncclose (cdfid) != -1) { /* should fail, since cdfid is a bad handle */
403 	error("%s: ncclose failed to report bad cdf handle ", pname);
404 	nerrs++;
405     }
406     if (nerrs > 0)
407       (void) fprintf(stderr,"FAILED! ***\n");
408     else
409       (void) fprintf(stderr,"ok ***\n");
410 }
411 
412 
413 /*
414  * Test ncinquire
415  *    try in data mode, check returned values
416  *    try in define mode, after adding an unlimited dimension, variable
417  *    try with bad handle, check error
418  *  On exit netcdf files are closed.
419  */
420 void
test_ncinquire(path)421 test_ncinquire(path)
422      char *path;		/* name of writable netcdf file to open */
423 {
424     int nerrs = 0;
425     static char pname[] = "test_ncinquire";
426     int cdfid;			/* netcdf id */
427     int ndims;			/* number of dimensions */
428     int nvars;			/* number of variables */
429     int ngatts;			/* number of global attributes */
430     int xdimid;			/* id of unlimited dimension */
431     int rec_dim;		/* dimension id */
432     static struct cdfdim rec =	/* dimension */
433       {"rec", NC_UNLIMITED};
434     static struct cdfdim dims[] = { /* dimensions */
435 	{"i1", 5},{"i2", 3},{"i3", 7}
436     };
437     int id, nd = LEN_OF(dims);	/* number of dimensions */
438     int dimids[LEN_OF(dims)];
439     int cc_id;			/* variable id */
440     static struct cdfvar cc[] =	{ /* record variables of various sizes */
441 	{"cc", NC_LONG, 1, ___, 0},
442 	{"cd", NC_SHORT, 2, ___, 0},
443 	{"ce", NC_FLOAT, 3, ___, 0}
444     };
445     int iv;
446     int nv = LEN_OF(cc);	/* number of record variables */
447     static char units_val[] = "moles";
448     static struct cdfatt cc_units = /* attribute */
449       {___, "units", NC_CHAR, LEN_OF(units_val), (void *)units_val};
450 
451     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
452 
453     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
454 	error("%s: ncopen failed", pname);
455 	return;
456     }
457     /* opened, in data mode */
458     if (ncinquire(cdfid, &ndims, &nvars, &ngatts, &xdimid) == -1) {
459 	error("%s: ncinquire in data mode failed", pname);
460 	ncclose(cdfid); return;
461     }
462     /* compare returned with expected values */
463     if (ndims != test.ndims) {
464 	error("%s: ndims returned as %d, expected %d",
465 	    pname, ndims, test.ndims);
466 	nerrs++;
467     }
468     if (nvars != test.nvars) {
469 	error("%s: nvars returned as %d, expected %d",
470 	    pname, nvars, test.nvars);
471 	nerrs++;
472     }
473     if (ngatts != test.ngatts) {
474 	error("%s: ngatts returned as %d, expected %d",
475 	    pname, ngatts, test.ngatts);
476 	nerrs++;
477     }
478     if (xdimid != test.xdimid) {
479 	error("%s: xdimid returned as %d, expected %d",
480 	    pname, xdimid, test.xdimid);
481 	nerrs++;
482     }
483 
484     if (ncredef(cdfid) == -1) {
485 	error("%s: ncredef failed", pname);
486 	ncclose(cdfid); return;
487     }
488     /* add dimensions */
489     for (id = 0; id < nd; id++) {
490 	if ((dimids[id] = ncdimdef(cdfid, dims[id].name, dims[id].size))
491 	    == -1) {
492 	    error("%s: ncdimdef failed on normal dimension", pname);
493 	    ncclose(cdfid); return;
494 	}
495 	add_dim(&test, &dims[id]);
496     }
497 
498     /* add an unlimited dimension */
499     if ((rec_dim = ncdimdef(cdfid, rec.name, rec.size)) == -1) {
500 	error("%s: ncdimdef failed on NC_UNLIMITED dimension", pname);
501 	ncclose(cdfid); return;
502     }
503     add_dim(&test, &rec);
504 
505     /* add some record variables */
506     for (iv = 0; iv < nv; iv++) {
507 	cc[iv].dims = (int *) emalloc(sizeof(int) * cc[iv].ndims);
508 	cc[iv].dims[0] = rec_dim; /* first dimension unlimited */
509 	for (id = 1; id < cc[iv].ndims; id++)
510 	  cc[iv].dims[id] = dimids[id];
511 	if ((cc_id = ncvardef(cdfid, cc[iv].name, cc[iv].type,
512 			       cc[iv].ndims, cc[iv].dims)) == -1) {
513 	    error("%s: ncvardef failed", pname);
514 	    ncclose(cdfid); return;
515 	}
516 	add_var(&test, &cc[iv]);
517 
518 	/* add a variable attribute */
519 	if (ncattput(cdfid, cc_id, cc_units.name, cc_units.type,
520 		      cc_units.len, (void *) cc_units.val) == -1) {
521 	    error("%s: ncattput failed", pname);
522 	    ncclose(cdfid); return;
523 	}
524 	add_att(&test, cc_id, &cc_units);
525     }
526     /* try calling from define mode, compare returned values to expected */
527     if (ncinquire(cdfid, &ndims, &nvars, &ngatts, &xdimid) == -1) {
528 	error("%s: ncinquire in define mode failed", pname);
529 	ncclose(cdfid); return;
530     }
531     /* compare returned with expected values */
532     if (ndims != test.ndims) {
533 	error("%s: ndims returned as %d, expected %d",
534 	    pname, ndims, test.ndims);
535 	nerrs++;
536     }
537     if (nvars != test.nvars) {
538 	error("%s: nvars returned as %d, expected %d",
539 	    pname, nvars, test.nvars);
540 	nerrs++;
541     }
542     if (ngatts != test.ngatts) {
543 	error("%s: ngatts returned as %d, expected %d",
544 	    pname, ngatts, test.ngatts);
545 	nerrs++;
546     }
547     if (xdimid != test.xdimid) {
548 	error("%s: xdimid returned as %d, expected %d",
549 	    pname, xdimid, test.xdimid);
550 	nerrs++;
551     }
552 
553     if (ncendef (cdfid) == -1) {
554 	error("%s: ncendef failed", pname);
555 	ncclose(cdfid); return;
556     }
557 
558     if (ncclose (cdfid) == -1) {
559 	error("%s: ncclose failed", pname);
560 	return;
561     }
562     /* should fail, since bad handle */
563     if (ncinquire (cdfid, &ndims, &nvars, &ngatts, &xdimid) != -1) {
564 	error("%s: ncinquire failed to report bad netcdf handle ", pname);
565 	nerrs++;
566     }
567     if (nerrs > 0)
568       (void) fprintf(stderr,"FAILED! ***\n");
569     else
570       (void) fprintf(stderr,"ok ***\n");
571 }
572 
573 
574 /*
575  * Test ncsync
576  *    try in define mode, check error
577  *    try writing with one handle, reading with another on same netCDF
578  *    try with bad handle, check error
579  *  On exit netcdf files are closed.
580  */
581 void
test_ncsync(path)582 test_ncsync(path)
583      char *path;		/* name of writable netcdf file to open */
584 {
585     int nerrs = 0;
586     static char pname[] = "test_ncsync";
587     int cdfid0, cdfid1;		/* netcdf ids */
588     int ll_dim;			/* dimension id */
589     static struct cdfdim ll =	/* dimension */
590       {"ll", 3};
591     int dd_id;			/* variable id */
592     static struct cdfvar dd =	/* variable */
593       {"dd", NC_SHORT, 1, ___, 0};
594     static short dd_fill_valv[] = {-999};
595     static struct cdfatt dd_fill_val = /* attribute */
596       {___, "fill_value", NC_SHORT, LEN_OF(dd_fill_valv), (void *) dd_fill_valv};
597 
598     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
599 
600     if ((cdfid0 = ncopen(path, NC_WRITE)) == -1) {
601 	error("%s: ncopen in NC_WRITE mode failed", pname);
602 	return;
603     }
604 
605     /* opened */
606     if (ncredef(cdfid0) == -1) {
607 	error("%s: ncredef failed", pname);
608 	ncclose(cdfid0); return;
609     }
610     /* in define mode, add a dimension, variable, and attribute */
611     if ((ll_dim = ncdimdef(cdfid0, ll.name, ll.size)) == -1) {
612 	error("%s: ncdimdef failed", pname);
613 	ncclose(cdfid0);
614 	return;
615     }
616     add_dim(&test, &ll);
617 
618     dd.dims = (int *) emalloc(sizeof(int) * dd.ndims);
619     dd.dims[0] = ll_dim;
620     if ((dd_id=ncvardef(cdfid0, dd.name, dd.type, dd.ndims, dd.dims)) == -1) {
621 	error("%s: ncvardef failed", pname);
622 	ncclose(cdfid0);
623 	return;
624     }
625     add_var(&test, &dd);
626 
627     if (ncattput(cdfid0, dd_id, dd_fill_val.name, dd_fill_val.type,
628 		  dd_fill_val.len, (void *) dd_fill_val.val) == -1) {
629 	error("%s: ncattput failed", pname);
630 	ncclose(cdfid0);
631 	return;
632     }
633     add_att(&test, dd_id, &dd_fill_val);
634 
635     if (ncsync (cdfid0) != -1) {
636 	error("%s: ncsync in define mode should fail", pname);
637 	nerrs++;
638     }
639 
640     if (ncendef (cdfid0) == -1) {
641 	error("%s: ncendef failed", pname);
642 	ncclose(cdfid0); return;
643     }
644     /* in data mode */
645     if (ncsync (cdfid0) == -1) {
646 	error("%s: ncsync in data mode failed", pname);
647 	nerrs++;
648     }
649 
650     /* put some data into a variable */
651     {
652 	static long dd_start[] = {0};
653 	static long dd_edges[] = {2};
654 	static short dd_vals[] = {1, 2};
655 	short got_vals[2];
656 
657 	if (ncvarput(cdfid0,dd_id,dd_start,dd_edges,(void *)dd_vals) == -1) {
658 	    error("%s: ncvarput failed", pname);
659 	    ncclose(cdfid0);
660 	    return;
661 	}
662 	add_data(&test,dd_id,dd_start,dd_edges); /* keep test in sync */
663 	if (ncsync (cdfid0) == -1) {
664 	    error("%s: ncsync after putting data failed", pname);
665 	    nerrs++;
666 	}
667 
668 	if ((cdfid1 = ncopen(path, NC_NOWRITE)) == -1) {
669 	    error("%s: second ncopen failed", pname);
670 	    nerrs++;
671 	} else {
672 		if (cdfid0 == cdfid1) {
673 		    error("%s: second ncopen should return distinct handle",
674 			  pname);
675 		    nerrs++;
676 		}	/* read data just put after a sync, should succeed */
677 		if (ncvarget(cdfid1,dd_id,dd_start,dd_edges,(void *)got_vals)
678 		    == -1) {
679 		    error("%s: ncvarget failed", pname);
680 		    nerrs++;
681 		}
682 		if (dd_vals[0] != got_vals[0] || dd_vals[1] != got_vals[1]) {
683 		    error("%s: ncvarget succeeded but data values wrong",
684 			  pname);
685 		}
686    		if (ncclose (cdfid1) == -1) {
687 		    error("%s: ncclose failed", pname);
688 		    nerrs++;
689 		}
690 	    }
691     }
692     if (ncclose (cdfid0) == -1) {
693 	error("%s: ncclose failed", pname);
694 	nerrs++;
695     }
696     if (ncsync (cdfid0) != -1) { /* should fail, since cdfid0 is bad handle */
697 	error("%s: ncsync failed to report bad cdf handle ", pname);
698 	nerrs++;
699     }
700     if (nerrs > 0)
701       (void) fprintf(stderr,"FAILED! ***\n");
702     else
703       (void) fprintf(stderr,"ok ***\n");
704 }
705 
706 
707 /*
708  * Test ncabort
709  *    try in define mode, check that file was deleted
710  *    try after writing variable
711  *    try with bad handle, check error
712  *  On exit netcdf files are closed.
713  */
714 void
test_ncabort(path)715 test_ncabort(path)
716      char *path;		/* name of writable netcdf file to open */
717 {
718     int nerrs = 0;
719     static char pname[] = "test_ncabort";
720     static char fpath[] = "ufo.cdf";
721     static short attv[] = {3};
722     static struct cdfatt att = /* attribute */
723       {___, "temp", NC_SHORT, LEN_OF(attv), (void *) attv};
724     int cdfid;			/* netcdf id */
725 
726     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
727 
728     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
729 	error("%s: ncopen failed", pname);
730 	return;
731     }
732     /* opened */
733     if (ncredef(cdfid) == -1) {
734 	error("%s: ncredef failed", pname);
735 	ncclose(cdfid); return;
736     }
737     /* in define mode, add a new global attribute */
738     if (ncattput(cdfid, NC_GLOBAL, att.name, att.type, att.len, att.val) == -1) {
739 	error("%s: ncattput failed", pname);
740 	ncclose(cdfid); return;
741     }
742 
743     /* abort in define mode, should restore to state before define mode */
744     if (ncabort(cdfid) == -1) {
745 	error("%s: ncabort in define mode failed", pname);
746 	ncclose(cdfid); return;
747     }
748     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
749 	error("%s: ncopen after ncabort failed", pname);
750 	return;
751     }
752     /* check that new global attribute was not added */
753     if (ncattinq(cdfid, NC_GLOBAL, att.name, &att.type, &att.len) != -1) {
754 	error("%s: ncabort should have restored state before ncredef", pname);
755 	ncclose(cdfid); return;
756     }
757     /* in data mode not being created, should just close */
758     if (ncabort(cdfid) == -1) {
759 	error("%s: ncabort in define mode failed", pname);
760 	return;
761     }
762     if ((cdfid = nccreate(fpath, NC_CLOBBER)) == -1) {
763 	error("%s: nccreate failed to NC_CLOBBER", pname);
764 	return;
765     }
766     /* in define mode being created, should delete */
767     if (ncabort(cdfid) == -1) {
768 	error("%s: ncabort after nccreate failed", pname);
769 	return;
770     }
771     /* check with ncopen that file doesn't exist */
772     if (ncopen(fpath, NC_NOWRITE) != -1) {
773 	error("%s: ncabort deleted file, but ncopen found it", pname);
774 	return;
775     }
776     if (ncabort(cdfid) != -1) {	/* should fail, cdfid is bad handle */
777 	error("%s: ncclose failed to report bad cdf handle ", pname);
778 	nerrs++;
779     }
780     if (nerrs > 0)
781       (void) fprintf(stderr,"FAILED! ***\n");
782     else
783       (void) fprintf(stderr,"ok ***\n");
784 }
785