static int tst_norm(char *filename, int cmode) { int ncid, dimid, varid; int dimids[NDIMS]; /* unnormalized UTF-8 encoding for Unicode 8-character "Hello" in Greek: */ unsigned char uname_utf8[] = { 0x41, /* LATIN CAPITAL LETTER A */ 0xCC, 0x80, /* COMBINING GRAVE ACCENT */ 0x41, /* LATIN CAPITAL LETTER A */ 0xCC, 0x81, /* COMBINING ACUTE ACCENT */ 0x41, /* LATIN CAPITAL LETTER A */ 0xCC, 0x82, /* COMBINING CIRCUMFLEX ACCENT */ 0x41, /* LATIN CAPITAL LETTER A */ 0xCC, 0x83, /* COMBINING TILDE */ 0x41, /* LATIN CAPITAL LETTER A */ 0xCC, 0x88, /* COMBINING DIAERESIS */ 0x41, /* LATIN CAPITAL LETTER A */ 0xCC, 0x8A, /* COMBINING RING ABOVE */ 0x43, /* LATIN CAPITAL LETTER C */ 0xCC, 0xA7, /* COMBINING CEDILLA */ 0x45, /* LATIN CAPITAL LETTER E */ 0xCC, 0x80, /* COMBINING GRAVE ACCENT */ 0x45, /* LATIN CAPITAL LETTER E */ 0xCC, 0x81, /* COMBINING ACUTE ACCENT */ 0x45, /* LATIN CAPITAL LETTER E */ 0xCC, 0x82, /* COMBINING CIRCUMFLEX ACCENT */ 0x45, /* LATIN CAPITAL LETTER E */ 0xCC, 0x88, /* COMBINING DIAERESIS */ 0x49, /* LATIN CAPITAL LETTER I */ 0xCC, 0x80, /* COMBINING GRAVE ACCENT */ 0x49, /* LATIN CAPITAL LETTER I */ 0xCC, 0x81, /* COMBINING ACUTE ACCENT */ 0x49, /* LATIN CAPITAL LETTER I */ 0xCC, 0x82, /* COMBINING CIRCUMFLEX ACCENT */ 0x49, /* LATIN CAPITAL LETTER I */ 0xCC, 0x88, /* COMBINING DIAERESIS */ 0x4E, /* LATIN CAPITAL LETTER N */ 0xCC, 0x83, /* COMBINING TILDE */ 0x00 }; /* NFC normalized UTF-8 encoding for same Unicode string: */ unsigned char nname_utf8[] = { 0xC3, 0x80, /* LATIN CAPITAL LETTER A WITH GRAVE */ 0xC3, 0x81, /* LATIN CAPITAL LETTER A WITH ACUTE */ 0xC3, 0x82, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ 0xC3, 0x83, /* LATIN CAPITAL LETTER A WITH TILDE */ 0xC3, 0x84, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ 0xC3, 0x85, /* LATIN CAPITAL LETTER A WITH RING ABOVE */ 0xC3, 0x87, /* LATIN CAPITAL LETTER C WITH CEDILLA */ 0xC3, 0x88, /* LATIN CAPITAL LETTER E WITH GRAVE */ 0xC3, 0x89, /* LATIN CAPITAL LETTER E WITH ACUTE */ 0xC3, 0x8A, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ 0xC3, 0x8B, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ 0xC3, 0x8C, /* LATIN CAPITAL LETTER I WITH GRAVE */ 0xC3, 0x8D, /* LATIN CAPITAL LETTER I WITH ACUTE */ 0xC3, 0x8E, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ 0xC3, 0x8F, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ 0xC3, 0x91, /* LATIN CAPITAL LETTER N WITH TILDE */ 0x00 }; /* Unnormalized name used for dimension, variable, and attribute value */ #define UNAME ((char *) uname_utf8) #define UNAMELEN (sizeof uname_utf8) /* Normalized name */ #define NNAME ((char *) nname_utf8) #define NNAMELEN (sizeof nname_utf8) char name_in[UNAMELEN + 1], strings_in[UNAMELEN + 1]; nc_type att_type; MPI_Offset att_len; int err, dimid_in, varid_in, attnum_in; int attvals[] = {42}; #define ATTNUM ((sizeof attvals)/(sizeof attvals[0])) err = ncmpi_create(MPI_COMM_WORLD, filename, cmode, MPI_INFO_NULL,&ncid); ERR /* Define dimension with unnormalized Unicode UTF-8 encoded name */ err = ncmpi_def_dim(ncid, UNAME, NX, &dimid); ERR dimids[0] = dimid; /* Define variable with same name */ err = ncmpi_def_var(ncid, UNAME, NC_CHAR, NDIMS, dimids, &varid); ERR /* Create string attribute with same value */ err = ncmpi_put_att_text(ncid, varid, UNITS, UNAMELEN, UNAME); ERR /* Create int attribute with same name */ err = ncmpi_put_att_int(ncid, varid, UNAME, NC_INT, ATTNUM, attvals); ERR /* Try to create dimension and variable with NFC-normalized * version of same name. These should fail, as unnormalized name * should have been normalized in library, so these are attempts to * create duplicate netCDF objects. */ if ((err = ncmpi_def_dim(ncid, NNAME, NX, &dimid)) != NC_ENAMEINUSE) { printf("Error at line %d: expecting error code %d but got %d\n",__LINE__,NC_ENAMEINUSE,err); return 1; } if ((err=ncmpi_def_var(ncid, NNAME, NC_CHAR, NDIMS, dimids, &varid)) != NC_ENAMEINUSE) { printf("Error at line %d: expecting error code %d but got %d\n",__LINE__,NC_ENAMEINUSE,err); return 1; } err = ncmpi_enddef(ncid); ERR /* Write string data, UTF-8 encoded, to the file */ err = ncmpi_put_var_text_all(ncid, varid, UNAME); ERR err = ncmpi_close(ncid); ERR /* Check it out. */ err = ncmpi_open(MPI_COMM_WORLD, filename, NC_NOWRITE, MPI_INFO_NULL, &ncid); ERR err = ncmpi_inq_varid(ncid, UNAME, &varid); ERR err = ncmpi_inq_varname(ncid, varid, name_in); ERR err = strncmp(NNAME, name_in, NNAMELEN); ERR err = ncmpi_inq_varid(ncid, NNAME, &varid_in); ERR if ((err = ncmpi_inq_dimid(ncid, UNAME, &dimid_in)) || dimid != dimid_in) {printf("Error at line %d\n",__LINE__);return 1;} if ((err = ncmpi_inq_dimid(ncid, NNAME, &dimid_in)) || dimid != dimid_in) {printf("Error at line %d\n",__LINE__);return 1;} err = ncmpi_inq_att(ncid, varid, UNITS, &att_type, &att_len); ERR if ( att_type != NC_CHAR || att_len != UNAMELEN) {printf("Error at line %d\n",__LINE__);return 1;} err = ncmpi_get_att_text(ncid, varid, UNITS, strings_in); ERR strings_in[UNAMELEN] = '\0'; err = strncmp(UNAME, strings_in, UNAMELEN); ERR if ((err = ncmpi_inq_attid(ncid, varid, UNAME, &attnum_in)) || ATTNUM != attnum_in) {printf("Error at line %d\n",__LINE__);return 1;} if ((err = ncmpi_inq_attid(ncid, varid, NNAME, &attnum_in)) || ATTNUM != attnum_in) {printf("Error at line %d\n",__LINE__);return 1;} err = ncmpi_close(ncid); ERR return 0; }
/*----< main() >--------------------------------------------------------------*/ int main(int argc, char **argv) { int i, j, c, err, rank, nprocs, verbose, quiet; int ncid1, ndims1, nvars1, natts1, unlimdimid1, *dimids1; int ncid2, ndims2, nvars2, natts2, unlimdimid2, *dimids2; char *name1, *name2; MPI_Offset *shape=NULL, varsize, *start=NULL; MPI_Offset attlen1, dimlen1, attlen2, dimlen2; nc_type type1, type2; MPI_Comm comm=MPI_COMM_WORLD; int nvars, check_header, check_variable_list, check_entire_file; long long numVarDIFF=0, numHeadDIFF=0, varDIFF, numDIFF; struct vspec var_list; extern char *optarg; extern int optind; MPI_Info info; MPI_Init(&argc, &argv); MPI_Comm_size(comm, &nprocs); MPI_Comm_rank(comm, &rank); progname = argv[0]; verbose = 0; quiet = 0; check_header = 0; check_variable_list = 0; check_entire_file = 0; var_list.names = NULL; var_list.nvars = 0; while ((c = getopt(argc, argv, "bhqv:")) != -1) switch(c) { case 'h': /* compare header only */ check_header = 1; break; case 'v': /* variable names */ /* make list of names of variables specified */ get_var_names(optarg, &var_list); check_variable_list = 1; break; case 'b': verbose = 1; break; case 'q': quiet = 1; break; case '?': usage(rank, argv[0]); break; } /* quiet overwrites verbose */ if (quiet) verbose = 0; if (argc - optind != 2) usage(rank, argv[0]); if (check_header == 0 && check_variable_list == 0) { check_entire_file = 1; check_header = 1; } name1 = (char*) malloc(NC_MAX_NAME); if (!name1) OOM_ERROR name2 = (char*) malloc(NC_MAX_NAME); if (!name2) OOM_ERROR /* Nov. 18, 2014 -- disable subfiling as it does not correctly handle the * cases when nprocs < num_subfiles */ MPI_Info_create (&info); MPI_Info_set (info, "pnetcdf_subfiling", "disable"); /* open files */ err = ncmpi_open(comm, argv[optind], NC_NOWRITE, info, &ncid1); HANDLE_ERROR err = ncmpi_open(comm, argv[optind+1], NC_NOWRITE, info, &ncid2); HANDLE_ERROR MPI_Info_free(&info); /* check header */ if (check_header && rank == 0) { /* only root checks header */ int attnump; err = ncmpi_inq(ncid1, &ndims1, &nvars1, &natts1, &unlimdimid1); HANDLE_ERROR err = ncmpi_inq(ncid2, &ndims2, &nvars2, &natts2, &unlimdimid2); HANDLE_ERROR if (ndims1 != ndims2) { /* check number of dimensions if equal */ if (!quiet) printf("DIFF: number of dimensions (%d) != (%d)\n",ndims1, ndims2); numHeadDIFF++; } else if (verbose) printf("SAME: number of dimensions (%d)\n",ndims1); if (nvars1 != nvars2) { /* check number of variables if equal */ if (!quiet) printf("DIFF: number of variables (%d) != (%d)\n",nvars1, nvars2); numHeadDIFF++; } else if (verbose) printf("SAME: number of variables (%d)\n",nvars1); if (natts1 != natts2) { /* check number of global attributes if equal */ if (!quiet) printf("DIFF: number of global attributes (%d) != (%d)\n",natts1, natts2); numHeadDIFF++; } else if (verbose) printf("SAME: number of global attributes (%d)\n",natts1); /* Compare global attributes, assume CHAR attributes. */ for (i=0; i<natts1; i++) { /* check what's in file1 also in file2 */ err = ncmpi_inq_attname(ncid1, NC_GLOBAL, i, name1); HANDLE_ERROR /* find the attr with the same name from ncid2 */ err = ncmpi_inq_attid(ncid2, NC_GLOBAL, name1, &attnump); if (err == NC_ENOTATT) { if (!quiet) printf("DIFF: global attribute \"%s\" not found in file %s\n", name1,argv[optind+1]); numHeadDIFF++; continue; } err = ncmpi_inq_att(ncid1, NC_GLOBAL, name1, &type1, &attlen1); HANDLE_ERROR err = ncmpi_inq_att(ncid2, NC_GLOBAL, name1, &type2, &attlen2); HANDLE_ERROR if (type1 != type2) { if (!quiet) printf("DIFF: global attribute \"%s\" data type (%s) != (%s)\n", name1,get_type(type1),get_type(type2)); numHeadDIFF++; continue; } else if (verbose) { printf("Global attribute \"%s\":\n",name1); printf("\tSAME: data type (%s)\n",get_type(type1)); } if (attlen1 != attlen2) { if (!quiet) printf("DIFF: global attribute \"%s\" length (%lld) != (%lld)\n", name1,attlen1,attlen2); numHeadDIFF++; continue; } else if (verbose) printf("\tSAME: length (%lld)\n",attlen1); switch (type1) { case NC_CHAR: CHECK_GLOBAL_ATT_DIFF(char, ncmpi_get_att_text, NC_CHAR) case NC_SHORT: CHECK_GLOBAL_ATT_DIFF(short, ncmpi_get_att_short, NC_SHORT) case NC_INT: CHECK_GLOBAL_ATT_DIFF(int, ncmpi_get_att_int, NC_INT) case NC_FLOAT: CHECK_GLOBAL_ATT_DIFF(float, ncmpi_get_att_float, NC_FLOAT) case NC_DOUBLE: CHECK_GLOBAL_ATT_DIFF(double, ncmpi_get_att_double, NC_DOUBLE) case NC_UBYTE: CHECK_GLOBAL_ATT_DIFF(ubyte, ncmpi_get_att_uchar, NC_UBYTE) case NC_USHORT: CHECK_GLOBAL_ATT_DIFF(ushort, ncmpi_get_att_ushort, NC_USHORT) case NC_UINT: CHECK_GLOBAL_ATT_DIFF(uint, ncmpi_get_att_uint, NC_UINT) case NC_INT64: CHECK_GLOBAL_ATT_DIFF(int64, ncmpi_get_att_longlong, NC_INT64) case NC_UINT64: CHECK_GLOBAL_ATT_DIFF(uint64, ncmpi_get_att_ulonglong, NC_UINT64) default: ; /* TODO: handle unexpected types */ } } for (i=0; i<natts2; i++) { /* check attributes in file2 but not in file1 */ err = ncmpi_inq_attname(ncid2, NC_GLOBAL, i, name2); HANDLE_ERROR /* find the attr with the same name from ncid1 */ if (ncmpi_inq_attid(ncid1, NC_GLOBAL, name2, &attnump) == NC_ENOTATT) { numHeadDIFF++; if (!quiet) printf("DIFF: global attribute \"%s\" not found in file %s\n", name1,argv[optind]); } } /* Compare dimension */ if (ndims1 && verbose) printf("Dimension:\n"); for (i=0; i<ndims1; i++) { /* check dimensions in file1 also in file2 */ int dimid; err = ncmpi_inq_dim(ncid1, i, name1, &dimlen1); HANDLE_ERROR /* find the dim with the same name from ncid2 */ err = ncmpi_inq_dimid(ncid2, name1, &dimid); if (err == NC_EBADDIM) { if (!quiet) printf("DIFF: dimension \"%s\" not found in file %s\n", name1,argv[optind+1]); numHeadDIFF++; continue; } err = ncmpi_inq_dimlen(ncid2, dimid, &dimlen2); HANDLE_ERROR if (dimlen1 != dimlen2) { /* cast to quiet warning on 32 bit platforms */ if (!quiet) printf("DIFF: dimension \"%s\" length (%lld) != (%lld)\n", name1,(long long int)dimlen1,(long long int)dimlen2); numHeadDIFF++; } else if (verbose) printf("\tSAME: dimension \"%s\" length (%lld)\n", name1,(long long int)dimlen1); } for (i=0; i<ndims2; i++) { /* check dimensions in file2 but not in file1 */ int dimid; err = ncmpi_inq_dim(ncid2, i, name2, &dimlen2); HANDLE_ERROR /* find the dim with the same name from ncid1 */ if (ncmpi_inq_dimid(ncid2, name1, &dimid) == NC_EBADDIM) { if (!quiet) printf("DIFF: dimension \"%s\" not found in file %s\n", name1,argv[optind]); numHeadDIFF++; } } /* Compare variables' metadata */ for (i=0; i<nvars1; i++) { int varid; err = ncmpi_inq_varndims(ncid1, i, &ndims1); HANDLE_ERROR dimids1 = (int*) malloc((size_t)ndims1 * SIZEOF_INT); if (!dimids1) OOM_ERROR err = ncmpi_inq_var(ncid1, i, name1, &type1, &ndims1, dimids1, &natts1); HANDLE_ERROR /* find the variable with the same name from ncid2 */ err = ncmpi_inq_varid(ncid2, name1, &varid); if (err == NC_ENOTVAR) { if (!quiet) printf("DIFF: variable \"%s\" not found in file %s\n", name1,argv[optind+1]); numHeadDIFF++; numVarDIFF++; continue; } err = ncmpi_inq_varndims(ncid2, varid, &ndims2); HANDLE_ERROR dimids2 = (int*) malloc((size_t)ndims2 * SIZEOF_INT); if (!dimids2) OOM_ERROR err = ncmpi_inq_var(ncid2, varid, name2, &type2, &ndims2, dimids2, &natts2); HANDLE_ERROR if (type1 != type2) { if (!quiet) printf("DIFF: variable \"%s\" data type (%s) != (%s)\n", name1,get_type(type1),get_type(type2)); numHeadDIFF++; } else if (verbose) { printf("Variable \"%s\":\n",name1); printf("\tSAME: data type (%s)\n",get_type(type1)); } if (ndims1 != ndims2) { if (!quiet) printf("DIFF: variable \"%s\" number of dimensions (%d) != (%d)\n", name1,ndims1,ndims2); numHeadDIFF++; } else { if (verbose) printf("\tSAME: number of dimensions (%d)\n",ndims1); for (j=0; j<ndims1; j++) { /* check variable's dimensionality */ char dimname1[NC_MAX_NAME], dimname2[NC_MAX_NAME]; /* get dim name for each dim ID */ err = ncmpi_inq_dim(ncid1, dimids1[j], dimname1, &dimlen1); HANDLE_ERROR err = ncmpi_inq_dim(ncid1, dimids2[j], dimname2, &dimlen2); HANDLE_ERROR if (verbose) printf("\tdimension %d:\n",j); if (strcmp(dimname1, dimname2) != 0) { if (!quiet) printf("DIFF: variable \"%s\" of type \"%s\" dimension %d's name (%s) != (%s)\n", name1,get_type(type1),j,dimname1,dimname2); numHeadDIFF++; } else if (verbose) printf("\t\tSAME: name (%s)\n",dimname1); if (dimlen1 != dimlen2) { if (!quiet) printf("DIFF: variable \"%s\" of type \"%s\" dimension %d's length (%lld) != (%lld)\n", name1,get_type(type1),j,(long long int)dimlen1,(long long int)dimlen2); numHeadDIFF++; } else if (verbose) printf("\t\tSAME: length (%lld)\n",(long long int)dimlen1); } } if (natts1 != natts2) { if (!quiet) printf("DIFF: variable \"%s\" number of attributes (%d) != (%d)\n", name1,natts1,natts2); numHeadDIFF++; } else if (verbose) printf("\tSAME: number of attributes (%d)\n",natts1); /* var attributes, assume CHAR attributes */ for (j=0; j<natts1; j++) { char attrname[NC_MAX_NAME]; err = ncmpi_inq_attname(ncid1, i, j, attrname); HANDLE_ERROR err = ncmpi_inq_att(ncid1, i, attrname, &type1, &attlen1); HANDLE_ERROR /* find the variable attr with the same name from ncid2 */ err = ncmpi_inq_att(ncid2, varid, attrname, &type2, &attlen2); if (err == NC_ENOTATT) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" not found in file %s\n", name1,attrname,argv[optind+1]); numHeadDIFF++; continue; } if (verbose) printf("\tattribute \"%s\":\n",attrname); if (type1 != type2) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" data type (%s) != (%s)\n", name1,attrname,get_type(type1),get_type(type2)); numHeadDIFF++; continue; /* skip this attribute */ } else if (verbose) printf("\t\tSAME: data type (%s)\n",get_type(type1)); if (attlen1 != attlen2) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" length (%lld) != (%lld)\n", name1,attrname,(long long int)attlen1,(long long int)attlen2); numHeadDIFF++; continue; /* skip this attribute */ } else if (verbose) printf("\t\tSAME: length (%lld)\n",(long long int)attlen1); switch (type1) { case NC_CHAR: CHECK_VAR_ATT_DIFF(char, ncmpi_get_att_text, NC_CHAR) case NC_SHORT: CHECK_VAR_ATT_DIFF(short, ncmpi_get_att_short, NC_SHORT) case NC_INT: CHECK_VAR_ATT_DIFF(int, ncmpi_get_att_int, NC_INT) case NC_FLOAT: CHECK_VAR_ATT_DIFF(float, ncmpi_get_att_float, NC_FLOAT) case NC_DOUBLE: CHECK_VAR_ATT_DIFF(double, ncmpi_get_att_double, NC_DOUBLE) case NC_UBYTE: CHECK_VAR_ATT_DIFF(ubyte, ncmpi_get_att_uchar, NC_UBYTE) case NC_USHORT: CHECK_VAR_ATT_DIFF(ushort, ncmpi_get_att_ushort, NC_USHORT) case NC_UINT: CHECK_VAR_ATT_DIFF(uint, ncmpi_get_att_uint, NC_UINT) case NC_INT64: CHECK_VAR_ATT_DIFF(int64, ncmpi_get_att_longlong, NC_INT64) case NC_UINT64: CHECK_VAR_ATT_DIFF(uint64, ncmpi_get_att_ulonglong, NC_UINT64) default: ; /* TODO: handle unexpected types */ } } for (j=0; j<natts2; j++) { char attrname[NC_MAX_NAME]; err = ncmpi_inq_attname(ncid2, varid, j, attrname); HANDLE_ERROR /* find the variable attr with the same name from ncid1 */ err = ncmpi_inq_att(ncid1, i, attrname, &type1, &attlen1); if (err == NC_ENOTATT) { if (!quiet) printf("DIFF: variable \"%s\" attribute \"%s\" not found in file %s\n", name1,attrname,argv[optind]); numHeadDIFF++; } } free(dimids1); free(dimids2); } for (i=0; i<nvars2; i++) { /* check variables in file2 but not in file1 */ int varid; err = ncmpi_inq_varname(ncid2, i, name2); HANDLE_ERROR /* find the variable with the same name from ncid1 */ err = ncmpi_inq_varid(ncid1, name2, &varid); if (err == NC_ENOTVAR) { if (!quiet) printf("DIFF: variable \"%s\" not found in file %s\n", name2,argv[optind]); numHeadDIFF++; numVarDIFF++; } } }