diff --git a/CMakeLists.txt b/CMakeLists.txt index 2327c9883..272690a89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ ENDIF() # Get system configuration find_program(UNAME NAMES uname) +IF(UNAME) macro(getuname name flag) exec_program("${UNAME}" ARGS "${flag}" OUTPUT_VARIABLE "${name}") endmacro(getuname) @@ -26,7 +27,7 @@ getuname(osname -s) getuname(osrel -r) getuname(cpu -m) set(BUILDNAME "${osname}-${osrel}-${cpu}" CACHE STRING "Build name variable for CDash") - +ENDIF() ENABLE_TESTING() INCLUDE(CTest) @@ -68,8 +69,9 @@ INCLUDE (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) INCLUDE (${CMAKE_ROOT}/Modules/CheckCXXSourceCompiles.cmake) INCLUDE (${CMAKE_ROOT}/Modules/TestBigEndian.cmake) INCLUDE (${CMAKE_ROOT}/Modules/CheckSymbolExists.cmake) -INCLUDE (${CMAKE_ROOT}/Modules/FindPkgConfig.cmake) INCLUDE (${CMAKE_ROOT}/Modules/GetPrerequisites.cmake) + +FIND_PACKAGE(PkgConfig QUIET) # Only necessary for Windows IF(MSVC) INCLUDE (${CMAKE_SOURCE_DIR}/cmake/modules/windows/FindHDF5.cmake) @@ -375,11 +377,24 @@ IF (USE_HDF5 OR ENABLE_NETCDF_4) #FIND_PACKAGE(HDF5 COMPONENTS C HL REQUIRED) FIND_LIBRARY(HDF5_LIB NAMES hdf5 libhdf5 hdf5dll) FIND_LIBRARY(HDF5_HL_LIB NAMES hdf5_hl libhdf5_hl hdf5_hldll) + + IF(NOT HDF5_LIB) + MESSAGE(FATAL_ERROR "netCDF-4 support specified, but hdf5 libraries not found.") + ELSEIF(NOT HDF5_HL_LIB) + MESSAGE(FATAL_ERROR "netCDF-4 support specified, but hdf5 high-level libraries not found.") + ENDIF() SET(HDF5_LIBRARIES ${HDF5_LIB} ${HDF5_HL_LIB}) FIND_PATH(HDF5_INCLUDE_DIR H5public.h) - MESSAGE(STATUS "${HDF5_LIB}, ${HDF5_HL_LIB}, ${HDF5_INCLUDE_DIR}") + IF(NOT HDF5_INCLUDE_DIR) + MESSAGE(FATAL_ERROR "netCDF-4 support specified, but hdf5 include directories not found.") + ENDIF() + + MESSAGE(STATUS "Found HDF5: ${HDF5_LIB}") + MESSAGE(STATUS "Found HDF5_HL: ${HDF5_HL_LIB}") + MESSAGE(STATUS "Found HDF5 Includes: ${HDF5_INCLUDE_DIR}") + INCLUDE_DIRECTORIES(${HDF5_INCLUDE_DIR}) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index aa4bfee0c..c7e6b7481 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -8,6 +8,11 @@ VERSION COMMENTS ------- -------- 4.3 Released 201?-??-?? + Fixed netCDF-4 bug with particular order of + creation of dimensions, coordinate variables, and + subgroups resulting in two dimensions with the same + dimension ID. [NCF-244] + Fixed bug with incorrect fixed-size variable offsets in header getting written when schema changed for files created by parallel-netcdf. Thanks to Wei-keng Liao for diff --git a/cf b/cf index 6164378d0..383b6dd5b 100644 --- a/cf +++ b/cf @@ -9,6 +9,7 @@ fi HDF5=1 DAP=1 #PNETCDF=1 +#HDF4=1 #RPC=1 #PGI=1 #M32=1 @@ -25,6 +26,11 @@ cmds="" #cmds="$cmds install" fi +# HDF4=>HDF5 +if test "x$HDF4" = x1 ; then +HDF5=1 +fi + # Test pgi compiler if test "x$PGI" = x1 ; then PATH="/opt/pgi/linux86/11.1/bin:$PATH" @@ -97,11 +103,16 @@ MAKE=make IGNORE="test 0 = 1" if test "x$HDF5" = "x1" ; then -CPPFLAGS="-I${stddir}/include -I${stddir}/include $CPPFLAGS" -LDFLAGS="-L${stddir}/lib -lhdf5_hl -lhdf5 -L${stddir}/lib -lz $LDFLAGS" +CPPFLAGS="-I${stddir}/include $CPPFLAGS" +LDFLAGS="-L${stddir}/lib -lhdf5_hl -lhdf5 -lz $LDFLAGS" LD_LIBRARY_PATH="${stddir}/lib:$LD_LIBRARY_PATH" fi +#if test "x$HDF4" = "x1" ; then +#CPPFLAGS="-I/machine/local/include $CPPFLAGS" +#LDFLAGS="-L/machine/local/lib $LDFLAGS" +#fi + if test "x$DAP" = "x1" -o "x$CDMR" = "x1" -o "x$RPC" = "x1" ; then if curl-config --version >/dev/null ; then TMP=`curl-config --cflags` @@ -133,23 +144,18 @@ FLAGS="$FLAGS --disable-examples" #FLAGS="$FLAGS --enable-dap-long-tests" #FLAGS="$FLAGS --enable-ffio" #FLAGS="$FLAGS --enable-benchmarks" -FLAGS="$FLAGS --enable-extra-tests" -FLAGS="$FLAGS --enable-logging" +#FLAGS="$FLAGS --enable-extra-tests" #FLAGS="$FLAGS --enable-large-file-tests" #FLAGS="$FLAGS --disable-testsets" #FLAGS="$FLAGS --disable-dap-remote-tests" #FLAGS="$FLAGS --enable-doxygen" -FLAGS="$FLAGS --enable-logging" +#FLAGS="$FLAGS --enable-logging" #FLAGS="$FLAGS --disable-diskless" #FLAGS="$FLAGS --enable-mmap" #FLAGS="$FLAGS --with-udunits" #FLAGS="$FLAGS --with-libcf" #valgrind => not shared #FLAGS="$FLAGS --enable-valgrind-tests" -# hdf4 requires adding to paths -#FLAGS="$FLAGS --enable-hdf4 --enable-hdf4-file-tests" -#CPPFLAGS="$CPPFLAGS -I/machine/local/include" -#LDFLAGS="$LDFLAGS -L/machine/local/lib -L/usr/local/lib" FLAGS="$FLAGS --disable-shared" #FLAGS="$FLAGS --enable-shared" @@ -157,6 +163,9 @@ FLAGS="$FLAGS --disable-shared" if test "x$HDF5" = "x" ; then FLAGS="$FLAGS --disable-netcdf-4" fi +if test "x$HDF4" = x1 ; then +FLAGS="$FLAGS --enable-hdf4 --enable-hdf4-file-tests" +fi if test "x$DAP" = "x" ; then FLAGS="$FLAGS --disable-dap" fi diff --git a/include/nc4internal.h b/include/nc4internal.h index 91c50bd24..f37579718 100644 --- a/include/nc4internal.h +++ b/include/nc4internal.h @@ -302,7 +302,8 @@ int nc4_pg_varm(NC_PG_T pg, NC *nc, int ncid, int varid, const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, const ptrdiff_t *imapp, nc_type xtype, int is_long, void *op); int nc4_rec_match_dimscales(NC_GRP_INFO_T *grp); -int nc4_rec_write_metadata(NC_GRP_INFO_T *grp); +int nc4_rec_detect_bad_coord_order(NC_GRP_INFO_T *grp, int *bad_coord_orderp); +int nc4_rec_write_metadata(NC_GRP_INFO_T *grp, int bad_coord_order); int nc4_rec_write_types(NC_GRP_INFO_T *grp); int nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5); int nc4_reopen_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var); diff --git a/include/netcdf.h b/include/netcdf.h index c644310f3..8891d4074 100644 --- a/include/netcdf.h +++ b/include/netcdf.h @@ -14,6 +14,10 @@ for more info. #include /* size_t, ptrdiff_t */ #include /* netcdf functions sometimes return system errors */ +/* Required for alloca on Windows */ +#if defined(_WIN32) || defined(_WIN64) +#include +#endif #ifdef _WIN64 #include diff --git a/libdap2/Make0 b/libdap2/Make0 index 0b341f758..45507c451 100755 --- a/libdap2/Make0 +++ b/libdap2/Make0 @@ -258,7 +258,7 @@ fix:: done ################################################## -T=civ2 +T=test_vara v:: cc -g -c ${T}.c ${INCL} diff --git a/libdap2/dceconstraints.h b/libdap2/dceconstraints.h index 64783a41c..1fb4982e0 100644 --- a/libdap2/dceconstraints.h +++ b/libdap2/dceconstraints.h @@ -136,6 +136,14 @@ extern size_t dcesafeindex(DCEsegment* seg, size_t start, size_t stop); /* Compute segment size for start upto stop */ extern size_t dcesegmentsize(DCEsegment*, size_t start, size_t stop); +/* Convert a DCE projection/selection/constraint instance into a string + that can be used with a url. Caller must free returned string. +*/ + +extern char* buildprojectionstring(NClist* projections); +extern char* buildselectionstring(NClist* selections); +extern char* buildconstraintstring(DCEconstraint* constraints); + extern int dceverbose; #endif /*DCECONSTRAINTS_H*/ diff --git a/libdap2/getvara3.c b/libdap2/getvara3.c index f1bb72446..fd4b7cf6b 100644 --- a/libdap2/getvara3.c +++ b/libdap2/getvara3.c @@ -695,6 +695,7 @@ findfield(CDFnode* node, CDFnode* field) } +#ifdef EXTERN_UNUSED int nc3d_getvarmx(int ncid, int varid, const size_t *start, @@ -879,6 +880,7 @@ fprintf(stderr,"old: %lu -> %lu %f\n", done: return ncstat; } +#endif /*EXTERN_UNUSED*/ static int conversionrequired(nc_type t1, nc_type t2) diff --git a/libdap2/ncd3dispatch.c b/libdap2/ncd3dispatch.c index 59c33cf6b..942d43ebf 100644 --- a/libdap2/ncd3dispatch.c +++ b/libdap2/ncd3dispatch.c @@ -42,7 +42,7 @@ static int NCD3_get_vars(int ncid, int varid, const size_t *start, const size_t *edges, const ptrdiff_t* stride, void *value, nc_type memtype); -NC_Dispatch NCD3_dispatch_base = { +static NC_Dispatch NCD3_dispatch_base = { NC_DISPATCH_NC3 | NC_DISPATCH_NCD, @@ -134,7 +134,7 @@ NULL, /*get_var_chunk_cache*/ NC_Dispatch* NCD3_dispatch_table = NULL; /* moved here from ddispatch.c */ -NC_Dispatch NCD3_dispatcher; /* overlay result */ +static NC_Dispatch NCD3_dispatcher; /* overlay result */ int NCD3_initialize(void) diff --git a/libdap2/ncdap3.c b/libdap2/ncdap3.c index 04785fd5d..bf95fdf35 100644 --- a/libdap2/ncdap3.c +++ b/libdap2/ncdap3.c @@ -32,7 +32,7 @@ static NCerror buildattribute3a(NCDAPCOMMON*, NCattribute*, nc_type, int); static char* getdefinename(CDFnode* node); -int nc3dinitialized = 0; +static int ncd3initialized = 0; size_t dap_one[NC_MAX_VAR_DIMS]; size_t dap_zero[NC_MAX_VAR_DIMS]; @@ -46,8 +46,8 @@ int nc__opendap(void) {return 0;} /**************************************************/ /* Do local initialization */ -int -nc3dinitialize(void) +static int +ncd3initialize(void) { int i; compute_nccalignments(); @@ -55,7 +55,7 @@ nc3dinitialize(void) dap_one[i] = 1; dap_zero[i] = 0; } - nc3dinitialized = 1; + ncd3initialized = 1; #ifdef DEBUG /* force logging to go to stderr */ nclogclose(); @@ -79,7 +79,7 @@ NCD3_open(const char * path, int mode, NCDAPCOMMON* dapcomm = NULL; const char* value; - if(!nc3dinitialized) nc3dinitialize(); + if(!ncd3initialized) ncd3initialize(); if(path == NULL) return NC_EDAPURL; diff --git a/libdap2/ncdap3.h b/libdap2/ncdap3.h index 45b6fcca0..09db76d11 100644 --- a/libdap2/ncdap3.h +++ b/libdap2/ncdap3.h @@ -130,7 +130,6 @@ extern size_t dap_zero[NC_MAX_VAR_DIMS]; extern NCerror nc3d_open(const char* path, int mode, int* ncidp); extern int nc3d_close(int ncid); -extern int nc3dinitialize(void); extern NCerror restruct3(CDFnode* ddsroot, CDFnode* template, NClist*); extern void setvisible(CDFnode* root, int visible); extern NCerror mapnodes3(CDFnode* dstroot, CDFnode* srcroot); diff --git a/libdap2/test_vara.c b/libdap2/test_vara.c index bd34940ac..90ed90e50 100644 --- a/libdap2/test_vara.c +++ b/libdap2/test_vara.c @@ -79,14 +79,15 @@ main() size_t start[RANK]; size_t count[RANK]; char URL[4096]; - const char* svc = NULL: + const char* svc = NULL; - /* Find Test Server *. + /* Find Test Server */ svc = NC_findtestserver("dts"); if(svc == NULL) { fprintf(stderr,"Cannot locate test server\n"); exit(1); } + printf("Using test server: %s\n",svc); strcpy(URL,svc); strcat(URL,DTSTEST); diff --git a/libdispatch/ddispatch.c b/libdispatch/ddispatch.c index cd5a0119d..c2e36dbf8 100644 --- a/libdispatch/ddispatch.c +++ b/libdispatch/ddispatch.c @@ -31,11 +31,13 @@ static struct NCPROTOCOLLIST { against future changes. */ static const char* servers[] = { -"http://motherlode.ucar.edu:8081", /* try this first */ -"http://remotetest.unidata.ucar.edu", -"http://remotetest.ucar.edu", +"http://thredds-test.ucar.edu", +"http://thredds.ucar.edu", +"http://motherlode.ucar.edu:8081", "http://motherlode.ucar.edu:8080", "http://motherlode.ucar.edu", +"http://remotetest.unidata.ucar.edu", +"http://remotetest.ucar.edu", "http://remotetests.unidata.ucar.edu", "http://remotetests.ucar.edu", NULL diff --git a/libdispatch/defcheck.c b/libdispatch/defcheck.c index 9108bd279..5facde137 100644 --- a/libdispatch/defcheck.c +++ b/libdispatch/defcheck.c @@ -4,7 +4,7 @@ #include #include -#define URL "http://motherlode.ucar.edu:8081/dts/test.02" +#define URL "http://thredds-test.ucar.edu/dts/test.02" #define VAR "i32" #define ERRCODE 2 diff --git a/libdispatch/dstring.c b/libdispatch/dstring.c index e8bb00869..32f21d21e 100644 --- a/libdispatch/dstring.c +++ b/libdispatch/dstring.c @@ -35,7 +35,7 @@ free_NC_string(NC_string *ncstrp) } -int +static int nextUTF8(const char* cp) { /* The goal here is to recognize the length of each diff --git a/libdispatch/dvarget.c b/libdispatch/dvarget.c index 0a33b916f..8919dab97 100644 --- a/libdispatch/dvarget.c +++ b/libdispatch/dvarget.c @@ -1383,6 +1383,10 @@ atomic type; it will not read user defined types. For this function, the type of the data in memory must match the type of the variable - no data conversion is done. +Use of this family of functions is discouraged, although not +formally deprecated. The reason is the complexity of the +algorithm makes its use difficult for users to properly use. + \param ncid NetCDF or group ID, from a previous call to nc_open(), nc_create(), nc_def_grp(), or associated inquiry functions such as nc_inq_ncid(). diff --git a/libdispatch/dvarput.c b/libdispatch/dvarput.c index 90f0b9395..28b4b66ca 100644 --- a/libdispatch/dvarput.c +++ b/libdispatch/dvarput.c @@ -1305,6 +1305,10 @@ atomic type; it will not write user defined types. For this function, the type of the data in memory must match the type of the variable - no data conversion is done. +Use of this family of functions is discouraged, although not +formally deprecated. The reason is the complexity of the +algorithm makes its use difficult for users to properly use. + \param ncid NetCDF or group ID, from a previous call to nc_open(), nc_create(), nc_def_grp(), or associated inquiry functions such as nc_inq_ncid(). diff --git a/libsrc/Makefile.am b/libsrc/Makefile.am index d5bb2bafd..1320f9968 100644 --- a/libsrc/Makefile.am +++ b/libsrc/Makefile.am @@ -39,7 +39,7 @@ noinst_LTLIBRARIES = libnetcdf3.la # with m4), but they are included in the distribution so that the user # does not have to have m4. MAINTAINERCLEANFILES = attr.c ncx.c putget.c $(man_MANS) attrx.c putgetx.c -EXTRA_DIST = attr.m4 ncx.m4 putget.m4 $(man_MANS) CMakeLists.txt +EXTRA_DIST = attr.m4 ncx.m4 putget.m4 $(man_MANS) CMakeLists.txt XGetopt.c # This tells make how to turn .m4 files into .c files. .m4.c: diff --git a/libsrc/nc3dispatch.c b/libsrc/nc3dispatch.c index 5c9b3ba90..4b992a8b4 100644 --- a/libsrc/nc3dispatch.c +++ b/libsrc/nc3dispatch.c @@ -77,7 +77,7 @@ static int NC3_set_var_chunk_cache(int,int,size_t,size_t,float); static int NC3_get_var_chunk_cache(int,int,size_t*,size_t*,float*); #endif /*USE_NETCDF4*/ -NC_Dispatch NC3_dispatcher = { +static NC_Dispatch NC3_dispatcher = { NC_DISPATCH_NC3, diff --git a/libsrc4/nc4dispatch.c b/libsrc4/nc4dispatch.c index c2933973c..1875a1c86 100644 --- a/libsrc4/nc4dispatch.c +++ b/libsrc4/nc4dispatch.c @@ -10,7 +10,7 @@ #include "ncdispatch.h" #include "nc4dispatch.h" -NC_Dispatch NC4_dispatcher = { +static NC_Dispatch NC4_dispatcher = { NC_DISPATCH_NC4, diff --git a/libsrc4/nc4file.c b/libsrc4/nc4file.c index ac5f212b2..feb2ea0a3 100644 --- a/libsrc4/nc4file.c +++ b/libsrc4/nc4file.c @@ -8,12 +8,14 @@ Copyright 2003, University Corporation for Atmospheric Research. See COPYRIGHT file for copying and redistribution conditions. */ -#include "nc4internal.h" -#include "nc.h" -#include +#include "config.h" +#include /* netcdf functions sometimes return system errors */ +#include "nc.h" +#include "nc4internal.h" #include "nc4dispatch.h" -#include "ncdispatch.h" + +#include #ifdef USE_HDF4 #include @@ -326,7 +328,9 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, /* Create the file. */ if ((nc4_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) - BAIL(NC_EFILEMETA); + /*Change the return error from NC_EFILEMETADATA to + System error EACCES because that is the more likely problem */ + BAIL(EACCES); /* Open the root group. */ if ((nc4_info->root_grp->hdf_grpid = H5Gopen2(nc4_info->hdfid, "/", @@ -2961,9 +2965,12 @@ sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) /* Write any metadata that has changed. */ if (!(h5->cmode & NC_NOWRITE)) { + int bad_coord_order = 0; /* if detected, propagate to all groups to consistently store dimids */ if ((retval = nc4_rec_write_types(h5->root_grp))) return retval; - if ((retval = nc4_rec_write_metadata(h5->root_grp))) + if ((retval = nc4_rec_detect_bad_coord_order(h5->root_grp, &bad_coord_order))) + return retval; + if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order))) return retval; } diff --git a/libsrc4/nc4hdf.c b/libsrc4/nc4hdf.c index 90bcc82de..adee1c347 100644 --- a/libsrc4/nc4hdf.c +++ b/libsrc4/nc4hdf.c @@ -1420,9 +1420,12 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid) maxdimsize[d] = var->dim[d]->unlimited ? H5S_UNLIMITED : (hsize_t)var->dim[d]->len; chunksize[d] = var->chunksizes[d];*/ - for (d = 0; d < var->ndims; d++) - for (g = grp; g && (dims_found < var->ndims); g = g->parent) - for (dim = g->dim; dim; dim = dim->next) + for (d = 0; d < var->ndims; d++) + { + for (g = grp; g && (dims_found < var->ndims); g = g->parent) + { + for (dim = g->dim; dim; dim = dim->next) + { if (dim->dimid == var->dimids[d]) { dimsize[d] = dim->unlimited ? NC_HDF5_UNLIMITED_DIMSIZE : dim->len; @@ -1456,6 +1459,9 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid) dims_found++; break; } + } + } + } if (var->contiguous) { @@ -2419,26 +2425,18 @@ write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, int write_dimid) return retval; } -/* Recursively write all the metadata in a group. Groups and types - * have all already been written. */ +/* Recursively determine if there is a mismatch between order of + * coordinate creation and associated dimensions in this group or any + * subgroups, to find out if we have to handle that situation. */ int -nc4_rec_write_metadata(NC_GRP_INFO_T *grp) +nc4_rec_detect_bad_coord_order(NC_GRP_INFO_T *grp, int *bad_coord_orderp) { NC_DIM_INFO_T *dim; NC_VAR_INFO_T *var; NC_GRP_INFO_T *child_grp; - int found_coord, coord_varid = -1, wrote_coord; - int bad_coord_order = 0; int last_dimid = -1; int retval; - assert(grp && grp->name && grp->hdf_grpid); - LOG((3, "nc4_rec_write_metadata: grp->name %s", grp->name)); - - /* Write global attributes for this group. */ - if ((retval = write_attlist(grp->att, NC_GLOBAL, grp))) - return retval; - /* If the user writes coord vars in a different order then he * defined their dimensions, then, when the file is reopened, the * order of the dimids will change to match the order of the coord @@ -2450,8 +2448,8 @@ nc4_rec_write_metadata(NC_GRP_INFO_T *grp) { if (var->dimids[0] < last_dimid) { - bad_coord_order++; - break; + *bad_coord_orderp = 1; + return NC_NOERR; } last_dimid = var->dimids[0]; } @@ -2466,9 +2464,38 @@ nc4_rec_write_metadata(NC_GRP_INFO_T *grp) if (!strcmp(dim->name, var->name) && !dim->dirty) { LOG((5, "coord var defined after enddef/redef")); - bad_coord_order++; + *bad_coord_orderp = 1; + return NC_NOERR; } + /* If there are any child groups, check them also for this condition. */ + for (child_grp = grp->children; child_grp; child_grp = child_grp->next) + if ((retval = nc4_rec_detect_bad_coord_order(child_grp, bad_coord_orderp))) + return retval; + + return NC_NOERR; +} + + +/* Recursively write all the metadata in a group. Groups and types + * have all already been written. Propagate bad cooordinate order to + * subgroups, if detected. */ +int +nc4_rec_write_metadata(NC_GRP_INFO_T *grp, int bad_coord_order) +{ + NC_DIM_INFO_T *dim; + NC_VAR_INFO_T *var; + NC_GRP_INFO_T *child_grp; + int found_coord, coord_varid = -1, wrote_coord; + + int retval; + + assert(grp && grp->name && grp->hdf_grpid); + LOG((3, "nc4_rec_write_metadata: grp->name %s, bad_coord_order %d", grp->name, bad_coord_order)); + + /* Write global attributes for this group. */ + if ((retval = write_attlist(grp->att, NC_GLOBAL, grp))) + return retval; /* For some stupid reason, the dim list is stored backwards! Get to * the back of the list. */ @@ -2516,7 +2543,7 @@ nc4_rec_write_metadata(NC_GRP_INFO_T *grp) /* If there are any child groups, write their metadata. */ for (child_grp = grp->children; child_grp; child_grp = child_grp->next) - if ((retval = nc4_rec_write_metadata(child_grp))) + if ((retval = nc4_rec_write_metadata(child_grp, bad_coord_order))) return retval; return NC_NOERR; diff --git a/libsrc4/nc4internal.c b/libsrc4/nc4internal.c index 995ce709d..af98d4282 100644 --- a/libsrc4/nc4internal.c +++ b/libsrc4/nc4internal.c @@ -668,6 +668,7 @@ nc4_dim_list_add(NC_DIM_INFO_T **list) } /* Add to the beginning of a dim list. */ +#ifdef EXTERN_UNUSED int nc4_dim_list_add2(NC_DIM_INFO_T **list, NC_DIM_INFO_T **new_dim) { @@ -684,6 +685,7 @@ nc4_dim_list_add2(NC_DIM_INFO_T **list, NC_DIM_INFO_T **new_dim) *new_dim = dim; return NC_NOERR; } +#endif /* Add to the end of an att list. */ int @@ -1012,7 +1014,7 @@ field_list_del(NC_FIELD_INFO_T **list, NC_FIELD_INFO_T *field) } /* Delete a type from a type list, and nc_free the memory. */ -int +static int type_list_del(NC_TYPE_INFO_T **list, NC_TYPE_INFO_T *type) { NC_FIELD_INFO_T *field, *f; diff --git a/libsrc4/nc4var.c b/libsrc4/nc4var.c index 1a69d85c0..8d7d2f51f 100644 --- a/libsrc4/nc4var.c +++ b/libsrc4/nc4var.c @@ -361,7 +361,6 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, NC_HDF5_FILE_INFO_T *h5; NC_TYPE_INFO_T *type_info; char norm_name[NC_MAX_NAME + 1]; - int new_varid = 0; int num_unlim = 0; int d; size_t num_values = 1; @@ -415,10 +414,6 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, if (h5->no_write) return NC_EPERM; - /* Get the new varid. */ - for (var = grp->var; var; var = var->next) - new_varid++; - /* Check all the dimids to make sure they exist. */ for (d = 0; d < ndims; d++) { diff --git a/nc_test4/tst_dims3.c b/nc_test4/tst_dims3.c index 6a38fb814..f29f8ea17 100644 --- a/nc_test4/tst_dims3.c +++ b/nc_test4/tst_dims3.c @@ -20,10 +20,18 @@ nc_set_log_level(0); #define FILE_NAME "tst_dims3.nc" #define RANK_time 1 #define GRP_NAME "G" +#define GRP2_NAME "G2" #define TIME_NAME "time" #define VAR2_NAME "z" #define TIME_RANK 1 #define NUM_TIMES 2 +#define LEV_NAME "level" +#define VRT_NAME "vert_number" +#define LEV_NUM 3 +#define LEV_RANK 1 +#define VRT_RANK 1 +#define VAR2_RANK 2 +#define NUM_VRT 3 int ncid, grpid; int time_dim, time_dim_in; int time_var, z_var; @@ -97,5 +105,98 @@ nc_set_log_level(0); ERR_RET; } SUMMARIZE_ERR; + printf("*** testing defining dimensions and coord variables in different orders in root group..."); + { + int ncid, grpid, grp2id; + int time_dimid, lev_dimid, vrt_dimid, g2lev_dimid, g2vrt_dimid; + int time_dimid_in, lev_dimid_in, vrt_dimid_in, g2lev_dimid_in, g2vrt_dimid_in; + int time_varid, lev_varid, gvar2_varid, g2lev_varid, g2vrt_varid; + int var2_dims[VAR2_RANK]; + /* Create test for fix of bug that resulted in two dimensions + * having the same dimid, which violates the Pauli exclusion + * principle for dimensions. */ + if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR_RET; + if (nc_def_grp(ncid, GRP_NAME, &grpid)) ERR; + if (nc_def_dim(ncid, TIME_NAME, NC_UNLIMITED, &time_dimid)) ERR_RET; + if (nc_def_dim(ncid, LEV_NAME, LEV_NUM, &lev_dimid)) ERR_RET; + var2_dims[0] = time_dimid; + var2_dims[1] = lev_dimid; + if (nc_def_var(grpid, VAR2_NAME, NC_FLOAT, VAR2_RANK, var2_dims, &gvar2_varid)) ERR; + /* define coord vars in opposite order of coord dims */ + if (nc_def_var(ncid, LEV_NAME, NC_FLOAT, LEV_RANK, &lev_dimid, &lev_varid)) ERR; + if (nc_def_var(ncid, TIME_NAME, NC_FLOAT, TIME_RANK, &time_dimid, &time_varid)) ERR; + + if (nc_def_grp(ncid, GRP2_NAME, &grp2id)) ERR; + if (nc_def_dim(grp2id, LEV_NAME, LEV_NUM, &g2lev_dimid)) ERR_RET; + if (nc_def_dim(grp2id, VRT_NAME, NUM_VRT, &g2vrt_dimid)) ERR_RET; + if (nc_def_var(grp2id, LEV_NAME, NC_FLOAT, LEV_RANK, &g2lev_dimid, &g2lev_varid)) ERR; + if (nc_def_var(grp2id, VRT_NAME, NC_FLOAT, VRT_RANK, &g2vrt_dimid, &g2vrt_varid)) ERR; + if (nc_close(ncid)) ERR; + + /* Re-open, in which dimids may get reassigned */ + if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, TIME_NAME, &time_dimid_in)) ERR; + if (nc_inq_dimid(ncid, LEV_NAME, &lev_dimid_in)) ERR; + if (nc_inq_ncid(ncid, GRP2_NAME, &grp2id)) ERR; + if (nc_inq_dimid(grp2id, LEV_NAME, &g2lev_dimid_in)) ERR; + if (nc_inq_dimid(grp2id, VRT_NAME, &g2vrt_dimid_in)) ERR; + /* dimids must still all be distinct */ + if (time_dimid_in == lev_dimid_in || + time_dimid_in == g2lev_dimid_in || + time_dimid_in == g2vrt_dimid_in || + lev_dimid_in == g2lev_dimid_in || + lev_dimid_in == g2vrt_dimid_in || + g2lev_dimid_in == g2vrt_dimid_in) ERR; + + if (nc_close(ncid)) + ERR_RET; + } + SUMMARIZE_ERR; + printf("*** testing defining dimensions and coord variables in different orders in subgroup..."); + { + int ncid, grpid, grp2id; + int time_dimid, lev_dimid, vrt_dimid, g2lev_dimid, g2vrt_dimid; + int time_dimid_in, lev_dimid_in, vrt_dimid_in, g2lev_dimid_in, g2vrt_dimid_in; + int time_varid, lev_varid, gvar2_varid, g2lev_varid, g2vrt_varid; + int var2_dims[VAR2_RANK]; + /* Create test for fix of bug inside a subgroup that results in two dimensions + * having the same dimid. */ + if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR_RET; + if (nc_def_grp(ncid, GRP_NAME, &grpid)) ERR; + if (nc_def_dim(ncid, TIME_NAME, NC_UNLIMITED, &time_dimid)) ERR_RET; + if (nc_def_dim(ncid, LEV_NAME, LEV_NUM, &lev_dimid)) ERR_RET; + var2_dims[0] = time_dimid; + var2_dims[1] = lev_dimid; + if (nc_def_var(grpid, VAR2_NAME, NC_FLOAT, VAR2_RANK, var2_dims, &gvar2_varid)) ERR; + if (nc_def_var(ncid, TIME_NAME, NC_FLOAT, TIME_RANK, &time_dimid, &time_varid)) ERR; + if (nc_def_var(ncid, LEV_NAME, NC_FLOAT, LEV_RANK, &lev_dimid, &lev_varid)) ERR; + + if (nc_def_grp(ncid, GRP2_NAME, &grp2id)) ERR; + if (nc_def_dim(grp2id, LEV_NAME, LEV_NUM, &g2lev_dimid)) ERR_RET; + if (nc_def_dim(grp2id, VRT_NAME, NUM_VRT, &g2vrt_dimid)) ERR_RET; + /* define coord vars in opposite order of coord dims */ + if (nc_def_var(grp2id, VRT_NAME, NC_FLOAT, VRT_RANK, &g2vrt_dimid, &g2vrt_varid)) ERR; + if (nc_def_var(grp2id, LEV_NAME, NC_FLOAT, LEV_RANK, &g2lev_dimid, &g2lev_varid)) ERR; + if (nc_close(ncid)) ERR; + + /* Re-open, in which dimids may get reassigned */ + if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, TIME_NAME, &time_dimid_in)) ERR; + if (nc_inq_dimid(ncid, LEV_NAME, &lev_dimid_in)) ERR; + if (nc_inq_ncid(ncid, GRP2_NAME, &grp2id)) ERR; + if (nc_inq_dimid(grp2id, LEV_NAME, &g2lev_dimid_in)) ERR; + if (nc_inq_dimid(grp2id, VRT_NAME, &g2vrt_dimid_in)) ERR; + /* dimids must still all be distinct */ + if (time_dimid_in == lev_dimid_in || + time_dimid_in == g2lev_dimid_in || + time_dimid_in == g2vrt_dimid_in || + lev_dimid_in == g2lev_dimid_in || + lev_dimid_in == g2vrt_dimid_in || + g2lev_dimid_in == g2vrt_dimid_in) ERR; + + if (nc_close(ncid)) + ERR_RET; + } + SUMMARIZE_ERR; FINAL_RESULTS; } diff --git a/ncdap_test/tst_remote.sh b/ncdap_test/tst_remote.sh index 0a5fdea57..cd2dc3a01 100755 --- a/ncdap_test/tst_remote.sh +++ b/ncdap_test/tst_remote.sh @@ -124,7 +124,7 @@ argo_all.cdp;1;&location.LATITUDE<1&location.LATITUDE>-1\ # Test string access # this test cannot be used because the # dataset has a limited lifetime -#REMOTEURLC4="http://motherlode.ucar.edu:$PORT/thredds/dodsC/station/metar" +#REMOTEURLC4="http://thredds-test.ucar.edu/thredds/dodsC/station/metar" #REMOTETESTSC4="\ #Surface_METAR_20120101_0000.nc;1;weather[0:10]" diff --git a/ncdap_test/tst_tds.sh b/ncdap_test/tst_tds.sh index 4a2647b59..b81a253af 100755 --- a/ncdap_test/tst_tds.sh +++ b/ncdap_test/tst_tds.sh @@ -42,9 +42,9 @@ EXPECTED="${srcdir}/expecttds3" # Special test info ################################################## # TDS files under 10 megabytes -# TDS Catalog: http://motherlode.ucar.edu:8080/thredds/catalog/public/dataset/catalog.html +# TDS Catalog: http://thredds.ucar.edu/thredds/catalog/public/dataset/catalog.html -TDSURL1="http://motherlode.ucar.edu:8080/thredds/dodsC/public/dataset" +TDSURL1="http://thredds.ucar.edu/thredds/dodsC/public/dataset" TDSTESTS1="\ tst-striped.nc \ tst-PROFILER_RASS.nc \ diff --git a/ncdump/Makefile.am b/ncdump/Makefile.am index 795955930..2bab7937d 100644 --- a/ncdump/Makefile.am +++ b/ncdump/Makefile.am @@ -123,7 +123,7 @@ ref_nc_test_netcdf4.cdl ref_tst_special_atts3.cdl tst_brecs.cdl \ ref_tst_grp_spec0.cdl ref_tst_grp_spec.cdl tst_grp_spec.sh \ ref_tst_charfill.cdl tst_charfill.cdl tst_charfill.sh \ tst_iter.sh tst_mud.sh ref_tst_mud4.cdl \ -ref_tst_ncf213.cdl CMakeLists.txt +ref_tst_ncf213.cdl CMakeLists.txt XGetopt.c # NCGEN4 additions SUBDIRS=cdl4 expected4 diff --git a/ncgen/Makefile.am b/ncgen/Makefile.am index 998da4714..14daed1a6 100644 --- a/ncgen/Makefile.am +++ b/ncgen/Makefile.am @@ -22,7 +22,7 @@ man_MANS = ncgen.1 # These files all need to be distributed. EXTRA_DIST = ncgen.y ncgenyy.c ncgen.l $(man_MANS) internals.html \ run_tests.sh run_nc4_tests.sh c0.cdl ref_camrun.cdl \ -ncf199.cdl CMakeLists.txt +ncf199.cdl CMakeLists.txt XGetopt.c # This shell script causes ncgen to build a classic and a 64-bit # offset file from a cdl file shipped with the distribution. diff --git a/ncgen3/Makefile.am b/ncgen3/Makefile.am index 2112d2d0f..a1485abf7 100644 --- a/ncgen3/Makefile.am +++ b/ncgen3/Makefile.am @@ -30,7 +30,7 @@ endif # USE_NETCDF4 CLEANFILES = c0.nc c0_64.nc c0_4.nc c0_4c.nc -EXTRA_DIST += CMakeLists.txt +EXTRA_DIST += CMakeLists.txt XGetopt.c # This is used if someone wants to rebuild ncgenyy.c or ncgentab.c # Otherwise never invoked, but records how to do it. Don't forget to diff --git a/oc2/daplex.c b/oc2/daplex.c index b7858fa1f..c92e54b57 100644 --- a/oc2/daplex.c +++ b/oc2/daplex.c @@ -300,8 +300,10 @@ dapsetwordchars(DAPlexstate* lexstate, int kind) void daplexinit(char* input, DAPlexstate** lexstatep) { - DAPlexstate* lexstate = (DAPlexstate*)malloc(sizeof(DAPlexstate)); - if(lexstatep) *lexstatep = lexstate; + DAPlexstate* lexstate; + if(lexstatep == NULL) return; /* no point in building it */ + lexstate = (DAPlexstate*)malloc(sizeof(DAPlexstate)); + *lexstatep = lexstate; if(lexstate == NULL) return; memset((void*)lexstate,0,sizeof(DAPlexstate)); lexstate->input = strdup(input); @@ -309,8 +311,6 @@ daplexinit(char* input, DAPlexstate** lexstatep) lexstate->yytext = ocbytesnew(); lexstate->reclaim = oclistnew(); dapsetwordchars(lexstate,0); /* Assume DDS */ - if(!lexstatep) - free(lexstate); } void diff --git a/oc2/oc.c b/oc2/oc.c index 67cf8f256..c8f5f5758 100644 --- a/oc2/oc.c +++ b/oc2/oc.c @@ -539,7 +539,7 @@ Obtain a dds node by name from a dds structure or dataset node. \param[in] link The link through which the server is accessed. \param[in] ddsnode The container node of interest. \param[in] name The name of the field to return. -\param[out] fieldnodep A pointer into which the name'th field node is stored. +\param[out] fieldp A pointer into which the name'th field node is stored. \retval OC_NOERR The procedure executed normally. \retval OC_EINDEX No field with the given name was found. @@ -836,7 +836,7 @@ oc_das_attr(OCobject link, OCobject dasnode, size_t index, OCtype* atomtypep, ch /**@}*/ /**************************************************/ -/*! Node Interconnection Management */ +/*!\defgroup Interconnection Node Interconnection Management */ /**@{*/ @@ -875,7 +875,7 @@ oc_merge_das(OCobject link, OCobject dasroot, OCobject ddsroot) /**************************************************/ -/*! Data Management */ +/*!\defgroup Data Data Management */ /**@{*/ /*! @@ -965,6 +965,8 @@ oc_data_fieldbyname(OCobject link, OCobject datanode, const char* name, OCobject OCerror err = OC_NOERR; size_t count,i; OCobject ddsnode; + OCVERIFY(OC_State,link); + OCVERIFY(OC_Data,datanode); /* Get the dds node for this datanode */ err = oc_data_ddsnode(link,datanode,&ddsnode); @@ -1492,11 +1494,140 @@ oc_data_readn(OCobject link, OCobject datanode, } + +/*! +This procedure has the same semantics as oc_data_read. +However, it takes an OCddsnode as argument. +The limitation is that the DDS node must be a top-level, +atomic variable. +Top-level means that it is not nested in a Sequence or a +dimensioned Structure; being in a Grid is ok as is being in +a scalar structure. + +\param[in] link The link through which the server is accessed. +\param[in] ddsnode The dds node instance of interest. +\param[in] start A vector of indices specifying the starting element +to return. +\param[in] edges A vector of indices specifying the count in each dimension +of the number of elements to return. +\param[in] memsize The size (in bytes) of the memory argument. +\param[out] memory User allocated memory into which the extracted +data is to be stored. The caller is responsible for allocating and free'ing +this argument. + +\retval OC_NOERR The procedure executed normally. +\retval OC_EINVAL The memsize argument is too small to hold +the specified data. +\retval OC_EINVALCOORDS The start and/or edges argument is outside +the range of legal indices. +\retval OC_EDATADDS The data retrieved from the server was malformed +and the read request cannot be completed. + +*/ + +OCerror +oc_dds_read(OCobject link, OCobject ddsnode, + size_t* start, size_t* edges, + size_t memsize, void* memory) +{ + OCdata* data; + OCnode* dds; + + OCVERIFY(OC_Node,ddsnode); + OCDEREF(OCnode*,dds,ddsnode); + + /* Get the data associated with this top-level node */ + data = dds->data; + if(data == NULL) return OC_EINVAL; + return oc_data_read(link,data,start,edges,memsize,memory); +} + + +/*! +This procedure is a variant of oc_data_read for reading a single scalar. +This procedure has the same semantics as oc_data_readscalar. +However, it takes an OCddsnode as argument. +The limitation is that the DDS node must be a top-level, atomic variable. +Top-level means that it is not nested in a Sequence or a +dimensioned Structure; being in a Grid is ok as is being in +a scalar structure. + +\param[in] link The link through which the server is accessed. +\param[in] ddsnode The dds node instance of interest. +\param[in] memsize The size (in bytes) of the memory argument. +\param[out] memory User allocated memory into which the extracted +data is to be stored. The caller is responsible for allocating and free'ing +this argument. + +\retval OC_NOERR The procedure executed normally. +\retval OC_EINVAL The memsize argument is too small to hold +the specified data. +\retval OC_ESCALAR The data instance is not a scalar. +\retval OC_EDATADDS The data retrieved from the server was malformed +and the read request cannot be completed. +\retval OC_EINVAL One of the arguments (link, etc.) was invalid. +*/ + +OCerror +oc_dds_readscalar(OCobject link, OCobject ddsnode, + size_t memsize, void* memory) +{ + return oc_dds_readn(link,ddsnode,NULL,0,memsize,memory); +} + +/*! +This procedure is a variant of oc_dds_read for reading +nelements of values starting at a given index position. +If the variable is a scalar, then the +index vector and count will be ignored. +This procedure has the same semantics as oc_data_readn. +However, it takes an OCddsnode as argument. +The limitation is that the DDS node must be a top-level, atomic variable. +Top-level means that it is not nested in a Sequence or a +dimensioned Structure; being in a Grid is ok as is being in +a scalar structure. + +\param[in] link The link through which the server is accessed. +\param[in] ddsnode The dds node instance of interest. +\param[in] start A vector of indices specifying the starting element +to return. +\param[in] N The number of elements to read. Reading is assumed +to use row-major order. +\param[in] memsize The size (in bytes) of the memory argument. +\param[out] memory User allocated memory into which the extracted +data is to be stored. The caller is responsible for allocating and free'ing +this argument. + +\retval OC_NOERR The procedure executed normally. +\retval OC_EINVAL The memsize argument is too small to hold +the specified data. +\retval OC_EINVALCOORDS The start and/or count argument is outside +the range of legal indices. +\retval OC_EDATADDS The data retrieved from the server was malformed +and the read request cannot be completed. +\retval OC_EINVAL One of the arguments (link, etc.) was invalid. +*/ + +OCerror +oc_dds_readn(OCobject link, OCobject ddsnode, + size_t* start, size_t N, + size_t memsize, void* memory) +{ + OCdata* data; + OCnode* dds; + + OCVERIFY(OC_Node,ddsnode); + OCDEREF(OCnode*,dds,ddsnode); + + /* Get the data associated with this top-level node */ + data = dds->data; + if(data == NULL) return OC_EINVAL; + return oc_data_readn(link,data,start,N,memsize,memory); +} + /**@}*/ /**************************************************/ -/* OCtype Management */ - /*!\defgroup OCtype OCtype Management @{*/ @@ -1775,6 +1906,7 @@ oc_ping(const char* url) /*! Set the user agent field. +\param[in] link The link through which the server is accessed. \param[in] agent The user agent string \retval OC_NOERR if the request succeeded. diff --git a/oc2/oc.h b/oc2/oc.h index fa84a1d1f..496c88587 100644 --- a/oc2/oc.h +++ b/oc2/oc.h @@ -400,12 +400,14 @@ extern OCerror oc_data_recordcount(OClink, OCdatanode, size_t*); If scalar, then index and count are ignored. Caller is responsible for allocating memory(of proper size) and free'ing it. + See also oc_dds_read(). */ extern OCerror oc_data_read(OClink, OCdatanode, size_t*, size_t*, size_t, void*); /* Like oc_data_read, but for reading a scalar. Caller is responsible for allocating memory(of proper size) and free'ing it. + See also oc_dds_readscalar(). */ extern OCerror oc_data_readscalar(OClink, OCdatanode, size_t, void*); @@ -413,6 +415,7 @@ extern OCerror oc_data_readscalar(OClink, OCdatanode, size_t, void*); and count of the number of elements to read. Caller is responsible for allocating memory(of proper size) and free'ing it. + See also oc_dds_readn(). */ extern OCerror oc_data_readn(OClink, OCdatanode, size_t*, size_t, size_t, void*); @@ -446,6 +449,22 @@ extern int oc_data_indexed(OClink, OCdatanode); */ extern int oc_data_indexable(OClink, OCdatanode); +/**************************************************/ +/* +For top-level, atomic variables, it is possible to directly +read the associated data without having to use the oc_data_XXX +procedures. Provide special procedures to support this. +*/ + +/* See oc_data_read for semantics */ +extern OCerror oc_dds_read(OClink, OCddsnode, size_t*, size_t*, size_t, void*); + +/* See oc_data_readscalar for semantics */ +extern OCerror oc_dds_readscalar(OClink, OCddsnode, size_t, void*); + +/* See oc_data_readn for semantics */ +extern OCerror oc_dds_readn(OClink, OCddsnode, size_t*, size_t, size_t, void*); + /**************************************************/ /* Misc. OCtype-related functions */ diff --git a/oc2/occompile.c b/oc2/occompile.c index 40c74481f..d74633af4 100644 --- a/oc2/occompile.c +++ b/oc2/occompile.c @@ -12,18 +12,22 @@ #include "ocdebug.h" #include "ocdump.h" +/* Mnemonic */ +#define TOPLEVEL 1 + /* Forward */ static OCdata* newocdata(OCnode* template); static size_t ocxdrsize(OCtype etype,int isscalar); static OCerror occompile1(OCstate*, OCnode*, XXDR*, OCdata**); static OCerror occompilerecord(OCstate*, OCnode*, XXDR*, OCdata**); -static OCerror occompilefields(OCstate*, OCdata*, XXDR*); +static OCerror occompilefields(OCstate*, OCdata*, XXDR*, int istoplevel); static OCerror occompileatomic(OCstate*, OCdata*, XXDR*); static int ocerrorstring(XXDR* xdrs); +static int istoplevel(OCnode* node); /* Sequence tag constant */ -const char StartOfSequence = '\x5A'; -const char EndOfSequence = '\xA5'; +static const char StartOfSequence = '\x5A'; +static const char EndOfSequence = '\xA5'; /* Provide an option that makes a single pass over @@ -86,13 +90,13 @@ occompile1(OCstate* state, OCnode* xnode, XXDR* xxdrs, OCdata** datap) case OC_Dataset: case OC_Grid: /* Always scalars */ - ocstat = occompilefields(state,data,xxdrs); + ocstat = occompilefields(state,data,xxdrs,istoplevel(xnode)); if(ocstat != OC_NOERR) goto fail; break; case OC_Structure: if(xnode->array.rank == 0) {/* scalar */ - ocstat = occompilefields(state,data,xxdrs); + ocstat = occompilefields(state,data,xxdrs,istoplevel(xnode)); if(ocstat != OC_NOERR) goto fail; } else { /* dimensioned structure */ unsigned int xdrcount; @@ -124,7 +128,7 @@ occompile1(OCstate* state, OCnode* xnode, XXDR* xxdrs, OCdata** datap) /* capture the current instance position */ instance->xdroffset = xxdr_getpos(xxdrs); /* Now compile the fields of this instance */ - ocstat = occompilefields(state,instance,xxdrs); + ocstat = occompilefields(state,instance,xxdrs,!TOPLEVEL); if(ocstat != OC_NOERR) {goto fail;} } } @@ -210,7 +214,7 @@ occompilerecord(OCstate* state, OCnode* xnode, XXDR* xxdrs, OCdata** recordp) /* capture the current record position */ record->xdroffset = xxdr_getpos(xxdrs); /* Compile the fields of this record */ - ocstat = OCTHROW(occompilefields(state,record,xxdrs)); + ocstat = OCTHROW(occompilefields(state,record,xxdrs,!TOPLEVEL)); if(ocstat == OC_NOERR) { if(recordp) *recordp = record; } @@ -218,7 +222,7 @@ occompilerecord(OCstate* state, OCnode* xnode, XXDR* xxdrs, OCdata** recordp) } static OCerror -occompilefields(OCstate* state, OCdata* data, XXDR* xxdrs) +occompilefields(OCstate* state, OCdata* data, XXDR* xxdrs, int istoplevel) { int i; OCerror ocstat = OC_NOERR; @@ -246,6 +250,15 @@ occompilefields(OCstate* state, OCdata* data, XXDR* xxdrs) fieldinstance->index = i; } + /* If top-level, then link the OCnode to the OCdata directly */ + if(istoplevel) { + for(i=0;isubnodes,i); + OCdata* fieldinstance = data->instances[i]; + fieldnode->data = fieldinstance; + } + } + done: return OCTHROW(ocstat); @@ -373,6 +386,23 @@ newocdata(OCnode* template) return data; } +static int +istoplevel(OCnode* node) +{ + if(node == NULL) + return 1; /* base case */ + if(!istoplevel(node->container)) + return 0; + switch (node->octype) { + case OC_Dataset: case OC_Grid: case OC_Atomic: return 1; + case OC_Structure: + return (node->array.rank == 0 ? 1 : 0); /* Toplevel if scalar */ + case OC_Sequence: default: return 0; + } + return 1; +} + + /* XDR representation size depends on if this is scalar or not */ static size_t ocxdrsize(OCtype etype, int isscalar) diff --git a/oc2/ocdebug.c b/oc2/ocdebug.c index aedf3bb59..a22703266 100644 --- a/oc2/ocdebug.c +++ b/oc2/ocdebug.c @@ -24,7 +24,7 @@ octhrow(int err) #endif int -xdrerror(void) +xxdrerror(void) { oclog(OCLOGERR,"xdr failure"); return OCTHROW(OC_EDATADDS); diff --git a/oc2/ocinternal.h b/oc2/ocinternal.h index 2ef74069d..bf1a960a0 100644 --- a/oc2/ocinternal.h +++ b/oc2/ocinternal.h @@ -6,6 +6,11 @@ #include "config.h" + +#if defined(_WIN32) || defined(_WIN64) +#include +#endif + #ifdef _AIX #include #endif @@ -205,5 +210,4 @@ extern int ocinternalinitialize(void); extern OCerror ocsetuseragent(OCstate* state, const char* agent); - #endif /*COMMON_H*/ diff --git a/oc2/oclog.c b/oc2/oclog.c index 5cd4e3f84..7c17ad2e3 100644 --- a/oc2/oclog.c +++ b/oc2/oclog.c @@ -152,7 +152,7 @@ number of arguments and operates like the stdio printf function. \param[in] tag Indicate the kind of this log message. -\param[in] format Format specification as with printf. +\param[in] fmt Format specification as with printf. */ void @@ -186,8 +186,10 @@ oclogtext(int tag, const char* text) /*! Send arbitrarily long text as a logging message. Each line will be sent using oclog with the specified tag. + \param[in] tag Indicate the kind of this log message. \param[in] text Arbitrary text to send as a logging message. +\param[in] count Maximum ength of the text to write. */ void diff --git a/oc2/ocnode.c b/oc2/ocnode.c index 929bd9dc4..11a88cd57 100644 --- a/oc2/ocnode.c +++ b/oc2/ocnode.c @@ -122,7 +122,7 @@ ocnode_new(char* name, OCtype ptype, OCnode* root) return cdf; } -OCattribute* +static OCattribute* makeattribute(char* name, OCtype ptype, OClist* values) { OCattribute* att = (OCattribute*)ocmalloc(sizeof(OCattribute)); /* ocmalloc zeros*/ diff --git a/oc2/ocnode.h b/oc2/ocnode.h index baf45e300..3e22390e0 100644 --- a/oc2/ocnode.h +++ b/oc2/ocnode.h @@ -57,6 +57,7 @@ struct OCnode { OClist* subnodes; /*oclist*/ /*int attributed;*/ /* 1 if merge was done*/ OClist* attributes; /* oclist*/ + OCdata* data; /* Defined only if this node is a top-level atomic variable*/ }; #if SIZEOF_SIZE_T == 4 diff --git a/oc2/ocutil.c b/oc2/ocutil.c index 42854e916..21699a7af 100644 --- a/oc2/ocutil.c +++ b/oc2/ocutil.c @@ -46,6 +46,7 @@ ocstrncmp(const char* s1, const char* s2, size_t len) } +#ifdef EXTERN_UNUSEd void makedimlist(OClist* path, OClist* dims) { @@ -59,6 +60,7 @@ makedimlist(OClist* path, OClist* dims) } } } +#endif void ocfreeprojectionclause(OCprojectionclause* clause) @@ -76,7 +78,8 @@ ocfreeprojectionclause(OCprojectionclause* clause) free(clause); } -static void +#ifdef EXTERN_UNUSED +void freeAttributes(OClist* attset) { unsigned int i,j; @@ -93,7 +96,9 @@ freeAttributes(OClist* attset) } } } +#endif +#ifdef EXTERN_UNUSED void freeOCnode(OCnode* cdf, int deep) { @@ -113,6 +118,7 @@ freeOCnode(OCnode* cdf, int deep) } free(cdf); } +#endif int ocfindbod(OCbytes* buffer, size_t* bodp, size_t* ddslenp) @@ -516,7 +522,7 @@ oc_ispacked(OCnode* node) /* Must be consistent with ocx.h.OCDT */ #define NMODES 6 #define MAXMODENAME 8 /*max (strlen(modestrings[i])) */ -char* modestrings[NMODES+1] = { +static char* modestrings[NMODES+1] = { "FIELD", /* ((OCDT)(1<<0)) field of a container */ "ELEMENT", /* ((OCDT)(1<<1)) element of a structure array */ "RECORD", /* ((OCDT)(1<<2)) record of a sequence */ diff --git a/oc2/ocutil.h b/oc2/ocutil.h index acdc02b21..a8e1f69e6 100644 --- a/oc2/ocutil.h +++ b/oc2/ocutil.h @@ -38,7 +38,6 @@ extern void ocmakedimlist(OClist* path, OClist* dims); extern int ocfindbod(OCbytes* buffer, size_t*, size_t*); /* Reclaimers*/ -extern void freeOCnode(OCnode*,int); extern void ocfreeprojectionclause(OCprojectionclause* clause); /* Misc. */ diff --git a/oc2/xxdr.c b/oc2/xxdr.c index 17ba5c41d..aa26c01ff 100644 --- a/oc2/xxdr.c +++ b/oc2/xxdr.c @@ -240,7 +240,7 @@ xxdr_skip_strings(XXDR* xdrs, off_t n) } unsigned int -xdr_roundup(unsigned int n) +xxdr_roundup(off_t n) { unsigned int rounded; rounded = RNDUP(n);