1 /*
2  *  Copyright (C) 2014, Northwestern University and Argonne National Laboratory
3  *  See COPYRIGHT notice in top-level directory.
4  */
5 /* $Id: t_nc.c 2744 2016-12-28 16:25:22Z wkliao $ */
6 
7 /* This program is based on the test program t_nc.c of the netCDF package */
8 
9 /* Copyright 1988-2010 University Corporation for Atmospheric Research
10    See netcdf/COPYRIGHT file for copying and redistribution
11    conditions.
12 
13    Program to create a cdf, exercise all cdf functions.  Creates cdf,
14    stuff it full of numbers, closes it. Then reopens it, and checks
15    for consistency.  Leaves the file around afterwards.
16 
17    Based on a program to test the nasa look-alike program, so not the
18    most appropropriate test. See ../nctest for a complete spec test.
19 */
20 
21 #define REDEF
22 /* #define SYNCDEBUG */
23 
24 #undef NDEBUG	/* always active assert() in this file */
25 
26 #include <stdio.h>
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <libgen.h> /* basename() */
31 #include <assert.h>
32 #include <mpi.h>
33 #include <pnetcdf.h>
34 
35 #include <testutils.h>
36 
37 #define MAXSHORT	32767
38 #define MAXINT		2147483647
39 #define MAXBYTE		127
40 
41 
42 #define	NUM_DIMS 	3
43 #define DONT_CARE	-1
44 /* make these numbers big when you want to give this a real workout */
45 #define NUM_RECS	8
46 #define SIZE_1		7
47 #define SIZE_2		8
48 
49 static struct {
50 	int num_dims;
51 	int num_vars;
52 	int num_attrs;
53 	int xtendim;
54 } cdesc[1];
55 
56 static struct {
57 	char mnem[NC_MAX_NAME];
58 	nc_type type;
59 	int ndims;
60 	int dims[NC_MAX_VAR_DIMS];
61 	int num_attrs;
62 } vdesc[1];
63 
64 static struct {
65 	char mnem[NC_MAX_NAME];
66 	nc_type type;
67 	MPI_Offset len;
68 } adesc[1];
69 
70 union getret
71 {
72     char            by[8];
73     short           sh[4];
74     int          in[2];
75     float           fl[2];
76     double          dbl;
77 };
78 
79 
80 #define ERR {if (err != NC_NOERR) {printf("Error at %s line %d: %s\n",__func__,__LINE__,ncmpi_strerror(err)); return 1;}}
81 
82 static void
chkgot(nc_type type,union getret got,double check)83 chkgot(nc_type type, union getret got, double check)
84 {
85 	switch(type){
86 	case NC_BYTE :
87 		assert( (char)check == got.by[0] );
88 		break;
89 	case NC_CHAR :	/* TODO */
90 		assert( (char)check == got.by[0] );
91 		break;
92 	case NC_SHORT :
93 		assert( (short)check == got.sh[0] );
94 		break;
95 	case NC_INT :
96 		assert( (int)check == got.in[0] );
97 		break;
98 	case NC_FLOAT :
99 		assert( (float)check == got.fl[0] );
100 		break;
101 	case NC_DOUBLE :
102 		assert( check == got.dbl );
103 		break;
104 	default:
105 		break;
106 	}
107 }
108 
109 
110 static size_t num_dims = NUM_DIMS;
111 static MPI_Offset sizes[] = { NC_UNLIMITED, SIZE_1 , SIZE_2 };
112 static const char * const dim_names[] = { "record", "ixx", "iyy"};
113 
114 static int
createtestdims(int cdfid,size_t num_dims,const MPI_Offset * sizes,const char * const dim_names[])115 createtestdims(int cdfid, size_t num_dims, const MPI_Offset *sizes, const char * const dim_names[])
116 {
117 	int dimid, err;
118 	while(num_dims-- != 0)
119 	{
120 		err = ncmpi_def_dim(cdfid, *dim_names++, *sizes, &dimid); ERR
121 		sizes++;
122 	}
123 	return 0;
124 }
125 
126 
127 static int
testdims(int cdfid,size_t num_dims,MPI_Offset * sizes,const char * const dim_names[])128 testdims(int cdfid, size_t num_dims, MPI_Offset *sizes, const char * const dim_names[])
129 {
130 	int ii, err;
131 	MPI_Offset size;
132 	char cp[NC_MAX_NAME];
133 	for(ii=0; (size_t) ii < num_dims; ii++, sizes++)
134 	{
135 		err = ncmpi_inq_dim(cdfid, ii, cp, &size); ERR
136 		if( size != *sizes)
137 			(void) fprintf(stderr, "%d: %lu != %lu\n",
138 				ii, (unsigned long)size, (unsigned long)*sizes);
139 		if ( size != *sizes) return 1;
140 		if ( strcmp(cp, *dim_names++) != 0) return 1;
141 	}
142 	return 0;
143 }
144 
145 
146 
147 static const char * const reqattr[] = {
148 	"UNITS",
149 	"VALIDMIN",
150 	"VALIDMAX",
151 	"SCALEMIN",
152 	"SCALEMAX",
153 	"FIELDNAM",
154 	_FillValue
155 };
156 #define NUM_RATTRS	6
157 
158 static struct tcdfvar {
159 	const char *mnem;
160 	nc_type type;
161 	const char *fieldnam;
162 	double validmin;
163 	double validmax;
164 	double scalemin;
165 	double scalemax;
166 	const char *units;
167 	int ndims;
168 	int dims[NUM_DIMS];
169 } const testvars[]  = {
170 #define Byte_id 0
171 	{ "Byte", NC_BYTE, "Byte sized integer variable",
172 		-MAXBYTE, MAXBYTE, -MAXBYTE, MAXBYTE , "ones",
173 			2, {0,1,DONT_CARE} },
174 #define Char_id 1
175 	{ "Char", NC_CHAR, "char (string) variable",
176 		DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, "(unitless)",
177 			2, {0,2,DONT_CARE} },
178 #define Short_id 2
179 	{ "Short", NC_SHORT, "Short variable",
180 		-MAXSHORT, MAXSHORT, -MAXSHORT, MAXSHORT , "ones",
181 			2, {0, 2, DONT_CARE }},
182 #define Long_id 3
183 	{ "Long", NC_INT, "Long Integer variable", /* 2.x backward strings */
184 		-MAXINT, MAXINT, -MAXINT, MAXINT, "ones",
185 			2, {1, 2, DONT_CARE}},
186 #define Float_id 4
187 	{ "Float", NC_FLOAT, "Single Precision Floating Point variable",
188 		-MAXINT, MAXINT, -MAXINT, MAXINT, "flots",
189 			3, {0, 1, 2 }},
190 #define Double_id 5
191 	{ "Double", NC_DOUBLE, "Double Precision Floating Point variable",
192 		-MAXINT, MAXINT, -MAXINT, MAXINT, "dflots",
193 			3, {0, 1, 2 }},
194 };
195 #define	NUM_TESTVARS	6
196 
197 static int
createtestvars(int id,const struct tcdfvar * testvars,size_t count)198 createtestvars(int id, const struct tcdfvar *testvars, size_t count)
199 {
200 	int ii, err;
201 	int varid;
202 	const struct tcdfvar *vp = testvars;
203 
204 	for(ii = 0; (size_t) ii < count; ii++, vp++ )
205 	{
206 		err = ncmpi_def_var(id, vp->mnem, vp->type, vp->ndims, vp->dims, &varid); ERR
207 
208 	 	err = ncmpi_put_att_text(id,ii,reqattr[0],strlen(vp->units), vp->units); ERR
209 	 	err = ncmpi_put_att_double(id,ii,reqattr[1],NC_DOUBLE,1, &vp->validmin); ERR
210 	 	err = ncmpi_put_att_double(id,ii,reqattr[2],NC_DOUBLE,1, &vp->validmax); ERR
211 	 	err = ncmpi_put_att_double(id,ii,reqattr[3],NC_DOUBLE,1, &vp->scalemin); ERR
212 	 	err = ncmpi_put_att_double(id,ii,reqattr[4],NC_DOUBLE,1, &vp->scalemax); ERR
213 	 	err = ncmpi_put_att_text(id,ii,reqattr[5],strlen(vp->fieldnam), vp->fieldnam); ERR
214 	}
215 	return 0;
216 }
217 
218 /* static void */
219 /* parray(const char *label, size_t count, const size_t array[]) */
220 /* { */
221 /* 	(void) fprintf(stdout, "%s", label); */
222 /* 	(void) fputc('\t',stdout);	 */
223 /* 	for(; count != 0; count--, array++) */
224 /* 		(void) fprintf(stdout," %lu", (unsigned long) *array); */
225 /* } */
226 
227 
228 static int
fill_seq(int id)229 fill_seq(int id)
230 {
231         int err;
232 	float values[NUM_RECS * SIZE_1 * SIZE_2];
233 	MPI_Offset vindices[NUM_DIMS];
234 
235 	{
236 		size_t ii = 0;
237 		for(; ii < sizeof(values)/sizeof(values[0]); ii++)
238 		{
239 			values[ii] = (float) ii;
240 		}
241 	}
242 
243 	/* zero the vindices */
244 	{
245 		MPI_Offset *cc = vindices;
246 		while (cc < &vindices[num_dims])
247 			*cc++ = 0;
248 	}
249 
250 	sizes[0] = NUM_RECS;
251 	err = ncmpi_put_vara_float(id, Float_id, vindices, sizes, values); ERR
252 	return 0;
253 }
254 
255 static int
check_fill_seq(int id)256 check_fill_seq(int id)
257 {
258 	MPI_Offset vindices[NUM_DIMS];
259 	MPI_Offset *cc, *mm;
260 	union getret got;
261 	int ii = 0;
262 	/*float val;*/
263 
264 	sizes[0] = NUM_RECS;
265 	cc = vindices;
266 	while (cc < &vindices[num_dims])
267 		*cc++ = 0;
268 
269 	/* ripple counter */
270 	cc = vindices;
271 	mm = sizes;
272 	while (*vindices < *sizes)
273 	{
274 	    while (*cc < *mm)
275 	    {
276 		if (mm == &sizes[num_dims - 1])
277 		{
278 	if(ncmpi_get_var1_float(id, Float_id, vindices, &got.fl[0]) == -1)
279 		goto bad_ret;
280 	/* val = (float) ii;  */
281 	/* if(val != got.fl[0]) */
282 	/* { */
283 	/* 	parray("indices", NUM_DIMS, vindices); */
284 	/* 	(void) printf("\t%f != %f\n", val, got.fl[0]); */
285 	/* } */
286 		    (*cc)++; ii++;
287 		    continue;
288 		}
289 		cc++;
290 		mm++;
291 	    }
292 		if(cc == vindices)
293 			break;
294 	    *cc = 0;
295 	    cc--;
296 	    mm--;
297 	    (*cc)++;
298 	}
299 	return 0;
300 bad_ret :
301 	(void) printf("couldn't get a var in check_fill_seq() %d\n", ii);
302 	return 1;
303 }
304 
305 static MPI_Offset	indices[][3] = {
306 	{0, 1, 3},
307 	{0, 3, 0},
308 	{1, 2, 3},
309 	{3, 2, 1},
310 	{2, 1, 3},
311 	{1, 0, 0},
312 	{0, 0, 0},
313 };
314 
315 static const char chs[] = {'A','B', ((char)0xff) };
316 static const MPI_Offset s_start[] = {0,1};
317 static const MPI_Offset s_edges[] = {NUM_RECS, SIZE_1 - 1};
318 static char sentence[NUM_RECS* SIZE_1 -1] =
319 	"The red death had long devastated the country.";
320 static short shs[] = {97, 99};
321 static int birthday = 82555;
322 #define M_E	2.7182818284590452354
323 static float e = (float) M_E;
324 static double pinot = 3.25;
325 static double zed = 0.0;
326 
327 
328 /*ARGSUSED*/
329 static
t_nc(char * filename,int cmode)330 int t_nc(char *filename, int cmode)
331 {
332 	int id, err;
333 	char buf[256];
334 #ifdef SYNCDEBUG
335 	char *str = "one";
336 #endif
337 	int ii;
338 	MPI_Offset ui;
339 	const struct tcdfvar *tvp = testvars;
340 	union getret got;
341 	MPI_Offset align = 8192/32;
342 
343 	err = ncmpi_create(MPI_COMM_WORLD, filename,cmode, MPI_INFO_NULL, &id); ERR
344 
345 	err = ncmpi_put_att_text(id, NC_GLOBAL, "TITLE", 12, "another name"); ERR
346 	err = ncmpi_get_att_text(id, NC_GLOBAL, "TITLE", buf); ERR
347 /*	(void) printf("title 1 \"%s\"\n", buf); */
348 	err = ncmpi_put_att_text(id, NC_GLOBAL, "TITLE", strlen(filename), filename); ERR
349 	err = ncmpi_get_att_text(id, NC_GLOBAL, "TITLE", buf); ERR
350 	buf[strlen(filename)] = 0;
351 /*	(void) printf("title 2 \"%s\"\n", buf); */
352 	assert(strcmp(filename, buf) == 0);
353 
354 	err = createtestdims(id, NUM_DIMS, sizes, dim_names); ERR
355 	testdims(id, NUM_DIMS, sizes, dim_names);
356 
357 	err = createtestvars(id, testvars, NUM_TESTVARS); ERR
358 
359  	{
360  	int ifill = -1; double dfill = -9999;
361  	err = ncmpi_put_att_int(id, Long_id, _FillValue, NC_INT, 1, &ifill); ERR
362  	err = ncmpi_put_att_double(id, Double_id, _FillValue, NC_DOUBLE, 1, &dfill); ERR
363  	}
364 
365 #ifdef REDEF
366 	err = ncmpi__enddef(id, 0, align, 0, 2*align); ERR
367 	err = ncmpi_begin_indep_data(id); ERR
368 	err = ncmpi_put_var1_int(id, Long_id, indices[3], &birthday); ERR
369 	err = fill_seq(id); ERR
370 	err = ncmpi_end_indep_data(id); ERR
371 
372 	err = ncmpi_redef(id); ERR
373 /*	err = ncmpi_rename_dim(id,2, "a long dim name"); ERR */
374 #endif
375 
376 	err = ncmpi_rename_dim(id,1, "IXX"); ERR
377 	err = ncmpi_inq_dim(id, 1, buf, &ui); ERR
378 	/* (void) printf("dimrename: %s\n", buf); */
379 	err = ncmpi_rename_dim(id,1, dim_names[1]); ERR
380 
381 #ifdef ATTRX
382 	err = ncmpi_rename_att(id, 1, "UNITS", "units"); ERR
383 	err = ncmpi_del_att(id, 4, "FIELDNAM"); ERR
384 	err = ncmpi_del_att(id, 2, "SCALEMIN"); ERR
385 	err = ncmpi_del_att(id, 2, "SCALEMAX"); ERR
386 #endif /* ATTRX */
387 
388 	err = ncmpi__enddef(id, 0, align, 0, 2*align); ERR
389 	err = ncmpi_begin_indep_data(id); ERR
390 
391 #ifndef REDEF
392 	err = fill_seq(id); ERR
393 	err = ncmpi_put_var1_int(id, Long_id, indices[3], &birthday); ERR
394 #endif
395 
396 	err = ncmpi_put_vara_schar(id, Byte_id, s_start, s_edges, (signed char *)sentence); ERR
397 	err = ncmpi_put_var1_schar(id, Byte_id, indices[6], (signed char *)(chs+1)); ERR
398 	err = ncmpi_put_var1_schar(id, Byte_id, indices[5], (signed char *)chs); ERR
399 
400 	err = ncmpi_put_vara_text(id, Char_id, s_start, s_edges, sentence); ERR
401 	err = ncmpi_put_var1_text(id, Char_id, indices[6], (chs+1)); ERR
402 	err = ncmpi_put_var1_text(id, Char_id, indices[5], chs); ERR
403 
404 	err = ncmpi_put_var1_short(id, Short_id, indices[4], shs); ERR
405 
406 	err = ncmpi_put_var1_float(id, Float_id, indices[2], &e); ERR
407 
408 	err = ncmpi_put_var1_double(id, Double_id, indices[1], &zed); ERR
409 	err = ncmpi_put_var1_double(id, Double_id, indices[0], &pinot); ERR
410 
411 #ifdef SYNCDEBUG
412 	(void) printf("Hit Return to sync\n");
413 	gets(str);
414 	ncmpi_sync(id,0);
415 	(void) printf("Sync done. Hit Return to continue\n");
416 	gets(str);
417 #endif /* SYNCDEBUG */
418 
419 	err = ncmpi_close(id); ERR
420 
421 
422 /*
423  *	read it
424  */
425 	err = ncmpi_open(MPI_COMM_WORLD, filename,NC_NOWRITE, MPI_INFO_NULL, &id); ERR
426 	err = ncmpi_begin_indep_data(id); ERR
427 
428 	/*	NC	*/
429 	/* (void) printf("NC "); */
430 	err = ncmpi_inq(id, &(cdesc->num_dims), &(cdesc->num_vars), &(cdesc->num_attrs), &(cdesc->xtendim) ); ERR
431 	assert((MPI_Offset) cdesc->num_dims == num_dims);
432 	assert(cdesc->num_attrs == 1);
433 	assert(cdesc->num_vars == NUM_TESTVARS);
434 	/* (void) printf("done\n"); */
435 
436 	/*	GATTR	*/
437 	/* (void) printf("GATTR "); */
438 
439 	err = ncmpi_inq_attname(id, NC_GLOBAL, 0, adesc->mnem); ERR
440 	assert(strcmp("TITLE",adesc->mnem) == 0);
441 	err = ncmpi_inq_att(id, NC_GLOBAL, adesc->mnem, &(adesc->type), &(adesc->len)); ERR
442 	assert( adesc->type == NC_CHAR );
443 	assert( adesc->len == strlen(filename) );
444 	err = ncmpi_get_att_text(id, NC_GLOBAL, "TITLE", buf); ERR
445 	buf[adesc->len] = 0;
446 	assert( strcmp(filename, buf) == 0);
447 
448 	/*	VAR	*/
449 	/* (void) printf("VAR "); */
450 	assert( cdesc->num_vars == NUM_TESTVARS );
451 
452 	for(ii = 0; ii < cdesc->num_vars; ii++, tvp++ )
453 	{
454 		int jj;
455 		err = ncmpi_inq_var(id, ii,
456 			vdesc->mnem,
457 			&(vdesc->type),
458 			&(vdesc->ndims),
459 			vdesc->dims,
460 			&(vdesc->num_attrs)); ERR
461 		if(strcmp(tvp->mnem , vdesc->mnem) != 0)
462 		{
463 			(void) printf("attr %d mnem mismatch %s, %s\n",
464 				ii, tvp->mnem, vdesc->mnem);
465 			continue;
466 		}
467 		if(tvp->type != vdesc->type)
468 		{
469 			(void) printf("attr %d type mismatch %d, %d\n",
470 				ii, (int)tvp->type, (int)vdesc->type);
471 			continue;
472 		}
473 		for(jj = 0; jj < vdesc->ndims; jj++ )
474 		{
475 			if(tvp->dims[jj] != vdesc->dims[jj] )
476 			{
477 		(void) printf(
478 		"inconsistent dim[%d] for variable %d: %d != %d\n",
479 		jj, ii, tvp->dims[jj], vdesc->dims[jj] );
480 			continue;
481 			}
482 		}
483 
484 		/* VATTR */
485 		/* (void) printf("VATTR\n"); */
486 		for(jj=0; jj<vdesc->num_attrs; jj++ )
487 		{
488 			err = ncmpi_inq_attname(id, ii, jj, adesc->mnem); ERR
489 			if( strcmp(adesc->mnem, reqattr[jj]) != 0 )
490 			{
491 				(void) printf("var %d attr %d mismatch %s != %s\n",
492 					ii, jj, adesc->mnem, reqattr[jj] );
493 				break;
494 			}
495 		}
496 
497 		if( ncmpi_inq_att(id, ii, reqattr[0], &(adesc->type), &(adesc->len))
498 			!= -1) {
499 		assert( adesc->type == NC_CHAR );
500 		assert( adesc->len == strlen(tvp->units) );
501 	 	err = ncmpi_get_att_text(id,ii,reqattr[0],buf); ERR
502 		buf[adesc->len] = 0;
503 		assert( strcmp(tvp->units, buf) == 0);
504 		}
505 
506 		if(
507 			ncmpi_inq_att(id, ii, reqattr[1], &(adesc->type), &(adesc->len))
508 			!= -1)
509 		{
510 		assert( adesc->type == NC_DOUBLE );
511 		assert( adesc->len == 1 );
512 	 	err = ncmpi_get_att_double(id, ii, reqattr[1], &got.dbl); ERR
513 		chkgot(adesc->type, got, tvp->validmin);
514 		}
515 
516 		if(
517 			ncmpi_inq_att(id, ii, reqattr[2], &(adesc->type), &(adesc->len))
518 			!= -1)
519 		{
520 		assert( adesc->type == NC_DOUBLE );
521 		assert( adesc->len == 1 );
522 	 	err = ncmpi_get_att_double(id, ii, reqattr[2], &got.dbl); ERR
523 		chkgot(adesc->type, got, tvp->validmax);
524 		}
525 
526 		if(
527 			ncmpi_inq_att(id, ii, reqattr[3], &(adesc->type), &(adesc->len))
528 			!= -1)
529 		{
530 		assert( adesc->type == NC_DOUBLE );
531 		assert( adesc->len ==1 );
532 	 	err = ncmpi_get_att_double(id, ii, reqattr[3], &got.dbl); ERR
533 		chkgot(adesc->type, got, tvp->scalemin);
534 		}
535 
536 		if(
537 			ncmpi_inq_att(id, ii, reqattr[4], &(adesc->type), &(adesc->len))
538 			!= -1)
539 		{
540 		assert( adesc->type == NC_DOUBLE );
541 		assert( adesc->len == 1 );
542 	 	err = ncmpi_get_att_double(id, ii, reqattr[4], &got.dbl); ERR
543 		chkgot(adesc->type, got, tvp->scalemax);
544 		}
545 
546 		if( ncmpi_inq_att(id, ii, reqattr[5], &(adesc->type), &(adesc->len)) == NC_NOERR)
547 		{
548 		assert( adesc->type == NC_CHAR );
549 		assert( adesc->len == strlen(tvp->fieldnam) );
550 	 	err = ncmpi_get_att_text(id,ii,reqattr[5],buf); ERR
551 		buf[adesc->len] = 0;
552 		assert( strcmp(tvp->fieldnam, buf) == 0);
553 		}
554 	}
555 
556 	/* (void) printf("fill_seq "); */
557 	err = check_fill_seq(id); ERR
558 	/* (void) printf("Done\n"); */
559 
560 	err = ncmpi_get_var1_double(id, Double_id, indices[0], &got.dbl); ERR
561 	/* (void) printf("got val = %f\n", got.dbl ); */
562 
563 	err = ncmpi_get_var1_double(id, Double_id, indices[1], &got.dbl); ERR
564 	/* (void) printf("got val = %f\n", got.dbl ); */
565 
566 	err = ncmpi_get_var1_float(id, Float_id, indices[2], &got.fl[0]); ERR
567 	/* (void) printf("got val = %f\n", got.fl[0] ); */
568 
569 	err = ncmpi_get_var1_int(id, Long_id, indices[3], &got.in[0]); ERR
570 	/* (void) printf("got val = %d\n", got.in[0] ); */
571 
572 	err = ncmpi_get_var1_short(id, Short_id, indices[4], &got.sh[0]); ERR
573 	/* (void) printf("got val = %d\n", got.sh[0] ); */
574 
575 	err = ncmpi_get_var1_text(id, Char_id, indices[5], &got.by[0]); ERR
576 	/* (void) printf("got NC_CHAR val = %c (0x%02x) \n", */
577 		 /* got.by[0] , got.by[0]); */
578 
579 	err = ncmpi_get_var1_text(id, Char_id, indices[6], &got.by[0]); ERR
580 	/* (void) printf("got NC_CHAR val = %c (0x%02x) \n", */
581 	/* 	 got.by[0], got.by[0] ); */
582 
583 	(void) memset(buf,0,sizeof(buf));
584 	err = ncmpi_get_vara_text(id, Char_id, s_start, s_edges, buf); ERR
585 	/* (void) printf("got NC_CHAR val = \"%s\"\n", buf); */
586 
587 	err = ncmpi_get_var1_schar(id, Byte_id, indices[5], (signed char *)&got.by[0]); ERR
588 	/* (void) printf("got val = %c (0x%02x) \n", got.by[0] , got.by[0]); */
589 
590 	err = ncmpi_get_var1_schar(id, Byte_id, indices[6], (signed char *)&got.by[0]); ERR
591 	/* (void) printf("got val = %c (0x%02x) \n", got.by[0], got.by[0] ); */
592 
593 	(void) memset(buf,0,sizeof(buf));
594 	err = ncmpi_get_vara_schar(id, Byte_id, s_start, s_edges, (signed char *)buf); ERR
595 	/* (void) printf("got val = \"%s\"\n", buf); */
596 
597 	{
598 		double dbuf[NUM_RECS * SIZE_1 * SIZE_2];
599                 err = ncmpi_get_var_double(id, Float_id, dbuf); ERR
600 
601 		/* (void) printf("got vals = %f ... %f\n", dbuf[0], */
602 		/* 	 dbuf[NUM_RECS * SIZE_1 * SIZE_2 -1] ); */
603 	}
604 
605 	err = ncmpi_close(id); ERR
606 
607 	return 0;
608 }
609 
main(int argc,char * argv[])610 int main(int argc, char *argv[])
611 {
612     char filename[256];
613     int rank, nprocs, cmode, err, nerrs=0;
614 
615     MPI_Init(&argc, &argv);
616     MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
617     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
618 
619     if (argc > 2) {
620         if (!rank) printf("Usage: %s [filename]\n",argv[0]);
621         MPI_Finalize();
622         return 0;
623     }
624     if (argc == 2) snprintf(filename, 256, "%s", argv[1]);
625     else           strcpy(filename, "testfile.nc");
626     MPI_Bcast(filename, 256, MPI_CHAR, 0, MPI_COMM_WORLD);
627 
628     if (rank == 0) {
629         char *cmd_str = (char*)malloc(strlen(argv[0]) + 256);
630         sprintf(cmd_str, "*** TESTING C   %s for emulating netCDF t_nc ", basename(argv[0]));
631         printf("%-66s ------ ", cmd_str);
632         free(cmd_str);
633     }
634 
635     /* test CDF-1 format */
636     cmode = NC_CLOBBER;
637     nerrs += t_nc(filename, cmode);
638 
639     /* test CDF-2 format */
640     cmode = NC_CLOBBER | NC_64BIT_OFFSET;
641     nerrs += t_nc(filename, cmode);
642 
643     /* test CDF-5 format */
644     cmode = NC_CLOBBER | NC_64BIT_DATA;
645     nerrs += t_nc(filename, cmode);
646 
647     /* check if PnetCDF freed all internal malloc */
648     MPI_Offset malloc_size, sum_size;
649     err = ncmpi_inq_malloc_size(&malloc_size);
650     if (err == NC_NOERR) {
651         MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
652         if (rank == 0 && sum_size > 0)
653             printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
654                    sum_size);
655     }
656 
657     MPI_Allreduce(MPI_IN_PLACE, &nerrs, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
658     if (rank == 0) {
659         if (nerrs) printf(FAIL_STR,nerrs);
660         else       printf(PASS_STR);
661     }
662 
663     MPI_Finalize();
664     return 0;
665 }
666 
667