diff --git a/CMakeLists.txt b/CMakeLists.txt
index 189f6d87c2..a925a88d51 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1160,7 +1160,8 @@ set_std_filter(Szip)
SET(HAVE_SZ ${Szip_FOUND})
set_std_filter(Blosc)
IF(Zstd_FOUND)
-set_std_filter(Zstd)
+ set_std_filter(Zstd)
+ SET(HAVE_ZSTD ON)
ENDIF()
IF(Bz2_FOUND)
set_std_filter(Bz2)
@@ -1168,7 +1169,7 @@ ELSE()
# The reason we use a local version is to support a more comples test case
MESSAGE("libbz2 not found using built-in version")
SET(HAVE_LOCAL_BZ2 ON)
- SET(HAVE_BZ2 ON)
+ SET(HAVE_BZ2 ON CACHE BOOL "")
set(STD_FILTERS "${STD_FILTERS} bz2")
ENDIF()
@@ -1507,6 +1508,7 @@ ENDIF()
# Enable Parallel IO with netCDF-4/HDF5 files using HDF5 parallel I/O.
SET(STATUS_PARALLEL "OFF")
+set(IMPORT_MPI "")
OPTION(ENABLE_PARALLEL4 "Build netCDF-4 with parallel IO" "${HDF5_PARALLEL}")
IF(ENABLE_PARALLEL4 AND ENABLE_HDF5)
IF(NOT HDF5_PARALLEL)
@@ -1528,6 +1530,7 @@ IF(ENABLE_PARALLEL4 AND ENABLE_HDF5)
FILE(COPY "${netCDF_BINARY_DIR}/tmp/run_par_tests.sh"
DESTINATION ${netCDF_BINARY_DIR}/h5_test
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+ set(IMPORT_MPI "include(CMakeFindDependencyMacro)\nfind_dependency(MPI COMPONENTS C)")
ENDIF()
ENDIF()
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 5830a3cbde..5dd9403045 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -8,6 +8,10 @@ This file contains a high-level description of this package's evolution. Release
## 4.9.3 - TBD
* Obviate a number of irrelevant warnings. See [Github #2781](https://github.com/Unidata/netcdf-c/pull/2781).
+* Improve the speed and data quantity for DAP4 queries. See [Github #2765](https://github.com/Unidata/netcdf-c/pull/2765).
+* Remove the use of execinfo to programmatically dump the stack; it never worked. See [Github #2789](https://github.com/Unidata/netcdf-c/pull/2789).
+* Update the internal copy of tinyxml2 to latest code. See [Github #2771](https://github.com/Unidata/netcdf-c/pull/2771).
+* Mitigate the problem of remote/nczarr-related test interference. See [Github #2755](https://github.com/Unidata/netcdf-c/pull/2755).
* Fix DAP2 proxy problems. See [Github #2764](https://github.com/Unidata/netcdf-c/pull/2764).
* Cleanup a number of misc issues. See [Github #2763](https://github.com/Unidata/netcdf-c/pull/2763).
* Mitigate the problem of test interference. See [Github #2755](https://github.com/Unidata/netcdf-c/pull/2755).
diff --git a/cmake/modules/FindBlosc.cmake b/cmake/modules/FindBlosc.cmake
old mode 100755
new mode 100644
diff --git a/cmake/modules/FindZip.cmake b/cmake/modules/FindZip.cmake
old mode 100755
new mode 100644
diff --git a/config.h.cmake.in b/config.h.cmake.in
index 04d876ff17..f10a3a91a5 100644
--- a/config.h.cmake.in
+++ b/config.h.cmake.in
@@ -118,6 +118,12 @@ are set when opening a binary file on Windows. */
/* if true, build byte-range Client */
#cmakedefine ENABLE_BYTERANGE 1
+/* if true, enable ERANGE fill */
+#cmakedefine ENABLE_ERANGE_FILL 1
+#ifdef ENABLE_ERANGE_FILL
+#define ERANGE_FILL 1
+#endif
+
/* if true, use hdf5 S3 virtual file reader */
#cmakedefine ENABLE_HDF5_ROS3 1
@@ -462,9 +468,6 @@ with zip */
/* if true, HDF5 is at least version 1.10.5 and supports UTF8 paths */
#cmakedefine HDF5_UTF8_PATHS 1
-/* if true, backtrace support will be used. */
-#cmakedefine HAVE_EXECINFO_H 1
-
/* if true, include JNA bug fix */
#cmakedefine JNA 1
diff --git a/configure.ac b/configure.ac
index 19386fe141..3c5b7e0a9e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -857,129 +857,136 @@ AC_MSG_RESULT([${have_sz}])
##########
-# See if we have libzip for NCZarr
-AC_SEARCH_LIBS([zip_open],[zip zip.dll cygzip.dll],[have_zip=yes],[have_zip=no])
-AC_MSG_CHECKING([whether libzip library is available])
-AC_MSG_RESULT([${have_zip}])
-enable_nczarr_zip=${have_zip} # alias
+##
+# Check to see if we're using NCZarr. If not, we don't need to check for dependencies and such.
+##
if test "x$enable_nczarr" = xno ; then
enable_nczarr_zip=no
-fi
+else
-AC_MSG_CHECKING([whether nczarr zip support is enabled])
-AC_MSG_RESULT([${enable_nczarr_zip}])
+ # See if we have libzip for NCZarr
+ AC_SEARCH_LIBS([zip_open],[zip zip.dll cygzip.dll],[have_zip=yes],[have_zip=no])
+ AC_MSG_CHECKING([whether libzip library is available])
+ AC_MSG_RESULT([${have_zip}])
+ enable_nczarr_zip=${have_zip} # alias
-if test "x$enable_nczarr_zip" = xyes ; then
-AC_DEFINE([ENABLE_NCZARR_ZIP], [1], [If true, then libzip found])
-fi
-# Check for enabling of S3 support
-AC_MSG_CHECKING([whether netcdf S3 support should be enabled])
-AC_ARG_ENABLE([s3],
- [AS_HELP_STRING([--enable-s3],
- [enable netcdf S3 support])])
-test "x$enable_s3" = xyes || enable_s3=no
-AC_MSG_RESULT($enable_s3)
-if test "x$enable_remote_functionality" = xno ; then
- AC_MSG_WARN([--disable-remote-functionality => --disable-s3])
- enable_s3=no
-fi
-
-# --enable-nczarr-s3 is synonym for --enable-s3 (but...)
-AC_MSG_CHECKING([whether netcdf NCZarr S3 support should be enabled])
-AC_ARG_ENABLE([nczarr-s3],
- [AS_HELP_STRING([--enable-nczarr-s3],
- [(Deprecated) enable netcdf NCZarr S3 support; Deprecated in favor of --enable-s3])])
-AC_MSG_RESULT([$enable_nczarr_s3 (Deprecated) Please use --enable-s3)])
-
-# Set enable_s3 instead of enable_nczarr_s3
-if test "x$enable_s3" = xno && test "x$enable_nczarr_s3" = xyes && test "x$enable_remote_functionality" = xyes; then
-enable_s3=yes # back compatibility
-fi
-unset enable_nczarr_s3
-
-# Note we check for the library after checking for enable_s3
-# because for some reason this fails if we unconditionally test for sdk
-# and it is not available. Fix someday
-S3LIBS=""
-if test "x$enable_s3" = xyes ; then
-# See if we have the s3 aws library
-# Check for the AWS S3 SDK library
- AC_LANG_PUSH([C++])
- AC_CHECK_LIB([aws-c-common], [aws_string_destroy], [enable_s3_aws=yes],[enable_s3_aws=no])
- if test "x$enable_s3_aws" = "xyes" ; then
- S3LIBS="-laws-cpp-sdk-core -laws-cpp-sdk-s3"
+ AC_MSG_CHECKING([whether nczarr zip support is enabled])
+ AC_MSG_RESULT([${enable_nczarr_zip}])
+
+ if test "x$enable_nczarr_zip" = xyes ; then
+ AC_DEFINE([ENABLE_NCZARR_ZIP], [1], [If true, then libzip found])
fi
- AC_LANG_POP
-else
- enable_s3_aws=no
-fi
-AC_MSG_CHECKING([whether AWS S3 SDK library is available])
-AC_MSG_RESULT([$enable_s3_aws])
+ # Check for enabling of S3 support
+ AC_MSG_CHECKING([whether netcdf S3 support should be enabled])
+ AC_ARG_ENABLE([s3],
+ [AS_HELP_STRING([--enable-s3],
+ [enable netcdf S3 support])])
+ test "x$enable_s3" = xyes || enable_s3=no
+ AC_MSG_RESULT($enable_s3)
+
+ if test "x$enable_remote_functionality" = xno ; then
+ AC_MSG_WARN([--disable-remote-functionality => --disable-s3])
+ enable_s3=no
+ fi
-# Check for enabling forced use of Internal S3 library
-AC_MSG_CHECKING([whether internal S3 support should be used])
-AC_ARG_ENABLE([s3-internal],
- [AS_HELP_STRING([--enable-s3-internal],
- [enable internal S3 support])])
-test "x$enable_s3_internal" = xyes || enable_s3_internal=no
-AC_MSG_RESULT($enable_s3_internal)
+ # --enable-nczarr-s3 is synonym for --enable-s3 (but...)
+ AC_MSG_CHECKING([whether netcdf NCZarr S3 support should be enabled])
+ AC_ARG_ENABLE([nczarr-s3],
+ [AS_HELP_STRING([--enable-nczarr-s3],
+ [(Deprecated) enable netcdf NCZarr S3 support; Deprecated in favor of --enable-s3])])
+ AC_MSG_RESULT([$enable_nczarr_s3 (Deprecated) Please use --enable-s3)])
-if test "x$enable_s3_aws" = xno && test "x$enable_s3_internal" = xno ; then
-AC_MSG_WARN([No S3 library available => S3 support disabled])
-enable_s3=no
-fi
+ # Set enable_s3 instead of enable_nczarr_s3
+ if test "x$enable_s3" = xno && test "x$enable_nczarr_s3" = xyes && test "x$enable_remote_functionality" = xyes; then
+ enable_s3=yes # back compatibility
+ fi
+ unset enable_nczarr_s3
+
+ # Note we check for the library after checking for enable_s3
+ # because for some reason this fails if we unconditionally test for sdk
+ # and it is not available. Fix someday
+ S3LIBS=""
+ if test "x$enable_s3" = xyes ; then
+ # See if we have the s3 aws library
+ # Check for the AWS S3 SDK library
+ AC_LANG_PUSH([C++])
+ AC_CHECK_LIB([aws-c-common], [aws_string_destroy], [enable_s3_aws=yes],[enable_s3_aws=no])
+ if test "x$enable_s3_aws" = "xyes" ; then
+ S3LIBS="-laws-cpp-sdk-core -laws-cpp-sdk-s3"
+ fi
+ AC_LANG_POP
+ else
+ enable_s3_aws=no
+ fi
-if test "x$enable_s3_aws" = xyes && test "x$enable_s3_internal" = xyes ; then
-AC_MSG_WARN([Both aws-sdk-cpp and s3-internal enabled => use s3-internal.])
-enable_s3_aws=no
-fi
+ AC_MSG_CHECKING([whether AWS S3 SDK library is available])
+ AC_MSG_RESULT([$enable_s3_aws])
-if test "x$enable_s3_internal" = xyes ; then
-if test "x$ISOSX" != xyes && test "x$ISMINGW" != xyes && test "x$ISMSVC" != xyes ; then
-# Find crypto libraries if using ssl
-AC_CHECK_LIB([ssl],[ssl_create_cipher_list])
-AC_CHECK_LIB([crypto],[SHA256])
-fi
-fi
+ # Check for enabling forced use of Internal S3 library
+ AC_MSG_CHECKING([whether internal S3 support should be used])
+ AC_ARG_ENABLE([s3-internal],
+ [AS_HELP_STRING([--enable-s3-internal],
+ [enable internal S3 support])])
+ test "x$enable_s3_internal" = xyes || enable_s3_internal=no
+ AC_MSG_RESULT($enable_s3_internal)
+
+ if test "x$enable_s3_aws" = xno && test "x$enable_s3_internal" = xno ; then
+ AC_MSG_WARN([No S3 library available => S3 support disabled])
+ enable_s3=no
+ fi
-# Check for enabling S3 testing
-AC_MSG_CHECKING([what level of netcdf S3 testing should be enabled])
-AC_ARG_WITH([s3-testing],
- [AS_HELP_STRING([--with-s3-testing=yes|no|public],
- [control netcdf S3 testing])],
- [], [with_s3_testing=public])
-AC_MSG_RESULT($with_s3_testing)
+ if test "x$enable_s3_aws" = xyes && test "x$enable_s3_internal" = xyes ; then
+ AC_MSG_WARN([Both aws-sdk-cpp and s3-internal enabled => use s3-internal.])
+ enable_s3_aws=no
+ fi
-# Disable S3 tests if S3 support is disabled
-if test "x$enable_s3" = xno ; then
- if test "x$with_s3_testing" != xno ; then
- AC_MSG_WARN([S3 support is disabled => no testing])
- with_s3_testing=no
- fi
-fi
+ if test "x$enable_s3_internal" = xyes ; then
+ if test "x$ISOSX" != xyes && test "x$ISMINGW" != xyes && test "x$ISMSVC" != xyes ; then
+ # Find crypto libraries if using ssl
+ AC_CHECK_LIB([ssl],[ssl_create_cipher_list])
+ AC_CHECK_LIB([crypto],[SHA256])
+ fi
+ fi
-if test "x$enable_s3" = xyes ; then
- AC_DEFINE([ENABLE_S3], [1], [if true, build netcdf-c with S3 support enabled])
-fi
+ # Check for enabling S3 testing
+ AC_MSG_CHECKING([what level of netcdf S3 testing should be enabled])
+ AC_ARG_WITH([s3-testing],
+ [AS_HELP_STRING([--with-s3-testing=yes|no|public],
+ [control netcdf S3 testing])],
+ [], [with_s3_testing=public])
+ AC_MSG_RESULT($with_s3_testing)
+
+ # Disable S3 tests if S3 support is disabled
+ if test "x$enable_s3" = xno ; then
+ if test "x$with_s3_testing" != xno ; then
+ AC_MSG_WARN([S3 support is disabled => no testing])
+ with_s3_testing=no
+ fi
+ fi
-if test "x$enable_s3_aws" = xyes ; then
- LIBS="$LIBS$S3LIBS"
- AC_DEFINE([ENABLE_S3_AWS], [1], [If true, then use aws S3 library])
-fi
+ if test "x$enable_s3" = xyes ; then
+ AC_DEFINE([ENABLE_S3], [1], [if true, build netcdf-c with S3 support enabled])
+ fi
-if test "x$enable_s3_internal" = xyes ; then
- AC_DEFINE([ENABLE_S3_INTERNAL], [1], [If true, then use internal S3 library])
-fi
+ if test "x$enable_s3_aws" = xyes ; then
+ LIBS="$LIBS$S3LIBS"
+ AC_DEFINE([ENABLE_S3_AWS], [1], [If true, then use aws S3 library])
+ fi
-AC_DEFINE_UNQUOTED([WITH_S3_TESTING], [$with_s3_testing], [control S3 testing.])
+ if test "x$enable_s3_internal" = xyes ; then
+ AC_DEFINE([ENABLE_S3_INTERNAL], [1], [If true, then use internal S3 library])
+ fi
+
+ AC_DEFINE_UNQUOTED([WITH_S3_TESTING], [$with_s3_testing], [control S3 testing.])
-if test "x$with_s3_testing" = xyes ; then
- AC_MSG_WARN([*** DO NOT SPECIFY WITH_S3_TESTING=YES UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***])
- AC_DEFINE([ENABLE_S3_TESTALL], [yes], [control S3 testing.])
+ if test "x$with_s3_testing" = xyes ; then
+ AC_MSG_WARN([*** DO NOT SPECIFY WITH_S3_TESTING=YES UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***])
+ AC_DEFINE([ENABLE_S3_TESTALL], [yes], [control S3 testing.])
+ fi
fi
# Check whether we want to enable strict null byte header padding.
@@ -1305,9 +1312,6 @@ AC_CHECK_HEADERS([sys/resource.h])
# See if we have ftw.h to walk directory trees
AC_CHECK_HEADERS([ftw.h])
-# See if we can do stack tracing programmatically
-AC_CHECK_HEADERS([execinfo.h])
-
# Check for these functions...
AC_CHECK_FUNCS([strlcat snprintf strcasecmp fileno \
strdup strtoll strtoull \
diff --git a/dap4_test/test_common.h b/dap4_test/test_common.h
index a005d9c9cd..d7e096e2da 100644
--- a/dap4_test/test_common.h
+++ b/dap4_test/test_common.h
@@ -21,6 +21,7 @@ typedef int TDMR;
static NCbytes* input = NULL;
static NCbytes* output = NULL;
static NCD4meta* metadata = NULL;
+static NCD4response* resp = NULL;
static char* infile = NULL;
static char* outfile = NULL;
static int ncid = 0;
@@ -85,16 +86,21 @@ setup(int tdmr, int argc, char** argv)
if(translatenc4)
controller->controls.translation = NCD4_TRANSNC4;
NCD4_applyclientfragmentcontrols(controller);
- if((metadata=NCD4_newmeta(controller))==NULL)
- fail(NC_ENOMEM);
- metadata->mode = mode;
- NCD4_attachraw(metadata, ncbyteslength(input),ncbytescontents(input));
- if((ret=NCD4_dechunk(metadata))) /* ok for mode == DMR or mode == DAP */
+ if((ret=NCD4_newMeta(controller,&metadata)))
+ fail(ret);
+
+ if((ret=NCD4_newResponse(controller,&resp)))
+ fail(ret);
+ resp->raw.size = ncbyteslength(input);
+ resp->raw.memory = ncbytescontents(input);
+ resp->mode = mode;
+
+ if((ret=NCD4_dechunk(resp))) /* ok for mode == DMR or mode == DAP */
fail(ret);
#ifdef DEBUG
{
- int swap = (metadata->serial.hostbigendian != metadata->serial.remotebigendian);
+ int swap = (controller->platform.hostlittleendian != resp->remotelittleendian);
void* d = metadata->serial.dap;
size_t sz = metadata->serial.dapsize;
fprintf(stderr,"====================\n");
diff --git a/dap4_test/test_meta.c b/dap4_test/test_meta.c
index f0bf2273b4..478fcfb62d 100644
--- a/dap4_test/test_meta.c
+++ b/dap4_test/test_meta.c
@@ -20,7 +20,7 @@ main(int argc, char** argv)
fprintf(stderr,"t_dmrmeta %s -> %s\n",infile,outfile);
#endif
- if((ret = NCD4_parse(metadata))) goto done;
+ if((ret = NCD4_parse(metadata,resp,0))) goto done;
if((ret = NCD4_metabuild(metadata,ncid))) goto done;
done:
diff --git a/dap4_test/test_parse.c b/dap4_test/test_parse.c
index 44075ffaa8..59afb74d5e 100644
--- a/dap4_test/test_parse.c
+++ b/dap4_test/test_parse.c
@@ -17,7 +17,7 @@ main(int argc, char** argv)
setup(TDMR_PARSE,argc,argv);
- if((ret = NCD4_parse(metadata))) goto done;
+ if((ret = NCD4_parse(metadata,resp,0))) goto done;
ret = NCD4_print(metadata,output);
ncbytesnull(output);
if(ret == NC_NOERR) {
diff --git a/docs/mainpage.dox b/docs/mainpage.dox
index 64c2df84ac..0284bd8318 100644
--- a/docs/mainpage.dox
+++ b/docs/mainpage.dox
@@ -13,7 +13,7 @@ The NetCDF homepage may be found at The NetCDF-Fortran Developer's Guide
+- The NetCDF-Fortran Developer's Guide
\section this_release Learn more about the current NetCDF-C Release
diff --git a/docs/testserver.dox b/docs/testserver.dox
old mode 100755
new mode 100644
diff --git a/examples/C/format.c b/examples/C/format.c
index 291aad65b6..40413dbe3f 100644
--- a/examples/C/format.c
+++ b/examples/C/format.c
@@ -45,7 +45,7 @@ main()
/* Create a bunch of phoney data so we have something to write in
the example file. */
for (fp=(float *)temp, i=0; i
#endif
+#ifdef HAVE_SYS_TYPES_H
+#include
+#endif
#ifdef HAVE_SYS_STAT_H
#include
#endif
diff --git a/include/ncs3sdk.h b/include/ncs3sdk.h
index 771faa6666..013710ccfd 100644
--- a/include/ncs3sdk.h
+++ b/include/ncs3sdk.h
@@ -6,6 +6,9 @@
#ifndef NCS3SDK_H
#define NCS3SDK_H 1
+#define AWSHOST ".amazonaws.com"
+#define GOOGLEHOST "storage.googleapis.com"
+
/* Track the server type, if known */
typedef enum NCS3SVC {NCS3UNK=0, /* unknown */
NCS3=1, /* s3.amazon.aws */
diff --git a/include/nctime.h b/include/nctime.h
index bbab97228e..04419efe88 100644
--- a/include/nctime.h
+++ b/include/nctime.h
@@ -150,14 +150,14 @@ typedef struct timeinfo_t {
# define MSC_NCTIME_EXTRA __declspec(dllimport)
# endif
-MSC_NCTIME_EXTRA extern void cdRel2Iso(cdCalenType timetype, char* relunits, int separator, double reltime, char* chartime);
+MSC_NCTIME_EXTRA extern void cdRel2Iso(cdCalenType timetype, char* relunits, int separator, double reltime, char* chartime, size_t chartime_size);
MSC_NCTIME_EXTRA extern void cdChar2Comp(cdCalenType timetype, char* chartime, cdCompTime* comptime);
MSC_NCTIME_EXTRA extern void Cdh2e(CdTime *htime, double *etime);
MSC_NCTIME_EXTRA extern void Cde2h(double etime, CdTimeType timeType, long baseYear, CdTime *htime);
MSC_NCTIME_EXTRA extern int cdParseRelunits(cdCalenType timetype, char* relunits, cdUnitTime* unit, cdCompTime* base_comptime);
MSC_NCTIME_EXTRA extern int cdSetErrOpts(int opts);
#else
-extern void cdRel2Iso(cdCalenType timetype, char* relunits, int separator, double reltime, char* chartime);
+extern void cdRel2Iso(cdCalenType timetype, char* relunits, int separator, double reltime, char* chartime, size_t chartime_size);
extern void cdChar2Comp(cdCalenType timetype, char* chartime, cdCompTime* comptime);
extern void Cdh2e(CdTime *htime, double *etime);
extern void Cde2h(double etime, CdTimeType timeType, long baseYear, CdTime *htime);
diff --git a/include/ncuri.h b/include/ncuri.h
index eafb9be97f..bd1b641012 100644
--- a/include/ncuri.h
+++ b/include/ncuri.h
@@ -35,12 +35,8 @@ typedef struct NCURI {
char* path; /*!< path */
char* query; /*!< query */
char* fragment; /*!< fragment */
- char** fraglist; /* envv style list of decomposed fragment*/
- char** querylist; /* envv style list of decomposed query*/
-#if 0
- char* projection; /*!< without leading '?'*/
- char* selection; /*!< with leading '&'*/
-#endif
+ void* fraglist; /* some representation of the decomposed fragment string */
+ void* querylist; /* some representation of the decomposed query string */
} NCURI;
#if 0
@@ -90,6 +86,18 @@ EXTERNL int ncurisetfragmentkey(NCURI* duri,const char* key, const char* value);
/* append a specific &key=...& in uri fragment */
EXTERNL int ncuriappendfragmentkey(NCURI* duri,const char* key, const char* value);
+/* Replace a specific &key=...& in uri query */
+EXTERNL int ncurisetquerykey(NCURI* duri,const char* key, const char* value);
+
+/* append a specific &key=...& in uri query */
+EXTERNL int ncuriappendquerykey(NCURI* duri,const char* key, const char* value);
+
+/* Get the actual list of queryies */
+EXTERNL void* ncuriqueryparams(NCURI* uri);
+/* Get the actual list of frags */
+EXTERNL void* ncurifragmentparams(NCURI* uri);
+
+
/* Construct a complete NC URI; caller frees returned string */
EXTERNL char* ncuribuild(NCURI*,const char* prefix, const char* suffix, int flags);
@@ -105,12 +113,6 @@ EXTERNL const char* ncurifragmentlookup(NCURI*, const char* param);
*/
EXTERNL const char* ncuriquerylookup(NCURI*, const char* param);
-/* Obtain the complete list of fragment pairs in envv format */
-EXTERNL const char** ncurifragmentparams(NCURI*);
-
-/* Obtain the complete list of query pairs in envv format */
-EXTERNL const char** ncuriqueryparams(NCURI*);
-
/* URL Encode/Decode */
EXTERNL char* ncuridecode(const char* s);
/* Partial decode */
diff --git a/libdap2/dapodom.c b/libdap2/dapodom.c
index 2c6611a98d..c8d4a22396 100644
--- a/libdap2/dapodom.c
+++ b/libdap2/dapodom.c
@@ -81,7 +81,7 @@ dapodom_print(Dapodometer* odom)
if(odom->rank == 0) {
strlcat(line,"[]",sizeof(line));
} else for(i=0;irank;i++) {
- sprintf(tmp,"[%lu/%lu:%lu:%lu]",
+ snprintf(tmp,sizeof(tmp),"[%lu/%lu:%lu:%lu]",
(size_t)odom->index[i],
(size_t)odom->start[i],
(size_t)odom->stride[i],
diff --git a/libdap2/dcetab.c b/libdap2/dcetab.c
index 60a602449d..4b4adf465b 100644
--- a/libdap2/dcetab.c
+++ b/libdap2/dcetab.c
@@ -978,7 +978,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
return 1;
}
- /* Avoid sprintf, as that infringes on the user's name space.
+ /* Avoid snprintf, as that infringes on the user's name space.
Don't have undefined behavior even if the translation
produced a string with the wrong number of "%s"s. */
{
diff --git a/libdap4/d4chunk.c b/libdap4/d4chunk.c
index e95f34b9c9..3f2fe44d7d 100644
--- a/libdap4/d4chunk.c
+++ b/libdap4/d4chunk.c
@@ -22,133 +22,128 @@ and whether it has checksums.
*/
/* Forward */
-static int processerrchunk(NCD4meta* metadata, void* errchunk, unsigned int count);
+static int processerrchunk(NCD4response*, void* errchunk, unsigned int count);
/**************************************************/
-
-void
-NCD4_resetSerial(NCD4serial* serial, size_t rawsize, void* rawdata)
-{
- nullfree(serial->errdata);
- nullfree(serial->dmr);
- nullfree(serial->dap);
- nullfree(serial->rawdata);
- /* clear all fields */
- memset(serial,0,sizeof(NCD4serial));
- /* Reset fields */
- serial->hostlittleendian = NCD4_isLittleEndian();
- serial->rawsize = rawsize;
- serial->rawdata = rawdata;
-}
-
int
-NCD4_dechunk(NCD4meta* metadata)
+NCD4_dechunk(NCD4response* resp)
{
- unsigned char *praw, *phdr, *pdap;
+ unsigned char *praw, *pdmr, *phdr, *pdap, *pappend, *pchunk;
NCD4HDR hdr;
+ int firstchunk;
#ifdef D4DUMPRAW
- NCD4_tagdump(metadata->serial.rawsize,metadata->serial.rawdata,0,"RAW");
+ NCD4_tagdump(resp->serial.raw.size,resp->serial.raw.data,0,"RAW");
#endif
/* Access the returned raw data */
- praw = metadata->serial.rawdata;
+ praw = (unsigned char*)resp->raw.memory;
- if(metadata->mode == NCD4_DSR) {
+ if(resp->mode == NCD4_DSR) {
return THROW(NC_EDMR);
- } else if(metadata->mode == NCD4_DMR) {
+ } else if(resp->mode == NCD4_DMR) {
/* Verify the mode; assume that the is optional */
if(memcmp(praw,"serial.rawsize;
- if((metadata->serial.dmr = malloc(len+1)) == NULL)
+ len = resp->raw.size;
+ if((resp->serial.dmr = malloc(len+1)) == NULL)
return THROW(NC_ENOMEM);
- memcpy(metadata->serial.dmr,praw,len);
- metadata->serial.dmr[len] = '\0';
+ memcpy(resp->serial.dmr,praw,len);
+ resp->serial.dmr[len] = '\0';
/* Suppress nuls */
- (void)NCD4_elidenuls(metadata->serial.dmr,len);
+ (void)NCD4_elidenuls(resp->serial.dmr,len);
return THROW(NC_NOERR);
}
- } else if(metadata->mode != NCD4_DAP)
+ } else if(resp->mode != NCD4_DAP)
return THROW(NC_EDAP);
/* We must be processing a DAP mode packet */
- praw = (metadata->serial.dap = metadata->serial.rawdata);
- metadata->serial.rawdata = NULL;
+ praw = resp->raw.memory;
/* If the raw data looks like xml, then we almost certainly have an error */
if(memcmp(praw,"serial.rawsize, metadata->serial.rawdata);
+ int stat = NCD4_seterrormessage(resp, resp->raw.size, resp->raw.memory);
return THROW(stat); /* slight lie */
}
- /* Get the DMR chunk header*/
- phdr = NCD4_getheader(praw,&hdr,metadata->serial.hostlittleendian);
+ /* Get the first header to get dmr content and endian flags*/
+ pdmr = NCD4_getheader(praw,&hdr,resp->controller->platform.hostlittleendian);
if(hdr.count == 0)
return THROW(NC_EDMR);
- if(hdr.flags & NCD4_ERR_CHUNK) {
- return processerrchunk(metadata, (void*)phdr, hdr.count);
- }
+ if(hdr.flags & NCD4_ERR_CHUNK)
+ return processerrchunk(resp, (void*)pdmr, hdr.count);
+ resp->remotelittleendian = ((hdr.flags & NCD4_LITTLE_ENDIAN_CHUNK) ? 1 : 0);
- metadata->serial.remotelittleendian = ((hdr.flags & NCD4_LITTLE_ENDIAN_CHUNK) ? 1 : 0);
- /* Again, avoid strxxx operations on dmr */
- if((metadata->serial.dmr = malloc(hdr.count+1)) == NULL)
+ /* avoid strxxx operations on dmr */
+ if((resp->serial.dmr = malloc(hdr.count+1)) == NULL)
return THROW(NC_ENOMEM);
- memcpy(metadata->serial.dmr,phdr,hdr.count);
- metadata->serial.dmr[hdr.count-1] = '\0';
+ memcpy(resp->serial.dmr,pdmr,hdr.count);
+ resp->serial.dmr[hdr.count-1] = '\0';
/* Suppress nuls */
- (void)NCD4_elidenuls(metadata->serial.dmr,hdr.count);
+ (void)NCD4_elidenuls(resp->serial.dmr,hdr.count);
+ /* See if there is any data after the DMR */
if(hdr.flags & NCD4_LAST_CHUNK)
return THROW(NC_ENODATA);
/* Read and concat together the data chunks */
- phdr = phdr + hdr.count; /* point to data chunk header */
+ phdr = pdmr + hdr.count; /* point to data chunk header */
/* Do a sanity check in case the server has shorted us with no data */
- if((hdr.count + CHUNKHDRSIZE) >= metadata->serial.rawsize) {
+ if((hdr.count + CHUNKHDRSIZE) >= resp->raw.size) {
/* Server only sent the DMR part */
- metadata->serial.dapsize = 0;
+ resp->serial.dapsize = 0;
return THROW(NC_EDATADDS);
}
- pdap = metadata->serial.dap;
- for(;;) {
- phdr = NCD4_getheader(phdr,&hdr,metadata->serial.hostlittleendian);
- if(hdr.flags & NCD4_ERR_CHUNK) {
- return processerrchunk(metadata, (void*)phdr, hdr.count);
+ /* walk all the data chunks */
+ /* invariants:
+ praw -- beginning of the raw response
+ pdmr -- beginning of the dmr in the raw data
+ pdap -- beginning of the dechunked dap data
+ phdr -- pointer to the hdr of the current chunk
+ pchunk -- pointer to the data part of the current chunk
+ pappend -- where to append next chunk to the growing dechunked data
+ */
+ for(firstchunk=1;;firstchunk=0) {
+ pchunk = NCD4_getheader(phdr,&hdr,resp->controller->platform.hostlittleendian); /* Process first data chunk header */
+ if(firstchunk) {
+ pdap = phdr; /* remember start point of the dechunked data */
+ pappend = phdr; /* start appending here */
}
+ if(hdr.flags & NCD4_ERR_CHUNK)
+ return processerrchunk(resp, (void*)pchunk, hdr.count);
/* data chunk; possibly last; possibly empty */
- if(hdr.count > 0) {
- d4memmove(pdap,phdr,hdr.count); /* will overwrite the header */
- phdr += hdr.count;
- pdap += hdr.count;
- }
+ if(hdr.count > 0)
+ d4memmove(pappend,pchunk,hdr.count); /* overwrite the header; this the heart of dechunking */
+ pappend += hdr.count; /* next append point */
+ phdr = pchunk + hdr.count; /* point to header of next chunk */
if(hdr.flags & NCD4_LAST_CHUNK) break;
}
- metadata->serial.dapsize = (size_t)DELTA(pdap,metadata->serial.dap);
+ resp->serial.dap = pdap; /* start of dechunked data */
+ resp->serial.dapsize = (size_t)DELTA(pappend,pdap);
#ifdef D4DUMPDMR
- fprintf(stderr,"%s\n",metadata->serial.dmr);
+ fprintf(stderr,"%s\n",resp->serial.dmr);
fflush(stderr);
#endif
#ifdef D4DUMPDAP
- NCD4_tagdump(metadata->serial.dapsize,metadata->serial.dap,0,"DAP");
+ NCD4_tagdump(resp->serial.dapsize,resp->serial.dap,0,"DAP");
#endif
return THROW(NC_NOERR);
}
static int
-processerrchunk(NCD4meta* metadata, void* errchunk, unsigned int count)
+processerrchunk(NCD4response* resp, void* errchunk, unsigned int count)
{
- metadata->serial.errdata = (char*)d4alloc(count+1);
- if(metadata->serial.errdata == NULL)
+ resp->serial.errdata = (char*)d4alloc(count+1);
+ if(resp->serial.errdata == NULL)
return THROW(NC_ENOMEM);
- memcpy(metadata->serial.errdata,errchunk,count);
- metadata->serial.errdata[count] = '\0';
+ memcpy(resp->serial.errdata,errchunk,count);
+ resp->serial.errdata[count] = '\0';
return THROW(NC_ENODATA); /* slight lie */
}
@@ -157,26 +152,26 @@ Given a raw response, attempt to infer the mode: DMR, DAP, DSR.
Since DSR is not standardizes, it becomes the default.
*/
int
-NCD4_infermode(NCD4meta* meta)
+NCD4_infermode(NCD4response* resp)
{
- d4size_t size = meta->serial.rawsize;
- char* raw = meta->serial.rawdata;
+ d4size_t size = resp->raw.size;
+ char* raw = resp->raw.memory;
if(size < 16)
return THROW(NC_EDAP); /* must have at least this to hold a hdr + partial dmr*/
if(memcmp(raw,"mode = NCD4_DMR;
+ resp->mode = NCD4_DMR;
goto done;
}
raw += 4; /* Pretend we have a DAP hdr */
if(memcmp(raw,"mode = NCD4_DAP;
+ resp->mode = NCD4_DAP;
goto done;
}
/* Default to DSR */
- meta->mode = NCD4_DSR;
+ resp->mode = NCD4_DSR;
done:
return NC_NOERR;
diff --git a/libdap4/d4curlfunctions.c b/libdap4/d4curlfunctions.c
index ee06e4cacd..b1f949b9f4 100644
--- a/libdap4/d4curlfunctions.c
+++ b/libdap4/d4curlfunctions.c
@@ -340,7 +340,7 @@ NCD4_get_rcproperties(NCD4INFO* state)
ncerror err = NC_NOERR;
char* option = NULL;
#ifdef HAVE_CURLOPT_BUFFERSIZE
- option = NC_rclookup(D4BUFFERSIZE,state->uri->uri,NULL);
+ option = NC_rclookup(D4BUFFERSIZE,state->dmruri->uri,NULL);
if(option != NULL && strlen(option) != 0) {
long bufsize;
if(strcasecmp(option,"max")==0)
@@ -351,7 +351,7 @@ NCD4_get_rcproperties(NCD4INFO* state)
}
#endif
#ifdef HAVE_CURLOPT_KEEPALIVE
- option = NC_rclookup(D4KEEPALIVE,state->uri->uri,NULL);
+ option = NC_rclookup(D4KEEPALIVE,state->dmruri->uri,NULL);
if(option != NULL && strlen(option) != 0) {
/* The keepalive value is of the form 0 or n/m,
where n is the idle time and m is the interval time;
diff --git a/libdap4/d4data.c b/libdap4/d4data.c
index 5d61b81dc4..eae5f32ed8 100644
--- a/libdap4/d4data.c
+++ b/libdap4/d4data.c
@@ -16,7 +16,7 @@ This code serves two purposes
(NCD4_processdata)
2. Walk a specified variable instance to convert to netcdf4
memory representation.
- (NCD4_fillinstance)
+ (NCD4_movetoinstance)
*/
@@ -29,7 +29,6 @@ static int fillopfixed(NCD4meta*, d4size_t opaquesize, NCD4offset* offset, void*
static int fillopvar(NCD4meta*, NCD4node* type, NCD4offset* offset, void** dstp, NClist* blobs);
static int fillstruct(NCD4meta*, NCD4node* type, NCD4offset* offset, void** dstp, NClist* blobs);
static int fillseq(NCD4meta*, NCD4node* type, NCD4offset* offset, void** dstp, NClist* blobs);
-static int NCD4_inferChecksums(NCD4meta* meta, NClist* toplevel);
static unsigned NCD4_computeChecksum(NCD4meta* meta, NCD4node* topvar);
/***************************************************/
@@ -54,8 +53,9 @@ static unsigned int debugcrc32(unsigned int crc, const void *buf, size_t size)
/***************************************************/
/* API */
+/* Parcel out the dechunked data to the corresponding vars */
int
-NCD4_processdata(NCD4meta* meta)
+NCD4_parcelvars(NCD4meta* meta, NCD4response* resp)
{
int ret = NC_NOERR;
int i;
@@ -68,35 +68,57 @@ NCD4_processdata(NCD4meta* meta)
toplevel = nclistnew();
NCD4_getToplevelVars(meta,root,toplevel);
- /* Otherwise */
- NCD4_inferChecksums(meta,toplevel);
+ /* Compute the offset and size of the toplevel vars in the raw dap data. */
+ offset = BUILDOFFSET(resp->serial.dap,resp->serial.dapsize);
+ for(i=0;iinferredchecksumming))) {
+ FAIL(ret,"delimit failure");
+ }
+ var->data.response = resp; /* cross link */
+ }
+done:
+ nclistfree(toplevel);
+ nullfree(offset);
+ return THROW(ret);
+}
+
+/* Process top level vars wrt checksums and swapping */
+int
+NCD4_processdata(NCD4meta* meta, NCD4response* resp)
+{
+ int ret = NC_NOERR;
+ int i;
+ NClist* toplevel = NULL;
+ NCD4node* root = meta->root;
+ NCD4offset* offset = NULL;
- /* If necessary, byte swap the serialized data */
/* Do we need to swap the dap4 data? */
- meta->swap = (meta->serial.hostlittleendian != meta->serial.remotelittleendian);
+ meta->swap = (meta->controller->platform.hostlittleendian != resp->remotelittleendian);
- /* Compute the offset and size of the toplevel vars in the raw dap data. */
- /* Also extract remote checksums */
- offset = BUILDOFFSET(meta->serial.dap,meta->serial.dapsize);
+ /* Recursively walk the tree in prefix order
+ to get the top-level variables; also mark as unvisited */
+ toplevel = nclistnew();
+ NCD4_getToplevelVars(meta,root,toplevel);
+
+ /* Extract remote checksums */
for(i=0;icontroller->data.inferredchecksumming) {
- /* Compute remote checksum: must occur before any byte swapping */
+ if(resp->inferredchecksumming) {
+ /* Compute checksum of response data: must occur before any byte swapping and after delimiting */
var->data.localchecksum = NCD4_computeChecksum(meta,var);
#ifdef DUMPCHECKSUM
fprintf(stderr,"var %s: remote-checksum = 0x%x\n",var->name,var->data.remotechecksum);
#endif
/* verify checksums */
- if(!meta->controller->data.checksumignore) {
+ if(!resp->checksumignore) {
if(var->data.localchecksum != var->data.remotechecksum) {
nclog(NCLOGERR,"Checksum mismatch: %s\n",var->name);
ret = NC_EDAP;
goto done;
}
/* Also verify checksum attribute */
- if(meta->controller->data.attrchecksumming) {
+ if(resp->attrchecksumming) {
if(var->data.attrchecksum != var->data.remotechecksum) {
nclog(NCLOGERR,"Attribute Checksum mismatch: %s\n",var->name);
ret = NC_EDAP;
@@ -105,13 +127,11 @@ NCD4_processdata(NCD4meta* meta)
}
}
}
- }
-
- /* Swap the data for each top level variable,
- */
- if(meta->swap) {
- if((ret=NCD4_swapdata(meta,toplevel)))
- FAIL(ret,"byte swapping failed");
+ if(meta->swap) {
+ if((ret=NCD4_swapdata(resp,var,meta->swap)))
+ FAIL(ret,"byte swapping failed");
+ }
+ var->data.valid = 1; /* Everything should be in place */
}
done:
@@ -133,7 +153,7 @@ Assumes that NCD4_processdata has been called.
*/
int
-NCD4_fillinstance(NCD4meta* meta, NCD4node* type, NCD4offset* offset, void** dstp, NClist* blobs)
+NCD4_movetoinstance(NCD4meta* meta, NCD4node* type, NCD4offset* offset, void** dstp, NClist* blobs)
{
int ret = NC_NOERR;
void* dst = *dstp;
@@ -149,30 +169,30 @@ NCD4_fillinstance(NCD4meta* meta, NCD4node* type, NCD4offset* offset, void** dst
} else switch(type->subsort) {
case NC_STRING: /* oob strings */
if((ret=fillstring(meta,offset,&dst,blobs)))
- FAIL(ret,"fillinstance");
+ FAIL(ret,"movetoinstance");
break;
case NC_OPAQUE:
if(type->opaque.size > 0) {
/* We know the size and its the same for all instances */
if((ret=fillopfixed(meta,type->opaque.size,offset,&dst)))
- FAIL(ret,"fillinstance");
+ FAIL(ret,"movetoinstance");
} else {
/* Size differs per instance, so we need to convert each opaque to a vlen */
if((ret=fillopvar(meta,type,offset,&dst,blobs)))
- FAIL(ret,"fillinstance");
+ FAIL(ret,"movetoinstance");
}
break;
case NC_STRUCT:
if((ret=fillstruct(meta,type,offset,&dst,blobs)))
- FAIL(ret,"fillinstance");
+ FAIL(ret,"movetoinstance");
break;
case NC_SEQ:
if((ret=fillseq(meta,type,offset,&dst,blobs)))
- FAIL(ret,"fillinstance");
+ FAIL(ret,"movetoinstance");
break;
default:
ret = NC_EINVAL;
- FAIL(ret,"fillinstance");
+ FAIL(ret,"movetoinstance");
}
*dstp = dst;
@@ -196,7 +216,7 @@ fillstruct(NCD4meta* meta, NCD4node* type, NCD4offset* offset, void** dstp, NCli
NCD4node* field = nclistget(type->vars,i);
NCD4node* ftype = field->basetype;
void* fdst = (((char*)dst) + field->meta.offset);
- if((ret=NCD4_fillinstance(meta,ftype,offset,&fdst,blobs)))
+ if((ret=NCD4_movetoinstance(meta,ftype,offset,&fdst,blobs)))
FAIL(ret,"fillstruct");
}
dst = ((char*)dst) + type->meta.memsize;
@@ -231,7 +251,7 @@ fillseq(NCD4meta* meta, NCD4node* type, NCD4offset* offset, void** dstp, NClist*
for(i=0;ip))+(recordsize * i);
- if((ret=NCD4_fillinstance(meta,vlentype,offset,&recdst,blobs)))
+ if((ret=NCD4_movetoinstance(meta,vlentype,offset,&recdst,blobs)))
FAIL(ret,"fillseq");
}
dst++;
@@ -373,12 +393,16 @@ fprintf(stderr,"toplevel: var=%s\n",node->name);
return THROW(ret);
}
-static int
-NCD4_inferChecksums(NCD4meta* meta, NClist* toplevel)
+int
+NCD4_inferChecksums(NCD4meta* meta, NCD4response* resp)
{
int ret = NC_NOERR;
int i, attrfound;
- NCD4INFO* info = meta->controller;
+ NClist* toplevel = NULL;
+
+ /* Get the toplevel vars */
+ toplevel = nclistnew();
+ NCD4_getToplevelVars(meta,meta->root,toplevel);
/* First, look thru the DMR to see if there is a checksum attribute */
attrfound = 0;
@@ -399,9 +423,10 @@ NCD4_inferChecksums(NCD4meta* meta, NClist* toplevel)
}
}
}
- info->data.attrchecksumming = (attrfound ? 1 : 0);
+ nclistfree(toplevel);
+ resp->attrchecksumming = (attrfound ? 1 : 0);
/* Infer checksums */
- info->data.inferredchecksumming = ((info->data.attrchecksumming || info->data.querychecksumming) ? 1 : 0);
+ resp->inferredchecksumming = ((resp->attrchecksumming || resp->querychecksumming) ? 1 : 0);
return THROW(ret);
}
diff --git a/libdap4/d4debug.c b/libdap4/d4debug.c
index d2d40b44a6..caed80027a 100644
--- a/libdap4/d4debug.c
+++ b/libdap4/d4debug.c
@@ -97,7 +97,7 @@ int
NCD4_debugcopy(NCD4INFO* info)
{
int i,ret=NC_NOERR;
- NCD4meta* meta = info->substrate.metadata;
+ NCD4meta* meta = info->dmrmetadata;
NClist* topvars = nclistnew();
NC* ncp = info->controller;
void* memory = NULL;
diff --git a/libdap4/d4file.c b/libdap4/d4file.c
index aeccc7423f..46c1a0fdbb 100644
--- a/libdap4/d4file.c
+++ b/libdap4/d4file.c
@@ -6,7 +6,6 @@
#include "ncdispatch.h"
#include "ncd4dispatch.h"
#include "d4includes.h"
-#include "d4read.h"
#include "d4curlfunctions.h"
#ifdef _MSC_VER
@@ -23,19 +22,20 @@
static int constrainable(NCURI*);
static void freeCurl(NCD4curl*);
-static void freeInfo(NCD4INFO*);
static int fragmentcheck(NCD4INFO*, const char* key, const char* subkey);
static const char* getfragment(NCD4INFO* info, const char* key);
static const char* getquery(NCD4INFO* info, const char* key);
static int set_curl_properties(NCD4INFO*);
static int makesubstrate(NCD4INFO* d4info);
-static void resetInfoforRead(NCD4INFO* d4info);
/**************************************************/
/* Constants */
static const char* checkseps = "+,:;";
+/*Define the set of protocols known to be constrainable */
+static const char* constrainableprotocols[] = {"http", "https",NULL};
+
/**************************************************/
int
NCD4_open(const char * path, int mode,
@@ -46,10 +46,10 @@ NCD4_open(const char * path, int mode,
NCD4INFO* d4info = NULL;
const char* value;
NC* nc;
- NCD4meta* meta = NULL;
size_t len = 0;
void* contents = NULL;
-
+ NCD4response* dmrresp = NULL;
+
if(path == NULL)
return THROW(NC_EDAPURL);
@@ -61,29 +61,27 @@ NCD4_open(const char * path, int mode,
/* Setup our NC and NCDAPCOMMON state*/
- d4info = (NCD4INFO*)calloc(1,sizeof(NCD4INFO));
- if(d4info == NULL) {ret = NC_ENOMEM; goto done;}
-
+ if((ret=NCD4_newInfo(&d4info))) goto done;
nc->dispatchdata = d4info;
nc->int_ncid = nc__pseudofd(); /* create a unique id */
d4info->controller = (NC*)nc;
/* Parse url and params */
- if(ncuriparse(nc->path,&d4info->uri))
+ if(ncuriparse(nc->path,&d4info->dmruri))
{ret = NC_EDAPURL; goto done;}
/* Load auth info from rc file */
- if((ret = NC_authsetup(&d4info->auth, d4info->uri)))
+ if((ret = NC_authsetup(&d4info->auth, d4info->dmruri)))
goto done;
NCD4_curl_protocols(d4info);
- if(!constrainable(d4info->uri))
+ if(!constrainable(d4info->dmruri))
SETFLAG(d4info->controls.flags,NCF_UNCONSTRAINABLE);
/* fail if we are unconstrainable but have constraints */
if(FLAGSET(d4info->controls.flags,NCF_UNCONSTRAINABLE)) {
- if(d4info->uri != NULL) {
- const char* ce = ncuriquerylookup(d4info->uri,DAP4CE); /* Look for dap4.ce */
+ if(d4info->dmruri != NULL) {
+ const char* ce = ncuriquerylookup(d4info->dmruri,DAP4CE); /* Look for dap4.ce */
if(ce != NULL) {
nclog(NCLOGWARN,"Attempt to constrain an unconstrainable data source: %s=%s",
DAP4CE,ce);
@@ -115,7 +113,7 @@ NCD4_open(const char * path, int mode,
}
/* Turn on logging; only do this after oc_open*/
- if((value = ncurifragmentlookup(d4info->uri,"log")) != NULL) {
+ if((value = ncurifragmentlookup(d4info->dmruri,"log")) != NULL) {
ncloginit();
ncsetloglevel(NCLOGNOTE);
}
@@ -150,30 +148,34 @@ NCD4_open(const char * path, int mode,
/* Reset the substrate */
if((ret=makesubstrate(d4info))) goto done;
- /* Always start by reading the DMR only */
+ /* Always start by reading the whole DMR only */
/* reclaim substrate.metadata */
- resetInfoforRead(d4info);
+ NCD4_resetInfoForRead(d4info);
/* Rebuild metadata */
- if((d4info->substrate.metadata=NCD4_newmeta(d4info))==NULL)
- {ret = NC_ENOMEM; goto done;}
+ if((ret = NCD4_newMeta(d4info,&d4info->dmrmetadata))) goto done;
+
+ /* Capture response */
+ if((dmrresp = (NCD4response*)calloc(1,sizeof(NCD4response)))==NULL)
+ {ret = NC_ENOMEM; goto done;}
+ dmrresp->controller = d4info;
- if((ret=NCD4_readDMR(d4info, d4info->controls.flags.flags))) goto done;
+ if((ret=NCD4_readDMR(d4info, d4info->controls.flags.flags, d4info->dmruri, dmrresp))) goto done;
/* set serial.rawdata */
len = ncbyteslength(d4info->curl->packet);
contents = ncbytesextract(d4info->curl->packet);
- NCD4_attachraw(d4info->substrate.metadata, len, contents);
-
- /* process query parameters */
- NCD4_applyclientquerycontrols(d4info);
+ assert(dmrresp != NULL);
+ dmrresp->raw.size = len;
+ dmrresp->raw.memory = contents;
- meta = d4info->substrate.metadata;
+ /* process checksum parameters */
+ NCD4_applychecksumcontrols(d4info,dmrresp);
/* Infer the mode */
- if((ret=NCD4_infermode(meta))) goto done;
+ if((ret=NCD4_infermode(dmrresp))) goto done;
/* Process the dmr part */
- if((ret=NCD4_dechunk(meta))) goto done;
+ if((ret=NCD4_dechunk(dmrresp))) goto done;
#ifdef D4DUMPDMR
{
@@ -184,13 +186,14 @@ NCD4_open(const char * path, int mode,
}
#endif
- if((ret = NCD4_parse(d4info->substrate.metadata))) goto done;
+ if((ret = NCD4_parse(d4info->dmrmetadata,dmrresp,0))) goto done;
#ifdef D4DEBUGMETA
{
+ meta = d4info->dmrmetadata;
fprintf(stderr,"\n/////////////\n");
NCbytes* buf = ncbytesnew();
- NCD4_print(d4info->substrate.metadata,buf);
+ NCD4_print(meta,buf);
ncbytesnull(buf);
fputs(ncbytescontents(buf),stderr);
ncbytesfree(buf);
@@ -200,12 +203,20 @@ NCD4_open(const char * path, int mode,
#endif
/* Build the substrate metadata */
- ret = NCD4_metabuild(d4info->substrate.metadata,d4info->substrate.metadata->ncid);
+ ret = NCD4_metabuild(d4info->dmrmetadata,d4info->dmrmetadata->ncid);
if(ret != NC_NOERR && ret != NC_EVARSIZE) goto done;
+ /* Remember the response */
+ nclistpush(d4info->responses,dmrresp);
+
+ /* Avoid duplicate reclaims */
+ dmrresp = NULL;
+ d4info = NULL;
+
done:
+ NCD4_reclaimResponse(dmrresp);
+ NCD4_reclaimInfo(d4info);
if(ret) {
- freeInfo(d4info);
nc->dispatchdata = NULL;
}
return THROW(ret);
@@ -236,7 +247,7 @@ NCD4_close(int ncid, void* ignore)
ret = nc_abort(substrateid);
}
- freeInfo(d4info);
+ NCD4_reclaimInfo(d4info);
done:
return THROW(ret);
@@ -248,82 +259,6 @@ NCD4_abort(int ncid)
return NCD4_close(ncid,NULL);
}
-/**************************************************/
-
-/* Reclaim an NCD4INFO instance */
-static void
-freeInfo(NCD4INFO* d4info)
-{
- if(d4info == NULL) return;
- d4info->controller = NULL; /* break link */
- nullfree(d4info->rawurltext);
- nullfree(d4info->urltext);
- ncurifree(d4info->uri);
- freeCurl(d4info->curl);
- nullfree(d4info->data.memory);
- nullfree(d4info->data.ondiskfilename);
- if(d4info->data.ondiskfile != NULL)
- fclose(d4info->data.ondiskfile);
- nullfree(d4info->fileproto.filename);
- if(d4info->substrate.realfile
- && !FLAGSET(d4info->controls.debugflags,NCF_DEBUG_COPY)) {
- /* We used real file, so we need to delete the temp file
- unless we are debugging.
- Assume caller has done nc_close|nc_abort on the ncid.
- Note that in theory, this should not be necessary since
- AFAIK the substrate file is still in def mode, and
- when aborted, it should be deleted. But that is not working
- for some reason, so we delete it ourselves.
- */
- if(d4info->substrate.filename != NULL) {
- unlink(d4info->substrate.filename);
- }
- }
- nullfree(d4info->substrate.filename); /* always reclaim */
- NCD4_reclaimMeta(d4info->substrate.metadata);
- NC_authfree(d4info->auth);
- nclistfree(d4info->blobs);
- free(d4info);
-}
-
-/* Reset NCD4INFO instance for new read request */
-static void
-resetInfoforRead(NCD4INFO* d4info)
-{
- if(d4info == NULL) return;
- if(d4info->substrate.realfile
- && !FLAGSET(d4info->controls.debugflags,NCF_DEBUG_COPY)) {
- /* We used real file, so we need to delete the temp file
- unless we are debugging.
- Assume caller has done nc_close|nc_abort on the ncid.
- Note that in theory, this should not be necessary since
- AFAIK the substrate file is still in def mode, and
- when aborted, it should be deleted. But that is not working
- for some reason, so we delete it ourselves.
- */
- if(d4info->substrate.filename != NULL) {
- unlink(d4info->substrate.filename);
- }
- }
- NCD4_resetMeta(d4info->substrate.metadata);
- nullfree(d4info->substrate.metadata);
- d4info->substrate.metadata = NULL;
-}
-
-static void
-freeCurl(NCD4curl* curl)
-{
- if(curl == NULL) return;
- NCD4_curlclose(curl->curl);
- ncbytesfree(curl->packet);
- nullfree(curl->errdata.code);
- nullfree(curl->errdata.message);
- free(curl);
-}
-
-/* Define the set of protocols known to be constrainable */
-static const char* constrainableprotocols[] = {"http", "https",NULL};
-
static int
constrainable(NCURI* durl)
{
@@ -449,11 +384,6 @@ NCD4_applyclientfragmentcontrols(NCD4INFO* info)
if(value != NULL)
strncpy(info->controls.substratename,value,(NC_MAX_NAME-1));
- value = getfragment(info,"hyrax");
- if(value != NULL) {
- info->data.checksumignore = 1; /* Assume checksum, but ignore */
- }
-
info->controls.opaquesize = DFALTOPAQUESIZE;
value = getfragment(info,"opaquesize");
if(value != NULL) {
@@ -476,22 +406,29 @@ NCD4_applyclientfragmentcontrols(NCD4INFO* info)
}
}
+/* Checksum controls are found both in the query and fragment
+ parts of a URL.
+*/
void
-NCD4_applyclientquerycontrols(NCD4INFO* info)
+NCD4_applychecksumcontrols(NCD4INFO* info, NCD4response* resp)
{
const char* value = getquery(info,DAP4CSUM);
if(value == NULL) {
- info->data.querychecksumming = DEFAULT_CHECKSUM_STATE;
+ resp->querychecksumming = DEFAULT_CHECKSUM_STATE;
} else {
if(strcasecmp(value,"false")==0) {
- info->data.querychecksumming = 0;
+ resp->querychecksumming = 0;
} else if(strcasecmp(value,"true")==0) {
- info->data.querychecksumming = 1;
+ resp->querychecksumming = 1;
} else {
nclog(NCLOGWARN,"Unknown checksum mode: %s ; using default",value);
- info->data.querychecksumming = DEFAULT_CHECKSUM_STATE;
+ resp->querychecksumming = DEFAULT_CHECKSUM_STATE;
}
}
+ value = getfragment(info,"hyrax");
+ if(value != NULL) {
+ resp->checksumignore = 1; /* Assume checksum, but ignore */
+ }
}
/* Search for substring in value of param. If substring == NULL; then just
@@ -523,7 +460,7 @@ getfragment(NCD4INFO* info, const char* key)
const char* value;
if(info == NULL || key == NULL) return NULL;
- if((value=ncurifragmentlookup(info->uri,key)) == NULL)
+ if((value=ncurifragmentlookup(info->dmruri,key)) == NULL)
return NULL;
return value;
}
@@ -537,7 +474,7 @@ getquery(NCD4INFO* info, const char* key)
const char* value;
if(info == NULL || key == NULL) return NULL;
- if((value=ncuriquerylookup(info->uri,key)) == NULL)
+ if((value=ncuriquerylookup(info->dmruri,key)) == NULL)
return NULL;
return value;
}
@@ -596,3 +533,175 @@ NCD4_get_substrate(NC* nc)
} else subnc = nc;
return subnc;
}
+
+/**************************************************/
+/* Allocate/Free for various structures */
+
+int
+NCD4_newInfo(NCD4INFO** d4infop)
+{
+ int ret = NC_NOERR;
+ NCD4INFO* info = NULL;
+ if((info = calloc(1,sizeof(NCD4INFO)))==NULL)
+ {ret = NC_ENOMEM; goto done;}
+ info->platform.hostlittleendian = NCD4_isLittleEndian();
+ info->responses = nclistnew();
+ if(d4infop) {*d4infop = info; info = NULL;}
+done:
+ if(info) NCD4_reclaimInfo(info);
+ return THROW(ret);
+}
+
+/* Reclaim an NCD4INFO instance */
+void
+NCD4_reclaimInfo(NCD4INFO* d4info)
+{
+ size_t i;
+ if(d4info == NULL) return;
+ d4info->controller = NULL; /* break link */
+ nullfree(d4info->rawdmrurltext);
+ nullfree(d4info->dmrurltext);
+ ncurifree(d4info->dmruri);
+ freeCurl(d4info->curl);
+ nullfree(d4info->fileproto.filename);
+ NCD4_resetInfoForRead(d4info);
+ nullfree(d4info->substrate.filename); /* always reclaim */
+ NC_authfree(d4info->auth);
+ nclistfree(d4info->blobs);
+ /* Reclaim dmr node tree */
+ NCD4_reclaimMeta(d4info->dmrmetadata);
+ /* Reclaim all responses */
+ for(i=0;iresponses);i++) {
+ NCD4response* resp = nclistget(d4info->responses,i);
+ NCD4_reclaimResponse(resp);
+ }
+ nclistfree(d4info->responses);
+ free(d4info);
+}
+
+/* Reset NCD4INFO instance for new read request */
+void
+NCD4_resetInfoForRead(NCD4INFO* d4info)
+{
+ if(d4info == NULL) return;
+ if(d4info->substrate.realfile
+ && !FLAGSET(d4info->controls.debugflags,NCF_DEBUG_COPY)) {
+ /* We used real file, so we need to delete the temp file
+ unless we are debugging.
+ Assume caller has done nc_close|nc_abort on the ncid.
+ Note that in theory, this should not be necessary since
+ AFAIK the substrate file is still in def mode, and
+ when aborted, it should be deleted. But that is not working
+ for some reason, so we delete it ourselves.
+ */
+ if(d4info->substrate.filename != NULL) {
+ unlink(d4info->substrate.filename);
+ }
+ }
+ NCD4_reclaimMeta(d4info->dmrmetadata);
+ d4info->dmrmetadata = NULL;
+}
+
+static void
+freeCurl(NCD4curl* curl)
+{
+ if(curl == NULL) return;
+ NCD4_curlclose(curl->curl);
+ ncbytesfree(curl->packet);
+ nullfree(curl->errdata.code);
+ nullfree(curl->errdata.message);
+ free(curl);
+}
+
+int
+NCD4_newResponse(NCD4INFO* info, NCD4response** respp)
+{
+ int ret = NC_NOERR;
+ NCD4response* resp = NULL;
+ NC_UNUSED(info);
+ if((resp = calloc(1,sizeof(NCD4response)))==NULL)
+ {ret = NC_ENOMEM; goto done;}
+ resp->controller = info;
+ if(respp) {*respp = resp; resp = NULL;}
+done:
+ if(resp) NCD4_reclaimResponse(resp);
+ return THROW(ret);
+}
+
+
+/* Reclaim an NCD4response instance */
+void
+NCD4_reclaimResponse(NCD4response* d4resp)
+{
+ struct NCD4serial* serial = NULL;
+ if(d4resp == NULL) return;
+ serial = &d4resp->serial;
+ d4resp->controller = NULL; /* break link */
+
+ nullfree(d4resp->raw.memory);
+ nullfree(serial->dmr);
+ nullfree(serial->errdata);
+
+ /* clear all fields */
+ memset(serial,0,sizeof(struct NCD4serial));
+
+ nullfree(d4resp->error.parseerror);
+ nullfree(d4resp->error.message);
+ nullfree(d4resp->error.context);
+ nullfree(d4resp->error.otherinfo);
+ memset(&d4resp->error,0,sizeof(d4resp->error));
+
+ free(d4resp);
+}
+
+/* Create an empty NCD4meta object for
+ use in subsequent calls
+ (is the the right src file to hold this?)
+*/
+
+int
+NCD4_newMeta(NCD4INFO* info, NCD4meta** metap)
+{
+ int ret = NC_NOERR;
+ NCD4meta* meta = (NCD4meta*)calloc(1,sizeof(NCD4meta));
+ if(meta == NULL) return NC_ENOMEM;
+ meta->allnodes = nclistnew();
+#ifdef D4DEBUG
+ meta->debuglevel = 1;
+#endif
+ meta->controller = info;
+ meta->ncid = info->substrate.nc4id; /* Transfer netcdf ncid */
+ if(metap) {*metap = meta; meta = NULL;}
+ return THROW(ret);
+}
+
+void
+NCD4_reclaimMeta(NCD4meta* dataset)
+{
+ int i;
+ if(dataset == NULL) return;
+
+ for(i=0;iallnodes);i++) {
+ NCD4node* node = (NCD4node*)nclistget(dataset->allnodes,i);
+ reclaimNode(node);
+ }
+ nclistfree(dataset->allnodes);
+ nclistfree(dataset->groupbyid);
+ nclistfree(dataset->atomictypes);
+ free(dataset);
+}
+
+#if 0
+void
+NCD4_resetMeta(NCD4meta* dataset)
+{
+ if(dataset == NULL) return;
+#if 0
+ for(i=0;iblobs);i++) {
+ void* p = nclistget(dataset->blobs,i);
+ nullfree(p);
+ }
+ nclistfree(dataset->blobs);
+#endif
+}
+#endif
diff --git a/libdap4/d4fix.c b/libdap4/d4fix.c
index 82049dd90f..b76a52d28b 100644
--- a/libdap4/d4fix.c
+++ b/libdap4/d4fix.c
@@ -190,7 +190,7 @@ walk(NCD4node* node, NClist* sorted)
*/
int
-NCD4_delimit(NCD4meta* compiler, NCD4node* topvar, NCD4offset* offset)
+NCD4_delimit(NCD4meta* compiler, NCD4node* topvar, NCD4offset* offset, int inferredchecksumming)
{
int ret = NC_NOERR;
NCD4mark mark = 0;
@@ -214,7 +214,7 @@ NCD4_delimit(NCD4meta* compiler, NCD4node* topvar, NCD4offset* offset)
topvar->data.dap4data.memory = mark;
topvar->data.dap4data.size = OFFSETSIZE(offset,mark);
/* extract the dap4 data checksum, if present */
- if(compiler->controller->data.inferredchecksumming) {
+ if(inferredchecksumming) {
union ATOMICS csum;
TRANSFER(csum.u8,offset,CHECKSUMSIZE);
topvar->data.remotechecksum = csum.u32[0];
diff --git a/libdap4/d4http.c b/libdap4/d4http.c
index 8e370d8793..13cb82a193 100644
--- a/libdap4/d4http.c
+++ b/libdap4/d4http.c
@@ -6,7 +6,6 @@
#include "d4includes.h"
#include "d4curlfunctions.h"
-static size_t WriteFileCallback(void*, size_t, size_t, void*);
static size_t WriteMemoryCallback(void*, size_t, size_t, void*);
static int curlerrtoncerr(CURLcode cstat);
@@ -33,59 +32,6 @@ NCD4_fetchhttpcode(CURL* curl)
return httpcode;
}
-int
-NCD4_fetchurl_file(CURL* curl, const char* url, FILE* stream,
- d4size_t* sizep, long* filetime)
-{
- int ret = NC_NOERR;
- CURLcode cstat = CURLE_OK;
- struct Fetchdata fetchdata;
-
- /* Set the URL */
- cstat = curl_easy_setopt(curl, CURLOPT_URL, (void*)url);
- if (cstat != CURLE_OK) goto fail;
-
- /* send all data to this function */
- cstat = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteFileCallback);
- if (cstat != CURLE_OK) goto fail;
-
- /* we pass our file to the callback function */
- cstat = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&fetchdata);
- if(cstat != CURLE_OK) goto fail;
-
- /* One last thing; always try to get the last modified time */
- cstat = curl_easy_setopt(curl, CURLOPT_FILETIME, (long)1);
- if (cstat != CURLE_OK) goto fail;
-
- fetchdata.stream = stream;
- fetchdata.size = 0;
- cstat = curl_easy_perform(curl);
- if (cstat != CURLE_OK)
- {ret = NC_EDAPSVC; goto fail;}
-
- if (ret == NC_NOERR) {
- /* return the file size*/
-#ifdef D4DEBUG
- nclog(NCLOGNOTE,"filesize: %lu bytes",fetchdata.size);
-#endif
- if (sizep != NULL)
- *sizep = fetchdata.size;
- /* Get the last modified time */
- if(filetime != NULL)
- cstat = curl_easy_getinfo(curl,CURLINFO_FILETIME,filetime);
- if(cstat != CURLE_OK)
- {ret = NC_ECURL; goto fail;}
- }
- return THROW(ret);
-
-fail:
- if(cstat != CURLE_OK) {
- nclog(NCLOGERR, "curl error: %s", curl_easy_strerror(cstat));
- ret = curlerrtoncerr(cstat);
- }
- return THROW(ret);
-}
-
int
NCD4_fetchurl(CURL* curl, const char* url, NCbytes* buf, long* filetime, int* httpcodep)
{
@@ -155,27 +101,6 @@ NCD4_fetchurl(CURL* curl, const char* url, NCbytes* buf, long* filetime, int* ht
return THROW(ret);
}
-static size_t
-WriteFileCallback(void* ptr, size_t size, size_t nmemb, void* data)
-{
- size_t realsize = size * nmemb;
- size_t count;
- struct Fetchdata* fetchdata;
- fetchdata = (struct Fetchdata*) data;
- if(realsize == 0)
- nclog(NCLOGWARN,"WriteFileCallback: zero sized chunk");
- count = fwrite(ptr, size, nmemb, fetchdata->stream);
- if (count > 0) {
- fetchdata->size += (count * size);
- } else {
- nclog(NCLOGWARN,"WriteFileCallback: zero sized write");
- }
-#ifdef PROGRESS
- nclog(NCLOGNOTE,"callback: %lu bytes",(d4size_t)realsize);
-#endif
- return count;
-}
-
static size_t
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
diff --git a/libdap4/d4meta.c b/libdap4/d4meta.c
index 4293b3727c..1cea62f613 100644
--- a/libdap4/d4meta.c
+++ b/libdap4/d4meta.c
@@ -89,75 +89,6 @@ NCD4_metabuild(NCD4meta* metadata, int ncid)
return THROW(ret);
}
-
-/* Create an empty NCD4meta object for
- use in subsequent calls
- (is the the right src file to hold this?)
-*/
-
-NCD4meta*
-NCD4_newmeta(NCD4INFO* info)
-{
- NCD4meta* meta = (NCD4meta*)calloc(1,sizeof(NCD4meta));
- if(meta == NULL) return NULL;
- meta->allnodes = nclistnew();
-#ifdef D4DEBUG
- meta->debuglevel = 1;
-#endif
- meta->controller = info;
- meta->ncid = info->substrate.nc4id; /* Transfer netcdf ncid */
- return meta;
-}
-
-/* Attach raw data to metadata */
-void
-NCD4_attachraw(NCD4meta* meta, size_t rawsize, void* rawdata)
-{
- assert(meta != NULL);
- NCD4_resetSerial(&meta->serial,rawsize,rawdata);
-}
-
-void
-NCD4_setdebuglevel(NCD4meta* meta, int debuglevel)
-{
- meta->debuglevel = debuglevel;
-}
-
-void
-NCD4_reclaimMeta(NCD4meta* dataset)
-{
- int i;
- if(dataset == NULL) return;
- NCD4_resetMeta(dataset);
-
- for(i=0;iallnodes);i++) {
- NCD4node* node = (NCD4node*)nclistget(dataset->allnodes,i);
- reclaimNode(node);
- }
- nclistfree(dataset->allnodes);
- nclistfree(dataset->groupbyid);
- nclistfree(dataset->atomictypes);
- free(dataset);
-}
-
-void
-NCD4_resetMeta(NCD4meta* dataset)
-{
- if(dataset == NULL) return;
- nullfree(dataset->error.parseerror); dataset->error.parseerror = NULL;
- nullfree(dataset->error.message); dataset->error.message = NULL;
- nullfree(dataset->error.context); dataset->error.context = NULL;
- nullfree(dataset->error.otherinfo); dataset->error.otherinfo = NULL;
- NCD4_resetSerial(&dataset->serial,0,NULL);
-#if 0
- for(i=0;iblobs);i++) {
- void* p = nclistget(dataset->blobs,i);
- nullfree(p);
- }
- nclistfree(dataset->blobs);
-#endif
-}
-
void
reclaimNode(NCD4node* node)
{
@@ -676,6 +607,39 @@ savevarbyid(NCD4node* group, NCD4node* var)
nclistinsert(group->group.varbyid,var->meta.id,var);
}
+/* Collect FQN path from var node up to and including
+ the root group and create an name from it
+*/
+char*
+NCD4_getVarFQN(NCD4node* var, const char* tail)
+{
+ int i;
+ NCD4node* x = NULL;
+ NClist* path = NULL;
+ NCbytes* fqn = NULL;
+ char* result;
+
+ path = nclistnew();
+ for(x=var->container;ISGROUP(x->sort);x=x->container) {
+ nclistinsert(path,0,x);
+ }
+ fqn = ncbytesnew();
+ for(i=0;iname);
+ if(escaped == NULL) return NULL;
+ if(i > 0) ncbytesappend(fqn,'/');
+ ncbytescat(fqn,escaped);
+ free(escaped);
+ }
+ nclistfree(path);
+ if(tail != NULL)
+ ncbytescat(fqn,tail);
+ result = ncbytesextract(fqn);
+ ncbytesfree(fqn);
+ return result;
+}
+
/* Collect FQN path from node up to (but not including)
the first enclosing group and create an name from it
*/
@@ -1180,7 +1144,7 @@ markdapsize(NCD4meta* meta)
}
int
-NCD4_findvar(NC* ncp, int ncid, int varid, NCD4node** varp, NCD4node** grpp)
+NCD4_findvar(NC* ncp, int gid, int varid, NCD4node** varp, NCD4node** grpp)
{
int ret = NC_NOERR;
NCD4INFO* info = NULL;
@@ -1192,11 +1156,11 @@ NCD4_findvar(NC* ncp, int ncid, int varid, NCD4node** varp, NCD4node** grpp)
info = getdap(ncp);
if(info == NULL)
return THROW(NC_EBADID);
- meta = info->substrate.metadata;
+ meta = info->dmrmetadata;
if(meta == NULL)
return THROW(NC_EBADID);
/* Locate var node via (grpid,varid) */
- grp_id = GROUPIDPART(ncid);
+ grp_id = GROUPIDPART(gid);
group = nclistget(meta->groupbyid,grp_id);
if(group == NULL)
return THROW(NC_EBADID);
@@ -1205,7 +1169,7 @@ NCD4_findvar(NC* ncp, int ncid, int varid, NCD4node** varp, NCD4node** grpp)
return THROW(NC_EBADID);
if(varp) *varp = var;
if(grpp) *grpp = group;
- return ret;
+ return THROW(ret);
}
static int
diff --git a/libdap4/d4odom.c b/libdap4/d4odom.c
index 1b7f650810..ed7d4639fd 100644
--- a/libdap4/d4odom.c
+++ b/libdap4/d4odom.c
@@ -78,7 +78,7 @@ d4odom_print(D4odometer* odom)
if(odom->rank == 0) {
strlcat(line,"[]",sizeof(line));
} else for(i=0;irank;i++) {
- sprintf(tmp,"[%lu/%lu:%lu:%lu]",
+ snprintf(tmp,sizeof(tmp),"[%lu/%lu:%lu:%lu]",
(size_t)odom->index[i],
(size_t)odom->start[i],
(size_t)odom->stride[i],
diff --git a/libdap4/d4parser.c b/libdap4/d4parser.c
index 013e320928..2948f80672 100644
--- a/libdap4/d4parser.c
+++ b/libdap4/d4parser.c
@@ -154,7 +154,7 @@ static int defineBytestringType(NCD4parser*);
/* API */
int
-NCD4_parse(NCD4meta* metadata)
+NCD4_parse(NCD4meta* metadata, NCD4response* resp, int dapparse)
{
int ret = NC_NOERR;
NCD4parser* parser = NULL;
@@ -168,8 +168,10 @@ NCD4_parse(NCD4meta* metadata)
/* Create and fill in the parser state */
parser = (NCD4parser*)calloc(1,sizeof(NCD4parser));
if(parser == NULL) {ret=NC_ENOMEM; goto done;}
+ parser->controller = metadata->controller;
parser->metadata = metadata;
- doc = ncxml_parse(parser->metadata->serial.dmr,strlen(parser->metadata->serial.dmr));
+ parser->response = resp;
+ doc = ncxml_parse(parser->response->serial.dmr,strlen(parser->response->serial.dmr));
if(doc == NULL) {ret=NC_ENOMEM; goto done;}
dom = ncxml_root(doc);
parser->types = nclistnew();
@@ -178,6 +180,7 @@ NCD4_parse(NCD4meta* metadata)
#ifdef D4DEBUG
parser->debuglevel = 1;
#endif
+ parser->dapparse = dapparse;
/*Walk the DOM tree to build the DAP4 node tree*/
ret = traverse(parser,dom);
@@ -214,9 +217,9 @@ traverse(NCD4parser* parser, ncxml_t dom)
ret=parseError(parser,dom);
/* Report the error */
fprintf(stderr,"DAP4 Error: http-code=%d message=\"%s\" context=\"%s\"\n",
- parser->metadata->error.httpcode,
- parser->metadata->error.message,
- parser->metadata->error.context);
+ parser->response->error.httpcode,
+ parser->response->error.message,
+ parser->response->error.context);
fflush(stderr);
ret=NC_EDMR;
goto done;
@@ -225,7 +228,8 @@ traverse(NCD4parser* parser, ncxml_t dom)
if((ret=makeNode(parser,NULL,NULL,NCD4_GROUP,NC_NULL,&parser->metadata->root))) goto done;
parser->metadata->root->group.isdataset = 1;
parser->metadata->root->meta.id = parser->metadata->ncid;
- parser->metadata->groupbyid = nclistnew();
+ if(parser->metadata->groupbyid == NULL)
+ parser->metadata->groupbyid = nclistnew();
SETNAME(parser->metadata->root,"/");
xattr = ncxml_attr(dom,"name");
if(xattr != NULL) parser->metadata->root->group.datasetname = xattr;
@@ -847,23 +851,23 @@ parseError(NCD4parser* parser, ncxml_t errxml)
char* shttpcode = ncxml_attr(errxml,"httpcode");
ncxml_t x;
if(shttpcode == NULL) shttpcode = strdup("400");
- if(sscanf(shttpcode,"%d",&parser->metadata->error.httpcode) != 1)
+ if(sscanf(shttpcode,"%d",&parser->response->error.httpcode) != 1)
nclog(NCLOGERR,"Malformed response");
nullfree(shttpcode);
x=ncxml_child(errxml, "Message");
if(x != NULL) {
char* txt = ncxml_text(x);
- parser->metadata->error.message = (txt == NULL ? NULL : txt);
+ parser->response->error.message = (txt == NULL ? NULL : txt);
}
x = ncxml_child(errxml, "Context");
if(x != NULL) {
const char* txt = ncxml_text(x);
- parser->metadata->error.context = (txt == NULL ? NULL : strdup(txt));
+ parser->response->error.context = (txt == NULL ? NULL : strdup(txt));
}
x=ncxml_child(errxml, "OtherInformation");
if(x != NULL) {
const char* txt = ncxml_text(x);
- parser->metadata->error.otherinfo = (txt == NULL ? NULL : strdup(txt));
+ parser->response->error.otherinfo = (txt == NULL ? NULL : strdup(txt));
}
return THROW(NC_NOERR);
}
@@ -1321,7 +1325,7 @@ makeNode(NCD4parser* parser, NCD4node* parent, ncxml_t xml, NCD4sort sort, nc_ty
record(parser,node);
if(nodep) *nodep = node;
done:
- return ret;
+ return THROW(ret);
}
static int
@@ -1652,12 +1656,19 @@ parseForwards(NCD4parser* parser, NCD4node* root)
const char* mapname = (const char*)nclistget(var->mapnames,j);
/* Find the corresponding variable */
NCD4node* mapref = lookupFQN(parser,mapname,NCD4_VAR);
- if(mapref == NULL)
+ if(mapref != NULL)
+ PUSH(var->maps,mapref);
+ else if(!parser->dapparse)
FAIL(NC_ENOTVAR,"